Skip to content

Commit

Permalink
fix(gui): resolve payload offset for switch insns in debug smali code (
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Jul 18, 2022
1 parent 1a877d6 commit c27f2ba
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 12 deletions.
15 changes: 10 additions & 5 deletions jadx-core/src/test/java/jadx/tests/api/SmaliTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@

public abstract class SmaliTest extends IntegrationTest {

private static final String SMALI_TESTS_PROJECT = "jadx-core";
private static final String SMALI_TESTS_DIR = "src/test/smali";
private static final String SMALI_TESTS_EXT = ".smali";

private String currentProject = "jadx-core";

public void setCurrentProject(String currentProject) {
this.currentProject = currentProject;
}

@BeforeEach
public void init() {
Assumptions.assumeFalse(USE_JAVA_INPUT, "skip smali test for java input tests");
Expand Down Expand Up @@ -89,24 +94,24 @@ private List<File> collectSmaliFiles(String pkg, @Nullable String testDir) {
.collect(Collectors.toList());
}

private static File getSmaliFile(String baseName) {
private File getSmaliFile(String baseName) {
File smaliFile = new File(SMALI_TESTS_DIR, baseName + SMALI_TESTS_EXT);
if (smaliFile.exists()) {
return smaliFile;
}
File pathFromRoot = new File(SMALI_TESTS_PROJECT, smaliFile.getPath());
File pathFromRoot = new File(currentProject, smaliFile.getPath());
if (pathFromRoot.exists()) {
return pathFromRoot;
}
throw new AssertionError("Smali file not found: " + smaliFile.getPath());
}

private static File getSmaliDir(String baseName) {
private File getSmaliDir(String baseName) {
File smaliDir = new File(SMALI_TESTS_DIR, baseName);
if (smaliDir.exists()) {
return smaliDir;
}
File pathFromRoot = new File(SMALI_TESTS_PROJECT, smaliDir.getPath());
File pathFromRoot = new File(currentProject, smaliDir.getPath());
if (pathFromRoot.exists()) {
return pathFromRoot;
}
Expand Down
26 changes: 19 additions & 7 deletions jadx-gui/src/main/java/jadx/gui/device/debugger/smali/Smali.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.exceptions.JadxRuntimeException;

import static jadx.api.plugins.input.data.AccessFlagsScope.FIELD;
import static jadx.api.plugins.input.data.AccessFlagsScope.METHOD;
Expand All @@ -60,7 +61,9 @@
import static jadx.api.plugins.input.insns.Opcode.INVOKE_CUSTOM_RANGE;
import static jadx.api.plugins.input.insns.Opcode.INVOKE_POLYMORPHIC;
import static jadx.api.plugins.input.insns.Opcode.INVOKE_POLYMORPHIC_RANGE;
import static jadx.api.plugins.input.insns.Opcode.PACKED_SWITCH;
import static jadx.api.plugins.input.insns.Opcode.PACKED_SWITCH_PAYLOAD;
import static jadx.api.plugins.input.insns.Opcode.SPARSE_SWITCH;
import static jadx.api.plugins.input.insns.Opcode.SPARSE_SWITCH_PAYLOAD;

public class Smali {
Expand Down Expand Up @@ -288,6 +291,14 @@ private void writeMethod(SmaliWriter smali, MethodNode methodNode, IMethodData m
if (codeReader.getDebugInfo() != null) {
formatDbgInfo(codeReader.getDebugInfo(), line);
}
// first pass to fill payload offsets for switch instructions
codeReader.visitInstructions(insn -> {
Opcode opcode = insn.getOpcode();
if (opcode == PACKED_SWITCH || opcode == SPARSE_SWITCH) {
insn.decode();
line.addPayloadOffset(insn.getOffset(), insn.getTarget());
}
});
codeReader.visitInstructions(insn -> {
InsnNode node = decodeInsn(insn, line);
nodes.put((long) insn.getOffset(), node);
Expand Down Expand Up @@ -404,7 +415,6 @@ private boolean tryFormatTargetIns(InsnData insn, InsnType insnType, LineInfo li
line.addTip(target, String.format(FMT_S_SWITCH_TAG, target), "");
line.getLineWriter().append(", ").append(String.format(FMT_S_SWITCH, target));
}
line.addPayloadOffset(insn.getOffset(), target);
return true;
}
}
Expand Down Expand Up @@ -733,7 +743,7 @@ private boolean fmtPayloadInsn(InsnData insn, LineInfo line) {

ISwitchPayload payload = (ISwitchPayload) insn.getPayload();
if (payload != null) {
fmtSwitchPayload(insn, FMT_P_SWITCH_CASE, FMT_P_SWITCH_CASE_TAG, line, payload, insn.getOffset());
fmtSwitchPayload(insn, FMT_P_SWITCH_CASE, FMT_P_SWITCH_CASE_TAG, line, payload);
}
return true;
}
Expand All @@ -743,7 +753,7 @@ private boolean fmtPayloadInsn(InsnData insn, LineInfo line) {

ISwitchPayload payload = (ISwitchPayload) insn.getPayload();
if (payload != null) {
fmtSwitchPayload(insn, FMT_S_SWITCH_CASE, FMT_S_SWITCH_CASE_TAG, line, payload, insn.getOffset());
fmtSwitchPayload(insn, FMT_S_SWITCH_CASE, FMT_S_SWITCH_CASE_TAG, line, payload);
}
return true;
}
Expand All @@ -755,17 +765,19 @@ private boolean fmtPayloadInsn(InsnData insn, LineInfo line) {
return false;
}

private void fmtSwitchPayload(InsnData insn, String fmtTarget, String fmtTag, LineInfo line,
ISwitchPayload payload, int curOffset) {
private void fmtSwitchPayload(InsnData insn, String fmtTarget, String fmtTag, LineInfo line, ISwitchPayload payload) {
int lineStart = getInsnColStart();
lineStart += CODE_OFFSET_COLUMN_WIDTH + 1 + 1; // plus 1s for space and the ':'
String basicIndent = new String(new byte[lineStart]).replace("\0", " ");
String indent = SmaliWriter.INDENT_STR + basicIndent;
int[] keys = payload.getKeys();
int[] targets = payload.getTargets();
int opcodeOffset = line.payloadOffsetMap.get(curOffset);
Integer switchOffset = line.payloadOffsetMap.get(insn.getOffset());
if (switchOffset == null) {
throw new JadxRuntimeException("Unknown switch insn for payload at " + insn.getOffset());
}
for (int i = 0; i < keys.length; i++) {
int target = opcodeOffset + targets[i];
int target = switchOffset + targets[i];
line.addInsnLine(insn.getOffset(),
String.format("%scase %d: -> " + fmtTarget, indent, keys[i], target));
line.addTip(target,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package jadx.gui.device.debugger.smali;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.SmaliTest;

class DbgSmaliTest extends SmaliTest {
private static final Logger LOG = LoggerFactory.getLogger(DbgSmaliTest.class);

@BeforeEach
public void initProject() {
setCurrentProject("jadx-gui");
}

@Test
void test() {
disableCompilation();
ClassNode cls = getClassNodeFromSmali("switch", "SwitchTest");
Smali disasm = Smali.disassemble(cls);
LOG.debug("{}", disasm.getCode());
}
}
81 changes: 81 additions & 0 deletions jadx-gui/src/test/smali/switch.smali
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
.class public final LSwitchTest;
.super Ljava/lang/Object;

.field public static final synthetic a:LSwitchTest;
.field public static final synthetic b:LSwitchTest;

.field private final synthetic c:I

.method public final test(Ljava/lang/Runnable;)Ljava/lang/Thread;
.registers 4
const v0, 0xa
const v1, 0xa
add-int v0, v0, v1
rem-int v0, v0, v1
if-gtz v0, :cond_f
goto/32 :goto_d2

:cond_f
:goto_f
goto/32 :goto_bf
:goto_18
const-string v1, "A"
goto/32 :goto_68
:goto_26
const-string v1, "B"
goto/32 :goto_7c
:goto_33
return-object v0

:pswitch_38
goto/32 :goto_4e
:goto_41
new-instance v0, Labo;
goto/32 :goto_84
:goto_4e
new-instance v0, Lwf;
goto/32 :goto_ab
:goto_5b
new-instance v0, Ljava/lang/Thread;
goto/32 :goto_18
:goto_68
invoke-direct {v0, p1, v1}, Ljava/lang/Thread;-><init>(Ljava/lang/Runnable;Ljava/lang/String;)V
goto/32 :goto_71
:goto_71
return-object v0
:pswitch_75
goto/32 :goto_b3
:goto_7c
invoke-direct {v0, p1, v1}, Ljava/lang/Thread;-><init>(Ljava/lang/Runnable;Ljava/lang/String;)V
goto/32 :goto_33
:goto_84
invoke-direct {v0, p1}, Labo;-><init>(Ljava/lang/Runnable;)V
goto/32 :goto_90
:goto_90
return-object v0

:pswitch_data_96
.packed-switch 0x0
:pswitch_a3
:pswitch_38
:pswitch_75
.end packed-switch

:goto_a0
return-object v0
:pswitch_a3
goto/32 :goto_41
:goto_ab
invoke-direct {v0, p1}, Lwf;-><init>(Ljava/lang/Runnable;)V
goto/32 :goto_a0
:goto_b3
new-instance v0, Ljava/lang/Thread;
goto/32 :goto_26
:goto_bf
iget v0, p0, LSwitchTest;->c:I

packed-switch v0, :pswitch_data_96
goto/32 :goto_5b
:goto_d2
goto/32 :goto_f
.end method

0 comments on commit c27f2ba

Please sign in to comment.