diff --git a/CHANGES b/CHANGES index 48471e3d1..9cd28ed38 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,7 @@ Features: - New unlicensed GB mappers: Pokémon Jade/Diamond, BBD, and Hitek - Stack tracing tools in ARM debugger (by ahigerd) - Command scripts for CLI debugger (by ahigerd) + - ARM disassembler now resolves addresses to symbol names Emulation fixes: - ARM: Fix ALU reading PC after shifting - ARM: Fix STR storing PC after address calculation diff --git a/include/mgba/internal/arm/decoder.h b/include/mgba/internal/arm/decoder.h index dffa7042a..1a3f9e7e9 100644 --- a/include/mgba/internal/arm/decoder.h +++ b/include/mgba/internal/arm/decoder.h @@ -212,11 +212,12 @@ struct ARMInstructionInfo { unsigned nDataCycles : 10; }; +struct mDebuggerSymbols; void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info); void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info); bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2, struct ARMInstructionInfo* out); -int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen); +int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* core, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen); uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc); CXX_GUARD_END diff --git a/src/arm/debugger/cli-debugger.c b/src/arm/debugger/cli-debugger.c index d5ee883be..df3e04c1c 100644 --- a/src/arm/debugger/cli-debugger.c +++ b/src/arm/debugger/cli-debugger.c @@ -98,28 +98,29 @@ static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) { struct CLIDebuggerBackend* be = debugger->backend; + struct mCore* core = debugger->d.core; char disassembly[64]; struct ARMInstructionInfo info; be->printf(be, "%08X: ", address); if (mode == MODE_ARM) { - uint32_t instruction = debugger->d.core->busRead32(debugger->d.core, address); + uint32_t instruction = core->busRead32(core, address); ARMDecodeARM(instruction, &info); - ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly)); + ARMDisassemble(&info, core->cpu, core->symbolTable, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly)); be->printf(be, "%08X\t%s\n", instruction, disassembly); return WORD_SIZE_ARM; } else { struct ARMInstructionInfo info2; struct ARMInstructionInfo combined; - uint16_t instruction = debugger->d.core->busRead16(debugger->d.core, address); - uint16_t instruction2 = debugger->d.core->busRead16(debugger->d.core, address + WORD_SIZE_THUMB); + uint16_t instruction = core->busRead16(core, address); + uint16_t instruction2 = core->busRead16(core, address + WORD_SIZE_THUMB); ARMDecodeThumb(instruction, &info); ARMDecodeThumb(instruction2, &info2); if (ARMDecodeThumbCombine(&info, &info2, &combined)) { - ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); + ARMDisassemble(&combined, core->cpu, core->symbolTable, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); be->printf(be, "%04X %04X\t%s\n", instruction, instruction2, disassembly); return WORD_SIZE_THUMB * 2; } else { - ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); + ARMDisassemble(&info, core->cpu, core->symbolTable, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); be->printf(be, "%04X \t%s\n", instruction, disassembly); return WORD_SIZE_THUMB; } diff --git a/src/arm/debugger/debugger.c b/src/arm/debugger/debugger.c index b7f345b3d..fe3d56117 100644 --- a/src/arm/debugger/debugger.c +++ b/src/arm/debugger/debugger.c @@ -467,6 +467,7 @@ static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatc static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMCore* cpu = debugger->cpu; + struct mCore* core = d->p->core; char disassembly[64]; @@ -475,17 +476,17 @@ static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* len if (cpu->executionMode == MODE_ARM) { uint32_t instruction = cpu->prefetch[0]; sprintf(disassembly, "%08X: ", instruction); - ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); + ARMDisassemble(&info, cpu, core->symbolTable, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); } else { uint16_t instruction = cpu->prefetch[0]; ARMDecodeThumb(instruction, &info); if (isWideInstruction) { uint16_t instruction2 = cpu->prefetch[1]; sprintf(disassembly, "%04X%04X: ", instruction, instruction2); - ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); + ARMDisassemble(&info, cpu, core->symbolTable, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); } else { sprintf(disassembly, " %04X: ", instruction); - ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); + ARMDisassemble(&info, cpu, core->symbolTable, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); } } diff --git a/src/arm/decoder.c b/src/arm/decoder.c index 3cb87d77c..81bf9f483 100644 --- a/src/arm/decoder.c +++ b/src/arm/decoder.c @@ -6,6 +6,7 @@ #include #include +#include #include #define ADVANCE(AMOUNT) \ @@ -20,8 +21,8 @@ static int _decodeRegister(int reg, char* buffer, int blen); static int _decodeRegisterList(int list, char* buffer, int blen); static int _decodePSR(int bits, char* buffer, int blen); -static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen); -static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen); +static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen); +static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen); static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen); static const char* _armConditions[] = { @@ -141,23 +142,66 @@ static int _decodePSR(int psrBits, char* buffer, int blen) { return total; } -static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) { - return snprintf(buffer, blen, "$%08X", address + pc); +static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen) { + address += pc; + const char* label = NULL; + if (symbols) { + label = mDebuggerSymbolReverseLookup(symbols, address, -1); + if (!label && thumbBranch) { + label = mDebuggerSymbolReverseLookup(symbols, address | 1, -1); + } + } + if (label) { + return strlcpy(buffer, label, blen); + } else { + return snprintf(buffer, blen, "0x%08X", address); + } } -static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) { +static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen) { if (blen <= 1) { return 0; } int total = 0; - strlcpy(buffer, "[", blen); - ADVANCE(1); + bool elideClose = false; int written; if (memory.format & ARM_MEMORY_REGISTER_BASE) { if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) { - written = _decodePCRelative(memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate, pc & 0xFFFFFFFC, buffer, blen); - ADVANCE(written); + uint32_t addrBase = memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate; + if (!cpu) { + strlcpy(buffer, "[", blen); + ADVANCE(1); + written = _decodePCRelative(addrBase, symbols, pc & 0xFFFFFFFC, false, buffer, blen); + ADVANCE(written); + } else { + uint32_t value; + addrBase += pc & 0xFFFFFFFC; // Thumb does not have PC-relative LDRH/LDRB + switch (memory.width & 7) { + case 1: + value = cpu->memory.load8(cpu, addrBase, NULL); + break; + case 2: + value = cpu->memory.load16(cpu, addrBase, NULL); + break; + case 4: + value = cpu->memory.load32(cpu, addrBase, NULL); + break; + } + const char* label = NULL; + if (symbols) { + label = mDebuggerSymbolReverseLookup(symbols, value, -1); + } + if (label) { + written = snprintf(buffer, blen, "=%s", label); + } else { + written = snprintf(buffer, blen, "=0x%08X", value); + } + ADVANCE(written); + elideClose = true; + } } else { + strlcpy(buffer, "[", blen); + ADVANCE(1); written = _decodeRegister(memory.baseReg, buffer, blen); ADVANCE(written); if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) { @@ -165,10 +209,14 @@ static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, in ADVANCE(2); } } + } else { + strlcpy(buffer, "[", blen); + ADVANCE(1); } if (memory.format & ARM_MEMORY_POST_INCREMENT) { strlcpy(buffer, "], ", blen); ADVANCE(3); + elideClose = true; } if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) { if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) { @@ -191,7 +239,7 @@ static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, in ADVANCE(written); } - if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) { + if (!elideClose) { strlcpy(buffer, "]", blen); ADVANCE(1); } @@ -322,7 +370,7 @@ static const char* _armAccessTypeStrings[] = { "" }; -int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) { +int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen) { const char* mnemonic = _armMnemonicStrings[info->mnemonic]; int written; int total = 0; @@ -394,7 +442,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i case ARM_MN_B: case ARM_MN_BL: if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) { - written = _decodePCRelative(info->op1.immediate, pc, buffer, blen); + written = _decodePCRelative(info->op1.immediate, symbols, pc, true, buffer, blen); ADVANCE(written); } break; @@ -403,7 +451,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i written = snprintf(buffer, blen, "#%i", info->op1.immediate); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) { - written = _decodeMemory(info->memory, pc, buffer, blen); + written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) { written = _decodeRegister(info->op1.reg, buffer, blen); @@ -428,7 +476,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i written = snprintf(buffer, blen, "#%i", info->op2.immediate); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) { - written = _decodeMemory(info->memory, pc, buffer, blen); + written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) { written = _decodeRegister(info->op2.reg, buffer, blen); @@ -449,7 +497,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i written = snprintf(buffer, blen, "#%i", info->op3.immediate); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) { - written = _decodeMemory(info->memory, pc, buffer, blen); + written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) { written = _decodeRegister(info->op3.reg, buffer, blen); @@ -470,7 +518,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i written = snprintf(buffer, blen, "#%i", info->op4.immediate); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) { - written = _decodeMemory(info->memory, pc, buffer, blen); + written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen); ADVANCE(written); } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) { written = _decodeRegister(info->op4.reg, buffer, blen);