All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scandroid.model.AppModelMethod Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
/*
 * 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 , Rogan Creswick ) Steve Suh * * *

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.model; import com.ibm.wala.classLoader.ArrayClass; import com.ibm.wala.classLoader.CallSiteReference; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IMethod; import com.ibm.wala.classLoader.Language; import com.ibm.wala.classLoader.NewSiteReference; import com.ibm.wala.ipa.callgraph.AnalysisScope; import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.ipa.summaries.MethodSummary; import com.ibm.wala.shrikeBT.IInvokeInstruction; import com.ibm.wala.shrikeBT.IInvokeInstruction.IDispatch; import com.ibm.wala.ssa.ConstantValue; import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; import com.ibm.wala.ssa.SSAArrayStoreInstruction; import com.ibm.wala.ssa.SSAInstructionFactory; import com.ibm.wala.ssa.SSANewInstruction; import com.ibm.wala.types.ClassLoaderReference; 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.collections.HashMapFactory; import com.ibm.wala.util.debug.UnimplementedError; import com.ibm.wala.util.strings.Atom; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.scandroid.spec.AndroidSpecs; import org.scandroid.spec.MethodNamePattern; import org.scandroid.util.LoaderUtils; public class AppModelMethod { int nextLocal; /** A mapping from String (variable name) -> Integer (local number) */ private Map symbolTable = null; private MethodSummary methodSummary; private final IClassHierarchy cha; private final AnalysisScope scope; private final Map constant2ValueNumber = HashMapFactory.make(); SSAInstructionFactory insts; // Maps a Type to variable name private final Map typeToID = new HashMap<>(); // innerclass dependencies private final Map> icDependencies = new HashMap<>(); // all callbacks to consider private final List callBacks = new ArrayList<>(); private final Map aClassToTR = new HashMap<>(); private static class MethodParams { public IMethod im; public int params[]; private MethodParams(IMethod method) { im = method; } private void setParams(int p[]) { params = p; } private IMethod getIMethod() { return im; } private int[] getParams() { return params; } } public AppModelMethod(IClassHierarchy cha, AnalysisScope scope, AndroidSpecs specs) { this.cha = cha; this.scope = scope; Language lang = scope.getLanguage(ClassLoaderReference.Application.getLanguage()); insts = lang.instructionFactory(); startMethod(); buildTypeMap(specs); processTypeMap(); processCallBackParams(); createLoopAndSwitch(); } private void createLoopAndSwitch() { int callbackSize = callBacks.size(); // start of while loop int loopLabel = methodSummary.getNumberOfStatements(); int switchValue = nextLocal++; // default label, for now same as case1 int defLabel = loopLabel + 1; int[] casesAndLabels = new int[2 * callbackSize]; for (int i = 0; i < callbackSize; i++) { casesAndLabels[i * 2] = i + 1; casesAndLabels[i * 2 + 1] = defLabel + i * 2; } methodSummary.addStatement( insts.SwitchInstruction( methodSummary.getNumberOfStatements(), switchValue, defLabel, casesAndLabels)); for (MethodParams mp : callBacks) { IMethod im = mp.getIMethod(); IDispatch dispatch; if (im.isInit()) { dispatch = IInvokeInstruction.Dispatch.SPECIAL; } else if (im.isAbstract()) { dispatch = IInvokeInstruction.Dispatch.INTERFACE; } else if (im.isStatic()) { dispatch = IInvokeInstruction.Dispatch.STATIC; } else dispatch = IInvokeInstruction.Dispatch.VIRTUAL; addInvocation( mp.getParams(), CallSiteReference.make( methodSummary.getNumberOfStatements(), mp.getIMethod().getReference(), dispatch)); methodSummary.addStatement( insts.GotoInstruction(methodSummary.getNumberOfStatements(), loopLabel)); } } private void startMethod() { String className = "Lcom/SCanDroid/AppModel"; String methodName = "entry"; TypeReference governingClass = TypeReference.findOrCreate( ClassLoaderReference.Application, TypeName.string2TypeName(className)); Atom mName = Atom.findOrCreateUnicodeAtom(methodName); Language lang = scope.getLanguage(ClassLoaderReference.Application.getLanguage()); Descriptor D = Descriptor.findOrCreateUTF8(lang, "()V"); MethodReference mref = MethodReference.findOrCreate(governingClass, mName, D); methodSummary = new MethodSummary(mref); methodSummary.setStatic(true); methodSummary.setFactory(false); int nParams = mref.getNumberOfParameters(); nextLocal = nParams + 1; symbolTable = HashMapFactory.make(5); for (int i = 0; i < nParams; i++) { symbolTable.put("arg" + i, i + 1); } } private void buildTypeMap(AndroidSpecs specs) { // Go through all possible callbacks found in Application code // Associate their TypeReference with a unique number in typeToID. // Also keep track of all anonymous classes found. for (MethodNamePattern mnp : specs.getCallBacks()) { for (IMethod im : mnp.getPossibleTargets(cha)) { // limit to functions defined within the application if (LoaderUtils.fromLoader(im, ClassLoaderReference.Application)) { callBacks.add(new MethodParams(im)); TypeReference tr = im.getDeclaringClass().getReference(); if (!typeToID.containsKey(tr)) { typeToID.put(tr, nextLocal++); // class is an innerclass if (tr.getName().getClassName().toString().contains("$")) { addDependencies(tr); } } } } } } private void addDependencies(TypeReference tr) { String packageName = 'L' + tr.getName().getPackage().toString() + '/'; String outerClassName; String innerClassName = tr.getName().getClassName().toString(); LinkedList trLL = new LinkedList<>(); trLL.push(tr); int index = innerClassName.lastIndexOf('$'); while (index != -1) { outerClassName = innerClassName.substring(0, index); TypeReference innerTR = TypeReference.findOrCreate( ClassLoaderReference.Application, packageName + outerClassName); trLL.push(innerTR); if (!typeToID.containsKey(innerTR)) { typeToID.put(innerTR, nextLocal++); aClassToTR.put(innerTR, tr); } innerClassName = outerClassName; index = outerClassName.lastIndexOf('$'); } icDependencies.put(tr, trLL); } private void processTypeMap() { Set createdIDs = new HashSet<>(); for (Entry eSet : typeToID.entrySet()) { Integer i = eSet.getValue(); if (createdIDs.contains(i)) continue; TypeReference tr = eSet.getKey(); String className = tr.getName().getClassName().toString(); // Not an anonymous innerclass if (!className.contains("$")) { processAllocation(tr, i, false); createdIDs.add(i); } // Is an anonymous innerclass else { LinkedList deps = icDependencies.get(tr); if (deps == null) { tr = aClassToTR.get(tr); } for (TypeReference trD : icDependencies.get(tr)) { Integer j = typeToID.get(trD); if (!createdIDs.contains(j)) { String depClassName = trD.getName().getClassName().toString(); processAllocation(trD, j, depClassName.contains("$")); createdIDs.add(j); } } } } assert (createdIDs.size() == typeToID.size()) : "typeToID and createdID size do not match"; } private void processCallBackParams() { for (MethodParams mp : callBacks) { int params[] = new int[mp.getIMethod().getNumberOfParameters()]; int startPos; if (mp.getIMethod().isStatic()) { startPos = 0; } else { params[0] = typeToID.get(mp.getIMethod().getDeclaringClass().getReference()); startPos = 1; } for (int i = startPos; i < params.length; i++) { params[i] = makeArgument(mp.getIMethod().getParameterType(i)); } mp.setParams(params); } } private int makeArgument(TypeReference tr) { if (tr.isPrimitiveType()) return addLocal(); else { SSANewInstruction n = processAllocation(tr, nextLocal++, false); return (n == null) ? -1 : n.getDef(); } } private int addLocal() { return nextLocal++; } private SSANewInstruction processAllocation(TypeReference tr, Integer i, boolean isInner) { // create the allocation statement and add it to the method summary NewSiteReference ref = NewSiteReference.make(methodSummary.getNumberOfStatements(), tr); SSANewInstruction a = null; if (tr.isArrayType()) { int[] sizes = new int[((ArrayClass) cha.lookupClass(tr)).getDimensionality()]; Arrays.fill(sizes, getValueNumberForIntConstant(1)); a = insts.NewInstruction(methodSummary.getNumberOfStatements(), i, ref, sizes); } else { a = insts.NewInstruction(methodSummary.getNumberOfStatements(), i, ref); } methodSummary.addStatement(a); IClass klass = cha.lookupClass(tr); if (klass == null) { return null; } if (klass.isArrayClass()) { int arrayRef = a.getDef(); TypeReference e = klass.getReference().getArrayElementType(); while (e != null && !e.isPrimitiveType()) { // allocate an instance for the array contents NewSiteReference n = NewSiteReference.make(methodSummary.getNumberOfStatements(), e); int alloc = nextLocal++; SSANewInstruction ni = null; if (e.isArrayType()) { int[] sizes = new int[((ArrayClass) cha.lookupClass(tr)).getDimensionality()]; Arrays.fill(sizes, getValueNumberForIntConstant(1)); ni = insts.NewInstruction(methodSummary.getNumberOfStatements(), alloc, n, sizes); } else { ni = insts.NewInstruction(methodSummary.getNumberOfStatements(), alloc, n); } methodSummary.addStatement(ni); // emit an astore SSAArrayStoreInstruction store = insts.ArrayStoreInstruction( methodSummary.getNumberOfStatements(), arrayRef, getValueNumberForIntConstant(0), alloc, e); methodSummary.addStatement(store); e = e.isArrayType() ? e.getArrayElementType() : null; arrayRef = alloc; } } // invoke constructor IMethod ctor = cha.resolveMethod(klass, MethodReference.initSelector); if (ctor != null) { // only check for more constructors when we're looking through the inner classes? if (isInner && !ctor.getDeclaringClass().getName().toString().equals(klass.getName().toString())) { boolean foundValidCtor = false; for (IMethod im : klass.getAllMethods()) { if (im.getDeclaringClass().getName().toString().equals(klass.getName().toString()) && im.getSelector() .getName() .toString() .equals(MethodReference.initAtom.toString())) { ctor = im; foundValidCtor = true; // found a default constructor that takes only the outer class as a parameter if (im.getDescriptor().getNumberOfParameters() == 1) { break; } } } if (!foundValidCtor) { throw new UnimplementedError( "Check for other constructors, or just use default Object constructor"); } } int[] params; if (ctor.getDescriptor().getNumberOfParameters() == 0) params = new int[] {i}; else { params = new int[ctor.getNumberOfParameters()]; params[0] = i; LinkedList deps = icDependencies.get(tr); if (deps == null) { deps = icDependencies.get(aClassToTR.get(tr)); int index = deps.lastIndexOf(tr); TypeReference otr = deps.get(index - 1); assert (ctor.getParameterType(1).equals(otr)) : "Type Mismatch"; params[1] = typeToID.get(otr); } else { TypeReference otr = deps.get(deps.size() - 2); assert (ctor.getParameterType(1).equals(otr)) : "Type Mismatch"; params[1] = typeToID.get(otr); } // Allocate new instances for each of the other parameters // in the current constructor. for (int pI = 2; pI < params.length; pI++) { params[pI] = makeArgument(ctor.getParameterType(pI)); } } addInvocation( params, CallSiteReference.make( methodSummary.getNumberOfStatements(), ctor.getReference(), IInvokeInstruction.Dispatch.SPECIAL)); } return a; } public SSAAbstractInvokeInstruction addInvocation(int[] params, CallSiteReference site) { if (site == null) { throw new IllegalArgumentException("site is null"); } CallSiteReference newSite = CallSiteReference.make( methodSummary.getNumberOfStatements(), site.getDeclaredTarget(), site.getInvocationCode()); SSAAbstractInvokeInstruction s = null; if (newSite.getDeclaredTarget().getReturnType().equals(TypeReference.Void)) { s = insts.InvokeInstruction( methodSummary.getNumberOfStatements(), params, nextLocal++, newSite, null); } else { s = insts.InvokeInstruction( methodSummary.getNumberOfStatements(), nextLocal++, params, nextLocal++, newSite, null); } methodSummary.addStatement(s); // cache.invalidate(this, Everywhere.EVERYWHERE); return s; } protected int getValueNumberForIntConstant(int c) { ConstantValue v = new ConstantValue(c); Integer result = constant2ValueNumber.get(v); if (result == null) { result = nextLocal++; constant2ValueNumber.put(v, result); } return result; } public MethodSummary getSummary() { return methodSummary; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy