diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java index ba4718a9d..cf565c9cf 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java @@ -86,6 +86,7 @@ import com.ibm.wala.dalvik.ipa.callgraph.androidModel.structure.AbstractAndroidM import com.ibm.wala.dalvik.ipa.callgraph.androidModel.stubs.AndroidBoot; import com.ibm.wala.dalvik.ipa.callgraph.androidModel.stubs.AndroidStartComponentTool; +import com.ibm.wala.classLoader.IField; import com.ibm.wala.util.strings.Atom; import com.ibm.wala.dalvik.util.AndroidTypes; @@ -618,6 +619,11 @@ public class AndroidModel /* makes SummarizedMethod */ final ParameterAccessor acc = new ParameterAccessor(asMethod, /* hasImplicitThis: */ true); //final AndroidModelParameterManager pm = new AndroidModelParameterManager(acc); final SSAValueManager pm = new SSAValueManager(acc); + if (callerNd != null) { + pm.breadCrumb = "Caller: " + caller + " Context: " + callerNd.getContext() + " Model: " + this.getClass() + " Name: " + this.getName(); + } else { + pm.breadCrumb = "Caller: " + caller + " Model: " + this.getClass(); + } final VolatileMethodSummary redirect = new VolatileMethodSummary(new MethodSummary(asMethod)); redirect.setStatic(false); final Parameter self = acc.getThis(); @@ -648,8 +654,28 @@ public class AndroidModel /* makes SummarizedMethod */ if (inAsMethod != null) { allActivities.add(inAsMethod); } else { - final SSAValue newInstance = instantiator.createInstance(activityType, false, null, null); - allActivities.add(newInstance); + final Atom fdName = activityType.getName().getClassName(); + final AndroidModelClass mClass = AndroidModelClass.getInstance(cha); + + if (mClass.getField(fdName) != null) { + final IField field = mClass.getField(fdName); + final int instPC = redirect.getNextProgramCounter(); + final SSAValue target = pm.getUnallocated(activityType, new SSAValue.WeaklyNamedKey(activityType.getName(), + "got" + fdName.toString())); + final SSAInstruction getInst = instructionFactory.GetInstruction(instPC, target, field.getReference()); + redirect.addStatement(getInst); + pm.setAllocation(target, getInst); + allActivities.add(target); + } else { + final SSAValue newInstance = instantiator.createInstance(activityType, false, null, null); + allActivities.add(newInstance); + + mClass.putField(fdName, activityType); + final int instPC = redirect.getNextProgramCounter(); + final FieldReference fdRef = FieldReference.findOrCreate(mClass.getReference(), fdName, activityType); + final SSAInstruction putInst = instructionFactory.PutInstruction(instPC, newInstance, fdRef); + redirect.addStatement(putInst); + } } } assert(allActivities.size() == modelsActivities.size()); @@ -844,6 +870,7 @@ public class AndroidModel /* makes SummarizedMethod */ final TypeSafeInstructionFactory instructionFactory = new TypeSafeInstructionFactory(getClassHierarchy()); final ParameterAccessor acc = new ParameterAccessor(asMethod, /* hasImplicitThis: */ false); final SSAValueManager pm = new SSAValueManager(acc); + pm.breadCrumb = "Encap: " + this.getClass().toString(); final SummarizedMethod model = getMethod(); final List params = new ArrayList(); @@ -852,9 +879,34 @@ public class AndroidModel /* makes SummarizedMethod */ for (int i = 0; i < model.getNumberOfParameters(); ++i) { final TypeReference argT = model.getParameterType(i); - final boolean managed = false; - final SSAValue.VariableKey key = new SSAValue.TypeKey(argT.getName()); - final SSAValue arg = instantiator.createInstance (argT, managed, key, null); + final SSAValue arg; + + if (AndroidComponent.isAndroidComponent(argT, cha)) { + // Get / Put filed in AndroidModelClass for Android-Components + final Atom fdName = argT.getName().getClassName(); + + if (mClass.getField(fdName) != null) { + final IField field = mClass.getField(fdName); + final int instPC = encap.getNextProgramCounter(); + arg = pm.getUnallocated(argT, new SSAValue.WeaklyNamedKey(argT.getName(), + "got" + fdName.toString())); + final SSAInstruction getInst = instructionFactory.GetInstruction(instPC, arg, field.getReference()); + encap.addStatement(getInst); + pm.setAllocation(arg, getInst); + } else { + arg = instantiator.createInstance(argT, false, null, null); + + mClass.putField(fdName, argT); + final int instPC = encap.getNextProgramCounter(); + final FieldReference fdRef = FieldReference.findOrCreate(mClass.getReference(), fdName, argT); + final SSAInstruction putInst = instructionFactory.PutInstruction(instPC, arg, fdRef); + encap.addStatement(putInst); + } + } else { + final boolean managed = false; + final SSAValue.VariableKey key = new SSAValue.TypeKey(argT.getName()); + arg = instantiator.createInstance (argT, managed, key, null); + } params.add(arg); } } diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModelClass.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModelClass.java index 07c145244..b834e68ab 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModelClass.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModelClass.java @@ -56,6 +56,9 @@ import com.ibm.wala.util.collections.HashSetFactory; import com.ibm.wala.util.debug.Assertions; import com.ibm.wala.util.debug.UnimplementedError; import com.ibm.wala.util.strings.Atom; +import com.ibm.wala.classLoader.FieldImpl; + +import com.ibm.wala.shrikeCT.ClassConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -64,6 +67,8 @@ import java.util.List; import java.util.ArrayList; import java.util.Set; import java.util.HashSet; +import java.util.Map; +import java.util.HashMap; /** * Encapsulates synthetic methods for modeling Androids lifecycle. @@ -188,13 +193,23 @@ public final /* singleton */ class AndroidModelClass extends SyntheticClass { // Contents of the class: Fields // We have none... // + private Map fields = new HashMap(); - /** - * This class does not contain any fields. - */ @Override public IField getField(Atom name) { - return null; + if (fields.containsKey(name)) { + return fields.get(name); + } else { + return null; + } + } + + public void putField(Atom name, TypeReference type) { + final FieldReference fdRef = FieldReference.findOrCreate(this.getReference(), name, type); + final int accessFlags = ClassConstants.ACC_STATIC | ClassConstants.ACC_PUBLIC; + final IField field = new FieldImpl(this, fdRef, accessFlags, null); + + this.fields.put(name, field); } /** @@ -202,7 +217,7 @@ public final /* singleton */ class AndroidModelClass extends SyntheticClass { */ @Override public Collection getAllFields() { - return Collections.emptySet(); + return fields.values(); } /** @@ -210,7 +225,7 @@ public final /* singleton */ class AndroidModelClass extends SyntheticClass { */ @Override public Collection getDeclaredStaticFields() { - return Collections.emptySet(); + return fields.values(); } /** @@ -218,7 +233,7 @@ public final /* singleton */ class AndroidModelClass extends SyntheticClass { */ @Override public Collection getAllStaticFields() { - return Collections.emptySet(); + return fields.values(); } /** diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/FlatInstantiator.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/FlatInstantiator.java index 92295750d..b5fa030c4 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/FlatInstantiator.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/FlatInstantiator.java @@ -158,7 +158,6 @@ public class FlatInstantiator implements IInstantiator { } if (currentDepth > this.maxDepth) { - System.out.println("Depth-Limit exceeded for: " + T); // TODO: Remove final SSAValue instance = this.pm.getUnmanaged(T, key); instance.setAssigned(); return instance; diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java index e3e691202..da839ac8e 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java @@ -75,6 +75,10 @@ import com.ibm.wala.ipa.callgraph.AnalysisScope; import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.dalvik.ipa.callgraph.androidModel.AndroidModelClass; +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.util.strings.Atom; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -158,7 +162,26 @@ public class Instantiator implements IInstantiator { instance = this.pm.getUnmanaged(T, key); } } - + + { // Try fetch Android-Components from AndroidModelClass + if (com.ibm.wala.dalvik.util.AndroidComponent.isAndroidComponent(T, cha)) { + final AndroidModelClass mClass = AndroidModelClass.getInstance(cha); + final Atom fdName = T.getName().getClassName(); + + if (mClass.getField(fdName) != null) { + final IField field = mClass.getField(fdName); + final int instPC = this.body.getNextProgramCounter(); + final SSAInstruction getInst = instructionFactory.GetInstruction(instPC, instance, field.getReference()); + this.body.addStatement(getInst); + pm.setAllocation(instance, getInst); + return instance; + } else { + System.out.println("NEW Component " + instance + "\n\tbreadCrumb: " + pm.breadCrumb); + assert(false); + } + } + } // */ + if (T.isPrimitiveType()) { createPrimitive(instance); return instance; diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/stubs/AndroidStartComponentTool.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/stubs/AndroidStartComponentTool.java index 78cdf3814..a9776a77b 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/stubs/AndroidStartComponentTool.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/stubs/AndroidStartComponentTool.java @@ -32,6 +32,7 @@ package com.ibm.wala.dalvik.ipa.callgraph.androidModel.stubs; import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.CallSiteReference; import com.ibm.wala.types.FieldReference; import com.ibm.wala.types.MethodReference; @@ -248,12 +249,16 @@ public class AndroidStartComponentTool { logger.warn("Asking for context when Context-Free"); return null; // XXX: Return a synthetic null? }*/ - - logger.debug("Fetching caller context..."); - final SSAValue androidContext; if (caller == null) { return null; - } else if (caller.getName().equals(AndroidTypes.ContextWrapperName)) { + } + + final IClass iCaller = cha.lookupClass(caller); + final IClass iActivity = cha.lookupClass(AndroidTypes.Activity); + + logger.debug("Fetching caller context..."); + final SSAValue androidContext; + if (caller.getName().equals(AndroidTypes.ContextWrapperName)) { { // Fetch ContextWrapperName.mBase => androidContext androidContext = pm.getUnmanaged(AndroidTypes.Context, "callerContext"); logger.debug("Fetching ContextWrapperName.mBase"); @@ -276,7 +281,7 @@ public class AndroidStartComponentTool { logger.info("Caller has android-context type: ContextImpl"); return androidContext; } - } else if (caller.getName().equals(AndroidTypes.ActivityName)) { + } else if (cha.isAssignableFrom(iActivity, iCaller)) { // We don't need it for now - TODO grab anyway androidContext = null; this.callerContext = AndroidTypes.AndroidContextType.ACTIVITY; @@ -349,7 +354,8 @@ public class AndroidStartComponentTool { logger.info("The context to use for the call is from an IBinder"); return iBinder; - } else if (caller.getName().equals(AndroidTypes.ActivityName)) { + //} else if (caller.getName().equals(AndroidTypes.ActivityName)) { + } else if (this.callerContext == AndroidTypes.AndroidContextType.ACTIVITY) { // The IBinder is Activity.mMainThread.getApplicationThread() // TODO: Verify final SSAValue mMainThread = pm.getUnmanaged(AndroidTypes.ActivityThread, "callersMainThred"); diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextInterpreter.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextInterpreter.java index 0f135cb33..92f1c81cf 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextInterpreter.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextInterpreter.java @@ -53,6 +53,7 @@ import com.ibm.wala.ipa.callgraph.AnalysisCache; import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.ssa.IR; import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.ContextKey; import com.ibm.wala.types.ClassLoaderReference; import com.ibm.wala.classLoader.IMethod; @@ -70,6 +71,8 @@ import com.ibm.wala.ssa.DefUse; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.types.FieldReference; +import com.ibm.wala.ipa.callgraph.propagation.AbstractTypeInNode; + import java.util.Iterator; import com.ibm.wala.util.collections.EmptyIterator; import java.util.Set; @@ -138,7 +141,23 @@ public class IntentContextInterpreter implements SSAContextInterpreter { final Intent intent = AndroidEntryPointManager.MANAGER.getIntent(inIntent); // Apply overrides final Atom target = intent.action; final IMethod method = node.getMethod(); - final TypeReference callingClass = node.getMethod().getReference().getDeclaringClass(); // TODO: This may not necessarily fit! + final TypeReference callingClass; + { + if (ctx.get(ContextKey.CALLER) != null) { + System.out.println("CALLER CONTEXT" + ctx.get(ContextKey.CALLER)); + callingClass = node.getMethod().getReference().getDeclaringClass(); // TODO: This may not necessarily fit! + } else if (ctx.get(ContextKey.CALLSITE) != null) { + System.out.println("CALLSITE CONTEXT" + ctx.get(ContextKey.CALLSITE)); + callingClass = node.getMethod().getReference().getDeclaringClass(); // TODO: This may not necessarily fit! + } else if (ctx.get(ContextKey.RECEIVER) != null) { + //System.out.println("RECEIVER CONTEXT" + ctx.get(ContextKey.RECEIVER).getClass()); + final AbstractTypeInNode aType = (AbstractTypeInNode) ctx.get(ContextKey.RECEIVER); + callingClass = aType.getConcreteType().getReference(); + } else { + callingClass = node.getMethod().getReference().getDeclaringClass(); // TODO: This may not necessarily fit! + } + } + final Intent.IntentType type = intent.getType(); final IR ir; diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidComponent.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidComponent.java index b9dd86f1a..6461adfb9 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidComponent.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidComponent.java @@ -113,6 +113,28 @@ public enum AndroidComponent { } } + public static boolean isAndroidComponent(final TypeReference T, final IClassHierarchy cha) { + for (final AndroidComponent candid : AndroidComponent.values()) { + if (candid == AndroidComponent.UNKNOWN) continue; + if (candid.getName().equals(T.getName())) { + return true; + } + + final IClass iT = cha.lookupClass(T); + final IClass iCand = cha.lookupClass(candid.toReference()); + if (iT == null) { + return false; // TODO + } + if (iCand == null) { + return false; // ???!!! + } + if (cha.isAssignableFrom(iCand, iT)) { + return true; + } + } + return false; + } + /** * A name usable for display-output. * diff --git a/com.ibm.wala.util/src/com/ibm/wala/util/ssa/SSAValueManager.java b/com.ibm.wala.util/src/com/ibm/wala/util/ssa/SSAValueManager.java index acd934e30..3bec3e2da 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/util/ssa/SSAValueManager.java +++ b/com.ibm.wala.util/src/com/ibm/wala/util/ssa/SSAValueManager.java @@ -80,6 +80,9 @@ public class SSAValueManager { private String description; private MethodReference forMethod; + /** User-Defined debugging info */ + public String breadCrumb = ""; + private static class Managed { public ValueStatus status = ValueStatus.UNUSED; public SSAInstruction setBy = null; diff --git a/com.ibm.wala.util/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java b/com.ibm.wala.util/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java index 27b0d1381..e1f74d654 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java +++ b/com.ibm.wala.util/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java @@ -396,6 +396,41 @@ public class TypeSafeInstructionFactory { return insts.GetInstruction(iindex, targetValue.getNumber(), containingInstance.getNumber(), field); } + /** + * Reads static field into targetValue. + * + * If type check passes the corresponding GetInstruction of the JavaInstructionFactory is called. + * Calls targetValue.setAssigned() + * + * @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.GetInstruction(int, int, int, FieldReference) + * + * @param iindex Zero or a positive number unique to any instruction of the same method + * @param targetValue the result of the GetInstruction is placed there + * @param containingInstance The Object instance to read the field from + * @param field The description of the field + */ + public SSAGetInstruction GetInstruction(final int iindex, final SSAValue targetValue, FieldReference field) { + logger.info("Now: Get {} into {}", field, targetValue); + + if (iindex < 0) { + throw new IllegalArgumentException("iIndex may not be negative"); + } + if (targetValue == null) { + throw new IllegalArgumentException("targetValue may not be null"); + } + if (field == null) { + throw new IllegalArgumentException("field may not be null"); + } + if (! isAssignableFrom(field.getFieldType(), targetValue.getType())) { + throw new IllegalArgumentException("The field " + targetValue + " is not assignable from " + field); + } + + targetValue.setAssigned(); + return insts.GetInstruction(iindex, targetValue.getNumber(), field); + } + + + /** * Writes newValue to field of targetInstance. * @@ -443,6 +478,40 @@ public class TypeSafeInstructionFactory { return insts.PutInstruction(iindex, targetInstance.getNumber(), newValue.getNumber(), field); } + /** + * Writes newValue to static field. + * + * If type check passes the corresponding PutInstruction of the JavaInstructionFactory is called. + * + * @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.PutInstruction(int, int, int, FieldReference) + * + * @param iindex Zero or a psitive number unique to any instruction of the same method + * @param targetInstance the instance of the object to write a field of + * @param newValue The value to write to the field + * @param field The description of the target + */ + public SSAPutInstruction PutInstruction(final int iindex, final SSAValue newValue, FieldReference field) { + logger.info("Now: Put {} to {}", newValue, field); + + if (iindex < 0) { + throw new IllegalArgumentException("iIndex may not be negative"); + } + if (newValue == null) { + throw new IllegalArgumentException("newValue may not be null"); + } + if (field == null) { + throw new IllegalArgumentException("field may not be null"); + } + if (! isAssignableFrom(newValue.getType(), field.getFieldType())) { + throw new IllegalArgumentException("The field " + field + " is not assignable from " + newValue); + } + + final MethodReference newValueValidIn = newValue.getValidIn(); + + return insts.PutInstruction(iindex, newValue.getNumber(), field); + } + + public SSANewInstruction NewInstruction(int iindex, SSAValue result, NewSiteReference site) { logger.info("Now: New {}", result);