diff --git a/src/main/java/jadx/codegen/InsnGen.java b/src/main/java/jadx/codegen/InsnGen.java index c2d98e917..84d497830 100644 --- a/src/main/java/jadx/codegen/InsnGen.java +++ b/src/main/java/jadx/codegen/InsnGen.java @@ -80,7 +80,6 @@ public class InsnGen { } public String assignVar(InsnNode insn) { - // return mgen.assignArg(arg); try { RegisterArg arg = insn.getResult(); if (insn.getAttributes().contains(AttributeType.DECLARE_VARIABLE)) { @@ -95,7 +94,11 @@ public class InsnGen { } public String declareVar(RegisterArg arg) throws CodegenException { - return TypeGen.translate(mgen.getClassGen(), arg.getType()) + " " + arg(arg); + String type = TypeGen.translate(mgen.getClassGen(), arg.getType()); + String generic = arg.getType().getGeneric(); + if (generic != null) + type += " /* " + generic + " */"; + return type + " " + arg(arg); } private String lit(LiteralArg arg) { diff --git a/src/main/java/jadx/dex/info/LocalVarInfo.java b/src/main/java/jadx/dex/info/LocalVarInfo.java index 51cfb2370..f86c6db1b 100644 --- a/src/main/java/jadx/dex/info/LocalVarInfo.java +++ b/src/main/java/jadx/dex/info/LocalVarInfo.java @@ -9,6 +9,9 @@ public class LocalVarInfo extends RegisterArg { private boolean isEnd; + private int startAddr; + private int endAddr; + public LocalVarInfo(DexNode dex, int rn, int nameId, int typeId, int signId) { super(rn); String name = (nameId == DexNode.NO_INDEX ? null : dex.getString(nameId)); @@ -24,6 +27,9 @@ public class LocalVarInfo extends RegisterArg { } private void init(String name, ArgType type, String sign) { + if (sign != null) { + type.setGeneric(sign); + } TypedVar tv = new TypedVar(type); tv.setName(name); setTypedVar(tv); @@ -31,13 +37,28 @@ public class LocalVarInfo extends RegisterArg { public void start(int addr, int line) { this.isEnd = false; + this.startAddr = addr; } public void end(int addr, int line) { this.isEnd = true; + this.endAddr = addr; } public boolean isEnd() { return isEnd; } + + public int getStartAddr() { + return startAddr; + } + + public int getEndAddr() { + return endAddr; + } + + @Override + public String toString() { + return super.toString() + " " + (isEnd ? "end" : "active"); + } } diff --git a/src/main/java/jadx/dex/instructions/args/ArgType.java b/src/main/java/jadx/dex/instructions/args/ArgType.java index 3c3af8dee..bd459743c 100644 --- a/src/main/java/jadx/dex/instructions/args/ArgType.java +++ b/src/main/java/jadx/dex/instructions/args/ArgType.java @@ -42,6 +42,8 @@ public final class ArgType { private final int hash; + private String generic; // TODO extract generic info from signature + private ArgType(PrimitiveType type, String object, ArgType arrayElement) { this.type = type; this.object = (object == null ? null : Utils.cleanObjectName(object)); @@ -96,6 +98,14 @@ public final class ArgType { return type == PrimitiveType.OBJECT; } + public String getGeneric() { + return generic; + } + + public void setGeneric(String generic) { + this.generic = generic; + } + public ArgType getArrayElement() { return arrayElement; } diff --git a/src/main/java/jadx/dex/nodes/MethodNode.java b/src/main/java/jadx/dex/nodes/MethodNode.java index 5a7b6c816..df4bc7bec 100644 --- a/src/main/java/jadx/dex/nodes/MethodNode.java +++ b/src/main/java/jadx/dex/nodes/MethodNode.java @@ -95,7 +95,7 @@ public class MethodNode extends AttrNode implements ILoadable { initJumps(insnByOffset); if (mthCode.getDebugInfoOffset() > 0) { - DebugInfoParser debugInfo = new DebugInfoParser(this, dex.openSection(mthCode.getDebugInfoOffset())); + DebugInfoParser debugInfo = new DebugInfoParser(this, mthCode.getDebugInfoOffset()); debugInfo.process(insnByOffset); } } catch (Exception e) { diff --git a/src/main/java/jadx/dex/nodes/parser/DebugInfoParser.java b/src/main/java/jadx/dex/nodes/parser/DebugInfoParser.java index 0f231a61e..dc97fcac7 100644 --- a/src/main/java/jadx/dex/nodes/parser/DebugInfoParser.java +++ b/src/main/java/jadx/dex/nodes/parser/DebugInfoParser.java @@ -33,10 +33,10 @@ public class DebugInfoParser { private final Section section; private final DexNode dex; - public DebugInfoParser(MethodNode mth, Section section) { + public DebugInfoParser(MethodNode mth, int debugOffset) { this.mth = mth; - this.section = section; this.dex = mth.dex(); + this.section = dex.openSection(debugOffset); } public void process(InsnNode[] insnByOffset) throws DecodeException { @@ -77,8 +77,9 @@ public class DebugInfoParser { int regNum = section.readUleb128(); int nameId = section.readUleb128() - 1; int type = section.readUleb128() - 1; - locals[regNum] = new LocalVarInfo(dex, regNum, nameId, type, DexNode.NO_INDEX); - locals[regNum].start(addr, line); + LocalVarInfo var = new LocalVarInfo(dex, regNum, nameId, type, DexNode.NO_INDEX); + var.start(addr, line); + locals[regNum] = var; break; } case DBG_START_LOCAL_EXTENDED: { @@ -86,20 +87,25 @@ public class DebugInfoParser { int nameId = section.readUleb128() - 1; int type = section.readUleb128() - 1; int sign = section.readUleb128() - 1; - locals[regNum] = new LocalVarInfo(dex, regNum, nameId, type, sign); - locals[regNum].start(addr, line); + LocalVarInfo var = new LocalVarInfo(dex, regNum, nameId, type, sign); + var.start(addr, line); + locals[regNum] = var; break; } case DBG_RESTART_LOCAL: { int regNum = section.readUleb128(); - if (locals[regNum] != null) - locals[regNum].start(addr, line); + LocalVarInfo var = locals[regNum]; + if (var != null) + var.start(addr, line); break; } case DBG_END_LOCAL: { int regNum = section.readUleb128(); - if (locals[regNum] != null) - locals[regNum].end(addr, line); + LocalVarInfo var = locals[regNum]; + if (var != null) { + var.end(addr, line); + setVar(var, insnByOffset); + } break; } @@ -115,12 +121,9 @@ public class DebugInfoParser { default: if (c >= DBG_FIRST_SPECIAL) { - int adjusted_opcode = c - DBG_FIRST_SPECIAL; line += DBG_LINE_BASE + (adjusted_opcode % DBG_LINE_RANGE); addr += (adjusted_opcode / DBG_LINE_RANGE); - - fillLocals(insnByOffset[addr], locals); } else { throw new DecodeException("Unknown debug insn code: " + c); } @@ -129,29 +132,41 @@ public class DebugInfoParser { c = section.readByte() & 0xFF; } + + for (LocalVarInfo var : locals) { + if (var != null && !var.isEnd()) { + var.end(addr, line); + setVar(var, insnByOffset); + } + } } - private void fillLocals(InsnNode insn, LocalVarInfo[] locals) { + private void setVar(LocalVarInfo var, InsnNode[] insnByOffset) { + int start = var.getStartAddr(); + int end = var.getEndAddr(); + + for (int i = start; i <= end; i++) { + InsnNode insn = insnByOffset[i]; + fillLocals(insn, var); + } + } + + private void fillLocals(InsnNode insn, LocalVarInfo var) { if (insn == null) return; if (insn.getResult() != null) - merge(insn.getResult(), locals); + merge(insn.getResult(), var); for (InsnArg arg : insn.getArguments()) - merge(arg, locals); + merge(arg, var); } - private void merge(InsnArg arg, LocalVarInfo[] locals) { + private void merge(InsnArg arg, LocalVarInfo var) { if (arg.isRegister()) { int rn = ((RegisterArg) arg).getRegNum(); - - for (LocalVarInfo var : locals) { - if (var != null && !var.isEnd()) { - if (var.getRegNum() == rn) - arg.replace(var); - } - } + if (var.getRegNum() == rn) + arg.setTypedVar(var.getTypedVar()); } } }