# HG changeset patch # User Michael Starzinger # Date 1301264995 -7200 # Node ID 2711ac37fdfbc9343728d60fe6657e3e996594aa # Parent b7b15d19d6ef2e9a4ea428428072efc2234be150 Fixed local variable information for DEX files. * dex/Code.java: Added end label marking the instruction stream end. * dex/DebugInfo.java (interpret): Optimistic approach for variable closing. * rewriter/DexRewriter.java (visitLocalVariable): Implemented. * rewriter/PatchMethodVisitor.java: Pass local variables to actual visitor. * rewriter/GenericTest.java: Enabled test case. diff -r b7b15d19d6ef -r 2711ac37fdfb src/main/java/org/icedrobot/daneel/dex/Code.java --- a/src/main/java/org/icedrobot/daneel/dex/Code.java Mon Mar 28 00:03:04 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/dex/Code.java Mon Mar 28 00:29:55 2011 +0200 @@ -715,6 +715,9 @@ throw new DexParseException("Unkown opcode: " + op); } } + + // Visit the end label after all instructions. + v.visitLabel(getEndLabel()); } /** The array associating bytecode instructions to their lengths. */ @@ -753,6 +756,20 @@ /** The map associating bytecode positions with labels. */ private final Map labelMap = new HashMap(); + /** The end label used to mark the address after the last instruction. */ + private final Label endLabel = new Label() { + + @Override + public boolean isJumpTarget() { + return false; + } + + @Override + public String toString() { + return "LEnd"; + } + }; + /** * Returns the label associated with the given bytecode position. * @@ -770,6 +787,16 @@ } /** + * Returns the label marking the end of the instruction stream. The label + * actually points to the address after the last instruction. + * + * @return The associated label, never returns {@code null}. + */ + Label getEndLabel() { + return endLabel; + } + + /** * Adds a new label to the given bytecode position. Keep this method * package-private in favor of private as long as there are inner classes * which call it, to avoid trampoline code. diff -r b7b15d19d6ef -r 2711ac37fdfb src/main/java/org/icedrobot/daneel/dex/DebugInfo.java --- a/src/main/java/org/icedrobot/daneel/dex/DebugInfo.java Mon Mar 28 00:03:04 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/dex/DebugInfo.java Mon Mar 28 00:29:55 2011 +0200 @@ -175,6 +175,9 @@ // Switch over all possible bytecodes. switch (opcode) { case DBG_END_SEQUENCE: + for (LocalVariable open : regs) + if (open != null && open.endLabel == null) + open.endLabel = code.getEndLabel(); return; case DBG_ADVANCE_PC: @@ -193,7 +196,7 @@ type = resolveType(typeIdx); local = regs[regNum]; if (local != null && local.endLabel == null) - throw new DexParseException("Live local in register."); + closeLocalVariable(local, addr); regs[regNum] = emitLocalVariable(regNum, addr, name, type, null); break; @@ -207,7 +210,7 @@ sig = resolveString(sigIdx); local = regs[regNum]; if (local != null && local.endLabel == null) - throw new DexParseException("Live local in register."); + closeLocalVariable(local, addr); regs[regNum] = emitLocalVariable(regNum, addr, name, type, sig); break; @@ -216,16 +219,16 @@ local = regs[regNum]; if (local == null || local.endLabel != null) throw new DexParseException("No live local in register."); - local.endLabel = code.putLabel(addr, false); + closeLocalVariable(local, addr); break; case DBG_RESTART_LOCAL: regNum = BufferUtil.getULEB128(buffer); local = regs[regNum]; - if (local == null || local.endLabel == null) - // XXX Check why this happens, this shouldn't happen. - //throw new DexParseException("No local to re-introduce."); - break; + if (local == null) + throw new DexParseException("No local to re-introduce."); + if (local != null && local.endLabel == null) + closeLocalVariable(local, addr); name = local.name; type = local.type; sig = local.sig; @@ -285,6 +288,21 @@ } /** + * Closes a previously emitted local variable information. The label at + * which the local variable runs out of scope is set here. + * + * @param local The local variable information. + * @param endAddr The instruction offset where the local variable ends. + */ + private void closeLocalVariable(LocalVariable local, int endAddr) { + Label endLabel = code.putLabel(endAddr, false); + if (endLabel == local.startLabel) + localVariables.remove(local); + else + local.endLabel = endLabel; + } + + /** * Emits a new line number entry. Line numbers are stored as part of the * label they are associated with. * diff -r b7b15d19d6ef -r 2711ac37fdfb src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java --- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Mon Mar 28 00:03:04 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Mon Mar 28 00:29:55 2011 +0200 @@ -322,7 +322,11 @@ @Override public void visitLocalVariable(String name, String desc, Label start, Label end, int reg) { - // XXX Ignore debug information for now. + reg = registerToSlot(reg); + if (name != null && desc != null) { + mv.visitLocalVariable(name, desc, null, getASMLabel(start), + getASMLabel(end), reg); + } } @Override diff -r b7b15d19d6ef -r 2711ac37fdfb src/main/java/org/icedrobot/daneel/rewriter/PatchMethodVisitor.java --- a/src/main/java/org/icedrobot/daneel/rewriter/PatchMethodVisitor.java Mon Mar 28 00:03:04 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/rewriter/PatchMethodVisitor.java Mon Mar 28 00:29:55 2011 +0200 @@ -218,7 +218,7 @@ @Override public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { - mv().visitLocalVariable(name, desc, signature, start, end, index); + mv.visitLocalVariable(name, desc, signature, start, end, index); } @Override diff -r b7b15d19d6ef -r 2711ac37fdfb src/test/java/org/icedrobot/daneel/rewriter/GenericTest.java --- a/src/test/java/org/icedrobot/daneel/rewriter/GenericTest.java Mon Mar 28 00:03:04 2011 +0200 +++ b/src/test/java/org/icedrobot/daneel/rewriter/GenericTest.java Mon Mar 28 00:29:55 2011 +0200 @@ -46,7 +46,6 @@ import org.junit.Test; import org.junit.runner.RunWith; -@org.junit.Ignore("Generic Debug Info not work") @RunWith(DexifyingRunner.class) public class GenericTest {