Debugger: Merge Thumb BL instructions when disassembling (fixes #133)
Jeffrey Pfau jeffrey@endrift.com
Sun, 18 Jan 2015 13:28:58 -0800
5 files changed,
66 insertions(+),
15 deletions(-)
M
CHANGES
→
CHANGES
@@ -78,6 +78,7 @@ - Debugger: Watchpoints now work on STM/LDM instructions
- GBA: Improve accuracy of event timing - Debugger: Clean up GDB stub network interfacing - Debugger: Simplify debugger state machine to play nicer with the GBA thread loop + - Debugger: Merge Thumb BL instructions when disassembling 0.1.0: (2014-12-13) - Initial release
M
src/arm/decoder-thumb.c
→
src/arm/decoder-thumb.c
@@ -290,14 +290,21 @@ info->op1.immediate = (((int32_t) immediate) >> 4);
info->operandFormat = ARM_OPERAND_IMMEDIATE_1; info->branchType = ARM_BRANCH;) -DEFINE_THUMB_DECODER(BL1, BLH, +DEFINE_THUMB_DECODER(BL1, BL, int16_t immediate = (opcode & 0x07FF) << 5; - info->op1.immediate = (((int32_t) immediate) << 7); - info->operandFormat = ARM_OPERAND_IMMEDIATE_1;) + info->op1.reg = ARM_LR; + info->op2.reg = ARM_PC; + info->op3.immediate = (((int32_t) immediate) << 7); + info->operandFormat = ARM_OPERAND_REGISTER_1 | ARM_OPERAND_AFFECTED_1 | + ARM_OPERAND_REGISTER_2 | ARM_OPERAND_AFFECTED_2 | + ARM_OPERAND_IMMEDIATE_3;) DEFINE_THUMB_DECODER(BL2, BL, - info->op1.immediate = (opcode & 0x07FF) << 1; - info->operandFormat = ARM_OPERAND_IMMEDIATE_1; + info->op1.reg = ARM_PC; + info->op2.reg = ARM_LR; + info->op3.immediate = (opcode & 0x07FF) << 1; + info->operandFormat = ARM_OPERAND_REGISTER_1 | ARM_OPERAND_AFFECTED_1 | + ARM_OPERAND_REGISTER_2 | ARM_OPERAND_IMMEDIATE_3; info->branchType = ARM_BRANCH_LINKED;) DEFINE_THUMB_DECODER(BX, BX,@@ -332,3 +339,33 @@ info->cCycles = 0;
ThumbDecoder decoder = _thumbDecoderTable[opcode >> 6]; decoder(opcode, info); } + +bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2, struct ARMInstructionInfo* out) { + if (info1->execMode != MODE_THUMB || info1->mnemonic != ARM_MN_BL) { + return false; + } + if (info2->execMode != MODE_THUMB || info2->mnemonic != ARM_MN_BL) { + return false; + } + if (info1->op1.reg != ARM_LR || info1->op2.reg != ARM_PC) { + return false; + } + if (info2->op1.reg != ARM_PC || info2->op2.reg != ARM_LR) { + return false; + } + out->op1.immediate = info1->op3.immediate | info2->op3.immediate; + out->operandFormat = ARM_OPERAND_IMMEDIATE_1; + out->execMode = MODE_THUMB; + out->mnemonic = ARM_MN_BL; + out->branchType = ARM_BRANCH_LINKED; + out->traps = 0; + out->affectsCPSR = 0; + out->condition = ARM_CONDITION_AL; + out->sDataCycles = 0; + out->nDataCycles = 0; + out->sInstructionCycles = 2; + out->nInstructionCycles = 0; + out->iCycles = 0; + out->cCycles = 0; + return true; +}
M
src/arm/decoder.c
→
src/arm/decoder.c
@@ -223,7 +223,6 @@ "b",
"bic", "bkpt", "bl", - "blh", "bx", "cmn", "cmp",@@ -355,8 +354,11 @@ ADVANCE(1);
} break; case ARM_MN_B: - written = _decodePCRelative(info->op1.immediate, pc, buffer, blen); - ADVANCE(written); + case ARM_MN_BL: + if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) { + written = _decodePCRelative(info->op1.immediate, pc, buffer, blen); + ADVANCE(written); + } break; default: if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
M
src/arm/decoder.h
→
src/arm/decoder.h
@@ -138,7 +138,6 @@ ARM_MN_B,
ARM_MN_BIC, ARM_MN_BKPT, ARM_MN_BL, - ARM_MN_BLH, ARM_MN_BX, ARM_MN_CMN, ARM_MN_CMP,@@ -203,6 +202,7 @@ };
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); #endif
M
src/debugger/cli-debugger.c
→
src/debugger/cli-debugger.c
@@ -43,7 +43,7 @@ static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*);
static void _breakIntoDefault(int signal); static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode); -static void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode); +static uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode); static struct CLIDebuggerCommandSummary _debuggerCommands[] = { { "b", _setBreakpoint, CLIDVParse, "Set a breakpoint" },@@ -172,8 +172,7 @@ }
int i; for (i = 0; i < size; ++i) { - _printLine(debugger, address, mode); - address += wordSize; + address += _printLine(debugger, address, mode);; } }@@ -238,7 +237,7 @@ }
} } -static inline void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) { +static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) { char disassembly[48]; struct ARMInstructionInfo info; printf("%08X: ", address);@@ -247,11 +246,23 @@ uint32_t instruction = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
ARMDecodeARM(instruction, &info); ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly)); printf("%08X\t%s\n", instruction, disassembly); + return WORD_SIZE_ARM; } else { + struct ARMInstructionInfo info2; + struct ARMInstructionInfo combined; uint16_t instruction = debugger->d.cpu->memory.load16(debugger->d.cpu, address, 0); + uint16_t instruction2 = debugger->d.cpu->memory.load16(debugger->d.cpu, address + WORD_SIZE_THUMB, 0); ARMDecodeThumb(instruction, &info); - ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); - printf("%04X\t%s\n", instruction, disassembly); + ARMDecodeThumb(instruction2, &info2); + if (ARMDecodeThumbCombine(&info, &info2, &combined)) { + ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); + printf("%04X %04X\t%s\n", instruction, instruction2, disassembly); + return WORD_SIZE_THUMB * 2; + } else { + ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); + printf("%04X \t%s\n", instruction, disassembly); + return WORD_SIZE_THUMB; + } } }