/* * 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) 2013, * Tobias Blaschke <code@tobiasblaschke.de> * 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 com.ibm.wala.dalvik.ipa.callgraph.androidModel.stubs; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ibm.wala.classLoader.CallSiteReference; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IMethod; import com.ibm.wala.dalvik.ipa.callgraph.androidModel.AndroidModel; import com.ibm.wala.dalvik.ipa.callgraph.androidModel.AndroidModelClass; import com.ibm.wala.dalvik.ipa.callgraph.androidModel.MiniModel; import com.ibm.wala.dalvik.ipa.callgraph.androidModel.parameters.Instantiator; import com.ibm.wala.dalvik.ipa.callgraph.impl.AndroidEntryPoint; import com.ibm.wala.dalvik.util.AndroidComponent; import com.ibm.wala.dalvik.util.AndroidEntryPointManager; import com.ibm.wala.ipa.callgraph.AnalysisCache; import com.ibm.wala.ipa.callgraph.AnalysisOptions; import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.ipa.summaries.MethodSummary; import com.ibm.wala.ipa.summaries.SummarizedMethod; import com.ibm.wala.ipa.summaries.VolatileMethodSummary; import com.ibm.wala.shrikeBT.IInvokeInstruction; import com.ibm.wala.ssa.SSAInstruction; import com.ibm.wala.types.Descriptor; import com.ibm.wala.types.MethodReference; import com.ibm.wala.types.TypeName; import com.ibm.wala.types.TypeReference; import com.ibm.wala.util.CancelException; import com.ibm.wala.util.ssa.ParameterAccessor; import com.ibm.wala.util.ssa.SSAValue; import com.ibm.wala.util.ssa.SSAValueManager; import com.ibm.wala.util.ssa.TypeSafeInstructionFactory; import com.ibm.wala.util.strings.Atom; /** * This Model is used to start an Android-Component of unknown Target. * * All internal Components of a Type (if given) then an ExternalModel is called. * Used by the IntentContextInterpreter. * * @see com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa.IntentContextInterpreter * * @author Tobias Blaschke <code@tobiasblaschke.de> * @since 2013-10-18 */ public class UnknownTargetModel extends AndroidModel { private static Logger logger = LoggerFactory.getLogger(UnknownTargetModel.class); public final Atom name; private boolean doMini = true; private MiniModel miniModel = null; private ExternalModel externalModel = null; private final AndroidComponent target; // uses AndroidModel.cha; /** * The UnknownTargetModel does not call any entrypoints on it's own. * * Instead it first creates a restricted AndroidModel and an ExternalModel. * These are actually called. */ @Override protected boolean selectEntryPoint(AndroidEntryPoint ep) { return false; } /** * @param target Component Type, may be null: No restrictions are imposed on AndroidModel then */ public UnknownTargetModel(final IClassHierarchy cha, final AnalysisOptions options, final AnalysisCache cache, AndroidComponent target) throws CancelException { super(cha, options, cache); if (target == null) { // TODO: Enable throw new IllegalArgumentException("The component type requested to create an UnknownTargetModel for was null"); } String sName = target.toString(); String cName = Character.toUpperCase(sName.charAt(0)) + sName.substring(1).toLowerCase(); this.name = Atom.findOrCreateAsciiAtom("startUnknown" + cName); this.target = target; //this.allInternal = new MiniModel(cha, options, cache, target); //this.external = new ExternalModel(cha, options, cache, target); logger.debug("Will be known as {}/{}", AndroidModelClass.ANDROID_MODEL_CLASS.getName(), this.name); } //@Override private void register(SummarizedMethod model) { AndroidModelClass mClass = AndroidModelClass.getInstance(cha); if (!(mClass.containsMethod(model.getSelector()))) { mClass.addMethod(model); } } @Override public SummarizedMethod getMethod() throws CancelException { if (!built) { super.build(this.name); this.register(super.model); } return super.model; } @Override protected void build(Atom name, Collection<? extends AndroidEntryPoint> entrypoints) throws CancelException { assert ((entrypoints == null) || (! entrypoints.iterator().hasNext())); { // Check if this Application has components, that implement target. If not we don't // have to build a MiniModel. doMini = false; for (final AndroidEntryPoint ep : AndroidEntryPointManager.ENTRIES) { if (ep.belongsTo(this.target)) { doMini = true; break; } } } if (doMini) { miniModel = new MiniModel(this.cha, this.options, this.cache, this.target); } externalModel = new ExternalModel(this.cha, this.options, this.cache, this.target); final Descriptor descr; // final Selector selector; { if (doMini) { final TypeName[] othersA = miniModel.getDescriptor().getParameters(); final Set<TypeName> others; if (othersA != null) { others = new HashSet<TypeName>(Arrays.asList(othersA)); } else { logger.error("{} has no paramteres!", miniModel); others = new HashSet<TypeName>(); } doMini = others.size() > 0; others.addAll(Arrays.asList(externalModel.getDescriptor().getParameters())); descr = Descriptor.findOrCreate(others.toArray(new TypeName[] {}), TypeReference.VoidName); // Return the intent of external? TODO } else { descr = Descriptor.findOrCreate(externalModel.getDescriptor().getParameters(), TypeReference.VoidName); } // selector = new Selector(name, descr); } /*{ // Skip construction if there already exists a model wit this name. This should // not happen. final AndroidModelClass mClass = AndroidModelClass.getInstance(this.cha); if (mClass.containsMethod(selector)) { logger.error("There is already an Android-Model with name {}!", selector); this.built = true; this.model = (SummarizedMethod) mClass.getMethod(selector); return; } } // */ { // Set some properties of the later method this.klass = AndroidModelClass.getInstance(this.cha); this.mRef = MethodReference.findOrCreate(AndroidModelClass.ANDROID_MODEL_CLASS, name, descr); this.body = new VolatileMethodSummary(new MethodSummary(this.mRef)); this.body.setStatic(true); } { // Start building populate(null); this.model = new SummarizedMethod(this.mRef, this.body.getMethodSummary(), this.klass) { @Override public TypeReference getParameterType (int i) { IClassHierarchy cha = getClassHierarchy(); TypeReference tRef = super.getParameterType(i); if (tRef.isClassType()) { if (cha.lookupClass(tRef) != null) { return tRef; } else { for (IClass c : cha) { if (c.getName().toString().equals(tRef.getName().toString())) { return c.getReference(); } } } throw new IllegalStateException("Error looking up " + tRef); } else { return tRef; } } }; // of this.model } this.built = true; } /** * Fill the model with instructions. * * Call both models: ExternalModel, MiniModel */ //@Override private void populate(Iterable<? extends AndroidEntryPoint> entrypoints) throws CancelException { assert ((entrypoints == null) || (! entrypoints.iterator().hasNext())); assert (! built) : "You can only build once"; final TypeSafeInstructionFactory instructionFactory = new TypeSafeInstructionFactory(this.cha); final ParameterAccessor pAcc = new ParameterAccessor(this.mRef, /* hasImplicitThis */ false); final SSAValueManager pm = new SSAValueManager(pAcc); final Instantiator instantiator = new Instantiator(this.body, instructionFactory, pm, this.cha, this.mRef, this.scope); if (doMini) { // Call a MiniModel //final MiniModel miniModel = new MiniModel(this.cha, this.options, this.cache, this.target); final IMethod mini = miniModel.getMethod(); final ParameterAccessor miniAcc = new ParameterAccessor(mini); final List<SSAValue> params = pAcc.connectThrough(miniAcc, null, null, this.cha, instantiator, false, null, null); final SSAValue excpetion = pm.getException(); final int pc = this.body.getNextProgramCounter(); final CallSiteReference site = CallSiteReference.make(pc, mini.getReference(), IInvokeInstruction.Dispatch.STATIC); final SSAInstruction invokation = instructionFactory.InvokeInstruction(pc, params, excpetion, site); this.body.addStatement(invokation); } final SSAValue extRet; { // Call the externalTarget Model //final ExternalModel externalModel = new ExternalModel(this.cha, this.options, this.cache, this.target); final IMethod external = externalModel.getMethod(); final ParameterAccessor externalAcc = new ParameterAccessor(external); final List<SSAValue> params = pAcc.connectThrough(externalAcc, null, null, this.cha, instantiator, false, null, null); final SSAValue excpetion = pm.getException(); extRet = pm.getUnmanaged(external.getReturnType() , "extRet"); final int pc = this.body.getNextProgramCounter(); final CallSiteReference site = CallSiteReference.make(pc, external.getReference(), IInvokeInstruction.Dispatch.STATIC); final SSAInstruction invokation = instructionFactory.InvokeInstruction(pc, extRet, params, excpetion, site); this.body.addStatement(invokation); } // TODO: Do somethig with extRet? this.body.setLocalNames(pm.makeLocalNames()); } /* final ParameterAccessor internalAcc = new ParameterAccessor(this.allInternal.getMethod()); final ParameterAccessor externalAcc = new ParameterAccessor(this.external.getMethod()); final ParameterAccessor thisAcc = new ParameterAccessor(this.mRef, false); final SSAValueManager pm = new SSAValueManager(thisAcc); final JavaInstructionFactory instructionFactory = new JavaInstructionFactory(); // TODO: Use a typesafe factory? final Instantiator instantiator = new Instantiator(this.body, new TypeSafeInstructionFactory(getClassHierarchy()), pm, getClassHierarchy(), this.mRef, this.scope); int nextLocal = thisAcc.getFirstAfter(); // TODO: Use manager? final List<SSAValue> internalArgs; { // Call the MiniModel // Map through the parameters of this.mRef to this.allInternal final List<SSAValue> args = thisAcc.connectThrough(internalAcc, null, null, getClassHierarchy(), instantiator, false, null, null); internalArgs = args; final IMethod allInternalMethod = this.allInternal.getMethod(); { logger.debug("Calling {} using {}", this.allInternal.getMethod(), args); final int callPC = this.body.getNextProgramCounter(); final CallSiteReference site = CallSiteReference.make(callPC, allInternalMethod.getReference(), IInvokeInstruction.Dispatch.STATIC); final int exception = nextLocal++; assert (exception > 0); final SSAInstruction invokation = instructionFactory.InvokeInstruction(callPC, internalAcc.forInvokeStatic(args), exception, site); this.body.addStatement(invokation); } } final int externalReturnIntent = nextLocal++; { // Call the external model final List<SSAValue> args = thisAcc.connectThrough(externalAcc, null, null , getClassHierarchy(), instantiator, false, null, null); final IMethod externalMethod = this.external.getMethod(); { logger.debug("Calling {} using parameters {}", externalMethod, args); final int callPC = this.body.getNextProgramCounter(); final CallSiteReference site = CallSiteReference.make(callPC, externalMethod.getReference(), IInvokeInstruction.Dispatch.STATIC); final int exception = nextLocal++; final SSAInstruction invokation = instructionFactory.InvokeInstruction(callPC, externalReturnIntent, externalAcc.forInvokeStatic(args), exception, site); this.body.addStatement(invokation); } } // TODO: Phi-Together returnIntents and return it. Or at least handle external }*/ }