/** * Traverse the statements in the given body, looking for aggregation possibilities; that is, * given a def d and a use u, d has no other uses, u has no other defs, collapse d and u. * * <p>option: only-stack-locals; if this is true, only aggregate variables starting with $ */ protected void internalTransform(Body b, String phaseName, Map<String, String> options) { StmtBody body = (StmtBody) b; boolean onlyStackVars = PhaseOptions.getBoolean(options, "only-stack-locals"); int aggregateCount = 1; if (Options.v().time()) Timers.v().aggregationTimer.start(); boolean changed = false; Map<ValueBox, Zone> boxToZone = new HashMap<ValueBox, Zone>(body.getUnits().size() * 2 + 1, 0.7f); // Determine the zone of every box { Zonation zonation = new Zonation(body); for (Unit u : body.getUnits()) { Zone zone = zonation.getZoneOf(u); for (ValueBox box : u.getUseBoxes()) { boxToZone.put(box, zone); } for (ValueBox box : u.getDefBoxes()) { boxToZone.put(box, zone); } } } do { if (Options.v().verbose()) G.v() .out .println( "[" + body.getMethod().getName() + "] Aggregating iteration " + aggregateCount + "..."); // body.printTo(new java.io.PrintWriter(G.v().out, true)); changed = internalAggregate(body, boxToZone, onlyStackVars); aggregateCount++; } while (changed); if (Options.v().time()) Timers.v().aggregationTimer.end(); }
/** * Returns a <code>ThrowableSet</code> representing the set of exceptions included in <code> * include</code> minus the set of exceptions included in <code>exclude</code>. Creates a new * <code>ThrowableSet</code> only if there was not already one whose contents correspond to * <code>include</code> - <code>exclude</code>. * * @param include A set of {@link RefLikeType} objects representing exception types included in * the result; may be <code>null</code> if there are no included types. * @param exclude A set of {@link AnySubType} objects representing exception types excluded from * the result; may be <code>null</code> if there are no excluded types. * @return a <code>ThrowableSet</code> representing the set of exceptions corresponding to * <code>include</code> - <code>exclude</code>. */ private ThrowableSet registerSetIfNew(Set include, Set exclude) { if (INSTRUMENTING) { registrationCalls++; } if (include == null) { include = Collections.EMPTY_SET; } if (exclude == null) { exclude = Collections.EMPTY_SET; } int size = include.size() + exclude.size(); Integer sizeKey = new Integer(size); List sizeList = (List) sizeToSets.get(sizeKey); if (sizeList == null) { sizeList = new LinkedList(); sizeToSets.put(sizeKey, sizeList); } for (Iterator i = sizeList.iterator(); i.hasNext(); ) { ThrowableSet set = (ThrowableSet) i.next(); if (set.exceptionsIncluded.equals(include) && set.exceptionsExcluded.equals(exclude)) { return set; } } if (INSTRUMENTING) { registeredSets++; } ThrowableSet result = new ThrowableSet(include, exclude); sizeList.add(result); return result; }
/** * given a DelayabilityAnalysis and the computations of each unit, calculates the latest * computation-point for each expression.<br> * the <code>equivRhsMap</code> could be calculated on the fly, but it is <b>very</b> likely that * it already exists (as similar maps are used for calculating Earliestness, Delayed,...<br> * the shared set allows more efficient set-operations, when they the computation is merged with * other analyses/computations. * * @param dg a ExceptionalUnitGraph * @param delayed the delayability-analysis of the same graph. * @param equivRhsMap all computations of the graph * @param set the shared flowSet */ public LatestComputation( UnitGraph unitGraph, DelayabilityAnalysis delayed, Map equivRhsMap, BoundedFlowSet set) { unitToLatest = new HashMap<Unit, FlowSet>(unitGraph.size() + 1, 0.7f); Iterator unitIt = unitGraph.iterator(); while (unitIt.hasNext()) { /* create a new Earliest-list for each unit */ Unit currentUnit = (Unit) unitIt.next(); /* basically the latest-set is: * (delayed) INTERSECT (comp UNION (UNION_successors ~Delayed)) = * (delayed) MINUS ((INTERSECTION_successors Delayed) MINUS comp). */ FlowSet delaySet = (FlowSet) delayed.getFlowBefore(currentUnit); /* Calculate (INTERSECTION_successors Delayed) */ FlowSet succCompSet = (FlowSet) set.topSet(); List succList = unitGraph.getSuccsOf(currentUnit); Iterator succIt = succList.iterator(); while (succIt.hasNext()) { Unit successor = (Unit) succIt.next(); succCompSet.intersection((FlowSet) delayed.getFlowBefore(successor), succCompSet); } /* remove the computation of this set: succCompSet is then: * ((INTERSECTION_successors Delayed) MINUS comp) */ if (equivRhsMap.get(currentUnit) != null) succCompSet.remove(equivRhsMap.get(currentUnit)); /* make the difference: */ FlowSet latest = (FlowSet) delaySet.emptySet(); delaySet.difference(succCompSet, latest); unitToLatest.put(currentUnit, latest); } }
/** * Utility method that produces a new map from the {@link Unit}s of this graph's body to the union * of the values stored in the two argument {@link Map}s, used to combine the maps of exceptional * and unexceptional predecessors and successors into maps of all predecessors and successors. The * values stored in both argument maps must be {@link List}s of {@link Unit}s, which are assumed * not to contain any duplicate <tt>Unit</tt>s. * * @param mapA The first map to be combined. * @param mapB The second map to be combined. */ protected Map combineMapValues(Map mapA, Map mapB) { // The duplicate screen Map result = new HashMap(mapA.size() * 2 + 1, 0.7f); for (Iterator chainIt = unitChain.iterator(); chainIt.hasNext(); ) { Unit unit = (Unit) chainIt.next(); List listA = (List) mapA.get(unit); if (listA == null) { listA = Collections.EMPTY_LIST; } List listB = (List) mapB.get(unit); if (listB == null) { listB = Collections.EMPTY_LIST; } int resultSize = listA.size() + listB.size(); if (resultSize == 0) { result.put(unit, Collections.EMPTY_LIST); } else { List resultList = new ArrayList(resultSize); Iterator listIt = null; // As a minor optimization of the duplicate screening, // copy the longer list first. if (listA.size() >= listB.size()) { resultList.addAll(listA); listIt = listB.iterator(); } else { resultList.addAll(listB); listIt = listA.iterator(); } while (listIt.hasNext()) { Object element = listIt.next(); // It is possible for there to be both an exceptional // and an unexceptional edge connecting two Units // (though probably not in a class generated by // javac), so we need to screen for duplicates. On the // other hand, we expect most of these lists to have // only one or two elements, so it doesn't seem worth // the cost to build a Set to do the screening. if (!resultList.contains(element)) { resultList.add(element); } } result.put(unit, Collections.unmodifiableList(resultList)); } } return result; }
/** * Utility method for adding an edge to maps representing the CFG. * * @param unitToSuccs The {@link Map} from {@link Unit}s to {@link List}s of their successors. * @param unitToPreds The {@link Map} from {@link Unit}s to {@link List}s of their successors. * @param head The {@link Unit} from which the edge starts. * @param tail The {@link Unit} to which the edge flows. */ protected void addEdge(Map unitToSuccs, Map unitToPreds, Unit head, Unit tail) { List headsSuccs = (List) unitToSuccs.get(head); if (headsSuccs == null) { headsSuccs = new ArrayList(3); // We expect this list to // remain short. unitToSuccs.put(head, headsSuccs); } if (!headsSuccs.contains(tail)) { headsSuccs.add(tail); List tailsPreds = (List) unitToPreds.get(tail); if (tailsPreds == null) { tailsPreds = new ArrayList(); unitToPreds.put(tail, tailsPreds); } tailsPreds.add(head); } }
private void addBoxToPatch(String aLabelName, UnitBox aUnitBox) { List patchList = (List) mLabelToPatchList.get(aLabelName); if (patchList == null) { patchList = new ArrayList(); mLabelToPatchList.put(aLabelName, patchList); } patchList.add(aUnitBox); }
/** * Utility method for <tt>UnitGraph</tt> constructors. It computes the edges corresponding to * unexceptional control flow. * * @param unitToSuccs A {@link Map} from {@link Unit}s to {@link List}s of {@link Unit}s. This is * an ``out parameter''; callers must pass an empty {@link Map}. * <tt>buildUnexceptionalEdges</tt> will add a mapping for every <tt>Unit</tt> in the body to * a list of its unexceptional successors. * @param unitToPreds A {@link Map} from {@link Unit}s to {@link List}s of {@link Unit}s. This is * an ``out parameter''; callers must pass an empty {@link Map}. * <tt>buildUnexceptionalEdges</tt> will add a mapping for every <tt>Unit</tt> in the body to * a list of its unexceptional predecessors. */ protected void buildUnexceptionalEdges(Map unitToSuccs, Map unitToPreds) { // Initialize the predecessor sets to empty for (Iterator unitIt = unitChain.iterator(); unitIt.hasNext(); ) { unitToPreds.put(unitIt.next(), new ArrayList()); } Iterator unitIt = unitChain.iterator(); Unit currentUnit, nextUnit; nextUnit = unitIt.hasNext() ? (Unit) unitIt.next() : null; while (nextUnit != null) { currentUnit = nextUnit; nextUnit = unitIt.hasNext() ? (Unit) unitIt.next() : null; List successors = new ArrayList(); if (currentUnit.fallsThrough()) { // Add the next unit as the successor if (nextUnit != null) { successors.add(nextUnit); ((List) unitToPreds.get(nextUnit)).add(currentUnit); } } if (currentUnit.branches()) { for (Iterator targetIt = currentUnit.getUnitBoxes().iterator(); targetIt.hasNext(); ) { Unit target = ((UnitBox) targetIt.next()).getUnit(); // Arbitrary bytecode can branch to the same // target it falls through to, so we screen for duplicates: if (!successors.contains(target)) { successors.add(target); ((List) unitToPreds.get(target)).add(currentUnit); } } } // Store away successors unitToSuccs.put(currentUnit, successors); } }
public void outADeclaration(ADeclaration node) { List localNameList = (List) mProductions.removeLast(); Type type = (Type) mProductions.removeLast(); Iterator it = localNameList.iterator(); List localList = new ArrayList(); while (it.hasNext()) { Local l = Jimple.v().newLocal((String) it.next(), type); mLocals.put(l.getName(), l); localList.add(l); } mProductions.addLast(localList); }
/** * Computes the analysis given a UnitGraph computed from a method body. It is recommended that a * ExceptionalUnitGraph (or similar) be provided for correct results in the case of exceptional * control flow. * * @param g a graph on which to compute the analysis. * @see ExceptionalUnitGraph */ public SimpleLiveLocals(UnitGraph graph) { if (Options.v().time()) Timers.v().liveTimer.start(); if (Options.v().verbose()) G.v() .out .println( "[" + graph.getBody().getMethod().getName() + "] Constructing SimpleLiveLocals..."); SimpleLiveLocalsAnalysis analysis = new SimpleLiveLocalsAnalysis(graph); if (Options.v().time()) Timers.v().livePostTimer.start(); // Build unitToLocals map { unitToLocalsAfter = new HashMap<Unit, List>(graph.size() * 2 + 1, 0.7f); unitToLocalsBefore = new HashMap<Unit, List>(graph.size() * 2 + 1, 0.7f); Iterator unitIt = graph.iterator(); while (unitIt.hasNext()) { Unit s = (Unit) unitIt.next(); FlowSet set = (FlowSet) analysis.getFlowBefore(s); unitToLocalsBefore.put(s, Collections.unmodifiableList(set.toList())); set = (FlowSet) analysis.getFlowAfter(s); unitToLocalsAfter.put(s, Collections.unmodifiableList(set.toList())); } } if (Options.v().time()) Timers.v().livePostTimer.end(); if (Options.v().time()) Timers.v().liveTimer.end(); }
/** * Returns a <code>ThrowableSet</code> which contains all the exceptions in <code>s</code> in * addition to those in this <code>ThrowableSet</code>. * * @param s set of exceptions to add to this set. * @return the union of this set with <code>s</code> * @throws ThrowableSet.AlreadyHasExclusionsException if this <code>ThrowableSet</code> or <code>s * </code> is the result of a {@link #whichCatchableAs(RefType)} operation, so that it is not * possible to represent the addition of <code>s</code> to this <code>ThrowableSet</code>. */ public ThrowableSet add(ThrowableSet s) throws ThrowableSet.AlreadyHasExclusionsException { if (INSTRUMENTING) { Manager.v().addsOfSet++; } if (exceptionsExcluded.size() > 0 || s.exceptionsExcluded.size() > 0) { throw new AlreadyHasExclusionsException( "ThrowableSet.Add(ThrowableSet): attempt to add to [" + this.toString() + "] after removals recorded."); } ThrowableSet result = getMemoizedAdds(s); if (result == null) { if (INSTRUMENTING) { Manager.v().addsInclusionFromSearch++; Manager.v().addsExclusionWithoutSearch++; } result = this.add(s.exceptionsIncluded); memoizedAdds.put(s, result); } else if (INSTRUMENTING) { Manager.v().addsInclusionFromMemo++; Manager.v().addsExclusionWithoutSearch++; } return result; }
/** * Returns a <code>ThrowableSet</code> which contains <code>e</code> and all of its subclasses as * well as the exceptions in this set. * * <p><code>e</code> should be an instance of {@link AnySubType} if you know that the compile-time * type of the exception you are representing is <code>e</code>, but the exception may be * instantiated at run-time by a subclass of <code>e</code>. * * <p>For example, if you were recording the type of the exception thrown by * * <pre> * catch (IOException e) { * throw e; * } * </pre> * * you would call * * <pre> * <code>add(AnySubtype.v(Scene.v().getRefType("java.lang.Exception.IOException")))</code> * </pre> * * since the handler might rethrow any subclass of <code>IOException</code>. * * @param e represents a subtree of the exception class hierarchy to add to this set. * @return a set containing <code>e</code> and all its subclasses, as well as the exceptions * represented by this set. * @throws ThrowableSet.AlreadyHasExclusionsException if this <code>ThrowableSet</code> is the * result of a {@link #whichCatchableAs(RefType)} operation and, thus, unable to represent the * addition of <code>e</code>. */ public ThrowableSet add(AnySubType e) throws ThrowableSet.AlreadyHasExclusionsException { if (INSTRUMENTING) { Manager.v().addsOfAnySubType++; } ThrowableSet result = getMemoizedAdds(e); if (result != null) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMemo++; Manager.v().addsExclusionWithoutSearch++; } return result; } else { FastHierarchy hierarchy = Scene.v().getOrMakeFastHierarchy(); RefType newBase = e.getBase(); if (INSTRUMENTING) { if (exceptionsExcluded.size() != 0) { Manager.v().addsExclusionWithSearch++; } else { Manager.v().addsExclusionWithoutSearch++; } } for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) { RefType exclusionBase = ((AnySubType) i.next()).getBase(); if (hierarchy.canStoreType(newBase, exclusionBase) || hierarchy.canStoreType(exclusionBase, newBase)) { if (INSTRUMENTING) { // To ensure that the subcategories total properly: Manager.v().addsInclusionInterrupted++; } throw new AlreadyHasExclusionsException( "ThrowableSet.add(" + e.toString() + ") to the set [ " + this.toString() + "] where " + exclusionBase.toString() + " is excluded."); } } if (this.exceptionsIncluded.contains(e)) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMap++; } return this; } else { if (INSTRUMENTING) { Manager.v().addsInclusionFromSearch++; } int changes = 0; boolean addNewException = true; Set resultSet = new HashSet(); for (Iterator i = this.exceptionsIncluded.iterator(); i.hasNext(); ) { RefLikeType incumbent = (RefLikeType) i.next(); if (incumbent instanceof RefType) { if (hierarchy.canStoreType(incumbent, newBase)) { // Omit incumbent from result. changes++; } else { resultSet.add(incumbent); } } else if (incumbent instanceof AnySubType) { RefType incumbentBase = ((AnySubType) incumbent).getBase(); // We have to use the base types in these hierarchy calls // because we want to know if _all_ possible // types represented by e can be represented by // the incumbent, or vice versa. if (hierarchy.canStoreType(newBase, incumbentBase)) { addNewException = false; resultSet.add(incumbent); } else if (hierarchy.canStoreType(incumbentBase, newBase)) { // Omit incumbent from result; changes++; } else { resultSet.add(incumbent); } } else { // assertion failure. throw new IllegalStateException( "ThrowableSet.add(AnySubType): Set element " + incumbent.toString() + " is neither a RefType nor an AnySubType."); } } if (addNewException) { resultSet.add(e); changes++; } if (changes > 0) { result = Manager.v().registerSetIfNew(resultSet, this.exceptionsExcluded); } else { result = this; } memoizedAdds.put(e, result); return result; } } }
/** * Returns a <code>ThrowableSet</code> which contains <code>e</code> in addition to the exceptions * in this <code>ThrowableSet</code>. * * <p>Add <code>e</code> as a {@link RefType} when you know that the run-time class of the * exception you are representing is necessarily <code>e</code> and cannot be a subclass of <code> * e</code>. * * <p>For example, if you were recording the type of the exception thrown by * * <pre> * throw new IOException("Permission denied"); * </pre> * * you would call * * <pre> * <code>add(Scene.v().getRefType("java.lang.Exception.IOException"))</code> * </pre> * * since the class of the exception is necessarily <code>IOException</code>. * * @param e the exception class * @return a set containing <code>e</code> as well as the exceptions in this set. * @throws {@link ThrowableSet.IllegalStateException} if this <code>ThrowableSet</code> is the * result of a {@link #whichCatchableAs(RefType)} operation and, thus, unable to represent the * addition of <code>e</code>. */ public ThrowableSet add(RefType e) throws ThrowableSet.AlreadyHasExclusionsException { if (INSTRUMENTING) { Manager.v().addsOfRefType++; } if (this.exceptionsIncluded.contains(e)) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMap++; Manager.v().addsExclusionWithoutSearch++; } return this; } else { ThrowableSet result = getMemoizedAdds(e); if (result != null) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMemo++; Manager.v().addsExclusionWithoutSearch++; } return result; } else { if (INSTRUMENTING) { Manager.v().addsInclusionFromSearch++; if (exceptionsExcluded.size() != 0) { Manager.v().addsExclusionWithSearch++; } else { Manager.v().addsExclusionWithoutSearch++; } } FastHierarchy hierarchy = Scene.v().getOrMakeFastHierarchy(); for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) { RefType exclusionBase = ((AnySubType) i.next()).getBase(); if (hierarchy.canStoreType(e, exclusionBase)) { throw new AlreadyHasExclusionsException( "ThrowableSet.add(RefType): adding" + e.toString() + " to the set [ " + this.toString() + "] where " + exclusionBase.toString() + " is excluded."); } } for (Iterator i = exceptionsIncluded.iterator(); i.hasNext(); ) { RefLikeType incumbent = (RefLikeType) i.next(); if (incumbent instanceof AnySubType) { // Need to use incumbent.getBase() because // hierarchy.canStoreType() assumes that parent // is not an AnySubType. RefType incumbentBase = ((AnySubType) incumbent).getBase(); if (hierarchy.canStoreType(e, incumbentBase)) { memoizedAdds.put(e, this); return this; } } else if (!(incumbent instanceof RefType)) { // assertion failure. throw new IllegalStateException( "ThrowableSet.add(RefType): Set element " + incumbent.toString() + " is neither a RefType nor an AnySubType."); } } Set resultSet = new HashSet(this.exceptionsIncluded); resultSet.add(e); result = Manager.v().registerSetIfNew(resultSet, this.exceptionsExcluded); memoizedAdds.put(e, result); return result; } } }
SimpleLiveLocalsAnalysis(UnitGraph g) { super(g); if (Options.v().time()) Timers.v().liveSetupTimer.start(); emptySet = new ArraySparseSet(); // Create kill sets. { unitToKillSet = new HashMap<Unit, FlowSet>(g.size() * 2 + 1, 0.7f); Iterator unitIt = g.iterator(); while (unitIt.hasNext()) { Unit s = (Unit) unitIt.next(); FlowSet killSet = emptySet.clone(); Iterator boxIt = s.getDefBoxes().iterator(); while (boxIt.hasNext()) { ValueBox box = (ValueBox) boxIt.next(); if (box.getValue() instanceof Local) killSet.add(box.getValue(), killSet); } unitToKillSet.put(s, killSet); } } // Create generate sets { unitToGenerateSet = new HashMap<Unit, FlowSet>(g.size() * 2 + 1, 0.7f); Iterator unitIt = g.iterator(); while (unitIt.hasNext()) { Unit s = (Unit) unitIt.next(); FlowSet genSet = emptySet.clone(); Iterator boxIt = s.getUseBoxes().iterator(); while (boxIt.hasNext()) { ValueBox box = (ValueBox) boxIt.next(); if (box.getValue() instanceof Local) genSet.add(box.getValue(), genSet); } unitToGenerateSet.put(s, genSet); } } if (Options.v().time()) Timers.v().liveSetupTimer.end(); if (Options.v().time()) Timers.v().liveAnalysisTimer.start(); doAnalysis(); if (Options.v().time()) Timers.v().liveAnalysisTimer.end(); }
public void outAFullMethodBody(AFullMethodBody node) { Object catchClause = null; JimpleBody jBody = Jimple.v().newBody(); if (node.getCatchClause() != null) { int size = node.getCatchClause().size(); for (int i = 0; i < size; i++) jBody.getTraps().addFirst((Trap) mProductions.removeLast()); } if (node.getStatement() != null) { int size = node.getStatement().size(); Unit lastStmt = null; for (int i = 0; i < size; i++) { Object o = mProductions.removeLast(); if (o instanceof Unit) { jBody.getUnits().addFirst(o); lastStmt = (Unit) o; } else if (o instanceof String) { if (lastStmt == null) throw new RuntimeException("impossible"); mLabelToStmtMap.put(o, lastStmt); } else throw new RuntimeException("impossible"); } } if (node.getDeclaration() != null) { int size = node.getDeclaration().size(); for (int i = 0; i < size; i++) { List localList = (List) mProductions.removeLast(); int listSize = localList.size(); for (int j = listSize - 1; j >= 0; j--) jBody.getLocals().addFirst(localList.get(j)); } } Iterator it = mLabelToPatchList.keySet().iterator(); while (it.hasNext()) { String label = (String) it.next(); Unit target = (Unit) mLabelToStmtMap.get(label); Iterator patchIt = ((List) mLabelToPatchList.get(label)).iterator(); while (patchIt.hasNext()) { UnitBox box = (UnitBox) patchIt.next(); box.setUnit(target); } } /* Iterator it = mLabelToStmtMap.keySet().iterator(); while(it.hasNext()) { String label = (String) it.next(); Unit target = (Unit) mLabelToStmtMap.get(label); List l = (List) mLabelToPatchList.get(label); if(l != null) { Iterator patchIt = l.iterator(); while(patchIt.hasNext()) { UnitBox box = (UnitBox) patchIt.next(); box.setUnit(target); } } } */ mProductions.addLast(jBody); }
void handleClassAnnotation(ClassDef classDef) { Set<? extends Annotation> aSet = classDef.getAnnotations(); if (aSet == null || aSet.isEmpty()) return; List<Tag> tags = handleAnnotation(aSet, classDef.getType()); if (tags == null) return; InnerClassAttribute ica = null; for (Tag t : tags) if (t != null) { if (t instanceof InnerClassTag) { if (ica == null) { // Do we already have an InnerClassAttribute? ica = (InnerClassAttribute) clazz.getTag("InnerClassAttribute"); // If not, create one if (ica == null) { ica = new InnerClassAttribute(); clazz.addTag(ica); } } ica.add((InnerClassTag) t); } else if (t instanceof VisibilityAnnotationTag) { // If a dalvik/annotation/AnnotationDefault tag is present // in a class, its AnnotationElements must be propagated // to methods through the creation of new AnnotationDefaultTag. VisibilityAnnotationTag vt = (VisibilityAnnotationTag) t; for (AnnotationTag a : vt.getAnnotations()) { if (a.getType().equals("Ldalvik/annotation/AnnotationDefault;")) { for (AnnotationElem ae : a.getElems()) { if (ae instanceof AnnotationAnnotationElem) { AnnotationAnnotationElem aae = (AnnotationAnnotationElem) ae; AnnotationTag at = aae.getValue(); // extract default elements Map<String, AnnotationElem> defaults = new HashMap<String, AnnotationElem>(); for (AnnotationElem aelem : at.getElems()) { defaults.put(aelem.getName(), aelem); } // create default tags containing default elements // and add tags on methods for (SootMethod sm : clazz.getMethods()) { String methodName = sm.getName(); if (defaults.containsKey(methodName)) { AnnotationElem e = defaults.get(methodName); // Okay, the name is the same, but is it actually the same type? Type annotationType = getSootType(e); boolean isCorrectType = false; if (annotationType == null) { // we do not know the type of the annotation, so we guess it's the correct // type. isCorrectType = true; } else { if (annotationType.equals(sm.getReturnType())) { isCorrectType = true; } else if (annotationType.equals(ARRAY_TYPE)) { if (sm.getReturnType() instanceof ArrayType) isCorrectType = true; } } if (isCorrectType && sm.getParameterCount() == 0) { e.setName("default"); AnnotationDefaultTag d = new AnnotationDefaultTag(e); sm.addTag(d); // In case there is more than one matching method, we only use the first one defaults.remove(sm.getName()); } } } for (Entry<String, AnnotationElem> leftOverEntry : defaults.entrySet()) { // We were not able to find a matching method for the tag, because the return // signature // does not match SootMethod found = clazz.getMethodByNameUnsafe(leftOverEntry.getKey()); AnnotationElem element = leftOverEntry.getValue(); if (found != null) { element.setName("default"); AnnotationDefaultTag d = new AnnotationDefaultTag(element); found.addTag(d); } } } } } } if (!(vt.getVisibility() == AnnotationConstants.RUNTIME_INVISIBLE)) clazz.addTag(vt); } else { clazz.addTag(t); } Debug.printDbg("add class annotation: ", t, " type: ", t.getClass()); } }
/** * Parse the command line arguments specific to CFGViewer, and convert them into phase options for * jtp.printcfg. * * @return an array of arguments to pass on to Soot.Main.main(). */ private String[] parse_options(String[] args) { List<String> sootArgs = new ArrayList<String>(args.length); for (int i = 0, n = args.length; i < n; i++) { if (args[i].equals("--alt-classpath") || args[i].equals("--alt-class-path")) { sootArgs.add("-p"); sootArgs.add(phaseFullname); sootArgs.add(altClassPathOptionName + ':' + args[++i]); } else if (args[i].startsWith("--graph=")) { sootArgs.add("-p"); sootArgs.add(phaseFullname); sootArgs.add(graphTypeOptionName + ':' + args[i].substring("--graph=".length())); } else if (args[i].startsWith("--ir=")) { sootArgs.add("-p"); sootArgs.add(phaseFullname); sootArgs.add(irOptionName + ':' + args[i].substring("--ir=".length())); } else if (args[i].equals("--brief")) { sootArgs.add("-p"); sootArgs.add(phaseFullname); sootArgs.add(briefLabelOptionName + ":true"); } else if (args[i].equals("--multipages")) { sootArgs.add("-p"); sootArgs.add(phaseFullname); sootArgs.add(multipageOptionName + ":true"); } else if (args[i].equals("--help")) { return new String[0]; // This is a cheesy method to inveigle // our caller into printing the help // and exiting. } else if (args[i].equals("--soot-class-path") || args[i].equals("-soot-class-path") || args[i].equals("--soot-classpath") || args[i].equals("-soot-classpath") || args[i].equals("--process-dir") || args[i].equals("-process-dir") || args[i].equals("--android-jars") || args[i].equals("-android-jars") || args[i].equals("--force-android-jar") || args[i].equals("-force-android-jar")) { // Pass classpaths without treating ":" as a method specifier. sootArgs.add(args[i]); sootArgs.add(args[++i]); } else if (args[i].equals("-p") || args[i].equals("--phase-option") || args[i].equals("-phase-option")) { // Pass phase options without treating ":" as a method // specifier. sootArgs.add(args[i]); sootArgs.add(args[++i]); sootArgs.add(args[++i]); } else { int smpos = args[i].indexOf(':'); if (smpos == -1) { sootArgs.add(args[i]); } else { String clsname = args[i].substring(0, smpos); sootArgs.add(clsname); String methname = args[i].substring(smpos + 1); if (methodsToPrint == null) { methodsToPrint = new HashMap<String, String>(); } methodsToPrint.put(methname, clsname); } } } String[] sootArgsArray = new String[sootArgs.size()]; return (String[]) sootArgs.toArray(sootArgsArray); }