Commit cb23b657 authored by Skylot's avatar Skylot

core: fix variable names propagation (#219)

parent 7a168148
...@@ -63,6 +63,21 @@ public class RegisterArg extends InsnArg implements Named { ...@@ -63,6 +63,21 @@ public class RegisterArg extends InsnArg implements Named {
return n.equals(((Named) arg).getName()); return n.equals(((Named) arg).getName());
} }
public void mergeName(InsnArg arg) {
if (arg instanceof Named) {
Named otherArg = (Named) arg;
String otherName = otherArg.getName();
String name = getName();
if (!Objects.equals(name, otherName)) {
if (name == null) {
setName(otherName);
} else if (otherName == null) {
otherArg.setName(name);
}
}
}
}
@Override @Override
public void setType(ArgType type) { public void setType(ArgType type) {
if (sVar != null) { if (sVar != null) {
......
...@@ -78,6 +78,8 @@ public class DebugInfoParser { ...@@ -78,6 +78,8 @@ public class DebugInfoParser {
addrChange(-1, 1, line); addrChange(-1, 1, line);
setLine(addr, line); setLine(addr, line);
boolean varsInfoFound = false;
int c = section.readByte() & 0xFF; int c = section.readByte() & 0xFF;
while (c != DBG_END_SEQUENCE) { while (c != DBG_END_SEQUENCE) {
switch (c) { switch (c) {
...@@ -98,6 +100,7 @@ public class DebugInfoParser { ...@@ -98,6 +100,7 @@ public class DebugInfoParser {
int type = section.readUleb128() - 1; int type = section.readUleb128() - 1;
LocalVar var = new LocalVar(dex, regNum, nameId, type, DexNode.NO_INDEX); LocalVar var = new LocalVar(dex, regNum, nameId, type, DexNode.NO_INDEX);
startVar(var, addr, line); startVar(var, addr, line);
varsInfoFound = true;
break; break;
} }
case DBG_START_LOCAL_EXTENDED: { case DBG_START_LOCAL_EXTENDED: {
...@@ -107,6 +110,7 @@ public class DebugInfoParser { ...@@ -107,6 +110,7 @@ public class DebugInfoParser {
int sign = section.readUleb128() - 1; int sign = section.readUleb128() - 1;
LocalVar var = new LocalVar(dex, regNum, nameId, type, sign); LocalVar var = new LocalVar(dex, regNum, nameId, type, sign);
startVar(var, addr, line); startVar(var, addr, line);
varsInfoFound = true;
break; break;
} }
case DBG_RESTART_LOCAL: { case DBG_RESTART_LOCAL: {
...@@ -118,6 +122,7 @@ public class DebugInfoParser { ...@@ -118,6 +122,7 @@ public class DebugInfoParser {
} }
var.start(addr, line); var.start(addr, line);
} }
varsInfoFound = true;
break; break;
} }
case DBG_END_LOCAL: { case DBG_END_LOCAL: {
...@@ -127,6 +132,7 @@ public class DebugInfoParser { ...@@ -127,6 +132,7 @@ public class DebugInfoParser {
var.end(addr, line); var.end(addr, line);
setVar(var); setVar(var);
} }
varsInfoFound = true;
break; break;
} }
...@@ -160,10 +166,12 @@ public class DebugInfoParser { ...@@ -160,10 +166,12 @@ public class DebugInfoParser {
c = section.readByte() & 0xFF; c = section.readByte() & 0xFF;
} }
for (LocalVar var : locals) { if (varsInfoFound) {
if (var != null && !var.isEnd()) { for (LocalVar var : locals) {
var.end(mth.getCodeSize() - 1, line); if (var != null && !var.isEnd()) {
setVar(var); var.end(mth.getCodeSize() - 1, line);
setVar(var);
}
} }
} }
setSourceLines(addr, insnByOffset.length, line); setSourceLines(addr, insnByOffset.length, line);
......
...@@ -142,6 +142,7 @@ public class PrepareForCodeGen extends AbstractVisitor { ...@@ -142,6 +142,7 @@ public class PrepareForCodeGen extends AbstractVisitor {
} }
if (replace) { if (replace) {
insn.add(AFlag.ARITH_ONEARG); insn.add(AFlag.ARITH_ONEARG);
insn.getResult().mergeName(arg);
} }
} }
} }
......
...@@ -22,7 +22,6 @@ import jadx.core.utils.exceptions.JadxException; ...@@ -22,7 +22,6 @@ import jadx.core.utils.exceptions.JadxException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
......
...@@ -8,6 +8,7 @@ import jadx.core.dex.instructions.PhiInsn; ...@@ -8,6 +8,7 @@ import jadx.core.dex.instructions.PhiInsn;
import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.instructions.args.SSAVar; import jadx.core.dex.instructions.args.SSAVar;
import jadx.core.dex.instructions.args.VarName;
import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
...@@ -141,14 +142,7 @@ public class SSATransform extends AbstractVisitor { ...@@ -141,14 +142,7 @@ public class SSATransform extends AbstractVisitor {
PhiListAttr phiList = enterBlock.get(AType.PHI_LIST); PhiListAttr phiList = enterBlock.get(AType.PHI_LIST);
if (phiList != null) { if (phiList != null) {
for (PhiInsn phiInsn : phiList.getList()) { for (PhiInsn phiInsn : phiList.getList()) {
int regNum = phiInsn.getResult().getRegNum(); bindPhiArg(vars, enterBlock, phiInsn);
SSAVar var = vars[regNum];
if (var == null) {
continue;
}
RegisterArg arg = phiInsn.bindArg(enterBlock);
var.use(arg);
var.setUsedInPhi(phiInsn);
} }
} }
} }
...@@ -183,14 +177,7 @@ public class SSATransform extends AbstractVisitor { ...@@ -183,14 +177,7 @@ public class SSATransform extends AbstractVisitor {
continue; continue;
} }
for (PhiInsn phiInsn : phiList.getList()) { for (PhiInsn phiInsn : phiList.getList()) {
int regNum = phiInsn.getResult().getRegNum(); bindPhiArg(vars, block, phiInsn);
SSAVar var = vars[regNum];
if (var == null) {
continue;
}
RegisterArg arg = phiInsn.bindArg(block);
var.use(arg);
var.setUsedInPhi(phiInsn);
} }
} }
for (BlockNode domOn : block.getDominatesOn()) { for (BlockNode domOn : block.getDominatesOn()) {
...@@ -199,6 +186,17 @@ public class SSATransform extends AbstractVisitor { ...@@ -199,6 +186,17 @@ public class SSATransform extends AbstractVisitor {
System.arraycopy(inputVars, 0, vars, 0, vars.length); System.arraycopy(inputVars, 0, vars, 0, vars.length);
} }
private static void bindPhiArg(SSAVar[] vars, BlockNode block, PhiInsn phiInsn) {
int regNum = phiInsn.getResult().getRegNum();
SSAVar var = vars[regNum];
if (var == null) {
return;
}
RegisterArg arg = phiInsn.bindArg(block);
var.use(arg);
var.setUsedInPhi(phiInsn);
}
/** /**
* Fix last try/catch assign instruction * Fix last try/catch assign instruction
*/ */
......
package jadx.core.dex.visitors.typeinference; package jadx.core.dex.visitors.typeinference;
import java.util.List;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.PhiListAttr;
import jadx.core.dex.instructions.PhiInsn; import jadx.core.dex.instructions.PhiInsn;
import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.instructions.args.SSAVar; import jadx.core.dex.instructions.args.SSAVar;
import jadx.core.dex.instructions.args.VarName;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.DexNode; import jadx.core.dex.nodes.DexNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.AbstractVisitor; import jadx.core.dex.visitors.AbstractVisitor;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
import java.util.List;
public class TypeInference extends AbstractVisitor { public class TypeInference extends AbstractVisitor {
@Override @Override
...@@ -19,6 +23,8 @@ public class TypeInference extends AbstractVisitor { ...@@ -19,6 +23,8 @@ public class TypeInference extends AbstractVisitor {
if (mth.isNoCode()) { if (mth.isNoCode()) {
return; return;
} }
fixPhiVarNames(mth);
DexNode dex = mth.dex(); DexNode dex = mth.dex();
for (SSAVar var : mth.getSVars()) { for (SSAVar var : mth.getSVars()) {
// inference variable type // inference variable type
...@@ -80,6 +86,32 @@ public class TypeInference extends AbstractVisitor { ...@@ -80,6 +86,32 @@ public class TypeInference extends AbstractVisitor {
} }
} }
private static void fixPhiVarNames(MethodNode mth) {
for (BlockNode block : mth.getBasicBlocks()) {
PhiListAttr phiList = block.get(AType.PHI_LIST);
if (phiList == null) {
continue;
}
for (PhiInsn phiInsn : phiList.getList()) {
RegisterArg resArg = phiInsn.getResult();
int argsCount = phiInsn.getArgsCount();
for (int i = 0; i < argsCount; i++) {
RegisterArg arg = phiInsn.getArg(i);
arg.mergeName(resArg);
}
VarName varName = resArg.getSVar().getVarName();
if (varName == null) {
varName = new VarName();
resArg.getSVar().setVarName(varName);
}
for (int i = 0; i < argsCount; i++) {
RegisterArg arg = phiInsn.getArg(i);
arg.getSVar().setVarName(varName);
}
}
}
}
private static String processVarName(SSAVar var) { private static String processVarName(SSAVar var) {
String name = var.getAssign().getName(); String name = var.getAssign().getName();
if (name != null) { if (name != null) {
......
...@@ -14,7 +14,7 @@ public class TestConditions10 extends IntegrationTest { ...@@ -14,7 +14,7 @@ public class TestConditions10 extends IntegrationTest {
public static class TestCls { public static class TestCls {
public void test(boolean a, int b) throws Exception { public void test(boolean a, int b) {
if (a || b > 2) { if (a || b > 2) {
b++; b++;
} }
......
package jadx.tests.integration.debuginfo;
import org.junit.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import jadx.tests.api.SmaliTest;
import static jadx.tests.api.utils.JadxMatchers.containsLines;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.junit.Assert.assertThat;
public class TestVariablesNames extends SmaliTest {
/*
public static class TestCls {
public void test(String s, int k) {
f1(s);
int i = k + 3;
String s2 = "i" + i;
f2(i, s2);
double d = i * 5;
String s3 = "d" + d;
f3(d, s3);
}
private void f1(String s) {
}
private void f2(int i, String i2) {
}
private void f3(double d, String d2) {
}
}
*/
/**
* Parameter register reused in variables assign with different types and names
* No variables names in debug info
*/
@Test
public void test() {
ClassNode cls = getClassNodeFromSmaliWithPath("debuginfo", "TestVariablesNames");
String code = cls.getCode().toString();
// TODO: don't use current variables naming in tests
assertThat(code, containsOne("f1(str);"));
assertThat(code, containsOne("f2(i2, \"i\" + i2);"));
assertThat(code, containsOne("f3(d, \"d\" + d);"));
}
}
...@@ -29,10 +29,11 @@ public class TestTryCatch7 extends IntegrationTest { ...@@ -29,10 +29,11 @@ public class TestTryCatch7 extends IntegrationTest {
ClassNode cls = getClassNode(TestCls.class); ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString(); String code = cls.getCode().toString();
String excVarName = "exception"; String excVarName = "e";
String catchExcVarName = "e2";
assertThat(code, containsOne("Exception " + excVarName + " = new Exception();")); assertThat(code, containsOne("Exception " + excVarName + " = new Exception();"));
assertThat(code, containsOne("} catch (Exception e) {")); assertThat(code, containsOne("} catch (Exception " + catchExcVarName + ") {"));
assertThat(code, containsOne(excVarName + " = e;")); assertThat(code, containsOne(excVarName + " = " + catchExcVarName + ";"));
assertThat(code, containsOne(excVarName + ".printStackTrace();")); assertThat(code, containsOne(excVarName + ".printStackTrace();"));
assertThat(code, containsOne("return " + excVarName + ";")); assertThat(code, containsOne("return " + excVarName + ";"));
} }
......
.class public LTestVariablesNames;
.super Ljava/lang/Object;
.source "TestVariablesNames.java"
.method public test(Ljava/lang/String;I)V
.registers 10
.prologue
.line 17
invoke-direct {p0, p1}, LTestVariablesNames;->f1(Ljava/lang/String;)V
.line 18
add-int/lit8 p1, p2, 0x3
.line 19
new-instance v5, Ljava/lang/StringBuilder;
invoke-direct {v5}, Ljava/lang/StringBuilder;-><init>()V
const-string v6, "i"
invoke-virtual {v5, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v5
invoke-virtual {v5, p1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v5
invoke-virtual {v5}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v3
.line 20
invoke-direct {p0, p1, v3}, LTestVariablesNames;->f2(ILjava/lang/String;)V
.line 21
mul-int/lit8 v5, p1, 0x5
int-to-double p1, v5
.line 22
new-instance v5, Ljava/lang/StringBuilder;
invoke-direct {v5}, Ljava/lang/StringBuilder;-><init>()V
const-string v6, "d"
invoke-virtual {v5, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v5
invoke-virtual {v5, p1, v1}, Ljava/lang/StringBuilder;->append(D)Ljava/lang/StringBuilder;
move-result-object v5
invoke-virtual {v5}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v4
.line 23
invoke-direct {p0, p1, v1, v4}, LTestVariablesNames;->f3(DLjava/lang/String;)V
.line 24
return-void
.end method
.method public constructor <init>()V
.registers 1
.prologue
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method private f1(Ljava/lang/String;)V
.registers 2
.prologue
return-void
.end method
.method private f2(ILjava/lang/String;)V
.registers 3
.prologue
return-void
.end method
.method private f3(DLjava/lang/String;)V
.registers 4
.prologue
return-void
.end method
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment