Debugger: Merge Thumb BL instructions when disassembling (fixes #133)

This commit is contained in:
Jeffrey Pfau 2015-01-18 13:28:58 -08:00
parent 99d75ee9ed
commit 6d43fb7890
5 changed files with 66 additions and 15 deletions

View File

@ -78,6 +78,7 @@ Misc:
- 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

View File

@ -290,14 +290,21 @@ DEFINE_THUMB_DECODER(B, B,
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 @@ void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info) {
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;
}

View File

@ -223,7 +223,6 @@ static const char* _armMnemonicStrings[] = {
"bic",
"bkpt",
"bl",
"blh",
"bx",
"cmn",
"cmp",
@ -355,8 +354,11 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i
}
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) {

View File

@ -138,7 +138,6 @@ enum ARMMnemonic {
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 @@ struct ARMInstructionInfo {
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

View File

@ -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 @@ static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector
int i;
for (i = 0; i < size; ++i) {
_printLine(debugger, address, mode);
address += wordSize;
address += _printLine(debugger, address, mode);;
}
}
@ -238,7 +237,7 @@ static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
}
}
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 @@ static inline void _printLine(struct CLIDebugger* debugger, uint32_t address, en
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;
}
}
}