presto.android.gui.JimpleUtil.java Source code

Java tutorial

Introduction

Here is the source code for presto.android.gui.JimpleUtil.java

Source

/*
 * JimpleUtil.java - part of the GATOR project
 *
 * Copyright (c) 2014, The Ohio State University
 *
 * This file is distributed under the terms described in LICENSE in the
 * root directory.
 */
package presto.android.gui;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import presto.android.Hierarchy;
import presto.android.MethodNames;
import soot.ArrayType;
import soot.Body;
import soot.IntType;
import soot.Local;
import soot.RefType;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Type;
import soot.Unit;
import soot.Value;
import soot.jimple.DefinitionStmt;
import soot.jimple.Expr;
import soot.jimple.IdentityStmt;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.InvokeExpr;
import soot.jimple.ReturnStmt;
import soot.jimple.Stmt;
import soot.jimple.ThisRef;
import soot.tagkit.LineNumberTag;

import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.Files;

public class JimpleUtil implements MethodNames {
    Hierarchy hier;

    private static JimpleUtil instance;

    public static JimpleUtil v(Hierarchy hier) {
        if (instance == null) {
            instance = new JimpleUtil();
            instance.s2m = Maps.newHashMap();
            instance.exprToStmt = Maps.newHashMap();
            instance.hier = hier;
        }
        return instance;
    }

    public static JimpleUtil v() {
        return v(Hierarchy.v());
    }

    // /////////////////////////////////////////
    // General Jimple utils
    // Assume "l = ..."
    public Local lhsLocal(Stmt s) {
        return (Local) ((DefinitionStmt) s).getLeftOp();
    }

    // Assume "... = ..."
    public Value lhs(Stmt s) {
        return ((DefinitionStmt) s).getLeftOp();
    }

    public Local receiver(Stmt s) {
        return (Local) ((InstanceInvokeExpr) s.getInvokeExpr()).getBase();
    }

    public Local receiver(InvokeExpr ie) {
        return (Local) ((InstanceInvokeExpr) ie).getBase();
    }

    public Local thisLocal(SootMethod m) {
        IdentityStmt first = (IdentityStmt) m.retrieveActiveBody().getUnits().iterator().next();
        if (!(first.getRightOp() instanceof ThisRef)) {
            throw new RuntimeException();
        }
        return lhsLocal(first);
    }

    /**
     * Returns the local variable corresponding to the n-th parameter in the
     * specified method. The counting starts from 0. For an instance method and
     * n=0, this method is equivalent to thisLocal().
     * @param method the specified method
     * @param index specifies the position of the parameter
     * @return
     */
    public Local localForNthParameter(SootMethod method, int index) {
        Iterator<Unit> stmts = method.retrieveActiveBody().getUnits().iterator();
        for (int i = 0; i < index; i++) {
            stmts.next();
        }
        Stmt idStmt = (Stmt) stmts.next();
        if (!(idStmt instanceof DefinitionStmt)) {
            System.out.println("--- " + method);
            System.out.println(method.retrieveActiveBody());
        }
        return lhsLocal(idStmt);
    }

    // /////////////////////////////////////////
    // App-specific recording
    public Map<Stmt, SootMethod> s2m;

    public SootMethod lookup(Stmt s) {
        return s2m.get(s);
    }

    public void record(Stmt s, SootMethod m) {
        s2m.put(s, m);
    }

    public Map<Expr, Stmt> exprToStmt;

    public Stmt lookup(Expr e) {
        return exprToStmt.get(e);
    }

    public void record(Expr e, Stmt s) {
        exprToStmt.put(e, s);
    }

    public String toString(Expr e) {
        Stmt s = lookup(e);
        SootMethod m = lookup(s);
        return s + " @ " + m;
    }

    public Set<Value> getReturnValues(SootMethod method) {
        Preconditions.checkArgument(method.isConcrete());

        Set<Value> returnValues = Sets.newHashSet();
        Body body = method.retrieveActiveBody();
        Iterator<Unit> stmts = body.getUnits().iterator();
        while (stmts.hasNext()) {
            Stmt d = (Stmt) stmts.next();
            if (!(d instanceof ReturnStmt)) {
                continue;
            }
            Value retval = ((ReturnStmt) d).getOp();
            returnValues.add(retval);
        }
        return returnValues;
    }

    // Analysis-specific
    public boolean interesting(Type t) {
        if (t instanceof ArrayType) {
            return interesting(((ArrayType) t).baseType);
        }
        return t instanceof IntType || t instanceof RefType;
    }

    public int getLineNumber(Unit u) {
        int lineNumber = -1;
        LineNumberTag tag = (LineNumberTag) u.getTag("LineNumberTag");
        if (tag != null) {
            lineNumber = tag.getLineNumber();
        }
        return lineNumber;
    }

    // /////////////////////////////////////////
    // Android-specific
    public Value getLayoutId(Stmt s) {
        InvokeExpr ie = s.getInvokeExpr();
        SootMethod m = ie.getMethod();
        SootClass c = m.getDeclaringClass();
        String sig = m.getSignature();
        String subsig = m.getSubSignature();
        if (subsig.equals(setContentViewSubSig)) {
            if (hier.libActivityClasses.contains(c) || hier.applicationActivityClasses.contains(c)) {
                return ie.getArg(0);
            }
        }
        if (sig.equals(layoutInflaterInflate) || sig.equals(layoutInflaterInflateBool)) {
            return ie.getArg(0);
        }
        if (sig.equals(viewCtxInflate)) {
            return ie.getArg(1);
        }
        return null;
    }

    /**
     * Returns the set of methods in the specified interface. When the parameter
     * is not an interface (as expected), return an empty set.
     *
     * @param interfaceType the interface specified in SootClass
     * @return set of the methods in the specified interface
     */
    public Set<SootMethod> getMethodsInInterface(SootClass interfaceType) {
        if (interfaceType.isInterface()) {
            return Sets.newHashSet(interfaceType.getMethods());
        } else {
            return Collections.emptySet();
        }
    }

    public void writeAllJimples() {
        File tempDir = Files.createTempDir();
        String absPath = tempDir.getAbsolutePath();
        ExecutorService executor = Executors.newFixedThreadPool(4);
        for (final SootClass cls : Scene.v().getApplicationClasses()) {
            String clsName = cls.getName();
            String fileName = absPath + "/" + clsName + ".jimple";
            final File jimpleFile = new File(fileName);
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    PrintWriter out = null;
                    try {
                        out = new PrintWriter(new FileWriter(jimpleFile));
                        for (SootField f : cls.getFields()) {
                            out.println("!!! " + f.getSignature());
                            out.println();
                        }
                        for (SootMethod m : cls.getMethods()) {
                            out.println("--- " + m.getSignature());
                            if (m.isConcrete()) {
                                out.println(m.retrieveActiveBody());
                            }
                            out.println();
                        }
                        out.flush();
                        System.out.print(".");
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            if (out != null) {
                                out.close();
                            }
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            });
        }
        try {
            executor.shutdown();
            executor.awaitTermination(30, TimeUnit.MINUTES);
            System.out.println("\nJimple code saved to " + absPath);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}