1) new support for function.prototype.apply in field-based CGs
2) fixes to Dalvik bytecode reader 3) fixes to Shrike writing Java 7 byte code
This commit is contained in:
parent
6aa3646849
commit
096e2f796f
|
@ -2,8 +2,13 @@ function f(g) {
|
|||
g();
|
||||
}
|
||||
|
||||
function x() {
|
||||
|
||||
}
|
||||
|
||||
function h() {
|
||||
f.call(null, k);
|
||||
x.apply(null, []);
|
||||
}
|
||||
|
||||
function k() {}
|
||||
|
|
|
@ -71,8 +71,8 @@ escape = function escape(str){
|
|||
/************************************************************************/
|
||||
/* Object properties, see spec 15.2 */
|
||||
/************************************************************************/
|
||||
|
||||
Object.prototype = {
|
||||
|
||||
Object$proto$__WALA__ = {
|
||||
|
||||
prototype: null,
|
||||
|
||||
|
@ -103,13 +103,13 @@ Object.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
Object.prototype = Object$proto$__WALA__;
|
||||
|
||||
/************************************************************************/
|
||||
/* Function properties, see spec 15.3 */
|
||||
/************************************************************************/
|
||||
|
||||
local_function.prototype = {
|
||||
Function$proto$__WALA__ = {
|
||||
|
||||
constructor: Function,
|
||||
|
||||
|
@ -134,6 +134,8 @@ local_function.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
local_function.prototype = Function$proto$__WALA__;
|
||||
|
||||
local_function.__proto__ = Function.prototype;
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -142,7 +144,7 @@ local_function.__proto__ = Function.prototype;
|
|||
|
||||
local_array.__proto__ = Function.prototype;
|
||||
|
||||
local_array.prototype = {
|
||||
Array$proto$__WALA__ = {
|
||||
|
||||
__proto__: Object.prototype,
|
||||
|
||||
|
@ -327,6 +329,7 @@ Array.isArray = function Array_isArray(a) {
|
|||
return true || false;
|
||||
};
|
||||
|
||||
local_array.prototype = Array$proto$__WALA__;
|
||||
|
||||
/************************************************************************/
|
||||
/* String properties, see spec 15.4 */
|
||||
|
@ -334,7 +337,7 @@ Array.isArray = function Array_isArray(a) {
|
|||
|
||||
local_string.__proto__ = Function.prototype;
|
||||
|
||||
local_string.prototype = {
|
||||
String$proto$__WALA__ = {
|
||||
|
||||
__proto__: Object.prototype,
|
||||
|
||||
|
@ -436,6 +439,7 @@ local_string.prototype = {
|
|||
|
||||
};
|
||||
|
||||
local_string.prototype = String$proto$__WALA__;
|
||||
|
||||
/************************************************************************/
|
||||
/* Number properties, see spec 15.7 */
|
||||
|
@ -443,7 +447,7 @@ local_string.prototype = {
|
|||
|
||||
local_number.__proto__ = Function.prototype;
|
||||
|
||||
local_number.prototype = {
|
||||
Number$proto$__WALA__ = {
|
||||
|
||||
__proto__: Object.prototype,
|
||||
|
||||
|
@ -457,6 +461,7 @@ local_number.prototype = {
|
|||
|
||||
};
|
||||
|
||||
local_number.prototype = Number$proto$__WALA__;
|
||||
|
||||
/************************************************************************/
|
||||
/* Math properties, see spec 15.8 */
|
||||
|
@ -537,7 +542,7 @@ Math = {
|
|||
|
||||
local_regexp.__proto__ = Function.prototype;
|
||||
|
||||
local_regexp.prototype = {
|
||||
RegExp$proto$__WALA__ = {
|
||||
|
||||
__proto__: Object.prototype,
|
||||
|
||||
|
@ -553,6 +558,7 @@ local_regexp.prototype = {
|
|||
|
||||
};
|
||||
|
||||
local_regexp.prototype = RegExp$proto$__WALA__;
|
||||
|
||||
/************************************************************************/
|
||||
/* Date properties, see spec 15.9 */
|
||||
|
@ -560,7 +566,7 @@ local_regexp.prototype = {
|
|||
|
||||
Date = function Date() {};
|
||||
|
||||
Date.prototype = {
|
||||
Data$proto$__WALA__ = {
|
||||
|
||||
__proto__: Object.prototype,
|
||||
|
||||
|
@ -636,6 +642,13 @@ Date.now = function Date_now() {
|
|||
return new Date().valueOf();
|
||||
};
|
||||
|
||||
Date.prototype = Data$proto$__WALA__;
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* internal stuff
|
||||
/************************************************************************/
|
||||
|
||||
function Error(str) {
|
||||
this.message = new String();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.VertexFactor
|
|||
import com.ibm.wala.cast.js.ipa.callgraph.JSAnalysisOptions;
|
||||
import com.ibm.wala.cast.js.ipa.callgraph.JSCallGraph;
|
||||
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptConstructTargetSelector;
|
||||
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptFunctionApplyContextInterpreter;
|
||||
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptFunctionApplyTargetSelector;
|
||||
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptFunctionDotCallTargetSelector;
|
||||
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions;
|
||||
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions.JavaScriptConstructor;
|
||||
|
@ -87,8 +89,7 @@ public abstract class FieldBasedCallGraphBuilder {
|
|||
private MethodTargetSelector setupMethodTargetSelector(IClassHierarchy cha, JavaScriptConstructorFunctions constructors2, AnalysisOptions options) {
|
||||
MethodTargetSelector result = new JavaScriptConstructTargetSelector(constructors2, options.getMethodTargetSelector());
|
||||
if (options instanceof JSAnalysisOptions && ((JSAnalysisOptions)options).handleCallApply()) {
|
||||
// TODO handle Function.prototype.apply
|
||||
result = new JavaScriptFunctionDotCallTargetSelector(result);
|
||||
result = new JavaScriptFunctionApplyTargetSelector(new JavaScriptFunctionDotCallTargetSelector(result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -141,7 +142,13 @@ public abstract class FieldBasedCallGraphBuilder {
|
|||
// set up call graph
|
||||
final JSCallGraph cg = new JSCallGraph(cha, options, cache);
|
||||
cg.init();
|
||||
cg.setInterpreter(new DelegatingSSAContextInterpreter(new AstContextInsensitiveSSAContextInterpreter(options, cache), new DefaultSSAInterpreter(options, cache)));
|
||||
|
||||
// setup context interpreters
|
||||
DelegatingSSAContextInterpreter interpreter = new DelegatingSSAContextInterpreter(new AstContextInsensitiveSSAContextInterpreter(options, cache), new DefaultSSAInterpreter(options, cache));
|
||||
if (options instanceof JSAnalysisOptions && ((JSAnalysisOptions)options).handleCallApply()) {
|
||||
interpreter = new DelegatingSSAContextInterpreter(new JavaScriptFunctionApplyContextInterpreter(options, cache), interpreter);
|
||||
}
|
||||
cg.setInterpreter(interpreter);
|
||||
|
||||
// set up call edges from fake root to all script nodes
|
||||
AbstractRootMethod fakeRootMethod = (AbstractRootMethod)cg.getFakeRootNode().getMethod();
|
||||
|
@ -167,9 +174,11 @@ public abstract class FieldBasedCallGraphBuilder {
|
|||
IMethod target = targetSelector.getCalleeTarget(caller, site, targetVertex.getConcreteType());
|
||||
boolean isFunctionPrototypeCall = target != null
|
||||
&& target.getName().toString().startsWith(JavaScriptFunctionDotCallTargetSelector.SYNTHETIC_CALL_METHOD_PREFIX);
|
||||
boolean isFunctionPrototypeApply = target != null
|
||||
&& target.getName().toString().startsWith(JavaScriptFunctionApplyTargetSelector.SYNTHETIC_APPLY_METHOD_PREFIX);
|
||||
|
||||
if (isFunctionPrototypeCall) {
|
||||
handleFunctionPrototypeCallInvocation(flowgraph, monitor, cg, callVertex, caller, site, target);
|
||||
if (isFunctionPrototypeCall || isFunctionPrototypeApply) {
|
||||
handleFunctionCallOrApplyInvocation(flowgraph, monitor, cg, callVertex, caller, site, target);
|
||||
} else {
|
||||
addEdgeToJSCallGraph(cg, site, target, caller);
|
||||
|
||||
|
@ -197,7 +206,7 @@ public abstract class FieldBasedCallGraphBuilder {
|
|||
return cg;
|
||||
}
|
||||
|
||||
private boolean handleFunctionPrototypeCallInvocation(FlowGraph flowgraph, IProgressMonitor monitor, final JSCallGraph cg,
|
||||
private boolean handleFunctionCallOrApplyInvocation(FlowGraph flowgraph, IProgressMonitor monitor, final JSCallGraph cg,
|
||||
CallVertex callVertex, CGNode caller, CallSiteReference site,
|
||||
IMethod target) throws CancelException {
|
||||
// use to get 1-level of call string for Function.prototype.call, to
|
||||
|
|
|
@ -83,8 +83,11 @@ public class OptimisticCallgraphBuilder extends FieldBasedCallGraphBuilder {
|
|||
// special handling of invocations of Function.prototype.call
|
||||
// TODO: since we've just added some edges to the flow graph, its transitive closure will be
|
||||
// recomputed here, which is slow and unnecessary
|
||||
if(handleCallApply && edge.snd.getFullName().equals("Lprologue.js/Function_prototype_call"))
|
||||
if(handleCallApply &&
|
||||
(edge.snd.getFullName().equals("Lprologue.js/Function_prototype_call") ||
|
||||
edge.snd.getFullName().equals("Lprologue.js/Function_prototype_apply"))) {
|
||||
addReflectiveCallEdge(flowgraph, edge.fst, monitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -329,7 +329,11 @@ public abstract class BytecodeClass<T extends IClassLoader> implements IClass {
|
|||
*/
|
||||
@Override
|
||||
public Collection<IField> getDeclaredInstanceFields() {
|
||||
return Collections.unmodifiableList(Arrays.asList(instanceFields));
|
||||
if (instanceFields == null) {
|
||||
return Collections.emptySet();
|
||||
} else {
|
||||
return Collections.unmodifiableList(Arrays.asList(instanceFields));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -454,21 +458,13 @@ public abstract class BytecodeClass<T extends IClassLoader> implements IClass {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find it yet. special logic for interfaces
|
||||
if (isInterface() || isAbstract()) {
|
||||
final Iterator<IClass> it = getAllImplementedInterfaces().iterator();
|
||||
// try each superinterface
|
||||
while (it.hasNext()) {
|
||||
IClass k = it.next();
|
||||
result = k.getMethod(selector);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// no method found
|
||||
if (inheritCache == null) {
|
||||
inheritCache = new BimodalMap<Selector, IMethod>(5);
|
||||
}
|
||||
inheritCache.put(selector, null);
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
protected void populateFieldArrayFromList(List<FieldImpl> L, IField[] A) {
|
||||
|
|
|
@ -67,6 +67,7 @@ public class AnalysisOptions {
|
|||
FULL("full", Integer.MAX_VALUE, false, false, false),
|
||||
APPLICATION_GET_METHOD("application_get_method", Integer.MAX_VALUE, false, false, true),
|
||||
NO_FLOW_TO_CASTS("no_flow_to_casts", 0, false, false, false),
|
||||
NO_FLOW_TO_CASTS_APPLICATION_GET_METHOD("no_flow_to_casts_application_get_method", 0, false, false, true),
|
||||
NO_METHOD_INVOKE("no_method_invoke", Integer.MAX_VALUE, true, false, false),
|
||||
NO_FLOW_TO_CASTS_NO_METHOD_INVOKE("no_flow_to_casts_no_method_invoke", 0, true, false, false),
|
||||
ONE_FLOW_TO_CASTS_NO_METHOD_INVOKE("one_flow_to_casts_no_method_invoke", 1, true, false, false),
|
||||
|
|
|
@ -1085,7 +1085,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
@Override
|
||||
public void act(int x) {
|
||||
if (!contentsAreInvariant(symbolTable, du, instruction.getUse(x))) {
|
||||
pks.add(getBuilder().getPointerKeyForLocal(node, instruction.getUse(x)));
|
||||
pks.add(getBuilder().getPointerKeyForLocal(node, instruction.getUse(x)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1532,7 +1532,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
if (constParams != null && constParams[i] != null) {
|
||||
InstanceKey[] ik = constParams[i];
|
||||
for (int j = 0; j < ik.length; j++) {
|
||||
system.newConstraint(formal, ik[j]);
|
||||
system.newConstraint(formal, ik[j]);
|
||||
}
|
||||
} else {
|
||||
if (instruction.getUse(i) < 0) {
|
||||
|
@ -2081,21 +2081,25 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
|
||||
FilteredPointerKey.TypeFilter filter = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.PARAMETERS[index]);
|
||||
if (filter != null && !filter.isRootFilter()) {
|
||||
return pointerKeyFactory.getFilteredPointerKeyForLocal(target, vn, filter);
|
||||
return getFilteredPointerKeyForLocal(target, vn, filter);
|
||||
|
||||
} else if (index == 0 && !target.getMethod().isStatic()) {
|
||||
} else {
|
||||
// the context does not select a particular concrete type for the
|
||||
// receiver, so use the type of the method
|
||||
IClass C = getReceiverClass(target.getMethod());
|
||||
if (C.getClassHierarchy().getRootClass().equals(C)) {
|
||||
return pointerKeyFactory.getPointerKeyForLocal(target, vn);
|
||||
IClass C;
|
||||
if (index == 0 && !target.getMethod().isStatic()) {
|
||||
C = getReceiverClass(target.getMethod());
|
||||
} else {
|
||||
return pointerKeyFactory.getFilteredPointerKeyForLocal(target, vn, new FilteredPointerKey.SingleClassFilter(C));
|
||||
C = cha.lookupClass(target.getMethod().getParameterType(index));
|
||||
}
|
||||
|
||||
} else {
|
||||
return pointerKeyFactory.getPointerKeyForLocal(target, vn);
|
||||
}
|
||||
if (C == null || C.getClassHierarchy().getRootClass().equals(C)) {
|
||||
return getPointerKeyForLocal(target, vn);
|
||||
} else {
|
||||
return getFilteredPointerKeyForLocal(target, vn, new FilteredPointerKey.SingleClassFilter(C));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
java\/awt\/.*
|
||||
javax\/swing\/.*
|
||||
java\/io\/ObjectStreamClass*
|
||||
org\/apache\/xerces\/.*
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.util.Set;
|
|||
|
||||
import com.ibm.wala.classLoader.IMethod;
|
||||
import com.ibm.wala.dalvik.test.callGraph.DalvikCallGraphTestBase;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisOptions.ReflectionOptions;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.CallGraph;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||
|
@ -46,6 +47,7 @@ public class APKCallGraphDriver {
|
|||
|
||||
protected static void doApk(File apk) throws IOException,
|
||||
ClassHierarchyException, CancelException {
|
||||
System.gc();
|
||||
System.err.println("Analyzing " + apk + "...");
|
||||
try {
|
||||
long time = System.currentTimeMillis();
|
||||
|
@ -95,7 +97,7 @@ public class APKCallGraphDriver {
|
|||
return "timeout";
|
||||
}
|
||||
};
|
||||
CG = DalvikCallGraphTestBase.makeAPKCallGraph(apk.getAbsolutePath(), pm).fst;
|
||||
CG = DalvikCallGraphTestBase.makeAPKCallGraph(apk.getAbsolutePath(), pm, ReflectionOptions.NONE).fst;
|
||||
}
|
||||
System.err.println("Analyzed " + apk + " in " + (System.currentTimeMillis() - time));
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
|||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
@ -28,6 +29,7 @@ import java.util.Set;
|
|||
import com.ibm.wala.classLoader.IClass;
|
||||
import com.ibm.wala.classLoader.JarFileModule;
|
||||
import com.ibm.wala.classLoader.Module;
|
||||
import com.ibm.wala.classLoader.NewSiteReference;
|
||||
import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil;
|
||||
import com.ibm.wala.core.tests.shrike.DynamicCallGraphTestBase;
|
||||
import com.ibm.wala.dalvik.classLoader.DexIRFactory;
|
||||
|
@ -36,21 +38,25 @@ import com.ibm.wala.dalvik.util.AndroidEntryPointLocator;
|
|||
import com.ibm.wala.dalvik.util.AndroidEntryPointLocator.LocatorFlags;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisOptions.ReflectionOptions;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.CallGraph;
|
||||
import com.ibm.wala.ipa.callgraph.Entrypoint;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisOptions.ReflectionOptions;
|
||||
import com.ibm.wala.ipa.callgraph.impl.Util;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.cfa.DefaultSSAInterpreter;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.properties.WalaProperties;
|
||||
import com.ibm.wala.shrikeBT.analysis.Analyzer.FailureException;
|
||||
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
import com.ibm.wala.ssa.SSANewInstruction;
|
||||
import com.ibm.wala.types.ClassLoaderReference;
|
||||
import com.ibm.wala.types.MethodReference;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
|
@ -59,7 +65,9 @@ import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
|||
import com.ibm.wala.util.NullProgressMonitor;
|
||||
import com.ibm.wala.util.Predicate;
|
||||
import com.ibm.wala.util.WalaException;
|
||||
import com.ibm.wala.util.collections.FilterIterator;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.MapIterator;
|
||||
import com.ibm.wala.util.collections.Pair;
|
||||
import com.ibm.wala.util.functions.Function;
|
||||
import com.ibm.wala.util.io.TemporaryFile;
|
||||
|
@ -128,8 +136,37 @@ public class DalvikCallGraphTestBase extends DynamicCallGraphTestBase {
|
|||
public static Pair<CallGraph, PointerAnalysis<InstanceKey>> makeAPKCallGraph(String apkFileName) throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException {
|
||||
return makeAPKCallGraph(apkFileName, new NullProgressMonitor());
|
||||
}
|
||||
|
||||
|
||||
public static Pair<CallGraph, PointerAnalysis<InstanceKey>> makeAPKCallGraph(String apkFileName, IProgressMonitor monitor) throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException {
|
||||
return makeAPKCallGraph(apkFileName, monitor, ReflectionOptions.ONE_FLOW_TO_CASTS_APPLICATION_GET_METHOD);
|
||||
}
|
||||
|
||||
private static SSAContextInterpreter makeDefaultInterpreter(AnalysisOptions options, AnalysisCache cache) {
|
||||
return new DefaultSSAInterpreter(options, cache) {
|
||||
@Override
|
||||
public Iterator<NewSiteReference> iterateNewSites(CGNode node) {
|
||||
return
|
||||
new MapIterator<SSAInstruction,NewSiteReference>(
|
||||
new FilterIterator<SSAInstruction>(
|
||||
node.getIR().iterateAllInstructions(),
|
||||
new Predicate<SSAInstruction>() {
|
||||
@Override
|
||||
public boolean test(SSAInstruction t) {
|
||||
return t instanceof SSANewInstruction;
|
||||
}
|
||||
}),
|
||||
new Function<SSAInstruction,NewSiteReference>() {
|
||||
@Override
|
||||
public NewSiteReference apply(SSAInstruction object) {
|
||||
return ((SSANewInstruction)object).getNewSite();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Pair<CallGraph, PointerAnalysis<InstanceKey>> makeAPKCallGraph(String apkFileName, IProgressMonitor monitor, ReflectionOptions policy) throws IOException, ClassHierarchyException, IllegalArgumentException, CancelException {
|
||||
AnalysisScope scope =
|
||||
AndroidAnalysisScope.setUpAndroidAnalysisScope(
|
||||
new File(apkFileName).toURI(),
|
||||
|
@ -150,8 +187,9 @@ public class DalvikCallGraphTestBase extends DynamicCallGraphTestBase {
|
|||
assert ! es.isEmpty();
|
||||
|
||||
AnalysisOptions options = new AnalysisOptions(scope, es);
|
||||
options.setReflectionOptions(ReflectionOptions.ONE_FLOW_TO_CASTS_APPLICATION_GET_METHOD);
|
||||
options.setReflectionOptions(policy);
|
||||
|
||||
// SSAPropagationCallGraphBuilder cgb = Util.makeZeroCFABuilder(options, cache, cha, scope, null, makeDefaultInterpreter(options, cache));
|
||||
SSAPropagationCallGraphBuilder cgb = Util.makeZeroCFABuilder(options, cache, cha, scope);
|
||||
|
||||
CallGraph callGraph = cgb.makeCallGraph(options, monitor);
|
||||
|
|
|
@ -300,11 +300,7 @@ public abstract class AbstractIntRegisterMachine implements FixedPointConstants
|
|||
// e.printStackTrace();
|
||||
// return NOT_CHANGED;
|
||||
|
||||
if (cfg.getDexMethod().getReference().toString().equals("< Application, Lcom/google/android/gms/tagmanager/v$a, onOpen(Landroid/database/sqlite/SQLiteDatabase;)V >")) {
|
||||
System.err.println("got here");
|
||||
}
|
||||
|
||||
if (!bb.isCatchBlock()) {
|
||||
if (!bb.isCatchBlock()) {
|
||||
return meet(lhs, rhs, bb, meeter) ? CHANGED : NOT_CHANGED;
|
||||
} else {
|
||||
return meetForCatchBlock(lhs, rhs, bb, meeter) ? CHANGED : NOT_CHANGED;
|
||||
|
|
|
@ -609,6 +609,7 @@ public class DexSSABuilder extends AbstractIntRegisterMachine {
|
|||
// int val = workingState.pop();
|
||||
// dex does not use this result, but we need it for the SSA CheckCastInstruction
|
||||
int result = reuseOrCreateDef();
|
||||
workingState.setLocal(instruction.object, result);
|
||||
// workingState.push(result);
|
||||
// TypeReference t = instruction.getType();
|
||||
emitInstruction(insts.CheckCastInstruction(getCurrentInstructionIndex(), result, val, instruction.type, instruction.isPEI()));
|
||||
|
@ -1160,9 +1161,6 @@ public class DexSSABuilder extends AbstractIntRegisterMachine {
|
|||
//System.out.println("Instruction: " + getCurrentInstructionIndex());
|
||||
int val = workingState.getLocal(instruction.source);
|
||||
// int val = workingState.pop();
|
||||
int dest = instruction.destination;
|
||||
int result = reuseOrCreateDef();
|
||||
setLocal(dest, result);
|
||||
// workingState.push(result);
|
||||
if(instruction.isConversion())
|
||||
{
|
||||
|
@ -1234,13 +1232,14 @@ public class DexSSABuilder extends AbstractIntRegisterMachine {
|
|||
default:
|
||||
throw new IllegalArgumentException("unknown conversion type "+instruction.op+" in unary instruction: "+instruction);
|
||||
}
|
||||
int dest = instruction.destination;
|
||||
int result = reuseOrCreateDef();
|
||||
setLocal(dest, result);
|
||||
emitInstruction(insts.ConversionInstruction(getCurrentInstructionIndex(), result, val, fromType, toType, overflows));
|
||||
}
|
||||
else
|
||||
{
|
||||
// emitInstruction(insts.UnaryOpInstruction(getCurrentInstructionIndex(), instruction.getOperator(), result, val));
|
||||
|
||||
if (instruction.op == UnaryOperation.OpID.MOVE) {
|
||||
if (instruction.op == UnaryOperation.OpID.MOVE) {
|
||||
setLocal(instruction.destination, workingState.getLocal(instruction.source));
|
||||
}
|
||||
else if (instruction.op == UnaryOperation.OpID.MOVE_WIDE) {
|
||||
|
@ -1249,6 +1248,11 @@ public class DexSSABuilder extends AbstractIntRegisterMachine {
|
|||
setLocal(instruction.destination+1, workingState.getLocal(instruction.source));
|
||||
else
|
||||
setLocal(instruction.destination+1, workingState.getLocal(instruction.source+1));
|
||||
} else {
|
||||
int dest = instruction.destination;
|
||||
int result = reuseOrCreateDef();
|
||||
setLocal(dest, result);
|
||||
emitInstruction(insts.UnaryOpInstruction(getCurrentInstructionIndex(), instruction.getOperator(), result, val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1377,12 +1381,6 @@ public class DexSSABuilder extends AbstractIntRegisterMachine {
|
|||
*/
|
||||
public void build() {
|
||||
try {
|
||||
if (method.getName().toString().contains("newCNfaPair")) {
|
||||
System.err.println(method);
|
||||
}
|
||||
if (method.getName().toString().contains("expandEscape")) {
|
||||
System.err.println(method);
|
||||
}
|
||||
solve();
|
||||
if (localMap != null) {
|
||||
localMap.finishLocalMap(this);
|
||||
|
|
|
@ -163,7 +163,7 @@ public class DynamicCallGraph {
|
|||
else
|
||||
w.emit(Util.makeGet(runtime, "NULL_TAG"));
|
||||
// w.emit(ConstantInstruction.make(Constants.TYPE_null, null));
|
||||
w.emit(Util.makeInvoke(runtime, "execution", new Class[] {String.class, String.class, Object.class}));
|
||||
w.emit(Util.makeInvoke(runtime, "execution", new Class[] {Class.class, String.class, Object.class}));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -246,10 +246,10 @@ public class DynamicCallGraph {
|
|||
entries.put(p.getCPUtf8(i), i);
|
||||
break;
|
||||
case CONSTANT_String:
|
||||
entries.put(new CWString(p.getCPString(i)), i);
|
||||
entries.put(new CWStringItem(p.getCPString(i), CONSTANT_String), i);
|
||||
break;
|
||||
case CONSTANT_Class:
|
||||
entries.put(new CWClass(p.getCPClass(i)), i);
|
||||
entries.put(new CWStringItem(p.getCPClass(i), CONSTANT_Class), i);
|
||||
break;
|
||||
case CONSTANT_MethodHandle:
|
||||
case CONSTANT_MethodType:
|
||||
|
|
|
@ -78,8 +78,18 @@ public class Runtime {
|
|||
}
|
||||
};
|
||||
|
||||
public static void execution(String klass, String method, Object receiver) {
|
||||
if (runtime.filter == null || ! runtime.filter.contains(klass)) {
|
||||
public static String bashToDescriptor(String className) {
|
||||
if (className.startsWith("class ")) {
|
||||
className = className.substring(6);
|
||||
}
|
||||
if (className.indexOf('.') >= 0) {
|
||||
className = className.replace('.', '/');
|
||||
}
|
||||
return className;
|
||||
}
|
||||
|
||||
public static void execution(Class klass, String method, Object receiver) {
|
||||
if (runtime.filter == null || ! runtime.filter.contains(bashToDescriptor(klass.getName()))) {
|
||||
if (runtime.output != null) {
|
||||
String caller = runtime.callStacks.get().peek();
|
||||
|
||||
|
@ -90,21 +100,22 @@ public class Runtime {
|
|||
// frames: me(0), callee(1), caller(2)
|
||||
StackTraceElement callerFrame = stack[2];
|
||||
if (! caller.contains(callerFrame.getMethodName()) ||
|
||||
! caller.contains(callerFrame.getClassName().replace('.', '/'))) {
|
||||
! caller.contains(bashToDescriptor(callerFrame.getClassName()))) {
|
||||
break checkValid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String line = caller + "\t" + klass + "\t" + method + "\n";
|
||||
String line = String.valueOf(caller) + "\t" + bashToDescriptor(String.valueOf(klass)) + "\t" + String.valueOf(method) + "\n";
|
||||
synchronized (runtime) {
|
||||
runtime.output.printf(line);
|
||||
runtime.output.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runtime.callStacks.get().push(klass + "\t" + method);
|
||||
runtime.callStacks.get().push(bashToDescriptor(klass.getName()) + "\t" + method);
|
||||
}
|
||||
|
||||
public static void termination(String klass, String method, Object receiver, boolean exception) {
|
||||
|
|
|
@ -15,9 +15,11 @@ import java.util.Arrays;
|
|||
import java.util.BitSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.shrikeBT.ConstantInstruction.ClassToken;
|
||||
import com.ibm.wala.shrikeBT.IBinaryOpInstruction.Operator;
|
||||
import com.ibm.wala.shrikeBT.analysis.ClassHierarchyProvider;
|
||||
import com.ibm.wala.shrikeBT.analysis.Verifier;
|
||||
import com.ibm.wala.shrikeCT.ConstantPoolParser.ReferenceToken;
|
||||
|
||||
/**
|
||||
* This class generates Java bytecode from ShrikeBT Instructions.
|
||||
|
@ -160,6 +162,10 @@ public abstract class Compiler implements Constants {
|
|||
|
||||
protected abstract int allocateConstantPoolClassType(String c);
|
||||
|
||||
protected abstract int allocateConstantPoolMethodType(String c);
|
||||
|
||||
protected abstract int allocateConstantPoolMethodHandle(ReferenceToken c);
|
||||
|
||||
protected abstract int allocateConstantPoolField(String c, String name, String type);
|
||||
|
||||
protected abstract int allocateConstantPoolMethod(String c, String name, String sig);
|
||||
|
@ -710,6 +716,12 @@ public abstract class Compiler implements Constants {
|
|||
cpIndex = allocateConstantPoolInteger(((ConstantInstruction.ConstInt) instr).getIntValue());
|
||||
} else if (t.equals(TYPE_String)) {
|
||||
cpIndex = allocateConstantPoolString((String) ((ConstantInstruction.ConstString) instr).getValue());
|
||||
} else if (t.equals(TYPE_Class)) {
|
||||
cpIndex = allocateConstantPoolClassType(((ClassToken) ((ConstantInstruction.ConstClass) instr).getValue()).getTypeName());
|
||||
} else if (t.equals(TYPE_MethodType)) {
|
||||
cpIndex = allocateConstantPoolMethodType(((String) ((ConstantInstruction.ConstMethodType) instr).getValue()));
|
||||
} else if (t.equals(TYPE_MethodHandle)) {
|
||||
cpIndex = allocateConstantPoolMethodHandle(((ReferenceToken) ((ConstantInstruction.ConstMethodHandle) instr).getValue()));
|
||||
} else {
|
||||
cpIndex = allocateConstantPoolFloat(((ConstantInstruction.ConstFloat) instr).getFloatValue());
|
||||
}
|
||||
|
|
|
@ -565,7 +565,7 @@ public abstract class ConstantInstruction extends Instruction {
|
|||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE_String;
|
||||
return TYPE_MethodType;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -636,7 +636,8 @@ public abstract class ConstantInstruction extends Instruction {
|
|||
String className = cp.getConstantPoolHandleClassType(getCPIndex());
|
||||
String eltName = cp.getConstantPoolHandleName(getCPIndex());
|
||||
String eltDesc = cp.getConstantPoolHandleType(getCPIndex());
|
||||
value = new ConstantPoolParser.ReferenceToken(className, eltName, eltDesc);
|
||||
byte kind = cp.getConstantPoolHandleKind(getCPIndex());
|
||||
value = new ConstantPoolParser.ReferenceToken(kind, className, eltName, eltDesc);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
@ -770,7 +771,7 @@ public abstract class ConstantInstruction extends Instruction {
|
|||
return ConstClass.makeInternal(s);
|
||||
}
|
||||
|
||||
static ConstantInstruction make(ConstantPoolReader cp, int index) {
|
||||
public static ConstantInstruction make(ConstantPoolReader cp, int index) {
|
||||
switch (cp.getConstantPoolItemType(index)) {
|
||||
case CONSTANT_Integer:
|
||||
return new LazyInt(OP_ldc_w, cp, index);
|
||||
|
|
|
@ -123,6 +123,8 @@ public abstract class ConstantPoolReader {
|
|||
*/
|
||||
public abstract String getConstantPoolHandleType(int index);
|
||||
|
||||
public abstract byte getConstantPoolHandleKind(int index);
|
||||
|
||||
public abstract BootstrapMethod getConstantPoolDynamicBootstrap(int index);
|
||||
|
||||
public abstract String getConstantPoolDynamicName(int index);
|
||||
|
|
|
@ -530,6 +530,8 @@ public interface Constants {
|
|||
|
||||
public static final String TYPE_MethodHandle = "Ljava/lang/invoke/MethodHandle;";
|
||||
|
||||
public static final String TYPE_MethodType = "Ljava/lang/invoke/MethodType;";
|
||||
|
||||
public static final String TYPE_Object = "Ljava/lang/Object;";
|
||||
|
||||
public static final String TYPE_Throwable = "Ljava/lang/Throwable;";
|
||||
|
|
|
@ -43,7 +43,7 @@ public class InvokeDynamicInstruction extends Instruction implements IInvokeInst
|
|||
}
|
||||
|
||||
@Override
|
||||
public IDispatch getInvocationCode() {
|
||||
public Dispatch getInvocationCode() {
|
||||
int invokeType = getBootstrap().invokeType();
|
||||
switch (invokeType) {
|
||||
case 5: return Dispatch.VIRTUAL;
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.Random;
|
|||
import com.ibm.wala.shrikeBT.Compiler;
|
||||
import com.ibm.wala.shrikeBT.MethodData;
|
||||
import com.ibm.wala.shrikeCT.ClassWriter;
|
||||
import com.ibm.wala.shrikeCT.ConstantPoolParser.ReferenceToken;
|
||||
|
||||
/**
|
||||
* This class lets you compile ShrikeBT intermediate code into real Java bytecodes using ShrikeCT.
|
||||
|
@ -62,6 +63,16 @@ final public class CTCompiler extends Compiler {
|
|||
return cw.addCPClass(convertTypeToClass(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int allocateConstantPoolMethodType(String c) {
|
||||
return cw.addCPMethodType(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int allocateConstantPoolMethodHandle(ReferenceToken c) {
|
||||
return cw.addCPMethodHandle(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a JVM type to the internal JVM class name (e.g., Ljava/lang/Object; to java/lang/Object)
|
||||
*
|
||||
|
|
|
@ -201,6 +201,15 @@ final public class CTDecoder extends Decoder {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getConstantPoolHandleKind(int index) {
|
||||
try {
|
||||
return cp.getCPHandleKind(index);
|
||||
} catch (InvalidClassFileException e) {
|
||||
throw convertToError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BootstrapMethod getConstantPoolDynamicBootstrap(int index) {
|
||||
try {
|
||||
|
|
|
@ -443,7 +443,7 @@ final public class ClassInstrumenter {
|
|||
}
|
||||
}
|
||||
|
||||
stacks = new StackMapTableWriter(w, md, output, cha, varTypes /*, sm*/);
|
||||
stacks = new StackMapTableWriter(w, md, output, cha, varTypes , sm);
|
||||
codeAttrCount++;
|
||||
} catch (IOException | FailureException e) {
|
||||
// TODO Auto-generated catch block
|
||||
|
|
|
@ -15,9 +15,7 @@ import java.io.IOException;
|
|||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/*******************************************************************************
|
||||
* 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.shrikeBT.shrikeCT.tools;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.shrikeBT.ConstantInstruction;
|
||||
import com.ibm.wala.shrikeBT.ConstantPoolReader;
|
||||
import com.ibm.wala.shrikeBT.Constants;
|
||||
import com.ibm.wala.shrikeBT.Decoder.InvalidBytecodeException;
|
||||
import com.ibm.wala.shrikeBT.IInstruction;
|
||||
import com.ibm.wala.shrikeBT.IInvokeInstruction.Dispatch;
|
||||
import com.ibm.wala.shrikeBT.InvokeDynamicInstruction;
|
||||
import com.ibm.wala.shrikeBT.InvokeInstruction;
|
||||
import com.ibm.wala.shrikeBT.MethodData;
|
||||
import com.ibm.wala.shrikeBT.ReturnInstruction;
|
||||
import com.ibm.wala.shrikeBT.shrikeCT.CTDecoder;
|
||||
import com.ibm.wala.shrikeBT.shrikeCT.CTUtils;
|
||||
import com.ibm.wala.shrikeBT.shrikeCT.ClassInstrumenter;
|
||||
import com.ibm.wala.shrikeBT.shrikeCT.OfflineInstrumenter;
|
||||
import com.ibm.wala.shrikeCT.BootstrapMethodsReader.BootstrapMethod;
|
||||
import com.ibm.wala.shrikeCT.ClassReader;
|
||||
import com.ibm.wala.shrikeCT.ClassWriter;
|
||||
import com.ibm.wala.shrikeCT.CodeReader;
|
||||
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
|
||||
public class BootstrapInstrumentor {
|
||||
final private PrintWriter w;
|
||||
|
||||
private int idx;
|
||||
|
||||
/**
|
||||
* Get ready to print a class to the given output stream.
|
||||
*/
|
||||
public BootstrapInstrumentor(PrintWriter w) {
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
PrintWriter w = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
|
||||
BootstrapInstrumentor p = new BootstrapInstrumentor(w);
|
||||
p.doit(args);
|
||||
}
|
||||
|
||||
public void doit(String[] args) throws Exception {
|
||||
OfflineInstrumenter oi = new OfflineInstrumenter(true);
|
||||
oi.parseStandardArgs(args);
|
||||
|
||||
oi.setPassUnmodifiedClasses(true);
|
||||
|
||||
ClassInstrumenter ci;
|
||||
oi.beginTraversal();
|
||||
while ((ci = oi.nextClass()) != null) {
|
||||
try {
|
||||
idx = 0;
|
||||
Set<MethodData> bss = doClass(ci);
|
||||
ClassWriter cw = ci.emitClass();
|
||||
for(MethodData md : bss) {
|
||||
CTUtils.compileAndAddMethodToClassWriter(md, cw, null);
|
||||
}
|
||||
oi.outputModifiedClass(ci, cw);
|
||||
} finally {
|
||||
w.flush();
|
||||
}
|
||||
}
|
||||
|
||||
oi.close();
|
||||
}
|
||||
|
||||
private Set<MethodData> dumpAttributes(ClassInstrumenter ci, int i, ClassReader.AttrIterator attrs) throws InvalidClassFileException,
|
||||
InvalidBytecodeException, IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
|
||||
Set<MethodData> result = HashSetFactory.make();
|
||||
ClassReader cr = ci.getReader();
|
||||
for (; attrs.isValid(); attrs.advance()) {
|
||||
String name = attrs.getName();
|
||||
if (name.equals("Code")) {
|
||||
CodeReader code = new CodeReader(attrs);
|
||||
|
||||
CTDecoder decoder = new CTDecoder(code);
|
||||
decoder.decode();
|
||||
ConstantPoolReader cpr = decoder.getConstantPool();
|
||||
IInstruction[] origInsts = decoder.getInstructions();
|
||||
for(IInstruction inst : origInsts) {
|
||||
if (inst instanceof InvokeDynamicInstruction) {
|
||||
InvokeDynamicInstruction x = (InvokeDynamicInstruction) inst;
|
||||
BootstrapMethod m = x.getBootstrap();
|
||||
|
||||
IInstruction insts[] = new IInstruction[ m.callArgumentCount() + 8];
|
||||
int arg = 0;
|
||||
|
||||
insts[arg++] = InvokeInstruction.make("()Ljava/lang/invoke/MethodHandles$Lookup;", "java/lang/invoke/MethodHandles", "lookup", Dispatch.STATIC);
|
||||
|
||||
insts[arg++] = ConstantInstruction.makeString(x.getMethodName());
|
||||
|
||||
insts[arg++] = ConstantInstruction.makeString(x.getMethodSignature());
|
||||
insts[arg++] = ConstantInstruction.makeClass(cr.getName());
|
||||
insts[arg++] = InvokeInstruction.make("()Ljava/lang/ClassLoader;", "java/lang/Class", "getClassLoader", Dispatch.VIRTUAL);
|
||||
insts[arg++] = InvokeInstruction.make("(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", "java/lang/invoke/MethodType", "fromMethodDescriptorString", Dispatch.STATIC);
|
||||
|
||||
for(int an = 0; an < m.callArgumentCount(); an++) {
|
||||
insts[arg++] = ConstantInstruction.make(cpr, m.callArgumentIndex(an));
|
||||
}
|
||||
|
||||
insts[arg++] = InvokeInstruction.make(m.methodType(), m.methodClass(), m.methodName(), ((InvokeDynamicInstruction) inst).getInvocationCode());
|
||||
insts[arg++] = ReturnInstruction.make("Ljava/lang/invoke/CallSite;");
|
||||
|
||||
result.add(MethodData.makeWithDefaultHandlersAndInstToBytecodes(Constants.ACC_PUBLIC|Constants.ACC_STATIC, cr.getName(), "bs" + (idx++), "()Ljava/lang/invoke/CallSite;", insts));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Print a class.
|
||||
* @throws InvocationTargetException
|
||||
* @throws IllegalAccessException
|
||||
* @throws SecurityException
|
||||
* @throws NoSuchMethodException
|
||||
* @throws ClassNotFoundException
|
||||
*
|
||||
* @throws IllegalArgumentException if cr is null
|
||||
* @throws NoSuchFieldException
|
||||
*/
|
||||
public Set<MethodData> doClass(final ClassInstrumenter ci) throws InvalidClassFileException, InvalidBytecodeException, IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
|
||||
ClassReader cr = ci.getReader();
|
||||
ClassReader.AttrIterator attrs = new ClassReader.AttrIterator();
|
||||
cr.initClassAttributeIterator(attrs);
|
||||
int methodCount = cr.getMethodCount();
|
||||
|
||||
Set<MethodData> result = HashSetFactory.make();
|
||||
for (int i = 0; i < methodCount; i++) {
|
||||
cr.initMethodAttributeIterator(i, attrs);
|
||||
result.addAll(dumpAttributes(ci, i, attrs));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -25,7 +25,9 @@ public class BootstrapMethodsReader extends AttributeReader {
|
|||
String methodClass();
|
||||
String methodName();
|
||||
String methodType();
|
||||
int callArgumentCount();
|
||||
Object callArgument(ClassLoader cl, int i);
|
||||
int callArgumentIndex(int i);
|
||||
int callArgumentKind(int i);
|
||||
}
|
||||
|
||||
|
@ -77,17 +79,28 @@ public class BootstrapMethodsReader extends AttributeReader {
|
|||
return methodType;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int callArgumentCount() {
|
||||
return argumentCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int callArgumentKind(int i) {
|
||||
return cp.getItemType(callArgumentIndex(i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int callArgumentIndex(int i) {
|
||||
assert 0 <= i && i < argumentCount;
|
||||
int index = argsBase + (2*i);
|
||||
return cp.getItemType(cr.getUShort(index));
|
||||
return cr.getUShort(index);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object callArgument(ClassLoader cl, int i) {
|
||||
try {
|
||||
int index = cr.getUShort(argsBase + (2*i));
|
||||
int index = callArgumentIndex(i);
|
||||
int t = callArgumentKind(i);
|
||||
switch (t) {
|
||||
case ClassConstants.CONSTANT_Utf8:
|
||||
|
|
|
@ -617,7 +617,7 @@ public final class ClassReader implements ClassConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the method descriptor of method m in JVM format (e.g., V(ILjava/lang/Object;) )
|
||||
* @return the method descriptor of method m in JVM format (e.g., (ILjava/lang/Object;)V )
|
||||
*/
|
||||
public String getMethodType(int m) throws InvalidClassFileException {
|
||||
verifyMethodIndex(m);
|
||||
|
|
|
@ -13,6 +13,8 @@ package com.ibm.wala.shrikeCT;
|
|||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.ibm.wala.shrikeCT.ConstantPoolParser.ReferenceToken;
|
||||
|
||||
/**
|
||||
* This class formats and writes class data into JVM format.
|
||||
*/
|
||||
|
@ -82,16 +84,18 @@ public class ClassWriter implements ClassConstants {
|
|||
abstract byte getType();
|
||||
}
|
||||
|
||||
public static class CWString extends CWItem {
|
||||
public static class CWStringItem extends CWItem {
|
||||
final private String s;
|
||||
final private byte type;
|
||||
|
||||
public CWString(String s) {
|
||||
public CWStringItem(String s, byte type) {
|
||||
this.s = s;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof CWString && ((CWString) o).s.equals(s);
|
||||
return o != null && o.getClass().equals(getClass()) && ((CWStringItem) o).s.equals(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,39 +105,16 @@ public class ClassWriter implements ClassConstants {
|
|||
|
||||
@Override
|
||||
byte getType() {
|
||||
return CONSTANT_String;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CWClass extends CWItem {
|
||||
final private String c;
|
||||
|
||||
public CWClass(String c) {
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof CWClass && ((CWClass) o).c.equals(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return c.hashCode() + 1431;
|
||||
}
|
||||
|
||||
@Override
|
||||
byte getType() {
|
||||
return CONSTANT_Class;
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
static class CWRef extends CWItem {
|
||||
final private String c;
|
||||
final protected String c;
|
||||
|
||||
final private String n;
|
||||
final protected String n;
|
||||
|
||||
final private String t;
|
||||
final protected String t;
|
||||
|
||||
final private byte type;
|
||||
|
||||
|
@ -146,7 +127,7 @@ public class ClassWriter implements ClassConstants {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof CWRef) {
|
||||
if (o.getClass().equals(getClass())) {
|
||||
CWRef r = (CWRef) o;
|
||||
return r.type == type && r.c.equals(c) && r.n.equals(n) && r.t.equals(t);
|
||||
} else {
|
||||
|
@ -165,6 +146,29 @@ public class ClassWriter implements ClassConstants {
|
|||
}
|
||||
}
|
||||
|
||||
static class CWHandle extends CWRef {
|
||||
private final byte kind;
|
||||
|
||||
CWHandle(byte type, byte kind, String c, String n, String t) {
|
||||
super(type, c, n, t);
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode() * kind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return super.equals(o) && ((CWHandle)o).kind == kind;
|
||||
}
|
||||
|
||||
public byte getKind() {
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
|
||||
static class CWNAT extends CWItem {
|
||||
final private String n;
|
||||
|
||||
|
@ -224,11 +228,15 @@ public class ClassWriter implements ClassConstants {
|
|||
byte t = cp.getItemType(i);
|
||||
switch (t) {
|
||||
case CONSTANT_String:
|
||||
cachedCPEntries.put(new CWString(cp.getCPString(i)), new Integer(i));
|
||||
cachedCPEntries.put(new CWStringItem(cp.getCPString(i), CONSTANT_String), new Integer(i));
|
||||
break;
|
||||
case CONSTANT_Class:
|
||||
cachedCPEntries.put(new CWClass(cp.getCPClass(i)), new Integer(i));
|
||||
cachedCPEntries.put(new CWStringItem(cp.getCPClass(i), CONSTANT_Class), new Integer(i));
|
||||
break;
|
||||
case CONSTANT_MethodType:
|
||||
cachedCPEntries.put(new CWStringItem(cp.getCPMethodType(i), CONSTANT_MethodType), new Integer(i));
|
||||
break;
|
||||
case CONSTANT_MethodHandle:
|
||||
case CONSTANT_FieldRef:
|
||||
case CONSTANT_InterfaceMethodRef:
|
||||
case CONSTANT_MethodRef:
|
||||
|
@ -331,13 +339,27 @@ public class ClassWriter implements ClassConstants {
|
|||
return addCPEntry(new Double(d), 2);
|
||||
}
|
||||
|
||||
private int addCPString(String s, byte type) {
|
||||
if (s == null) {
|
||||
throw new IllegalArgumentException("null s: " + s);
|
||||
}
|
||||
return addCPEntry(new CWStringItem(s, type), 1);
|
||||
}
|
||||
|
||||
public int addCPMethodHandle(ReferenceToken c) {
|
||||
if (c == null) {
|
||||
throw new IllegalArgumentException("null c: " + c);
|
||||
}
|
||||
return addCPEntry(new CWHandle(CONSTANT_MethodHandle, c.getKind(), c.getClassName(), c.getElementName(), c.getDescriptor()), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a String to the constant pool if necessary.
|
||||
*
|
||||
* @return the index of a constant pool item with the right value
|
||||
*/
|
||||
public int addCPString(String s) {
|
||||
return addCPEntry(new CWString(s), 1);
|
||||
return addCPString(s, CONSTANT_String);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,10 +369,17 @@ public class ClassWriter implements ClassConstants {
|
|||
* @return the index of a constant pool item with the right value
|
||||
*/
|
||||
public int addCPClass(String s) {
|
||||
if (s == null) {
|
||||
throw new IllegalArgumentException("null s: " + s);
|
||||
}
|
||||
return addCPEntry(new CWClass(s), 1);
|
||||
return addCPString(s, CONSTANT_Class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Class to the constant pool if necessary.
|
||||
*
|
||||
* @param s the class name, in JVM format (e.g., java/lang/Object)
|
||||
* @return the index of a constant pool item with the right value
|
||||
*/
|
||||
public int addCPMethodType(String s) {
|
||||
return addCPString(s, CONSTANT_MethodType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -717,12 +746,10 @@ public class ClassWriter implements ClassConstants {
|
|||
int offset;
|
||||
switch (t) {
|
||||
case CONSTANT_Class:
|
||||
offset = reserveBuf(3);
|
||||
setUShort(buf, offset + 1, addCPUtf8(((CWClass) item).c));
|
||||
break;
|
||||
case CONSTANT_String:
|
||||
case CONSTANT_MethodType:
|
||||
offset = reserveBuf(3);
|
||||
setUShort(buf, offset + 1, addCPUtf8(((CWString) item).s));
|
||||
setUShort(buf, offset + 1, addCPUtf8(((CWStringItem) item).s));
|
||||
break;
|
||||
case CONSTANT_NameAndType: {
|
||||
offset = reserveBuf(5);
|
||||
|
@ -731,6 +758,39 @@ public class ClassWriter implements ClassConstants {
|
|||
setUShort(buf, offset + 3, addCPUtf8(nat.t));
|
||||
break;
|
||||
}
|
||||
case CONSTANT_MethodHandle: {
|
||||
offset = reserveBuf(4);
|
||||
CWHandle handle = (CWHandle) item;
|
||||
setUByte(buf, offset + 1, handle.getKind());
|
||||
switch (handle.getKind()) {
|
||||
case REF_getStatic:
|
||||
case REF_getField:
|
||||
case REF_putField:
|
||||
case REF_putStatic: {
|
||||
int x = addCPFieldRef(handle.c, handle.n, handle.t);
|
||||
setUShort(buf, offset + 2, x);
|
||||
break;
|
||||
}
|
||||
case REF_invokeVirtual:
|
||||
case REF_newInvokeSpecial: {
|
||||
int x = addCPMethodRef(handle.c, handle.n, handle.t);
|
||||
setUShort(buf, offset + 2, x);
|
||||
break;
|
||||
}
|
||||
case REF_invokeSpecial:
|
||||
case REF_invokeStatic: {
|
||||
int x = addCPMethodRef(handle.c, handle.n, handle.t);
|
||||
setUShort(buf, offset + 2, x);
|
||||
break;
|
||||
}
|
||||
case REF_invokeInterface: {
|
||||
int x = addCPInterfaceMethodRef(handle.c, handle.n, handle.t);
|
||||
setUShort(buf, offset + 2, x);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONSTANT_MethodRef:
|
||||
case CONSTANT_FieldRef:
|
||||
case CONSTANT_InterfaceMethodRef: {
|
||||
|
|
|
@ -18,17 +18,22 @@ import com.ibm.wala.shrikeCT.ClassReader.AttrIterator;
|
|||
*/
|
||||
public final class ConstantPoolParser implements ClassConstants {
|
||||
public static class ReferenceToken {
|
||||
private final byte kind;
|
||||
private final String className;
|
||||
private final String elementName;
|
||||
private final String descriptor;
|
||||
|
||||
public ReferenceToken(String className, String elementName, String descriptor) {
|
||||
super();
|
||||
public ReferenceToken(byte kind, String className, String elementName, String descriptor) {
|
||||
this.kind = kind;
|
||||
this.className = className;
|
||||
this.elementName = elementName;
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
public byte getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
@ -60,6 +65,9 @@ public final class ConstantPoolParser implements ClassConstants {
|
|||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
ReferenceToken other = (ReferenceToken) obj;
|
||||
if (kind != other.kind) {
|
||||
return false;
|
||||
}
|
||||
if (className == null) {
|
||||
if (other.className != null)
|
||||
return false;
|
||||
|
@ -410,7 +418,7 @@ public final class ConstantPoolParser implements ClassConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the type of the MethodHandle at constant pool item i, in JVM format (e.g., I, Z, or Ljava/lang/Object;)
|
||||
* @return the type of the MethodHandle at constant pool item i
|
||||
*/
|
||||
public byte getCPHandleKind(int i) throws InvalidClassFileException, IllegalArgumentException {
|
||||
if (i < 1 || i >= cpItems.length) {
|
||||
|
|
Loading…
Reference in New Issue