ARM Debugger: Disassembler now resolves addresses to symbol names

This commit is contained in:
Vicki Pfau 2020-09-07 15:54:49 -07:00
parent 17ca8f524a
commit 87ec3f3d4a
5 changed files with 78 additions and 26 deletions

View File

@ -9,6 +9,7 @@ Features:
- New unlicensed GB mappers: Pokémon Jade/Diamond, BBD, and Hitek - New unlicensed GB mappers: Pokémon Jade/Diamond, BBD, and Hitek
- Stack tracing tools in ARM debugger (by ahigerd) - Stack tracing tools in ARM debugger (by ahigerd)
- Command scripts for CLI debugger (by ahigerd) - Command scripts for CLI debugger (by ahigerd)
- ARM disassembler now resolves addresses to symbol names
Emulation fixes: Emulation fixes:
- ARM: Fix ALU reading PC after shifting - ARM: Fix ALU reading PC after shifting
- ARM: Fix STR storing PC after address calculation - ARM: Fix STR storing PC after address calculation

View File

@ -212,11 +212,12 @@ struct ARMInstructionInfo {
unsigned nDataCycles : 10; unsigned nDataCycles : 10;
}; };
struct mDebuggerSymbols;
void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info); void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info);
void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info); void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info);
bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2, bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2,
struct ARMInstructionInfo* out); 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); uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc);
CXX_GUARD_END CXX_GUARD_END

View File

@ -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) { static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
struct CLIDebuggerBackend* be = debugger->backend; struct CLIDebuggerBackend* be = debugger->backend;
struct mCore* core = debugger->d.core;
char disassembly[64]; char disassembly[64];
struct ARMInstructionInfo info; struct ARMInstructionInfo info;
be->printf(be, "%08X: ", address); be->printf(be, "%08X: ", address);
if (mode == MODE_ARM) { 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); 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); be->printf(be, "%08X\t%s\n", instruction, disassembly);
return WORD_SIZE_ARM; return WORD_SIZE_ARM;
} else { } else {
struct ARMInstructionInfo info2; struct ARMInstructionInfo info2;
struct ARMInstructionInfo combined; struct ARMInstructionInfo combined;
uint16_t instruction = debugger->d.core->busRead16(debugger->d.core, address); uint16_t instruction = core->busRead16(core, address);
uint16_t instruction2 = debugger->d.core->busRead16(debugger->d.core, address + WORD_SIZE_THUMB); uint16_t instruction2 = core->busRead16(core, address + WORD_SIZE_THUMB);
ARMDecodeThumb(instruction, &info); ARMDecodeThumb(instruction, &info);
ARMDecodeThumb(instruction2, &info2); ARMDecodeThumb(instruction2, &info2);
if (ARMDecodeThumbCombine(&info, &info2, &combined)) { 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); be->printf(be, "%04X %04X\t%s\n", instruction, instruction2, disassembly);
return WORD_SIZE_THUMB * 2; return WORD_SIZE_THUMB * 2;
} else { } 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); be->printf(be, "%04X \t%s\n", instruction, disassembly);
return WORD_SIZE_THUMB; return WORD_SIZE_THUMB;
} }

View File

@ -467,6 +467,7 @@ static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatc
static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) { static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMDebugger* debugger = (struct ARMDebugger*) d;
struct ARMCore* cpu = debugger->cpu; struct ARMCore* cpu = debugger->cpu;
struct mCore* core = d->p->core;
char disassembly[64]; char disassembly[64];
@ -475,17 +476,17 @@ static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* len
if (cpu->executionMode == MODE_ARM) { if (cpu->executionMode == MODE_ARM) {
uint32_t instruction = cpu->prefetch[0]; uint32_t instruction = cpu->prefetch[0];
sprintf(disassembly, "%08X: ", instruction); 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 { } else {
uint16_t instruction = cpu->prefetch[0]; uint16_t instruction = cpu->prefetch[0];
ARMDecodeThumb(instruction, &info); ARMDecodeThumb(instruction, &info);
if (isWideInstruction) { if (isWideInstruction) {
uint16_t instruction2 = cpu->prefetch[1]; uint16_t instruction2 = cpu->prefetch[1];
sprintf(disassembly, "%04X%04X: ", instruction, instruction2); 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 { } else {
sprintf(disassembly, " %04X: ", instruction); 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: "));
} }
} }

View File

@ -6,6 +6,7 @@
#include <mgba/internal/arm/decoder.h> #include <mgba/internal/arm/decoder.h>
#include <mgba/internal/arm/decoder-inlines.h> #include <mgba/internal/arm/decoder-inlines.h>
#include <mgba/internal/debugger/symbols.h>
#include <mgba-util/string.h> #include <mgba-util/string.h>
#define ADVANCE(AMOUNT) \ #define ADVANCE(AMOUNT) \
@ -20,8 +21,8 @@
static int _decodeRegister(int reg, char* buffer, int blen); static int _decodeRegister(int reg, char* buffer, int blen);
static int _decodeRegisterList(int list, char* buffer, int blen); static int _decodeRegisterList(int list, char* buffer, int blen);
static int _decodePSR(int bits, 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 _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen);
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);
static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen); static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen);
static const char* _armConditions[] = { static const char* _armConditions[] = {
@ -141,23 +142,66 @@ static int _decodePSR(int psrBits, char* buffer, int blen) {
return total; return total;
} }
static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) { static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen) {
return snprintf(buffer, blen, "$%08X", address + pc); 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) { if (blen <= 1) {
return 0; return 0;
} }
int total = 0; int total = 0;
strlcpy(buffer, "[", blen); bool elideClose = false;
ADVANCE(1);
int written; int written;
if (memory.format & ARM_MEMORY_REGISTER_BASE) { if (memory.format & ARM_MEMORY_REGISTER_BASE) {
if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) { 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); uint32_t addrBase = memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate;
ADVANCE(written); 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 { } else {
strlcpy(buffer, "[", blen);
ADVANCE(1);
written = _decodeRegister(memory.baseReg, buffer, blen); written = _decodeRegister(memory.baseReg, buffer, blen);
ADVANCE(written); ADVANCE(written);
if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) { 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); ADVANCE(2);
} }
} }
} else {
strlcpy(buffer, "[", blen);
ADVANCE(1);
} }
if (memory.format & ARM_MEMORY_POST_INCREMENT) { if (memory.format & ARM_MEMORY_POST_INCREMENT) {
strlcpy(buffer, "], ", blen); strlcpy(buffer, "], ", blen);
ADVANCE(3); ADVANCE(3);
elideClose = true;
} }
if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) { if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) { if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
@ -191,7 +239,7 @@ static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, in
ADVANCE(written); ADVANCE(written);
} }
if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) { if (!elideClose) {
strlcpy(buffer, "]", blen); strlcpy(buffer, "]", blen);
ADVANCE(1); 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]; const char* mnemonic = _armMnemonicStrings[info->mnemonic];
int written; int written;
int total = 0; 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_B:
case ARM_MN_BL: case ARM_MN_BL:
if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) { 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); ADVANCE(written);
} }
break; break;
@ -403,7 +451,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i
written = snprintf(buffer, blen, "#%i", info->op1.immediate); written = snprintf(buffer, blen, "#%i", info->op1.immediate);
ADVANCE(written); ADVANCE(written);
} else if (info->operandFormat & ARM_OPERAND_MEMORY_1) { } 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); ADVANCE(written);
} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) { } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
written = _decodeRegister(info->op1.reg, buffer, blen); 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); written = snprintf(buffer, blen, "#%i", info->op2.immediate);
ADVANCE(written); ADVANCE(written);
} else if (info->operandFormat & ARM_OPERAND_MEMORY_2) { } 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); ADVANCE(written);
} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) { } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
written = _decodeRegister(info->op2.reg, buffer, blen); 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); written = snprintf(buffer, blen, "#%i", info->op3.immediate);
ADVANCE(written); ADVANCE(written);
} else if (info->operandFormat & ARM_OPERAND_MEMORY_3) { } 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); ADVANCE(written);
} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) { } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
written = _decodeRegister(info->op3.reg, buffer, blen); 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); written = snprintf(buffer, blen, "#%i", info->op4.immediate);
ADVANCE(written); ADVANCE(written);
} else if (info->operandFormat & ARM_OPERAND_MEMORY_4) { } 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); ADVANCE(written);
} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) { } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
written = _decodeRegister(info->op4.reg, buffer, blen); written = _decodeRegister(info->op4.reg, buffer, blen);