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

com.googlecode.d2j.converter.Dex2IRConverter Maven / Gradle / Ivy

The newest version!
package com.googlecode.d2j.converter;

import com.googlecode.d2j.DexLabel;
import com.googlecode.d2j.DexType;
import com.googlecode.d2j.Field;
import com.googlecode.d2j.Method;
import com.googlecode.d2j.node.DexCodeNode;
import com.googlecode.d2j.node.TryCatchNode;
import com.googlecode.d2j.node.analysis.DvmFrame;
import com.googlecode.d2j.node.analysis.DvmInterpreter;
import com.googlecode.d2j.node.insn.*;
import com.googlecode.d2j.reader.Op;
import com.googlecode.dex2jar.ir.IrMethod;
import com.googlecode.dex2jar.ir.Trap;
import com.googlecode.dex2jar.ir.TypeClass;
import com.googlecode.dex2jar.ir.expr.Exprs;
import com.googlecode.dex2jar.ir.expr.Local;
import com.googlecode.dex2jar.ir.expr.Value;
import com.googlecode.dex2jar.ir.stmt.*;

import java.util.*;

import static com.googlecode.dex2jar.ir.expr.Exprs.*;
import static com.googlecode.dex2jar.ir.stmt.Stmts.*;

public class Dex2IRConverter {
    Map labelMap = new HashMap<>();
    List insnList;
    int[] parentCount;
    IrMethod target;
    DexCodeNode dexCodeNode;
    List preEmit = new ArrayList<>();
    List currentEmit;
    Map map = new HashMap<>();
    private Dex2IrFrame[] frames;
    private ArrayList[] emitStmts;
    boolean initAllToZero = true;

    static int sizeofType(String s) {
        char t = s.charAt(0);
        if (t == 'J' || t == 'D') {
            return 2;
        } else {
            return 1;
        }
    }

    static class Dex2IrFrame extends DvmFrame {
        public Dex2IrFrame(int totalRegister) {
            super(totalRegister);
        }
    }

    static int methodArgCount(String[] args) {
        int i = 0;
        for (String s : args) {
            i += sizeofType(s);
        }
        return i;
    }

    public IrMethod convert(boolean isStatic, Method method, DexCodeNode dexCodeNode) {
        this.dexCodeNode = dexCodeNode;
        IrMethod irMethod = new IrMethod();
        irMethod.args = method.getParameterTypes();
        irMethod.ret = method.getReturnType();
        irMethod.owner = method.getOwner();
        irMethod.name = method.getName();
        irMethod.isStatic = isStatic;
        target = irMethod;


        insnList = dexCodeNode.stmts;
        for (int i = 0; i < insnList.size(); i++) {
            DexStmtNode stmtNode = insnList.get(i);
            stmtNode.__index = i;
            if (stmtNode instanceof DexLabelStmtNode) {
                DexLabelStmtNode dexLabelStmtNode = (DexLabelStmtNode) stmtNode;
                labelMap.put(dexLabelStmtNode.label, dexLabelStmtNode);
            }
        }

        fixExceptionHandlers();

        BitSet[] exBranch = new BitSet[insnList.size()];
        parentCount = new int[insnList.size()];
        initParentCount(parentCount);

        BitSet handlers = new BitSet(insnList.size());
        initExceptionHandlers(dexCodeNode, exBranch, handlers);

        DvmInterpreter interpreter = buildInterpreter();
        frames = new Dex2IrFrame[insnList.size()];
        emitStmts = new ArrayList[insnList.size()];
        BitSet access = new BitSet(insnList.size());

        dfs(exBranch, handlers, access, interpreter);


        StmtList stmts = target.stmts;
        stmts.addAll(preEmit);
        for (int i = 0; i < insnList.size(); i++) {
            DexStmtNode p = insnList.get(i);
            if (access.get(i)) {
                List es = emitStmts[i];
                if (es != null) {
                    stmts.addAll(es);
                }
            } else {
                if (p instanceof DexLabelStmtNode) {
                    stmts.add(getLabel(((DexLabelStmtNode) p).label));
                }
            }
        }
        emitStmts = null;


        Queue queue = new LinkedList<>();

        for (int i1 = 0; i1 < frames.length; i1++) {
            Dex2IrFrame frame = frames[i1];
            if (parentCount[i1] > 1 && frame != null && access.get(i1)) {
                for (int j = 0; j < frame.getTotalRegisters(); j++) {
                    DvmValue v = frame.getReg(j);
                    addToQueue(queue, v);
                }
            }

        }

        while (!queue.isEmpty()) {
            DvmValue v = queue.poll();
            getLocal(v);
            if (v.parent != null) {
                if (v.parent.local == null) {
                    queue.add(v.parent);
                }
            }
            if (v.otherParent != null) {
                for (DvmValue v2 : v.otherParent) {
                    if (v2.local == null) {
                        queue.add(v2);
                    }
                }
            }
        }

        Set phiValues = new HashSet<>();
        List phiLabels = new ArrayList<>();
        for (int i = 0; i < frames.length; i++) {
            Dex2IrFrame frame = frames[i];
            if (parentCount[i] > 1 && frame != null && access.get(i)) {
                DexStmtNode p = insnList.get(i);
                LabelStmt labelStmt = getLabel(((DexLabelStmtNode) p).label);
                List phis = new ArrayList<>();
                for (int j = 0; j < frame.getTotalRegisters(); j++) {
                    DvmValue v = frame.getReg(j);
                    addPhi(v, phiValues, phis);
                }

                labelStmt.phis = phis;
                phiLabels.add(labelStmt);
            }
        }
        if (phiLabels.size() > 0) {
            target.phiLabels = phiLabels;
        }

        return target;
    }

    /**
     * issue 63
     * 
     * L1:
     *    STMTs
     * L2:
     *    RETURN
     * L1~L2 > L2 Exception
     * 
*

* fix to *

*

     * L1:
     *    STMTs
     * L2:
     *    RETURN
     * L3:
     *    goto L2
     * L1~L2 > L3 Exception
     * 
*/ private void fixExceptionHandlers() { if (dexCodeNode.tryStmts == null) { return; } Queue q = new LinkedList<>(); Set handlers = new TreeSet<>(); for (TryCatchNode tcb : dexCodeNode.tryStmts) { for (DexLabel h : tcb.handler) { int index = indexOf(h); q.add(index + 1); // add the next insn after label handlers.add(index); } } q.add(0); Map needChange = new HashMap<>(); BitSet access = new BitSet(insnList.size()); while (!q.isEmpty()) { Integer key = q.poll(); int index = key; if (access.get(index)) { continue; } else { access.set(index); } if (handlers.contains(key)) { // the cfg goes to a exception handler needChange.put(key, null); } DexStmtNode node = insnList.get(key); if (node.op == null) { q.add(index + 1); } else { Op op = node.op; if (op.canContinue()) { q.add(index + 1); } if (op.canBranch()) { JumpStmtNode jump = (JumpStmtNode) node; q.add(indexOf(jump.label)); } if (op.canSwitch()) { for (DexLabel dexLabel : ((BaseSwitchStmtNode) node).labels) { q.add(indexOf(dexLabel)); } } } } if (needChange.size() > 0) { for (TryCatchNode tcb : dexCodeNode.tryStmts) { DexLabel[] handler = tcb.handler; for (int i = 0; i < handler.length; i++) { DexLabel h = handler[i]; int index = indexOf(h); if (needChange.containsKey(index)) { DexLabel n = needChange.get(index); if (n == null) { n = new DexLabel(); needChange.put(index, n); DexLabelStmtNode dexStmtNode = new DexLabelStmtNode(n); dexStmtNode.__index = insnList.size(); insnList.add(dexStmtNode); labelMap.put(n, dexStmtNode); JumpStmtNode jumpStmtNode = new JumpStmtNode(Op.GOTO, 0, 0, h); jumpStmtNode.__index = insnList.size(); insnList.add(jumpStmtNode); } handler[i] = n; } } } } } private void initExceptionHandlers(DexCodeNode dexCodeNode, BitSet[] exBranch, BitSet handlers) { if (dexCodeNode.tryStmts != null) { for (TryCatchNode tcb : dexCodeNode.tryStmts) { for (DexLabel h : tcb.handler) { handlers.set(indexOf(h)); } boolean hasEx = false; int endIndex = indexOf(tcb.end); for (int p = indexOf(tcb.start) + 1; p < endIndex; p++) { DexStmtNode stmt = insnList.get(p); if (stmt.op != null && stmt.op.canThrow()) { hasEx = true; BitSet x = exBranch[p]; if (x == null) { x = exBranch[p] = new BitSet(insnList.size()); } for (DexLabel h : tcb.handler) { int hIndex = indexOf(h); x.set(hIndex); parentCount[hIndex]++; } } } if (hasEx) { target.traps.add(new Trap(getLabel(tcb.start), getLabel(tcb.end), getLabels(tcb.handler), tcb.type)); } } } } private void addPhi(DvmValue v, Set phiValues, List phis) { if (v != null) { if (v.local != null) { if (v.parent != null) { phiValues.add(getLocal(v.parent)); } if (v.otherParent != null) { for (DvmValue v2 : v.otherParent) { phiValues.add(getLocal(v2)); } } if (phiValues.size() > 0) { phis.add(Stmts.nAssign(v.local, Exprs .nPhi(phiValues.toArray(new com.googlecode.dex2jar.ir.expr.Value[phiValues.size()])))); phiValues.clear(); } } } } Local getLocal(DvmValue value) { Local local = value.local; if (local == null) { local = value.local = newLocal(); } return local; } private void addToQueue(Queue queue, DvmValue v) { if (v != null) { if (v.local != null) { if (v.parent != null) { if (v.parent.local == null) { queue.add(v.parent); } } if (v.otherParent != null) { for (DvmValue v2 : v.otherParent) { if (v2.local == null) { queue.add(v2); } } } } } } private void setCurrentEmit(int index) { currentEmit = emitStmts[index]; if (currentEmit == null) { currentEmit = emitStmts[index] = new ArrayList<>(1); } } private void dfs(BitSet[] exBranch, BitSet handlers, BitSet access, DvmInterpreter interpreter) { currentEmit = preEmit; Dex2IrFrame first = initFirstFrame(dexCodeNode, target); if (parentCount[0] > 1) { merge(first, 0); } else { frames[0] = first; } Stack stack = new Stack<>(); stack.push(insnList.get(0)); Dex2IrFrame tmp = new Dex2IrFrame(dexCodeNode.totalRegister); while (!stack.isEmpty()) { DexStmtNode p = stack.pop(); int index = p.__index; if (!access.get(index)) { access.set(index); } else { continue; } Dex2IrFrame frame = frames[index]; setCurrentEmit(index); if (p instanceof DexLabelStmtNode) { emit(getLabel(((DexLabelStmtNode) p).label)); if (handlers.get(index)) { Local ex = newLocal(); emit(Stmts.nIdentity(ex, Exprs.nExceptionRef("Ljava/lang/Throwable;"))); frame.setTmp(new DvmValue(ex)); } } BitSet ex = exBranch[index]; if (ex != null) { for (int i = ex.nextSetBit(0); i >= 0; i = ex.nextSetBit(i + 1)) { merge(frame, i); stack.push(insnList.get(i)); } } tmp.init(frame); try { if (p.op != null) { switch (p.op) { case RETURN_VOID: emit(nReturnVoid()); break; case GOTO: case GOTO_16: case GOTO_32: emit(nGoto(getLabel(((JumpStmtNode) p).label))); break; case NOP: emit(nNop()); break; case BAD_OP: emit(nThrow(nInvokeNew(new Value[]{nString("bad dex opcode")}, new String[]{ "Ljava/lang/String;"}, "Ljava/lang/VerifyError;"))); break; default: tmp.execute(p, interpreter); break; } } } catch (Exception exception) { throw new RuntimeException("Fail on Op " + p.op + " index " + index, exception); } if (p.op != null) { Op op = p.op; if (op.canBranch()) { JumpStmtNode jump = (JumpStmtNode) p; int targetIndex = indexOf(jump.label); stack.push(insnList.get(targetIndex)); merge(tmp, targetIndex); } if (op.canSwitch()) { BaseSwitchStmtNode switchStmtNode = (BaseSwitchStmtNode) p; for (DexLabel label : switchStmtNode.labels) { int targetIndex = indexOf(label); stack.push(insnList.get(targetIndex)); merge(tmp, targetIndex); } } if (op.canContinue()) { stack.push(insnList.get(index + 1)); merge(tmp, index + 1); } } else { stack.push(insnList.get(index + 1)); merge(tmp, index + 1); } // cleanup frame it is useless if (parentCount[index] <= 1) { frames[index] = null; } } } private void relate(DvmValue parent, DvmValue child) { if (child.parent == null) { child.parent = parent; } else if (child.parent == parent) { // } else { if (child.otherParent == null) { child.otherParent = new HashSet<>(5); } child.otherParent.add(parent); } } void merge(Dex2IrFrame src, int dst) { Dex2IrFrame distFrame = frames[dst]; if (distFrame == null) { distFrame = frames[dst] = new Dex2IrFrame(dexCodeNode.totalRegister); } if (parentCount[dst] > 1) { for (int i = 0; i < src.getTotalRegisters(); i++) { DvmValue p = src.getReg(i); DvmValue q = distFrame.getReg(i); if (p != null) { if (q == null) { q = new DvmValue(); distFrame.setReg(i, q); } relate(p, q); } } } else { distFrame.init(src); } } private Local newLocal() { Local thiz = Exprs.nLocal(target.locals.size()); target.locals.add(thiz); return thiz; } void emit(Stmt stmt) { currentEmit.add(stmt); } private Dex2IrFrame initFirstFrame(DexCodeNode methodNode, IrMethod target) { Dex2IrFrame first = new Dex2IrFrame(methodNode.totalRegister); int x = methodNode.totalRegister - methodArgCount(target.args); if (!target.isStatic) {// not static Local thiz = newLocal(); emit(Stmts.nIdentity(thiz, Exprs.nThisRef(target.owner))); first.setReg(x - 1, new DvmValue(thiz)); } for (int i = 0; i < target.args.length; i++) { Local p = newLocal(); emit(Stmts.nIdentity(p, Exprs.nParameterRef(target.args[i], i))); first.setReg(x, new DvmValue(p)); x += sizeofType(target.args[i]); } if (initAllToZero) { for (int i = 0; i < first.getTotalRegisters(); i++) { if (first.getReg(i) == null) { Local p = newLocal(); emit(nAssign(p, nInt(0))); first.setReg(i, new DvmValue(p)); } } } return first; } private DvmInterpreter buildInterpreter() { return new DvmInterpreter() { DvmValue b(com.googlecode.dex2jar.ir.expr.Value value) { Local local = newLocal(); emit(Stmts.nAssign(local, value)); return new DvmValue(local); } @Override public DvmValue newOperation(DexStmtNode insn) { switch (insn.op) { case CONST: case CONST_16: case CONST_4: case CONST_HIGH16: return b(nInt((Integer) ((ConstStmtNode) insn).value)); case CONST_WIDE: case CONST_WIDE_16: case CONST_WIDE_32: case CONST_WIDE_HIGH16: return b(nLong((Long) ((ConstStmtNode) insn).value)); case CONST_CLASS: return b(nType((DexType) ((ConstStmtNode) insn).value)); case CONST_STRING: case CONST_STRING_JUMBO: return b(nString((String) ((ConstStmtNode) insn).value)); case SGET: case SGET_BOOLEAN: case SGET_BYTE: case SGET_CHAR: case SGET_OBJECT: case SGET_SHORT: case SGET_WIDE: Field field = ((FieldStmtNode) insn).field; return b(nStaticField(field.getOwner(), field.getName(), field.getType())); case NEW_INSTANCE: return b(nNew(((TypeStmtNode) insn).type)); default: } return null; } @Override public DvmValue copyOperation(DexStmtNode insn, DvmValue value) { if (value == null) { emitNotFindOperand(insn); return b(nInt(0)); } return b(getLocal(value)); } @Override public DvmValue unaryOperation(DexStmtNode insn, DvmValue value) { if (value == null) { emitNotFindOperand(insn); return b(nInt(0)); } Local local = getLocal(value); switch (insn.op) { case NOT_INT: return b(nNot(local, "I")); case NOT_LONG: return b(nNot(local, "J")); case NEG_DOUBLE: return b(nNeg(local, "D")); case NEG_FLOAT: return b(nNeg(local, "F")); case NEG_INT: return b(nNeg(local, "I")); case NEG_LONG: return b(nNeg(local, "J")); case INT_TO_BYTE: return b(nCast(local, "I", "B")); case INT_TO_CHAR: return b(nCast(local, "I", "C")); case INT_TO_DOUBLE: return b(nCast(local, "I", "D")); case INT_TO_FLOAT: return b(nCast(local, "I", "F")); case INT_TO_LONG: return b(nCast(local, "I", "J")); case INT_TO_SHORT: return b(nCast(local, "I", "S")); case FLOAT_TO_DOUBLE: return b(nCast(local, "F", "D")); case FLOAT_TO_INT: return b(nCast(local, "F", "I")); case FLOAT_TO_LONG: return b(nCast(local, "F", "J")); case DOUBLE_TO_FLOAT: return b(nCast(local, "D", "F")); case DOUBLE_TO_INT: return b(nCast(local, "D", "I")); case DOUBLE_TO_LONG: return b(nCast(local, "D", "J")); case LONG_TO_DOUBLE: return b(nCast(local, "J", "D")); case LONG_TO_FLOAT: return b(nCast(local, "J", "F")); case LONG_TO_INT: return b(nCast(local, "J", "I")); case ARRAY_LENGTH: return b(nLength(local)); case IF_EQZ: emit(nIf(Exprs .nEq(local, nInt(0), TypeClass.ZIL.name), getLabel(((JumpStmtNode) insn).label))); return null; case IF_GEZ: emit(nIf(Exprs.nGe(local, nInt(0), "I"), getLabel(((JumpStmtNode) insn).label))); return null; case IF_GTZ: emit(nIf(Exprs.nGt(local, nInt(0), "I"), getLabel(((JumpStmtNode) insn).label))); return null; case IF_LEZ: emit(nIf(Exprs.nLe(local, nInt(0), "I"), getLabel(((JumpStmtNode) insn).label))); return null; case IF_LTZ: emit(nIf(Exprs.nLt(local, nInt(0), "I"), getLabel(((JumpStmtNode) insn).label))); return null; case IF_NEZ: emit(nIf(Exprs .nNe(local, nInt(0), TypeClass.ZIL.name), getLabel(((JumpStmtNode) insn).label))); return null; case PACKED_SWITCH: case SPARSE_SWITCH: DexLabel[] labels = ((BaseSwitchStmtNode) insn).labels; LabelStmt[] lss = new LabelStmt[labels.length]; for (int i = 0; i < labels.length; i++) { lss[i] = getLabel(labels[i]); } LabelStmt d = new LabelStmt(); if (insn.op == Op.PACKED_SWITCH) { emit(nTableSwitch(local, ((PackedSwitchStmtNode) insn).first_case, lss, d)); } else { emit(nLookupSwitch(local, ((SparseSwitchStmtNode) insn).cases, lss, d)); } emit(d); return null; case SPUT: case SPUT_BOOLEAN: case SPUT_BYTE: case SPUT_CHAR: case SPUT_OBJECT: case SPUT_SHORT: case SPUT_WIDE: { Field field = ((FieldStmtNode) insn).field; emit(nAssign(nStaticField(field.getOwner(), field.getName(), field.getType()), local)); return null; } case IGET: case IGET_BOOLEAN: case IGET_BYTE: case IGET_CHAR: case IGET_OBJECT: case IGET_SHORT: case IGET_WIDE: { Field field = ((FieldStmtNode) insn).field; return b(nField(local, field.getOwner(), field.getName(), field.getType())); } case INSTANCE_OF: return b(nInstanceOf(local, ((TypeStmtNode) insn).type)); case NEW_ARRAY: return b(nNewArray(((TypeStmtNode) insn).type.substring(1), local)); case CHECK_CAST: return b(nCheckCast(local, ((TypeStmtNode) insn).type)); case MONITOR_ENTER: emit(nLock(local)); return null; case MONITOR_EXIT: emit(nUnLock(local)); return null; case THROW: emit(nThrow(local)); return null; case ADD_INT_LIT16: case ADD_INT_LIT8: return b(nAdd(local, nInt(((Stmt2R1NNode) insn).content), "I")); case RSUB_INT_LIT8: case RSUB_INT:// return b(nSub(nInt(((Stmt2R1NNode) insn).content), local, "I")); case MUL_INT_LIT8: case MUL_INT_LIT16: return b(nMul(local, nInt(((Stmt2R1NNode) insn).content), "I")); case DIV_INT_LIT16: case DIV_INT_LIT8: return b(nDiv(local, nInt(((Stmt2R1NNode) insn).content), "I")); case REM_INT_LIT16: case REM_INT_LIT8: return b(nRem(local, nInt(((Stmt2R1NNode) insn).content), "I")); case AND_INT_LIT16: case AND_INT_LIT8: return b(nAnd(local, nInt(((Stmt2R1NNode) insn).content), ((Stmt2R1NNode) insn).content < 0 || ((Stmt2R1NNode) insn).content > 1 ? "I" : TypeClass.ZI.name)); case OR_INT_LIT16: case OR_INT_LIT8: return b(nOr(local, nInt(((Stmt2R1NNode) insn).content), ((Stmt2R1NNode) insn).content < 0 || ((Stmt2R1NNode) insn).content > 1 ? "I" : TypeClass.ZI.name)); case XOR_INT_LIT16: case XOR_INT_LIT8: return b(nXor(local, nInt(((Stmt2R1NNode) insn).content), ((Stmt2R1NNode) insn).content < 0 || ((Stmt2R1NNode) insn).content > 1 ? "I" : TypeClass.ZI.name)); case SHL_INT_LIT8: return b(nShl(local, nInt(((Stmt2R1NNode) insn).content), "I")); case SHR_INT_LIT8: return b(nShr(local, nInt(((Stmt2R1NNode) insn).content), "I")); case USHR_INT_LIT8: return b(nUshr(local, nInt(((Stmt2R1NNode) insn).content), "I")); case FILL_ARRAY_DATA: emit(nFillArrayData(local, nArrayValue(((FillArrayDataStmtNode) insn).array))); return null; } throw new RuntimeException(); } @Override public DvmValue binaryOperation(DexStmtNode insn, DvmValue value1, DvmValue value2) { if (value1 == null || value2 == null) { emitNotFindOperand(insn); return b(nInt(0)); } Local local1 = getLocal(value1); Local local2 = getLocal(value2); switch (insn.op) { case AGET: return b(nArray(local1, local2, TypeClass.IF.name)); case AGET_BOOLEAN: return b(nArray(local1, local2, "Z")); case AGET_BYTE: return b(nArray(local1, local2, "B")); case AGET_CHAR: return b(nArray(local1, local2, "C")); case AGET_OBJECT: return b(nArray(local1, local2, "L")); case AGET_SHORT: return b(nArray(local1, local2, "S")); case AGET_WIDE: return b(nArray(local1, local2, TypeClass.JD.name)); case CMP_LONG: return b(nLCmp(local1, local2)); case CMPG_DOUBLE: return b(nDCmpg(local1, local2)); case CMPG_FLOAT: return b(nFCmpg(local1, local2)); case CMPL_DOUBLE: return b(nDCmpl(local1, local2)); case CMPL_FLOAT: return b(nFCmpl(local1, local2)); case ADD_DOUBLE: return b(nAdd(local1, local2, "D")); case ADD_FLOAT: return b(nAdd(local1, local2, "F")); case ADD_INT: return b(nAdd(local1, local2, "I")); case ADD_LONG: return b(nAdd(local1, local2, "J")); case SUB_DOUBLE: return b(nSub(local1, local2, "D")); case SUB_FLOAT: return b(nSub(local1, local2, "F")); case SUB_INT: return b(nSub(local1, local2, "I")); case SUB_LONG: return b(nSub(local1, local2, "J")); case MUL_DOUBLE: return b(nMul(local1, local2, "D")); case MUL_FLOAT: return b(nMul(local1, local2, "F")); case MUL_INT: return b(nMul(local1, local2, "I")); case MUL_LONG: return b(nMul(local1, local2, "J")); case DIV_DOUBLE: return b(nDiv(local1, local2, "D")); case DIV_FLOAT: return b(nDiv(local1, local2, "F")); case DIV_INT: return b(nDiv(local1, local2, "I")); case DIV_LONG: return b(nDiv(local1, local2, "J")); case REM_DOUBLE: return b(nRem(local1, local2, "D")); case REM_FLOAT: return b(nRem(local1, local2, "F")); case REM_INT: return b(nRem(local1, local2, "I")); case REM_LONG: return b(nRem(local1, local2, "J")); case AND_INT: return b(nAnd(local1, local2, TypeClass.ZI.name)); case AND_LONG: return b(nAnd(local1, local2, "J")); case OR_INT: return b(nOr(local1, local2, TypeClass.ZI.name)); case OR_LONG: return b(nOr(local1, local2, "J")); case XOR_INT: return b(nXor(local1, local2, TypeClass.ZI.name)); case XOR_LONG: return b(nXor(local1, local2, "J")); case SHL_INT: return b(nShl(local1, local2, "I")); case SHL_LONG: return b(nShl(local1, local2, "J")); case SHR_INT: return b(nShr(local1, local2, "I")); case SHR_LONG: return b(nShr(local1, local2, "J")); case USHR_INT: return b(nUshr(local1, local2, "I")); case USHR_LONG: return b(nUshr(local1, local2, "J")); case IF_EQ: emit(nIf(Exprs .nEq(local1, local2, TypeClass.ZIL.name), getLabel(((JumpStmtNode) insn).label))); return null; case IF_GE: emit(nIf(Exprs.nGe(local1, local2, "I"), getLabel(((JumpStmtNode) insn).label))); return null; case IF_GT: emit(nIf(Exprs.nGt(local1, local2, "I"), getLabel(((JumpStmtNode) insn).label))); return null; case IF_LE: emit(nIf(Exprs.nLe(local1, local2, "I"), getLabel(((JumpStmtNode) insn).label))); return null; case IF_LT: emit(nIf(Exprs.nLt(local1, local2, "I"), getLabel(((JumpStmtNode) insn).label))); return null; case IF_NE: emit(nIf(Exprs .nNe(local1, local2, TypeClass.ZIL.name), getLabel(((JumpStmtNode) insn).label))); return null; case IPUT: case IPUT_BOOLEAN: case IPUT_BYTE: case IPUT_CHAR: case IPUT_OBJECT: case IPUT_SHORT: case IPUT_WIDE: Field field = ((FieldStmtNode) insn).field; emit(nAssign(nField(local1, field.getOwner(), field.getName(), field.getType()), local2)); return null; case ADD_DOUBLE_2ADDR: return b(nAdd(local1, local2, "D")); case ADD_FLOAT_2ADDR: return b(nAdd(local1, local2, "F")); case ADD_INT_2ADDR: return b(nAdd(local1, local2, "I")); case ADD_LONG_2ADDR: return b(nAdd(local1, local2, "J")); case SUB_DOUBLE_2ADDR: return b(nSub(local1, local2, "D")); case SUB_FLOAT_2ADDR: return b(nSub(local1, local2, "F")); case SUB_INT_2ADDR: return b(nSub(local1, local2, "I")); case SUB_LONG_2ADDR: return b(nSub(local1, local2, "J")); case MUL_DOUBLE_2ADDR: return b(nMul(local1, local2, "D")); case MUL_FLOAT_2ADDR: return b(nMul(local1, local2, "F")); case MUL_INT_2ADDR: return b(nMul(local1, local2, "I")); case MUL_LONG_2ADDR: return b(nMul(local1, local2, "J")); case DIV_DOUBLE_2ADDR: return b(nDiv(local1, local2, "D")); case DIV_FLOAT_2ADDR: return b(nDiv(local1, local2, "F")); case DIV_INT_2ADDR: return b(nDiv(local1, local2, "I")); case DIV_LONG_2ADDR: return b(nDiv(local1, local2, "J")); case REM_DOUBLE_2ADDR: return b(nRem(local1, local2, "D")); case REM_FLOAT_2ADDR: return b(nRem(local1, local2, "F")); case REM_INT_2ADDR: return b(nRem(local1, local2, "I")); case REM_LONG_2ADDR: return b(nRem(local1, local2, "J")); case AND_INT_2ADDR: return b(nAnd(local1, local2, TypeClass.ZI.name)); case AND_LONG_2ADDR: return b(nAnd(local1, local2, "J")); case OR_INT_2ADDR: return b(nOr(local1, local2, TypeClass.ZI.name)); case OR_LONG_2ADDR: return b(nOr(local1, local2, "J")); case XOR_INT_2ADDR: return b(nXor(local1, local2, TypeClass.ZI.name)); case XOR_LONG_2ADDR: return b(nXor(local1, local2, "J")); case SHL_INT_2ADDR: return b(nShl(local1, local2, "I")); case SHL_LONG_2ADDR: return b(nShl(local1, local2, "J")); case SHR_INT_2ADDR: return b(nShr(local1, local2, "I")); case SHR_LONG_2ADDR: return b(nShr(local1, local2, "J")); case USHR_INT_2ADDR: return b(nUshr(local1, local2, "I")); case USHR_LONG_2ADDR: return b(nUshr(local1, local2, "J")); } throw new RuntimeException(); } @Override public DvmValue ternaryOperation(DexStmtNode insn, DvmValue value1, DvmValue value2, DvmValue value3) { if (value1 == null || value2 == null || value3 == null) { emitNotFindOperand(insn); return b(nInt(0)); } Local localArray = getLocal(value1); Local localIndex = getLocal(value2); Local localValue = getLocal(value3); switch (insn.op) { case APUT: emit(nAssign(nArray(localArray, localIndex, TypeClass.IF.name), localValue)); break; case APUT_BOOLEAN: emit(nAssign(nArray(localArray, localIndex, "Z"), localValue)); break; case APUT_BYTE: emit(nAssign(nArray(localArray, localIndex, "B"), localValue)); break; case APUT_CHAR: emit(nAssign(nArray(localArray, localIndex, "C"), localValue)); break; case APUT_OBJECT: emit(nAssign(nArray(localArray, localIndex, "L"), localValue)); break; case APUT_SHORT: emit(nAssign(nArray(localArray, localIndex, "S"), localValue)); break; case APUT_WIDE: emit(nAssign(nArray(localArray, localIndex, TypeClass.JD.name), localValue)); break; } return null; } @Override public DvmValue naryOperation(DexStmtNode insn, List values) { for (DvmValue v : values) { if (v == null) { emitNotFindOperand(insn); return b(nInt(0)); } } switch (insn.op) { case FILLED_NEW_ARRAY: case FILLED_NEW_ARRAY_RANGE: DvmValue value = new DvmValue(); FilledNewArrayStmtNode filledNewArrayStmtNode = (FilledNewArrayStmtNode) insn; String type = filledNewArrayStmtNode.type; String elem = type.substring(1); emit(nAssign(getLocal(value), nNewArray(elem, nInt(values.size())))); for (int i = 0; i < values.size(); i++) { emit(nAssign(nArray(getLocal(value), nInt(i), elem), getLocal(values.get(i)))); } return value; case INVOKE_CUSTOM: case INVOKE_CUSTOM_RANGE: { Value[] vs = new Value[values.size()]; for (int i = 0; i < vs.length; i++) { vs[i] = getLocal(values.get(i)); } MethodCustomStmtNode n = (MethodCustomStmtNode) insn; Value invoke = nInvokeCustom(vs, n.name, n.proto, n.bsm, n.bsmArgs); if ("V".equals(n.getProto().getReturnType())) { emit(nVoidInvoke(invoke)); return null; } else { return b(invoke); } } case INVOKE_POLYMORPHIC: case INVOKE_POLYMORPHIC_RANGE: { Value[] vs = new Value[values.size()]; for (int i = 0; i < vs.length; i++) { vs[i] = getLocal(values.get(i)); } MethodPolymorphicStmtNode n = (MethodPolymorphicStmtNode) insn; Value invoke = nInvokePolymorphic(vs, n.proto, n.method); if ("V".equals(n.getProto().getReturnType())) { emit(nVoidInvoke(invoke)); return null; } else { return b(invoke); } } default: Op op = insn.op; Value[] vs = new Value[values.size()]; for (int i = 0; i < vs.length; i++) { vs[i] = getLocal(values.get(i)); } Method method = ((MethodStmtNode) insn).method; Value invoke = null; switch (op) { case INVOKE_VIRTUAL_RANGE: case INVOKE_VIRTUAL: invoke = nInvokeVirtual(vs, method.getOwner(), method.getName(), method .getParameterTypes(), method.getReturnType()); break; case INVOKE_SUPER_RANGE: case INVOKE_DIRECT_RANGE: case INVOKE_SUPER: case INVOKE_DIRECT: invoke = nInvokeSpecial(vs, method.getOwner(), method.getName(), method .getParameterTypes(), method.getReturnType()); break; case INVOKE_STATIC_RANGE: case INVOKE_STATIC: invoke = nInvokeStatic(vs, method.getOwner(), method.getName(), method .getParameterTypes(), method.getReturnType()); break; case INVOKE_INTERFACE_RANGE: case INVOKE_INTERFACE: invoke = nInvokeInterface(vs, method.getOwner(), method.getName(), method .getParameterTypes(), method.getReturnType()); break; default: throw new RuntimeException(); } if ("V".equals(method.getReturnType())) { emit(nVoidInvoke(invoke)); return null; } else { return b(invoke); } } } void emitNotFindOperand(DexStmtNode insn) { String msg; switch (insn.op) { case MOVE_RESULT: case MOVE_RESULT_OBJECT: case MOVE_RESULT_WIDE: msg = "can't get operand(s) for " + insn.op + ", wrong position ?"; break; default: msg = "can't get operand(s) for " + insn.op + ", out-of-range or not initialized ?"; break; } System.err.println("WARN: " + msg); emit(nThrow(nInvokeNew(new Value[]{nString("d2j: " + msg)}, new String[]{"Ljava/lang/String;"}, "Ljava/lang/VerifyError;"))); } @Override public void returnOperation(DexStmtNode insn, DvmValue value) { if (value == null) { emitNotFindOperand(insn); return; } emit(nReturn(getLocal(value))); } }; } private LabelStmt[] getLabels(DexLabel[] handler) { LabelStmt[] ts = new LabelStmt[handler.length]; for (int i = 0; i < handler.length; i++) { ts[i] = getLabel(handler[i]); } return ts; } LabelStmt getLabel(DexLabel label) { LabelStmt ls = map.get(label); if (ls == null) { ls = Stmts.nLabel(); map.put(label, ls); } return ls; } private void initParentCount(int[] parentCount) { parentCount[0] = 1; // first stmt always have one parent for (DexStmtNode p : insnList) { Op op = p.op; if (op == null) { if (p.__index < parentCount.length - 1) { // not the last label parentCount[p.__index + 1]++; } } else { if (op.canBranch()) { parentCount[indexOf(((JumpStmtNode) p).label)]++; } if (op.canSwitch()) { BaseSwitchStmtNode switchStmtNode = (BaseSwitchStmtNode) p; for (DexLabel label : switchStmtNode.labels) { parentCount[indexOf(label)]++; } } if (op.canContinue()) { parentCount[p.__index + 1]++; } } } } int indexOf(DexLabel label) { DexLabelStmtNode dexLabelStmtNode = labelMap.get(label); return dexLabelStmtNode.__index; } static class DvmValue { public DvmValue parent; public Set otherParent; Local local; public DvmValue(Local thiz) { this.local = thiz; } public DvmValue() { } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy