From 0fafcfa0069b1ebb8d9c71ba1a71f61b9812620a Mon Sep 17 00:00:00 2001 From: Skylot Date: Mon, 12 Dec 2022 21:49:56 +0000 Subject: [PATCH] fix(gui): improve smali disasm method param write (#1739) --- .../jadx/gui/device/debugger/smali/Smali.java | 79 +++++++++++-------- .../device/debugger/smali/DbgSmaliTest.java | 14 +++- jadx-gui/src/test/smali/params.smali | 58 ++++++++++++++ 3 files changed, 115 insertions(+), 36 deletions(-) create mode 100644 jadx-gui/src/test/smali/params.smali diff --git a/jadx-gui/src/main/java/jadx/gui/device/debugger/smali/Smali.java b/jadx-gui/src/main/java/jadx/gui/device/debugger/smali/Smali.java index ed0e6c7a..1d606e43 100644 --- a/jadx-gui/src/main/java/jadx/gui/device/debugger/smali/Smali.java +++ b/jadx-gui/src/main/java/jadx/gui/device/debugger/smali/Smali.java @@ -13,6 +13,8 @@ import java.util.Map.Entry; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import jadx.api.ICodeInfo; import jadx.api.plugins.input.data.AccessFlags; @@ -46,6 +48,7 @@ import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; +import jadx.core.utils.Utils; import jadx.core.utils.exceptions.JadxRuntimeException; import static jadx.api.plugins.input.data.AccessFlagsScope.FIELD; @@ -67,6 +70,7 @@ import static jadx.api.plugins.input.insns.Opcode.SPARSE_SWITCH; import static jadx.api.plugins.input.insns.Opcode.SPARSE_SWITCH_PAYLOAD; public class Smali { + private static final Logger LOG = LoggerFactory.getLogger(Smali.class); private static SmaliInsnDecoder insnDecoder = null; @@ -219,7 +223,15 @@ public class Smali { writeFields(smali, clsData, fields, colWidths); fields.clear(); } - writeMethod(smali, cls.getMethods().get(mthIndex[0]++), m, line); + try { + writeMethod(smali, cls.getMethods().get(mthIndex[0]++), m, line); + } catch (Throwable e) { + IMethodRef methodRef = m.getMethodRef(); + String mthFullName = methodRef.getParentClassType() + "->" + methodRef.getName(); + smali.setIndent(0); + smali.startLine("Failed to write method: " + mthFullName + "\n" + Utils.getStackTrace(e)); + LOG.error("Failed to write smali code for method: {}", mthFullName, e); + } line.reset(); }); @@ -451,48 +463,45 @@ public class Smali { if (types.isEmpty()) { return false; } - int paramCount = 0; - int paramStart = 0; - int regNum = line.smaliMthNode.getParamRegStart(); - if (!hasStaticFlag(mth.getAccessFlags())) { - line.addRegName(regNum, "p0"); - line.smaliMthNode.setParamReg(regNum, "p0"); - regNum += 1; - paramStart = 1; - } + ILocalVar[] params = new ILocalVar[codeReader.getRegistersCount()]; IDebugInfo dbgInfo = codeReader.getDebugInfo(); if (dbgInfo != null) { for (ILocalVar var : dbgInfo.getLocalVars()) { - if (var.getRegNum() == regNum) { - int i = writeParamInfo(smali, line, regNum, paramStart, var.getName(), var.getType()); - regNum += i; - paramStart += i; - paramCount++; + // collect only method parameters + if (var.getStartOffset() <= 0) { + params[var.getRegNum()] = var; } } } - for (; paramCount < types.size(); paramCount++) { - int i = writeParamInfo(smali, line, regNum, paramStart, "", types.get(paramCount)); - regNum += i; - paramStart += i; - } - return true; - } - - private static int writeParamInfo(SmaliWriter smali, LineInfo line, - int regNum, int paramNum, String dbgInfoName, String type) { - smali.startLine(String.format(".param p%d, \"%s\":%s", paramNum, dbgInfoName, type)); - String pName = "p" + paramNum; - line.addRegName(regNum, pName); - line.smaliMthNode.setParamReg(regNum, pName); - if (isWideType(type)) { + int paramStart = 0; + int regNum = line.smaliMthNode.getParamRegStart(); + if (!hasStaticFlag(mth.getAccessFlags())) { + // add 'this' register + line.addRegName(regNum, "p0"); + line.smaliMthNode.setParamReg(regNum, "p0"); regNum++; - dbgInfoName = "p" + (paramNum + 1); - line.addRegName(regNum, dbgInfoName); - line.smaliMthNode.setParamReg(regNum, dbgInfoName); - return 2; + paramStart++; + } + 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 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 1; + return true; } private static int getParamStartRegNum(IMethodData mth) { diff --git a/jadx-gui/src/test/java/jadx/gui/device/debugger/smali/DbgSmaliTest.java b/jadx-gui/src/test/java/jadx/gui/device/debugger/smali/DbgSmaliTest.java index 124d2167..43e6c542 100644 --- a/jadx-gui/src/test/java/jadx/gui/device/debugger/smali/DbgSmaliTest.java +++ b/jadx-gui/src/test/java/jadx/gui/device/debugger/smali/DbgSmaliTest.java @@ -8,6 +8,8 @@ import org.slf4j.LoggerFactory; import jadx.core.dex.nodes.ClassNode; import jadx.tests.api.SmaliTest; +import static org.assertj.core.api.Assertions.assertThat; + class DbgSmaliTest extends SmaliTest { private static final Logger LOG = LoggerFactory.getLogger(DbgSmaliTest.class); @@ -17,10 +19,20 @@ class DbgSmaliTest extends SmaliTest { } @Test - void test() { + void testSwitch() { disableCompilation(); ClassNode cls = getClassNodeFromSmali("switch", "SwitchTest"); Smali disasm = Smali.disassemble(cls); LOG.debug("{}", disasm.getCode()); } + + @Test + void testParams() { + disableCompilation(); + ClassNode cls = getClassNodeFromSmali("params", "ParamsTest"); + Smali disasm = Smali.disassemble(cls); + String code = disasm.getCode(); + LOG.debug("{}", code); + assertThat(code).doesNotContain("Failed to write method"); + } } diff --git a/jadx-gui/src/test/smali/params.smali b/jadx-gui/src/test/smali/params.smali new file mode 100644 index 00000000..b171c320 --- /dev/null +++ b/jadx-gui/src/test/smali/params.smali @@ -0,0 +1,58 @@ +.class LParamsTest; +.super Ljava/lang/Object; + +.method public test(Landroid/widget/AdapterView;Landroid/view/View;IJ)V + .registers 10 + .param p2, "arg1" # Landroid/view/View; + .param p3, "arg2" # I + .param p4, "arg3" # J + .annotation system Ldalvik/annotation/Signature; + value = { + "(", + "Landroid/widget/AdapterView", + "<*>;", + "Landroid/view/View;", + "IJ)V" + } + .end annotation + + .prologue + .line 69 + .local p1, "arg0":Landroid/widget/AdapterView;, "Landroid/widget/AdapterView<*>;" + iget-object v2, p0, LParamsTest;->this$0:Ltest/ColorListActivity; + + .line 72 + iget-object v2, v2, Ltest/ColorListActivity;->mSortedColorList:[Ljava/lang/String; + + .line 75 + aget-object v0, v2, p3 + + .line 80 + .local v0, "colorString":Ljava/lang/String; + new-instance v1, Landroid/content/Intent; + + .line 83 + iget-object v2, p0, LParamsTest;->this$0:Ltest/ColorListActivity; + + .line 86 + const-class v3, Ltest/ColorItemActivity; + + .line 89 + invoke-direct {v1, v2, v3}, Landroid/content/Intent;->(Landroid/content/Context;Ljava/lang/Class;)V + + .line 94 + .local v1, "intent":Landroid/content/Intent; + const-string v2, "colorString" + + .line 97 + invoke-virtual {v1, v2, v0}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent; + + .line 101 + iget-object v2, p0, LParamsTest;->this$0:Ltest/ColorListActivity; + + .line 104 + invoke-virtual {v2, v1}, Ltest/ColorListActivity;->startActivity(Landroid/content/Intent;)V + + .line 108 + return-void +.end method -- GitLab