org.scandroid.synthmethod.XMLSummaryWriter Maven / Gradle / Ivy
Show all versions of com.ibm.wala.scandroid Show documentation
/*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
* Copyright (c) 2009-2012,
*
* Galois, Inc. (Aaron Tomb , Rogan Creswick , Adam
* Foltzer ) Steve Suh
*
* All rights reserved.
*
*
Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
*
1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
*
2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
*
*
3. The names of the contributors may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.scandroid.synthmethod;
import com.ibm.wala.ipa.summaries.MethodSummary;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.strings.Atom;
import java.io.ByteArrayOutputStream;
import java.io.UTFDataFormatException;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class XMLSummaryWriter {
//
// Define XML element names
//
static final String E_CLASSLOADER = "classloader";
static final String E_METHOD = "method";
static final String E_CLASS = "class";
static final String E_PACKAGE = "package";
static final String E_CALL = "call";
static final String E_NEW = "new";
static final String E_POISON = "poison";
static final String E_SUMMARY_SPEC = "summary-spec";
static final String E_RETURN = "return";
static final String E_PUTSTATIC = "putstatic";
static final String E_GETSTATIC = "getstatic";
static final String E_PUTFIELD = "putfield";
static final String E_AALOAD = "aaload";
static final String E_AASTORE = "aastore";
static final String E_GETFIELD = "getfield";
static final String E_ATHROW = "throw";
static final String E_CONSTANT = "constant";
//
// Define XML attribute names
//
static final String A_NAME = "name";
static final String A_TYPE = "type";
static final String A_CLASS = "class";
static final String A_SIZE = "size";
static final String A_DESCRIPTOR = "descriptor";
static final String A_REASON = "reason";
static final String A_LEVEL = "level";
static final String A_WILDCARD = "*";
static final String A_DEF = "def";
static final String A_STATIC = "static";
static final String A_VALUE = "value";
static final String A_FIELD = "field";
static final String A_FIELD_TYPE = "fieldType";
static final String A_ARG = "arg";
static final String A_ALLOCATABLE = "allocatable";
static final String A_REF = "ref";
static final String A_INDEX = "index";
static final String A_IGNORE = "ignore";
static final String A_FACTORY = "factory";
static final String A_NUM_ARGS = "numArgs";
static final String V_NULL = "null";
static final String V_TRUE = "true";
private final Document doc;
private final Element rootElement;
private Element clrElt = null;
private Element pkgElt = null;
private final Map classElts;
public XMLSummaryWriter() throws ParserConfigurationException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
doc = docBuilder.newDocument();
rootElement = doc.createElement(E_SUMMARY_SPEC);
doc.appendChild(rootElement);
classElts = HashMapFactory.make();
}
public String serialize() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
// transformerFactory.setAttribute("indent-number", new Integer(4));
try {
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(baos);
transformer.transform(source, result);
} catch (TransformerException | IllegalArgumentException e) {
e.printStackTrace();
}
// using the default encoding here, since the bytes were just written
// with a default encoding...
return baos.toString();
}
/**
* Throws various exceptions if a problem occurred serializing this method.
*
* No guarantees as to the state of the Document if an exception is thrown.
*/
public void add(MethodSummary summary) throws UTFDataFormatException {
// create a method element, and populate it's attributes:
Element methElt;
TypeReference methClass = summary.getMethod().getDeclaringClass();
Atom clrName = methClass.getClassLoader().getName();
Atom pkg = methClass.getName().getPackage();
Atom className = methClass.getName().getClassName();
Atom methodName = summary.getMethod().getName();
methElt = doc.createElement(E_METHOD);
methElt.setAttribute(A_NAME, methodName.toUnicodeString());
String descriptor = getMethodDescriptor(summary);
methElt.setAttribute(A_DESCRIPTOR, descriptor);
// default is false:
if (summary.isStatic()) {
methElt.setAttribute(A_STATIC, "true");
}
// default is false:
if (summary.isFactory()) {
methElt.setAttribute(A_FACTORY, "true");
}
// summarize the instructions:
List instructions = summarizeInstructions(summary);
for (Element elt : instructions) {
methElt.appendChild(elt);
}
// get an element to add this method to:
Element classElt = findOrCreateClassElt(clrName, pkg, className);
classElt.appendChild(methElt);
}
private Element findOrCreateClassElt(Atom classLoaderName, Atom pkg, Atom className)
throws UTFDataFormatException {
Element classElt = classElts.get(className);
if (classElt == null) {
Element pkgElt = findOrCreatePkgElt(classLoaderName, pkg);
classElt = doc.createElement(E_CLASS);
classElt.setAttribute(A_NAME, className.toUnicodeString());
pkgElt.appendChild(classElt);
classElts.put(className, classElt);
}
return classElt;
}
private Element findOrCreateClrElt(Atom classLoaderName)
throws DOMException, UTFDataFormatException {
if (clrElt == null) {
clrElt = doc.createElement(E_CLASSLOADER);
clrElt.setAttribute(A_NAME, classLoaderName.toUnicodeString());
rootElement.appendChild(clrElt);
}
return clrElt;
}
private Element findOrCreatePkgElt(Atom classLoaderName, Atom pkg) throws UTFDataFormatException {
if (pkgElt == null) {
Element clrElt = findOrCreateClrElt(classLoaderName);
pkgElt = doc.createElement(E_PACKAGE);
pkgElt.setAttribute(A_NAME, pkg.toUnicodeString());
clrElt.appendChild(pkgElt);
}
return pkgElt;
}
private List summarizeInstructions(MethodSummary summary) {
SSAtoXMLVisitor v = new SSAtoXMLVisitor(doc, summary.getNumberOfParameters());
for (SSAInstruction inst : summary.getStatements()) {
inst.visit(v);
}
return v.getInstSummary();
}
/** Generate a method descriptor, such as (I[Ljava/lang/String;)[Ljava/lang/String; */
private static String getMethodDescriptor(MethodSummary summary) {
StringBuilder typeSigs = new StringBuilder("(");
int i = 0;
if (!summary.isStatic()) {
i = 1; // if it's not static, start with param 1.
}
for (; i < summary.getNumberOfParameters(); i++) {
TypeReference tr = summary.getParameterType(i);
// unwrap array types
while (tr.isArrayType()) {
typeSigs.append('[');
tr = tr.getArrayElementType();
}
if (tr.isPrimitiveType()) {
typeSigs.append(tr.getName().toUnicodeString());
} else {
typeSigs.append(tr.getName().toUnicodeString()).append(';');
}
}
typeSigs.append(')');
TypeReference returnType = summary.getReturnType();
if (returnType.isPrimitiveType()) {
typeSigs.append(returnType.getName().toUnicodeString());
} else {
typeSigs.append(returnType.getName().toUnicodeString()).append(';');
}
String descriptor = typeSigs.toString();
return descriptor;
}
}