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
- 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

View File

@ -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

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) {
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;
}

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) {
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: "));
}
}

View File

@ -6,6 +6,7 @@
#include <mgba/internal/arm/decoder.h>
#include <mgba/internal/arm/decoder-inlines.h>
#include <mgba/internal/debugger/symbols.h>
#include <mgba-util/string.h>
#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);