diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java index e700d7851..88037f960 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -205,11 +205,11 @@ public class InsnGen { mgen.getClassGen().useType(code, type); } - public boolean makeInsn(InsnNode insn, CodeWriter code) throws CodegenException { - return makeInsn(insn, code, null); + public void makeInsn(InsnNode insn, CodeWriter code) throws CodegenException { + makeInsn(insn, code, null); } - protected boolean makeInsn(InsnNode insn, CodeWriter code, Flags flag) throws CodegenException { + protected void makeInsn(InsnNode insn, CodeWriter code, Flags flag) throws CodegenException { try { Set state = EnumSet.noneOf(Flags.class); if (flag == Flags.BODY_ONLY || flag == Flags.BODY_ONLY_NOWRAP) { @@ -231,7 +231,6 @@ public class InsnGen { } catch (Exception th) { throw new CodegenException(mth, "Error generate insn: " + insn, th); } - return true; } private void makeInsnBody(CodeWriter code, InsnNode insn, Set state) throws CodegenException { diff --git a/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java b/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java index 47c7fc060..8c35d2b78 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java @@ -11,8 +11,10 @@ import jadx.core.Consts; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.annotations.MethodParameters; +import jadx.core.dex.attributes.nodes.JumpInfo; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.ClassInfo; +import jadx.core.dex.instructions.IfNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.CodeVar; @@ -136,7 +138,6 @@ public class MethodGen { } else { var = ssaVar.getCodeVar(); } - ArgType argType = var.getType(); // add argument annotation if (paramsAnnotation != null) { @@ -145,6 +146,7 @@ public class MethodGen { if (var.isFinal()) { code.add("final "); } + ArgType argType = var.getType(); if (!it.hasNext() && mth.getAccessFlags().isVarArgs()) { // change last array argument to varargs if (argType.isArray()) { @@ -197,6 +199,7 @@ public class MethodGen { if (mth.getInstructions() == null) { // load original instructions try { + mth.unload(); mth.load(); DepthTraversal.visit(new FallbackModeVisitor(), mth); } catch (DecodeException e) { @@ -218,29 +221,59 @@ public class MethodGen { public static void addFallbackInsns(CodeWriter code, MethodNode mth, InsnNode[] insnArr, boolean addLabels) { InsnGen insnGen = new InsnGen(getFallbackMethodGen(mth), true); + InsnNode prevInsn = null; for (InsnNode insn : insnArr) { if (insn == null || insn.getType() == InsnType.NOP) { continue; } - if (addLabels && (insn.contains(AType.JUMP) || insn.contains(AType.EXC_HANDLER))) { + if (addLabels && needLabel(insn, prevInsn)) { code.decIndent(); code.startLine(getLabelName(insn.getOffset()) + ":"); code.incIndent(); } try { - if (insnGen.makeInsn(insn, code)) { - CatchAttr catchAttr = insn.get(AType.CATCH_BLOCK); - if (catchAttr != null) { - code.add("\t " + catchAttr); + code.startLine(); + RegisterArg resArg = insn.getResult(); + if (resArg != null) { + ArgType varType = resArg.getInitType(); + if (varType.isTypeKnown()) { + code.add(varType.toString()).add(' '); } } + insnGen.makeInsn(insn, code, InsnGen.Flags.INLINE); + CatchAttr catchAttr = insn.get(AType.CATCH_BLOCK); + if (catchAttr != null) { + code.add(" // " + catchAttr); + } } catch (CodegenException e) { LOG.debug("Error generate fallback instruction: ", e.getCause()); code.startLine("// error: " + insn); } + prevInsn = insn; } } + private static boolean needLabel(InsnNode insn, InsnNode prevInsn) { + if (insn.contains(AType.EXC_HANDLER)) { + return true; + } + if (insn.contains(AType.JUMP)) { + // don't add label for ifs else branch + if (prevInsn != null && prevInsn.getType() == InsnType.IF) { + List jumps = insn.getAll(AType.JUMP); + if (jumps.size() == 1) { + JumpInfo jump = jumps.get(0); + if (jump.getSrc() == prevInsn.getOffset() && jump.getDest() == insn.getOffset()) { + int target = ((IfNode) prevInsn).getTarget(); + return insn.getOffset() == target; + } + } + } + return true; + } + return false; + } + /** * Return fallback variant of method codegen */ diff --git a/jadx-core/src/test/java/jadx/tests/integration/fallback/TestFallbackMode.java b/jadx-core/src/test/java/jadx/tests/integration/fallback/TestFallbackMode.java index 185e257c3..b13cf2310 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/fallback/TestFallbackMode.java +++ b/jadx-core/src/test/java/jadx/tests/integration/fallback/TestFallbackMode.java @@ -5,6 +5,7 @@ import org.junit.Test; import jadx.core.dex.nodes.ClassNode; import jadx.tests.api.IntegrationTest; +import static jadx.tests.api.utils.JadxMatchers.containsOne; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertThat; @@ -30,8 +31,10 @@ public class TestFallbackMode extends IntegrationTest { String code = cls.getCode().toString(); assertThat(code, containsString("public int test(int r2) {")); - assertThat(code, containsString("r1 = this;")); - assertThat(code, containsString("L_0x0004:")); + assertThat(code, containsOne("r1 = this;")); + assertThat(code, containsOne("L_0x0000:")); + assertThat(code, containsOne("L_0x0007:")); + assertThat(code, containsOne("int r2 = r2 + 1")); assertThat(code, not(containsString("throw new UnsupportedOperationException"))); } }