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 {
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
public void setType(ArgType type) {
if (sVar != null) {
......
......@@ -78,6 +78,8 @@ public class DebugInfoParser {
addrChange(-1, 1, line);
setLine(addr, line);
boolean varsInfoFound = false;
int c = section.readByte() & 0xFF;
while (c != DBG_END_SEQUENCE) {
switch (c) {
......@@ -98,6 +100,7 @@ public class DebugInfoParser {
int type = section.readUleb128() - 1;
LocalVar var = new LocalVar(dex, regNum, nameId, type, DexNode.NO_INDEX);
startVar(var, addr, line);
varsInfoFound = true;
break;
}
case DBG_START_LOCAL_EXTENDED: {
......@@ -107,6 +110,7 @@ public class DebugInfoParser {
int sign = section.readUleb128() - 1;
LocalVar var = new LocalVar(dex, regNum, nameId, type, sign);
startVar(var, addr, line);
varsInfoFound = true;
break;
}
case DBG_RESTART_LOCAL: {
......@@ -118,6 +122,7 @@ public class DebugInfoParser {
}
var.start(addr, line);
}
varsInfoFound = true;
break;
}
case DBG_END_LOCAL: {
......@@ -127,6 +132,7 @@ public class DebugInfoParser {
var.end(addr, line);
setVar(var);
}
varsInfoFound = true;
break;
}
......@@ -160,12 +166,14 @@ public class DebugInfoParser {
c = section.readByte() & 0xFF;
}
if (varsInfoFound) {
for (LocalVar var : locals) {
if (var != null && !var.isEnd()) {
var.end(mth.getCodeSize() - 1, line);
setVar(var);
}
}
}
setSourceLines(addr, insnByOffset.length, line);
}
......
......@@ -142,6 +142,7 @@ public class PrepareForCodeGen extends AbstractVisitor {
}
if (replace) {
insn.add(AFlag.ARITH_ONEARG);
insn.getResult().mergeName(arg);
}
}
}
......
......@@ -22,7 +22,6 @@ import jadx.core.utils.exceptions.JadxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
......
......@@ -8,6 +8,7 @@ import jadx.core.dex.instructions.PhiInsn;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.RegisterArg;
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.InsnNode;
import jadx.core.dex.nodes.MethodNode;
......@@ -141,14 +142,7 @@ public class SSATransform extends AbstractVisitor {
PhiListAttr phiList = enterBlock.get(AType.PHI_LIST);
if (phiList != null) {
for (PhiInsn phiInsn : phiList.getList()) {
int regNum = phiInsn.getResult().getRegNum();
SSAVar var = vars[regNum];
if (var == null) {
continue;
}
RegisterArg arg = phiInsn.bindArg(enterBlock);
var.use(arg);
var.setUsedInPhi(phiInsn);
bindPhiArg(vars, enterBlock, phiInsn);
}
}
}
......@@ -183,21 +177,25 @@ public class SSATransform extends AbstractVisitor {
continue;
}
for (PhiInsn phiInsn : phiList.getList()) {
bindPhiArg(vars, block, phiInsn);
}
}
for (BlockNode domOn : block.getDominatesOn()) {
renameVar(mth, vars, vers, domOn);
}
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) {
continue;
return;
}
RegisterArg arg = phiInsn.bindArg(block);
var.use(arg);
var.setUsedInPhi(phiInsn);
}
}
for (BlockNode domOn : block.getDominatesOn()) {
renameVar(mth, vars, vers, domOn);
}
System.arraycopy(inputVars, 0, vars, 0, vars.length);
}
/**
* Fix last try/catch assign instruction
......
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.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.RegisterArg;
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.MethodNode;
import jadx.core.dex.visitors.AbstractVisitor;
import jadx.core.utils.exceptions.JadxException;
import java.util.List;
public class TypeInference extends AbstractVisitor {
@Override
......@@ -19,6 +23,8 @@ public class TypeInference extends AbstractVisitor {
if (mth.isNoCode()) {
return;
}
fixPhiVarNames(mth);
DexNode dex = mth.dex();
for (SSAVar var : mth.getSVars()) {
// inference variable type
......@@ -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) {
String name = var.getAssign().getName();
if (name != null) {
......
......@@ -14,7 +14,7 @@ public class TestConditions10 extends IntegrationTest {
public static class TestCls {
public void test(boolean a, int b) throws Exception {
public void test(boolean a, int b) {
if (a || b > 2) {
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 {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
String excVarName = "exception";
String excVarName = "e";
String catchExcVarName = "e2";
assertThat(code, containsOne("Exception " + excVarName + " = new Exception();"));
assertThat(code, containsOne("} catch (Exception e) {"));
assertThat(code, containsOne(excVarName + " = e;"));
assertThat(code, containsOne("} catch (Exception " + catchExcVarName + ") {"));
assertThat(code, containsOne(excVarName + " = " + catchExcVarName + ";"));
assertThat(code, containsOne(excVarName + ".printStackTrace();"));
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