
com.ibm.wala.shrike.cg.OfflineDynamicCallGraph Maven / Gradle / Ivy
Show all versions of com.ibm.wala.shrike Show documentation
/*
* Copyright (c) 2002,2006 IBM Corporation.
* All rights reserved. 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*/
package com.ibm.wala.shrike.cg;
import com.ibm.wala.shrike.shrikeBT.ConstantInstruction;
import com.ibm.wala.shrike.shrikeBT.Constants;
import com.ibm.wala.shrike.shrikeBT.Disassembler;
import com.ibm.wala.shrike.shrikeBT.IInvokeInstruction;
import com.ibm.wala.shrike.shrikeBT.IInvokeInstruction.Dispatch;
import com.ibm.wala.shrike.shrikeBT.InvokeDynamicInstruction;
import com.ibm.wala.shrike.shrikeBT.InvokeInstruction;
import com.ibm.wala.shrike.shrikeBT.LoadInstruction;
import com.ibm.wala.shrike.shrikeBT.MethodData;
import com.ibm.wala.shrike.shrikeBT.MethodEditor;
import com.ibm.wala.shrike.shrikeBT.MethodEditor.Output;
import com.ibm.wala.shrike.shrikeBT.ReturnInstruction;
import com.ibm.wala.shrike.shrikeBT.ThrowInstruction;
import com.ibm.wala.shrike.shrikeBT.Util;
import com.ibm.wala.shrike.shrikeBT.analysis.Analyzer.FailureException;
import com.ibm.wala.shrike.shrikeBT.analysis.ClassHierarchyStore;
import com.ibm.wala.shrike.shrikeBT.analysis.Verifier;
import com.ibm.wala.shrike.shrikeBT.shrikeCT.CTUtils;
import com.ibm.wala.shrike.shrikeBT.shrikeCT.ClassInstrumenter;
import com.ibm.wala.shrike.shrikeBT.shrikeCT.OfflineInstrumenter;
import com.ibm.wala.shrike.shrikeCT.ClassReader;
import com.ibm.wala.shrike.shrikeCT.ClassWriter;
import com.ibm.wala.shrike.shrikeCT.ConstantPoolParser;
import com.ibm.wala.shrike.shrikeCT.InvalidClassFileException;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.config.FileOfClasses;
import com.ibm.wala.util.config.SetOfClasses;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Map;
/**
* Class files are taken as input arguments (or if there are none, from standard input). The methods
* in those files are instrumented: we insert a System.err.println() at ever method call, and a
* System.err.println() at every method entry.
*
* The instrumented classes are placed in the directory "output" under the current directory.
* Disassembled code is written to the file "report" under the current directory.
*
* @author CHammer
* @author Julian Dolby ([email protected])
* @since 10/18
*/
public class OfflineDynamicCallGraph {
private static class AddTracingToInvokes extends MethodEditor.Visitor {
@Override
public void visitInvoke(IInvokeInstruction inv) {
final String calleeClass = inv.getClassType();
final String calleeMethod = inv.getMethodName() + inv.getMethodSignature();
addInstructionExceptionHandler(
/*"java.lang.Throwable"*/ null,
new MethodEditor.Patch() {
@Override
public void emitTo(MethodEditor.Output w) {
w.emit(Util.makeInvoke(runtime, "pop", new Class[] {}));
w.emit(ThrowInstruction.make(true));
}
});
insertBefore(
new MethodEditor.Patch() {
@Override
public void emitTo(MethodEditor.Output w) {
w.emit(ConstantInstruction.makeString(calleeClass));
w.emit(ConstantInstruction.makeString(calleeMethod));
// target unknown
w.emit(Util.makeGet(runtime, "NULL_TAG"));
// w.emit(ConstantInstruction.make(Constants.TYPE_null, null));
w.emit(
Util.makeInvoke(
runtime,
"addToCallStack",
new Class[] {String.class, String.class, Object.class}));
}
});
insertAfter(
new MethodEditor.Patch() {
@Override
public void emitTo(MethodEditor.Output w) {
w.emit(Util.makeInvoke(runtime, "pop", new Class[] {}));
}
});
}
}
private static final boolean disasm = true;
private static final boolean verify = true;
private static boolean patchExits = true;
private static boolean patchCalls = true;
private static final boolean extractCalls = true;
private static boolean extractDynamicCalls = false;
private static boolean extractConstructors = true;
private static Class> runtime = Runtime.class;
private static SetOfClasses filter;
private static final ClassHierarchyStore cha = new ClassHierarchyStore();
public static void main(String[] args)
throws IOException, ClassNotFoundException, InvalidClassFileException, FailureException {
OfflineInstrumenter instrumenter;
ClassInstrumenter ci;
try (final Writer w = new BufferedWriter(new FileWriter("build/report", false))) {
for (int i = 0; i < args.length; i++) {
if ("--runtime".equals(args[i])) {
runtime = Class.forName(args[i + 1]);
} else if ("--exclusions".equals(args[i])) {
try (FileInputStream input = new FileInputStream(args[i + 1])) {
filter = new FileOfClasses(input);
}
} else if ("--dont-patch-exits".equals(args[i])) {
patchExits = false;
} else if ("--patch-calls".equals(args[i])) {
patchCalls = true;
} else if ("--extract-dynamic-calls".equals(args[i])) {
extractDynamicCalls = true;
} else if ("--extract-constructors".equals(args[i])) {
extractConstructors = true;
} else if ("--rt-jar".equals(args[i])) {
System.err.println("using " + args[i + 1] + " as stdlib");
OfflineInstrumenter libReader = new OfflineInstrumenter();
libReader.addInputJar(new File(args[i + 1]));
while ((ci = libReader.nextClass()) != null) {
CTUtils.addClassToHierarchy(cha, ci.getReader());
}
}
}
instrumenter = new OfflineInstrumenter();
args = instrumenter.parseStandardArgs(args);
instrumenter.setPassUnmodifiedClasses(true);
instrumenter.beginTraversal();
while ((ci = instrumenter.nextClass()) != null) {
CTUtils.addClassToHierarchy(cha, ci.getReader());
}
instrumenter.setClassHierarchyProvider(cha);
instrumenter.beginTraversal();
while ((ci = instrumenter.nextClass()) != null) {
ClassWriter cw = doClass(ci, w);
if (cw != null) {
instrumenter.outputModifiedClass(ci, cw);
}
}
}
instrumenter.close();
}
static ClassWriter doClass(final ClassInstrumenter ci, Writer w)
throws InvalidClassFileException, IOException, FailureException {
final String className = ci.getReader().getName();
if (filter != null && filter.contains(className)) {
return null;
}
if (disasm) {
w.write("Class: " + className + '\n');
w.flush();
}
final ClassReader r = ci.getReader();
final Map