mirror of https://github.com/mgba-emu/mgba.git
Debugger: parse memory operations correctly
This commit is contained in:
parent
07667955f6
commit
daf2193894
|
@ -217,6 +217,7 @@ 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);
|
||||
uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <mgba/internal/debugger/stack-trace.h>
|
||||
#include <mgba-util/math.h>
|
||||
|
||||
#define FRAME_PRIV(FRAME) ((struct ARMRegisterFile*) FRAME->regs)->cpsr.priv
|
||||
|
||||
DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
|
||||
|
||||
static bool ARMDecodeCombined(struct ARMCore* cpu, struct ARMInstructionInfo* info) {
|
||||
|
@ -29,16 +31,6 @@ static bool ARMDecodeCombined(struct ARMCore* cpu, struct ARMInstructionInfo* in
|
|||
}
|
||||
}
|
||||
|
||||
static inline int ARMGetStack(struct ARMRegisterFile* regs) {
|
||||
if (!regs) {
|
||||
return MODE_USER;
|
||||
}
|
||||
if (regs->cpsr.priv == MODE_SYSTEM) {
|
||||
return MODE_USER;
|
||||
}
|
||||
return regs->cpsr.priv;
|
||||
}
|
||||
|
||||
static bool ARMDebuggerUpdateStackTraceInternal(struct mDebuggerPlatform* d, uint32_t pc) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||
struct ARMCore* cpu = debugger->cpu;
|
||||
|
@ -46,8 +38,8 @@ static bool ARMDebuggerUpdateStackTraceInternal(struct mDebuggerPlatform* d, uin
|
|||
struct mStackTrace* stack = &d->p->stackTrace;
|
||||
|
||||
struct mStackFrame* frame = mStackTraceGetFrame(stack, 0);
|
||||
int currentStack = ARMGetStack(&cpu->regs);
|
||||
if (frame && frame->frameBaseAddress < (uint32_t) cpu->gprs[ARM_SP] && currentStack == ARMGetStack(frame->regs)) {
|
||||
enum RegisterBank currentStack = ARMSelectBank(cpu->cpsr.priv);
|
||||
if (frame && frame->frameBaseAddress < (uint32_t) cpu->gprs[ARM_SP] && currentStack == ARMSelectBank(FRAME_PRIV(frame))) {
|
||||
// The stack frame has been popped off the stack. This means the function
|
||||
// has been returned from, or that the stack pointer has been otherwise
|
||||
// manipulated. Either way, the function is done executing.
|
||||
|
@ -56,7 +48,7 @@ static bool ARMDebuggerUpdateStackTraceInternal(struct mDebuggerPlatform* d, uin
|
|||
shouldBreak = shouldBreak || frame->breakWhenFinished;
|
||||
mStackTracePop(stack);
|
||||
frame = mStackTraceGetFrame(stack, 0);
|
||||
} while (frame && frame->frameBaseAddress < (uint32_t) cpu->gprs[ARM_SP] && currentStack == ARMGetStack(frame->regs));
|
||||
} while (frame && frame->frameBaseAddress < (uint32_t) cpu->gprs[ARM_SP] && currentStack == ARMSelectBank(FRAME_PRIV(frame)));
|
||||
if (shouldBreak) {
|
||||
struct mDebuggerEntryInfo debuggerInfo = {
|
||||
.address = pc,
|
||||
|
@ -95,7 +87,7 @@ static bool ARMDebuggerUpdateStackTraceInternal(struct mDebuggerPlatform* d, uin
|
|||
return false;
|
||||
}
|
||||
|
||||
bool isCall = (info.branchType & ARM_BRANCH_LINKED);
|
||||
bool isCall = info.branchType & ARM_BRANCH_LINKED;
|
||||
uint32_t destAddress;
|
||||
|
||||
if (interrupt && !isCall) {
|
||||
|
@ -126,8 +118,9 @@ static bool ARMDebuggerUpdateStackTraceInternal(struct mDebuggerPlatform* d, uin
|
|||
bool isBranch = ARMInstructionIsBranch(info.mnemonic);
|
||||
int reg = (isBranch ? info.op1.reg : info.op2.reg);
|
||||
destAddress = cpu->gprs[reg];
|
||||
if ((info.operandFormat & ARM_OPERAND_MEMORY_2) && (info.branchType & ARM_BRANCH_INDIRECT)) {
|
||||
destAddress = cpu->memory.load32(cpu, destAddress, NULL);
|
||||
if (!isBranch && (info.branchType & ARM_BRANCH_INDIRECT) && info.op1.reg == ARM_PC && info.operandFormat & ARM_OPERAND_MEMORY_2) {
|
||||
uint32_t ptrAddress = ARMResolveMemoryAccess(&info, &cpu->regs, pc);
|
||||
destAddress = cpu->memory.load32(cpu, ptrAddress, NULL);
|
||||
}
|
||||
if (isBranch || (info.op1.reg == ARM_PC && !isMovPcLr)) {
|
||||
// ARMv4 doesn't have the BLX opcode, so it uses an assignment to LR before a BX for that purpose.
|
||||
|
@ -166,7 +159,7 @@ static bool ARMDebuggerUpdateStackTraceInternal(struct mDebuggerPlatform* d, uin
|
|||
return false;
|
||||
}
|
||||
} else if (!interrupt) {
|
||||
if (frame && currentStack == ARMGetStack(frame->regs)) {
|
||||
if (frame && currentStack == ARMSelectBank(FRAME_PRIV(frame))) {
|
||||
mStackTracePop(stack);
|
||||
}
|
||||
if (!(debugger->stackTraceMode & STACK_TRACE_BREAK_ON_RETURN)) {
|
||||
|
|
|
@ -488,3 +488,46 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i
|
|||
buffer[blen - 1] = '\0';
|
||||
return total;
|
||||
}
|
||||
|
||||
uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc) {
|
||||
uint32_t address = 0;
|
||||
int32_t offset = 0;
|
||||
if (info->memory.format & ARM_MEMORY_REGISTER_BASE) {
|
||||
if (info->memory.baseReg == ARM_PC && info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
|
||||
address = pc;
|
||||
} else {
|
||||
address = regs->gprs[info->memory.baseReg];
|
||||
}
|
||||
}
|
||||
if (info->memory.format & ARM_MEMORY_POST_INCREMENT) {
|
||||
return address;
|
||||
}
|
||||
if (info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
|
||||
offset = info->memory.offset.immediate;
|
||||
} else if (info->memory.format & ARM_MEMORY_REGISTER_OFFSET) {
|
||||
offset = info->memory.offset.reg == ARM_PC ? pc : regs->gprs[info->memory.offset.reg];
|
||||
}
|
||||
if (info->memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
|
||||
uint8_t shiftSize = info->memory.offset.shifterImm;
|
||||
switch (info->memory.offset.shifterOp) {
|
||||
case ARM_SHIFT_LSL:
|
||||
offset <<= shiftSize;
|
||||
break;
|
||||
case ARM_SHIFT_LSR:
|
||||
offset = ((uint32_t) offset) >> shiftSize;
|
||||
break;
|
||||
case ARM_SHIFT_ASR:
|
||||
offset >>= shiftSize;
|
||||
break;
|
||||
case ARM_SHIFT_ROR:
|
||||
offset = ROR(offset, shiftSize);
|
||||
break;
|
||||
case ARM_SHIFT_RRX:
|
||||
offset = (regs->cpsr.c << 31) | ((uint32_t) offset >> 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
return address + (info->memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -offset : offset);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue