WALA/com.ibm.wala.scandroid/source/org/scandroid/synthmethod/XMLSummaryWriter.java

306 lines
11 KiB
Java

/*
* 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 <atomb@galois.com>,
* Rogan Creswick <creswick@galois.com>,
* Adam Foltzer <acfoltzer@galois.com>)
* Steve Suh <suhsteve@gmail.com>
*
* 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 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.TransformerConfigurationException;
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;
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;
public class XMLSummaryWriter {
//
// Define XML element names
//
final static String E_CLASSLOADER = "classloader";
final static String E_METHOD = "method";
final static String E_CLASS = "class";
final static String E_PACKAGE = "package";
final static String E_CALL = "call";
final static String E_NEW = "new";
final static String E_POISON = "poison";
final static String E_SUMMARY_SPEC = "summary-spec";
final static String E_RETURN = "return";
final static String E_PUTSTATIC = "putstatic";
final static String E_GETSTATIC = "getstatic";
final static String E_PUTFIELD = "putfield";
final static String E_AALOAD = "aaload";
final static String E_AASTORE = "aastore";
final static String E_GETFIELD = "getfield";
final static String E_ATHROW = "throw";
final static String E_CONSTANT = "constant";
//
// Define XML attribute names
//
final static String A_NAME = "name";
final static String A_TYPE = "type";
final static String A_CLASS = "class";
final static String A_SIZE = "size";
final static String A_DESCRIPTOR = "descriptor";
final static String A_REASON = "reason";
final static String A_LEVEL = "level";
final static String A_WILDCARD = "*";
final static String A_DEF = "def";
final static String A_STATIC = "static";
final static String A_VALUE = "value";
final static String A_FIELD = "field";
final static String A_FIELD_TYPE = "fieldType";
final static String A_ARG = "arg";
final static String A_ALLOCATABLE = "allocatable";
final static String A_REF = "ref";
final static String A_INDEX = "index";
final static String A_IGNORE = "ignore";
final static String A_FACTORY = "factory";
final static String A_NUM_ARGS = "numArgs";
final static String V_NULL = "null";
final static String V_TRUE = "true";
private final Document doc;
private final Element rootElement;
private Element clrElt = null;
private Element pkgElt = null;
private final Map<Atom, Element> 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 (TransformerConfigurationException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (TransformerException 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.
*
* @param summary
* @throws DOMException
* @throws UTFDataFormatException
* @throws SSASerializationException
*/
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<Element> 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<Element> 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;
*
* @param summary
*/
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()+ ";");
}
}
typeSigs.append(")");
TypeReference returnType = summary.getReturnType();
if (returnType.isPrimitiveType()) {
typeSigs.append(returnType.getName().toUnicodeString());
} else {
typeSigs.append(returnType.getName().toUnicodeString() + ";");
}
String descriptor = typeSigs.toString();
return descriptor;
}
}