fix(gui): make bytecode output closer to smali (#1739)
This commit is contained in:
@@ -1286,7 +1286,10 @@ public class SmaliDebugger {
|
||||
@Override
|
||||
public String getType() {
|
||||
String gen = getSignature();
|
||||
return gen.isEmpty() ? this.slot.signature : gen;
|
||||
if (gen == null || gen.isEmpty()) {
|
||||
return this.slot.signature;
|
||||
}
|
||||
return gen;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -1304,6 +1307,11 @@ public class SmaliDebugger {
|
||||
public int getEndOffset() {
|
||||
return (int) (slot.codeIndex + slot.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedAsParameter() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RuntimeDebugInfo {
|
||||
|
||||
@@ -285,24 +285,25 @@ public class Smali {
|
||||
writeMethodDef(smali, mth, line);
|
||||
ICodeReader codeReader = mth.getCodeReader();
|
||||
if (codeReader != null) {
|
||||
int regsCount = codeReader.getRegistersCount();
|
||||
line.smaliMthNode.setParamRegStart(getParamStartRegNum(mth));
|
||||
line.smaliMthNode.setRegCount(codeReader.getRegistersCount());
|
||||
line.smaliMthNode.setRegCount(regsCount);
|
||||
Map<Long, InsnNode> nodes = new HashMap<>(codeReader.getUnitsCount() / 2);
|
||||
line.smaliMthNode.setInsnNodes(nodes, codeReader.getUnitsCount());
|
||||
line.smaliMthNode.initRegInfoList(codeReader.getRegistersCount(), codeReader.getUnitsCount());
|
||||
line.smaliMthNode.initRegInfoList(regsCount, codeReader.getUnitsCount());
|
||||
|
||||
smali.incIndent();
|
||||
smali.startLine(".registers ")
|
||||
.add("" + codeReader.getRegistersCount())
|
||||
.startLine();
|
||||
smali.startLine(".registers ").add(Integer.toString(regsCount));
|
||||
|
||||
writeTries(codeReader, line);
|
||||
if (formatMthParamInfo(mth, smali, codeReader, line)) {
|
||||
smali.startLine();
|
||||
IDebugInfo debugInfo = codeReader.getDebugInfo();
|
||||
List<ILocalVar> localVars = debugInfo != null ? debugInfo.getLocalVars() : Collections.emptyList();
|
||||
formatMthParamInfo(mth, smali, line, regsCount, localVars);
|
||||
if (debugInfo != null) {
|
||||
formatDbgInfo(debugInfo, localVars, line);
|
||||
}
|
||||
smali.newLine();
|
||||
smali.startLine();
|
||||
if (codeReader.getDebugInfo() != null) {
|
||||
formatDbgInfo(codeReader.getDebugInfo(), line);
|
||||
}
|
||||
// first pass to fill payload offsets for switch instructions
|
||||
codeReader.visitInstructions(insn -> {
|
||||
Opcode opcode = insn.getOpcode();
|
||||
@@ -458,20 +459,11 @@ public class Smali {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean formatMthParamInfo(IMethodData mth, SmaliWriter smali, ICodeReader codeReader, LineInfo line) {
|
||||
private void formatMthParamInfo(IMethodData mth, SmaliWriter smali, LineInfo line,
|
||||
int regsCount, List<ILocalVar> localVars) {
|
||||
List<String> types = mth.getMethodRef().getArgTypes();
|
||||
if (types.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
ILocalVar[] params = new ILocalVar[codeReader.getRegistersCount()];
|
||||
IDebugInfo dbgInfo = codeReader.getDebugInfo();
|
||||
if (dbgInfo != null) {
|
||||
for (ILocalVar var : dbgInfo.getLocalVars()) {
|
||||
// collect only method parameters
|
||||
if (var.getStartOffset() <= 0) {
|
||||
params[var.getRegNum()] = var;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
int paramStart = 0;
|
||||
int regNum = line.smaliMthNode.getParamRegStart();
|
||||
@@ -482,26 +474,30 @@ public class Smali {
|
||||
regNum++;
|
||||
paramStart++;
|
||||
}
|
||||
if (localVars.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ILocalVar[] params = new ILocalVar[regsCount];
|
||||
for (ILocalVar var : localVars) {
|
||||
if (var.isMarkedAsParameter()) {
|
||||
params[var.getRegNum()] = var;
|
||||
}
|
||||
}
|
||||
smali.newLine();
|
||||
for (String paramType : types) {
|
||||
String name;
|
||||
String type;
|
||||
ILocalVar param = params[regNum];
|
||||
if (param != null) {
|
||||
name = Utils.getOrElse(param.getName(), "");
|
||||
type = Utils.getOrElse(param.getSignature(), paramType);
|
||||
} else {
|
||||
name = "";
|
||||
type = paramType;
|
||||
String name = Utils.getOrElse(param.getName(), "");
|
||||
String type = Utils.getOrElse(param.getSignature(), paramType);
|
||||
String varName = "p" + paramStart;
|
||||
smali.startLine(String.format(".param %s, \"%s\" # %s", varName, name, type));
|
||||
line.addRegName(regNum, varName);
|
||||
line.smaliMthNode.setParamReg(regNum, varName);
|
||||
}
|
||||
String varName = "p" + paramStart;
|
||||
smali.startLine(String.format(".param %s, \"%s\" # %s", varName, name, type));
|
||||
line.addRegName(regNum, varName);
|
||||
line.smaliMthNode.setParamReg(regNum, varName);
|
||||
int regSize = isWideType(paramType) ? 2 : 1;
|
||||
regNum += regSize;
|
||||
paramStart += regSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int getParamStartRegNum(IMethodData mth) {
|
||||
@@ -558,32 +554,44 @@ public class Smali {
|
||||
smali.startLine(".end annotation");
|
||||
}
|
||||
|
||||
private void formatDbgInfo(IDebugInfo dbgInfo, LineInfo line) {
|
||||
private void formatDbgInfo(IDebugInfo dbgInfo, List<ILocalVar> localVars, LineInfo line) {
|
||||
dbgInfo.getSourceLineMapping().forEach((codeOffset, srcLine) -> {
|
||||
if (codeOffset > -1) {
|
||||
line.addDebugLineTip(codeOffset, String.format(".line %d", srcLine), "");
|
||||
}
|
||||
});
|
||||
for (ILocalVar localVar : dbgInfo.getLocalVars()) {
|
||||
String type = localVar.getSignature();
|
||||
if (type == null || type.trim().isEmpty()) {
|
||||
type = localVar.getType();
|
||||
for (ILocalVar localVar : localVars) {
|
||||
if (localVar.isMarkedAsParameter()) {
|
||||
continue;
|
||||
}
|
||||
if (localVar.getStartOffset() > -1) {
|
||||
line.addTip(
|
||||
localVar.getStartOffset(),
|
||||
String.format(".local v%d", localVar.getRegNum()),
|
||||
String.format(", \"%s\":%s", localVar.getName(), type));
|
||||
}
|
||||
if (localVar.getEndOffset() > -1) {
|
||||
line.addTip(
|
||||
localVar.getEndOffset(),
|
||||
String.format(".end local v%d", localVar.getRegNum()),
|
||||
String.format(" # \"%s\":%s", localVar.getName(), type));
|
||||
String type = localVar.getType();
|
||||
String sign = localVar.getSignature();
|
||||
String longTypeStr;
|
||||
if (sign == null || sign.trim().isEmpty()) {
|
||||
longTypeStr = String.format(", \"%s\":%s", localVar.getName(), type);
|
||||
} else {
|
||||
longTypeStr = String.format(", \"%s\":%s, \"%s\"", localVar.getName(), type, localVar.getSignature());
|
||||
}
|
||||
line.addTip(
|
||||
localVar.getStartOffset(),
|
||||
".local " + formatVarName(line.smaliMthNode, localVar),
|
||||
longTypeStr);
|
||||
line.addTip(
|
||||
localVar.getEndOffset(),
|
||||
".end local " + formatVarName(line.smaliMthNode, localVar),
|
||||
String.format(" # \"%s\":%s", localVar.getName(), type));
|
||||
}
|
||||
}
|
||||
|
||||
private String formatVarName(SmaliMethodNode smaliMthNode, ILocalVar localVar) {
|
||||
int paramRegStart = smaliMthNode.getParamRegStart();
|
||||
int regNum = localVar.getRegNum();
|
||||
if (regNum < paramRegStart) {
|
||||
return "v" + regNum;
|
||||
}
|
||||
return "p" + (regNum - paramRegStart);
|
||||
}
|
||||
|
||||
private void writeEncodedValue(SmaliWriter smali, EncodedValue value, boolean wrapArray) {
|
||||
switch (value.getType()) {
|
||||
case ENCODED_ARRAY:
|
||||
|
||||
@@ -94,7 +94,6 @@ class SmaliMethodNode {
|
||||
protected void setParamReg(int regNum, String name) {
|
||||
SmaliRegister r = regList.get(regNum);
|
||||
r.setParam(name);
|
||||
r.setStartOffset(-1);
|
||||
}
|
||||
|
||||
protected void setParamRegStart(int paramRegStart) {
|
||||
|
||||
@@ -33,10 +33,6 @@ public class SmaliRegister extends RegisterInfo {
|
||||
}
|
||||
|
||||
protected void setStartOffset(int off) {
|
||||
if (startOffset == -1 && !isParam) {
|
||||
startOffset = off;
|
||||
return;
|
||||
}
|
||||
if (off < startOffset) {
|
||||
startOffset = off;
|
||||
}
|
||||
@@ -71,4 +67,9 @@ public class SmaliRegister extends RegisterInfo {
|
||||
public int getEndOffset() {
|
||||
return endOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedAsParameter() {
|
||||
return isParam;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ class DbgSmaliTest extends SmaliTest {
|
||||
Smali disasm = Smali.disassemble(cls);
|
||||
String code = disasm.getCode();
|
||||
LOG.debug("{}", code);
|
||||
assertThat(code).doesNotContain("Failed to write method");
|
||||
assertThat(code)
|
||||
.doesNotContain("Failed to write method")
|
||||
.doesNotContain(".param p1")
|
||||
.contains(".local p1, \"arg0\":Landroid/widget/AdapterView;, \"Landroid/widget/AdapterView<*>;\"");
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -96,8 +96,9 @@ public class DebugInfoParser {
|
||||
int nameId = in.readUleb128p1();
|
||||
String name = ext.getString(nameId);
|
||||
if (name != null && i < argsCount) {
|
||||
int regNum = argRegs[i];
|
||||
startVar(new DexLocalVar(regNum, name, argTypes.get(i)), -1);
|
||||
DexLocalVar paramVar = new DexLocalVar(argRegs[i], name, argTypes.get(i));
|
||||
startVar(paramVar, addr);
|
||||
paramVar.markAsParameter();
|
||||
varsInfoFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -7,6 +7,8 @@ import jadx.api.plugins.utils.Utils;
|
||||
import jadx.plugins.input.dex.sections.SectionReader;
|
||||
|
||||
public class DexLocalVar implements ILocalVar {
|
||||
private static final int PARAM_START_OFFSET = -1;
|
||||
|
||||
private final int regNum;
|
||||
private final String name;
|
||||
private final String type;
|
||||
@@ -78,6 +80,15 @@ public class DexLocalVar implements ILocalVar {
|
||||
return startOffset;
|
||||
}
|
||||
|
||||
public void markAsParameter() {
|
||||
startOffset = PARAM_START_OFFSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedAsParameter() {
|
||||
return startOffset == PARAM_START_OFFSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEndOffset() {
|
||||
return endOffset;
|
||||
|
||||
+5
@@ -61,6 +61,11 @@ public class JavaLocalVar implements ILocalVar {
|
||||
return endOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedAsParameter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = regNum;
|
||||
|
||||
@@ -15,4 +15,10 @@ public interface ILocalVar {
|
||||
int getStartOffset();
|
||||
|
||||
int getEndOffset();
|
||||
|
||||
/**
|
||||
* Hint if variable is a method parameter.
|
||||
* Can be incorrect and shouldn't be trusted.
|
||||
*/
|
||||
boolean isMarkedAsParameter();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user