diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/ConstStringNode.java b/jadx-core/src/main/java/jadx/core/dex/instructions/ConstStringNode.java index f80a3f70d..ccb1bd1cc 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/ConstStringNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/ConstStringNode.java @@ -35,6 +35,6 @@ public final class ConstStringNode extends InsnNode { @Override public String toString() { - return super.toString() + ' ' + StringUtils.getInstance().unescapeString(str); + return super.baseString() + StringUtils.getInstance().unescapeString(str) + super.attributesString(); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnWrapArg.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnWrapArg.java index cc25ba374..d463c9a4d 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnWrapArg.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnWrapArg.java @@ -84,7 +84,7 @@ public final class InsnWrapArg extends InsnArg { if (wrappedInsn.getType() == InsnType.CONST_STR) { return "(\"" + ((ConstStringNode) wrappedInsn).getString() + "\")"; } - return "(wrap:" + type + ":" + wrappedInsn.getType() + ')'; + return "(wrap " + type + ":" + wrappedInsn.getType() + ')'; } @Override @@ -92,6 +92,6 @@ public final class InsnWrapArg extends InsnArg { if (wrappedInsn.getType() == InsnType.CONST_STR) { return "(\"" + ((ConstStringNode) wrappedInsn).getString() + "\")"; } - return "(wrap:" + type + ":" + wrappedInsn + ')'; + return "(wrap " + type + ":" + wrappedInsn + ')'; } } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java index 7923879e7..bedc31075 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java @@ -406,6 +406,14 @@ public class InsnNode extends LineAttrNode { && Objects.equals(arguments, other.arguments); } + @SuppressWarnings("unchecked") + public static @Nullable T duplicateArg(@Nullable T arg) { + if (arg == null) { + return null; + } + return (T) arg.duplicate(); + } + protected final T copyCommonParams(T copy) { if (copy.getArgsCount() == 0) { for (InsnArg arg : this.getArguments()) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java index 7afdf7a1d..176f6b592 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java @@ -85,7 +85,6 @@ public class SimplifyVisitor extends AbstractVisitor { int insnCount = list.size(); InsnNode modInsn = simplifyInsn(mth, insn, null); if (modInsn != null) { - modInsn.rebindArgs(); if (i < list.size() && list.get(i) == insn) { list.set(i, modInsn); } else { @@ -95,6 +94,8 @@ public class SimplifyVisitor extends AbstractVisitor { } list.set(idx, modInsn); } + InsnRemover.unbindInsn(mth, insn); + modInsn.rebindArgs(); if (list.size() < insnCount) { // some insns removed => restart block processing simplifyBlock(mth, block); @@ -239,8 +240,8 @@ public class SimplifyVisitor extends AbstractVisitor { || shadowedByOuterCast(mth.root(), castToType, parentInsn)) { InsnNode insnNode = new InsnNode(InsnType.MOVE, 1); insnNode.setOffset(castInsn.getOffset()); - insnNode.setResult(castInsn.getResult()); - insnNode.addArg(castArg); + insnNode.setResult(InsnNode.duplicateArg(castInsn.getResult())); + insnNode.addArg(castArg.duplicate()); return insnNode; } return null; @@ -576,7 +577,11 @@ public class SimplifyVisitor extends AbstractVisitor { if (litArg.isNegative()) { LiteralArg negLitArg = litArg.negate(); if (negLitArg != null) { - return new ArithNode(ArithOp.SUB, arith.getResult(), arith.getArg(0), negLitArg); + RegisterArg resArg = InsnNode.duplicateArg(arith.getResult()); + ArithNode newInsn = new ArithNode(ArithOp.SUB, resArg, arith.getArg(0).duplicate(), negLitArg); + newInsn.copyAttributesFrom(arith); + newInsn.setOffset(arith.getOffset()); + return newInsn; } } break; @@ -586,10 +591,12 @@ public class SimplifyVisitor extends AbstractVisitor { InsnArg firstArg = arith.getArg(0); long lit = litArg.getLiteral(); if (firstArg.getType() == ArgType.BOOLEAN && (lit == 0 || lit == 1)) { - InsnNode node = new InsnNode(lit == 0 ? InsnType.MOVE : InsnType.NOT, 1); - node.setResult(arith.getResult()); - node.addArg(firstArg); - return node; + InsnNode newInsn = new InsnNode(lit == 0 ? InsnType.MOVE : InsnType.NOT, 1); + newInsn.setResult(InsnNode.duplicateArg(arith.getResult())); + newInsn.addArg(firstArg.duplicate()); + newInsn.copyAttributesFrom(arith); + newInsn.setOffset(arith.getOffset()); + return newInsn; } break; } @@ -637,16 +644,22 @@ public class SimplifyVisitor extends AbstractVisitor { } if (wrapType == InsnType.ARITH) { ArithNode ar = (ArithNode) wrap; - return ArithNode.oneArgOp(ar.getOp(), fArg, ar.getArg(1)); + ArithNode newInsn = ArithNode.oneArgOp(ar.getOp(), fArg, ar.getArg(1).duplicate()); + newInsn.copyAttributesFrom(insn); + newInsn.setOffset(insn.getOffset()); + return newInsn; } int argsCount = wrap.getArgsCount(); InsnNode concat = new InsnNode(InsnType.STR_CONCAT, argsCount - 1); for (int i = 1; i < argsCount; i++) { - concat.addArg(wrap.getArg(i)); + concat.addArg(wrap.getArg(i).duplicate()); } InsnArg concatArg = InsnArg.wrapArg(concat); concatArg.setType(ArgType.STRING); - return ArithNode.oneArgOp(ArithOp.ADD, fArg, concatArg); + ArithNode newInsn = ArithNode.oneArgOp(ArithOp.ADD, fArg, concatArg); + newInsn.copyAttributesFrom(wrap); + newInsn.setOffset(wrap.getOffset()); + return newInsn; } catch (Exception e) { LOG.debug("Can't convert field arith insn: {}, mth: {}", insn, mth, e); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryMod.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryMod.java index 5ef8d9774..b32e9c080 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryMod.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryMod.java @@ -111,23 +111,26 @@ public class TernaryMod extends AbstractRegionVisitor implements IRegionIterativ RegisterArg resArg; if (thenPhi.getArgsCount() == 2) { resArg = thenPhi.getResult(); - InsnRemover.unbindResult(mth, thenInsn); } else { resArg = thenResArg; thenPhi.removeArg(elseResArg); } - InsnArg thenArg = InsnArg.wrapInsnIntoArg(thenInsn); - InsnArg elseArg = InsnArg.wrapInsnIntoArg(elseInsn); - TernaryInsn ternInsn = new TernaryInsn(ifRegion.getCondition(), resArg, thenArg, elseArg); + InsnArg thenArg = InsnArg.wrapInsnIntoArg(thenInsn.copyWithoutResult()); + InsnArg elseArg = InsnArg.wrapInsnIntoArg(elseInsn.copyWithoutResult()); + TernaryInsn ternInsn = new TernaryInsn(ifRegion.getCondition(), resArg.duplicate(), thenArg, elseArg); int branchLine = Math.max(thenInsn.getSourceLine(), elseInsn.getSourceLine()); ternInsn.setSourceLine(Math.max(ifRegion.getSourceLine(), branchLine)); - thenInsn.setResult(null); // unset without unbind, SSA var still in use - InsnRemover.unbindResult(mth, elseInsn); + InsnRemover.unbindInsn(mth, thenInsn); + InsnRemover.unbindInsn(mth, elseInsn); + ternInsn.rebindArgs(); + if (thenPhi.getArgsCount() == 0) { + InsnRemover.unbindResult(mth, thenPhi); + InsnRemover.delistPhi(mth, thenPhi); + } // remove 'if' instruction header.getInstructions().clear(); - ternInsn.rebindArgs(); header.getInstructions().add(ternInsn); clearConditionBlocks(conditionBlocks, header); @@ -321,11 +324,11 @@ public class TernaryMod extends AbstractRegionVisitor implements IRegionIterativ InsnArg elseArg; if (elseAssign != null && elseAssign.isConstInsn()) { // inline constant + elseArg = InsnArg.wrapInsnIntoArg(elseAssign.copyWithoutResult()); SSAVar elseVar = elseAssign.getResult().getSVar(); if (elseVar.getUseCount() == 1 && elseVar.getOnlyOneUseInPhi() == phiInsn) { InsnRemover.remove(mth, elseAssign); } - elseArg = InsnArg.wrapInsnIntoArg(elseAssign); } else { elseArg = otherArg.duplicate(); } diff --git a/jadx-core/src/main/java/jadx/core/utils/DebugChecks.java b/jadx-core/src/main/java/jadx/core/utils/DebugChecks.java index f58f52f7a..b5f98be3e 100644 --- a/jadx-core/src/main/java/jadx/core/utils/DebugChecks.java +++ b/jadx-core/src/main/java/jadx/core/utils/DebugChecks.java @@ -78,8 +78,13 @@ public class DebugChecks { for (InsnArg arg : insn.getArguments()) { if (arg instanceof RegisterArg) { checkVar(mth, insn, (RegisterArg) arg); - } else if (arg.isInsnWrap()) { + } else if (arg instanceof InsnWrapArg) { InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn(); + if (wrapInsn.contains(AFlag.DONT_GENERATE) + && !insn.contains(AFlag.DONT_GENERATE) + && !mth.contains(AFlag.DONT_GENERATE)) { + throw new JadxRuntimeException("Not generated wrapped insn: \n " + wrapInsn + ",\nouter insn:\n " + insn); + } checkInsn(mth, block, wrapInsn); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/arith/TestFieldIncrement.java b/jadx-core/src/test/java/jadx/tests/integration/arith/TestFieldIncrement.java index 65efe6453..2f11dd4b1 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/arith/TestFieldIncrement.java +++ b/jadx-core/src/test/java/jadx/tests/integration/arith/TestFieldIncrement.java @@ -3,10 +3,12 @@ package jadx.tests.integration.arith; import org.junit.jupiter.api.Test; import jadx.tests.api.IntegrationTest; -import jadx.tests.api.utils.assertj.JadxAssertions; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; public class TestFieldIncrement extends IntegrationTest { + @SuppressWarnings("unused") public static class TestCls { public int instanceField = 1; public static int staticField = 1; @@ -27,7 +29,7 @@ public class TestFieldIncrement extends IntegrationTest { @Test public void test() { - JadxAssertions.assertThat(getClassNode(TestCls.class)) + assertThat(getClassNode(TestCls.class)) .code() .contains("instanceField++;") .contains("staticField--;") diff --git a/jadx-core/src/test/java/jadx/tests/integration/arith/TestFieldIncrement3.java b/jadx-core/src/test/java/jadx/tests/integration/arith/TestFieldIncrement3.java index 22322eaec..8f9abd79b 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/arith/TestFieldIncrement3.java +++ b/jadx-core/src/test/java/jadx/tests/integration/arith/TestFieldIncrement3.java @@ -5,10 +5,12 @@ import java.util.Random; import org.junit.jupiter.api.Test; import jadx.tests.api.IntegrationTest; -import jadx.tests.api.utils.assertj.JadxAssertions; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; public class TestFieldIncrement3 extends IntegrationTest { + @SuppressWarnings("SpellCheckingInspection") public static class TestCls { static int tileX; static int tileY; @@ -21,20 +23,20 @@ public class TestFieldIncrement3 extends IntegrationTest { int direction = rd.nextInt(7); switch (direction) { case 0: - targetPos.x = ((tileX + 1) * 55) + 55; - targetPos.y = ((tileY + 1) * 35) + 35; + targetPos.x = (tileX + 1) * 55 + 55; + targetPos.y = (tileY + 1) * 35 + 35; break; case 2: - targetPos.x = ((tileX + 1) * 55) + 55; - targetPos.y = ((tileY - 1) * 35) + 35; + targetPos.x = (tileX + 1) * 55 + 55; + targetPos.y = (tileY - 1) * 35 + 35; break; case 4: - targetPos.x = ((tileX - 1) * 55) + 55; - targetPos.y = ((tileY - 1) * 35) + 35; + targetPos.x = (tileX - 1) * 55 + 55; + targetPos.y = (tileY - 1) * 35 + 35; break; case 6: - targetPos.x = ((tileX - 1) * 55) + 55; - targetPos.y = ((tileY + 1) * 35) + 35; + targetPos.x = (tileX - 1) * 55 + 55; + targetPos.y = (tileY + 1) * 35 + 35; break; default: break; @@ -42,7 +44,7 @@ public class TestFieldIncrement3 extends IntegrationTest { directVect.x = targetPos.x - newPos.x; directVect.y = targetPos.y - newPos.y; - float hPos = (float) Math.sqrt((directVect.x * directVect.x) + (directVect.y * directVect.y)); + float hPos = (float) Math.sqrt(directVect.x * directVect.x + directVect.y * directVect.y); directVect.x /= hPos; directVect.y /= hPos; } @@ -57,14 +59,14 @@ public class TestFieldIncrement3 extends IntegrationTest { } public boolean equals(Vector2 other) { - return (this.x == other.x && this.y == other.y); + return this.x == other.x && this.y == other.y; } } } @Test public void test() { - JadxAssertions.assertThat(getClassNode(TestCls.class)) + assertThat(getClassNode(TestCls.class)) .code() .contains("directVect.x = targetPos.x - newPos.x;"); } diff --git a/jadx-core/src/test/java/jadx/tests/integration/variables/TestVariables7.java b/jadx-core/src/test/java/jadx/tests/integration/variables/TestVariables7.java new file mode 100644 index 000000000..2efcd97a9 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/variables/TestVariables7.java @@ -0,0 +1,17 @@ +package jadx.tests.integration.variables; + +import org.junit.jupiter.api.Test; + +import jadx.tests.api.SmaliTest; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +public class TestVariables7 extends SmaliTest { + @Test + public void testNoDebug() { + getArgs().setDebugInfo(false); + assertThat(getClassNodeFromSmali()) + .code() + .doesNotContain("r0"); + } +} diff --git a/jadx-core/src/test/smali/variables/TestVariables7.smali b/jadx-core/src/test/smali/variables/TestVariables7.smali new file mode 100644 index 000000000..a1720284c --- /dev/null +++ b/jadx-core/src/test/smali/variables/TestVariables7.smali @@ -0,0 +1,57 @@ +.class Lvariables/TestVariables7; +.super Ljava/lang/Object; + +.method test([BII)I + .registers 12 + .param p1, "a" # [B + .param p2, "b" # I + .param p3, "c" # I + + .prologue + .line 290 + invoke-static {p3}, Ljava/lang/Integer;->toOctalString(I)Ljava/lang/String; + move-result-object v3 + + .line 291 + .local v3, "oct":Ljava/lang/String; + invoke-virtual {v3}, Ljava/lang/String;->length()I + move-result v2 + + .line 292 + .local v2, "len":I + sub-int v4, p2, v2 + + .line 293 + .local v4, "off":I + const/4 v5, 0x0 + + .line 294 + .local v5, "sum":I + const/4 v1, 0x0 + .local v1, "j":I + :goto_c + if-lt v1, v2, :cond_f + + .line 299 + return v5 + + .line 295 + :cond_f + invoke-virtual {v3, v1}, Ljava/lang/String;->charAt(I)C + move-result v0 + + .line 296 + .local v0, "ch":C + and-int/lit16 v6, v0, 0xff + add-int/lit8 v6, v6, -0x30 + add-int/2addr v5, v6 + + .line 297 + add-int v6, v4, v1 + int-to-byte v7, v0 + aput-byte v7, p1, v6 + + .line 294 + add-int/lit8 v1, v1, 0x1 + goto :goto_c +.end method