src/arm/debugger/debugger.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/arm/debugger/debugger.h>
7
8#include <mgba/core/core.h>
9#include <mgba/internal/arm/arm.h>
10#include <mgba/internal/arm/decoder.h>
11#include <mgba/internal/arm/isa-inlines.h>
12#include <mgba/internal/arm/debugger/memory-debugger.h>
13#include <mgba/internal/debugger/parser.h>
14#include <mgba/internal/debugger/stack-trace.h>
15#include <mgba-util/math.h>
16
17DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
18
19static bool ARMDebuggerUpdateStackTraceInternal(struct mDebuggerPlatform* d, uint32_t pc) {
20 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
21 struct ARMCore* cpu = debugger->cpu;
22 struct ARMInstructionInfo info;
23 uint32_t instruction = cpu->prefetch[0];
24 struct mStackTrace* stack = &d->p->stackTrace;
25 bool interrupt = false;
26 ARMDecodeARM(instruction, &info);
27
28 if (_ARMModeHasSPSR(cpu->cpsr.priv)) {
29 struct mStackFrame* irqFrame = mStackTraceGetFrame(stack, 0);
30 // TODO: uint32_t ivtBase = ARMControlRegIsVE(cpu->cp15.r1.c0) ? 0xFFFF0000 : 0x00000000;
31 uint32_t ivtBase = 0x00000000;
32 if (ivtBase <= pc && pc < ivtBase + 0x20 && !(irqFrame && _ARMModeHasSPSR(((struct ARMRegisterFile*) irqFrame->regs)->cpsr.priv))) {
33 // TODO: Potential enhancement opportunity: add break-on-exception mode
34 irqFrame = mStackTracePush(stack, pc, pc, cpu->gprs[ARM_SP], &cpu->regs);
35 irqFrame->interrupt = true;
36 interrupt = true;
37 }
38 }
39
40 if (info.branchType == ARM_BRANCH_NONE && !interrupt) {
41 return false;
42 }
43
44 struct mStackFrame* frame = mStackTraceGetFrame(stack, 0);
45 bool isCall = (info.branchType & ARM_BRANCH_LINKED);
46 uint32_t destAddress;
47
48 if (frame && frame->finished) {
49 mStackTracePop(stack);
50 frame = NULL;
51 }
52
53 if (interrupt && info.branchType == ARM_BRANCH_NONE) {
54 // The stack frame was already pushed up above, so there's no
55 // action necessary here, but we still want to check for a
56 // breakpoint down below.
57 //
58 // The first instruction could possibly be a call, which would
59 // need ANOTHER stack frame, so only skip if it's not.
60 } else if (info.operandFormat & ARM_OPERAND_MEMORY_1) {
61 // This is most likely ldmia ..., {..., pc}, which is a function return.
62 // To find which stack slot holds the return address, count the number of set bits.
63 int regCount = popcount32(info.op1.immediate);
64 uint32_t baseAddress = cpu->gprs[info.memory.baseReg] + ((regCount - 1) << 2);
65 destAddress = cpu->memory.load32(cpu, baseAddress, NULL);
66 } else if (info.operandFormat & ARM_OPERAND_IMMEDIATE_1) {
67 if (!isCall) {
68 return false;
69 }
70 destAddress = info.op1.immediate + cpu->gprs[ARM_PC];
71 } else if (info.operandFormat & ARM_OPERAND_REGISTER_1) {
72 if (!isCall && info.op1.reg != ARM_LR && !(_ARMModeHasSPSR(cpu->cpsr.priv) && info.op1.reg == ARM_PC)) {
73 return false;
74 }
75 destAddress = cpu->gprs[info.op1.reg];
76 } else {
77 mLOG(DEBUGGER, ERROR, "Unknown branch operand in stack trace");
78 return false;
79 }
80
81 if (info.branchType & ARM_BRANCH_INDIRECT) {
82 destAddress = cpu->memory.load32(cpu, destAddress, NULL);
83 }
84
85 if (isCall) {
86 int instructionLength = _ARMInstructionLength(debugger->cpu);
87 frame = mStackTracePush(stack, pc, destAddress + instructionLength, cpu->gprs[ARM_SP], &cpu->regs);
88 if (!(debugger->stackTraceMode & STACK_TRACE_BREAK_ON_CALL)) {
89 return false;
90 }
91 } else {
92 frame = mStackTraceGetFrame(stack, 0);
93 if (!frame) {
94 return false;
95 }
96 if (!frame->breakWhenFinished && !(debugger->stackTraceMode & STACK_TRACE_BREAK_ON_RETURN)) {
97 mStackTracePop(stack);
98 return false;
99 }
100 frame->finished = true;
101 }
102 struct mDebuggerEntryInfo debuggerInfo = {
103 .address = pc,
104 .type.st.traceType = isCall ? STACK_TRACE_BREAK_ON_CALL : STACK_TRACE_BREAK_ON_RETURN,
105 .pointId = 0
106 };
107 mDebuggerEnter(d->p, DEBUGGER_ENTER_STACK, &debuggerInfo);
108 return true;
109}
110
111static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointList* breakpoints, uint32_t address) {
112 size_t i;
113 for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
114 if (ARMDebugBreakpointListGetPointer(breakpoints, i)->d.address == address) {
115 return ARMDebugBreakpointListGetPointer(breakpoints, i);
116 }
117 }
118 return 0;
119}
120
121static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) {
122 if (breakpoint->d.condition) {
123 parseFree(breakpoint->d.condition);
124 free(breakpoint->d.condition);
125 }
126}
127
128static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
129 if (watchpoint->condition) {
130 parseFree(watchpoint->condition);
131 free(watchpoint->condition);
132 }
133}
134
135static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
136 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
137 int instructionLength = _ARMInstructionLength(debugger->cpu);
138 uint32_t pc = debugger->cpu->gprs[ARM_PC] - instructionLength;
139 if (debugger->stackTraceMode != STACK_TRACE_DISABLED && ARMDebuggerUpdateStackTraceInternal(d, pc)) {
140 return;
141 }
142 struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, pc);
143 if (!breakpoint) {
144 return;
145 }
146 if (breakpoint->d.condition) {
147 int32_t value;
148 int segment;
149 if (!mDebuggerEvaluateParseTree(d->p, breakpoint->d.condition, &value, &segment) || !(value || segment >= 0)) {
150 return;
151 }
152 }
153 struct mDebuggerEntryInfo info = {
154 .address = breakpoint->d.address,
155 .type.bp.breakType = BREAKPOINT_HARDWARE,
156 .pointId = breakpoint->d.id
157 };
158 mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);
159}
160
161static void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform);
162static void ARMDebuggerDeinit(struct mDebuggerPlatform* platform);
163
164static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info);
165
166static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, const struct mBreakpoint*);
167static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, ssize_t id);
168static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform*, struct mBreakpointList*);
169static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, const struct mWatchpoint*);
170static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatchpointList*);
171static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
172static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
173static void ARMDebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length);
174static void ARMDebuggerFormatRegisters(struct ARMRegisterFile* regs, char* out, size_t* length);
175static void ARMDebuggerFrameFormatRegisters(struct mStackFrame* frame, char* out, size_t* length);
176static bool ARMDebuggerGetRegister(struct mDebuggerPlatform*, const char* name, int32_t* value);
177static bool ARMDebuggerSetRegister(struct mDebuggerPlatform*, const char* name, int32_t value);
178static uint32_t ARMDebuggerGetStackTraceMode(struct mDebuggerPlatform*);
179static void ARMDebuggerSetStackTraceMode(struct mDebuggerPlatform*, uint32_t);
180static bool ARMDebuggerUpdateStackTrace(struct mDebuggerPlatform* d);
181
182struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) {
183 struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct ARMDebugger));
184 platform->entered = ARMDebuggerEnter;
185 platform->init = ARMDebuggerInit;
186 platform->deinit = ARMDebuggerDeinit;
187 platform->setBreakpoint = ARMDebuggerSetBreakpoint;
188 platform->listBreakpoints = ARMDebuggerListBreakpoints;
189 platform->clearBreakpoint = ARMDebuggerClearBreakpoint;
190 platform->setWatchpoint = ARMDebuggerSetWatchpoint;
191 platform->listWatchpoints = ARMDebuggerListWatchpoints;
192 platform->checkBreakpoints = ARMDebuggerCheckBreakpoints;
193 platform->hasBreakpoints = ARMDebuggerHasBreakpoints;
194 platform->trace = ARMDebuggerTrace;
195 platform->getRegister = ARMDebuggerGetRegister;
196 platform->setRegister = ARMDebuggerSetRegister;
197 platform->getStackTraceMode = ARMDebuggerGetStackTraceMode;
198 platform->setStackTraceMode = ARMDebuggerSetStackTraceMode;
199 platform->updateStackTrace = ARMDebuggerUpdateStackTrace;
200 return platform;
201}
202
203void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
204 struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
205 debugger->cpu = cpu;
206 debugger->originalMemory = debugger->cpu->memory;
207 debugger->nextId = 1;
208 debugger->stackTraceMode = STACK_TRACE_DISABLED;
209 ARMDebugBreakpointListInit(&debugger->breakpoints, 0);
210 ARMDebugBreakpointListInit(&debugger->swBreakpoints, 0);
211 mWatchpointListInit(&debugger->watchpoints, 0);
212 struct mStackTrace* stack = &platform->p->stackTrace;
213 mStackTraceInit(stack, sizeof(struct ARMRegisterFile));
214 stack->formatRegisters = ARMDebuggerFrameFormatRegisters;
215}
216
217void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
218 struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
219 if (debugger->clearSoftwareBreakpoint) {
220 // Clear the stack backwards in case any overlap
221 size_t b;
222 for (b = ARMDebugBreakpointListSize(&debugger->swBreakpoints); b; --b) {
223 struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListGetPointer(&debugger->swBreakpoints, b - 1);
224 debugger->clearSoftwareBreakpoint(debugger, breakpoint);
225 }
226 }
227 ARMDebuggerRemoveMemoryShim(debugger);
228
229 size_t i;
230 for (i = 0; i < ARMDebugBreakpointListSize(&debugger->breakpoints); ++i) {
231 _destroyBreakpoint(ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i));
232 }
233 ARMDebugBreakpointListDeinit(&debugger->breakpoints);
234
235 for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) {
236 _destroyWatchpoint(mWatchpointListGetPointer(&debugger->watchpoints, i));
237 }
238 ARMDebugBreakpointListDeinit(&debugger->swBreakpoints);
239 mWatchpointListDeinit(&debugger->watchpoints);
240 mStackTraceDeinit(&platform->p->stackTrace);
241}
242
243static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
244 struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
245 struct ARMCore* cpu = debugger->cpu;
246 cpu->nextEvent = cpu->cycles;
247 if (reason == DEBUGGER_ENTER_BREAKPOINT) {
248 struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu));
249 if (breakpoint && breakpoint->d.type == BREAKPOINT_SOFTWARE) {
250 info->address = breakpoint->d.address;
251 info->pointId = breakpoint->d.id;
252 if (debugger->clearSoftwareBreakpoint) {
253 debugger->clearSoftwareBreakpoint(debugger, breakpoint);
254 }
255
256 ARMRunFake(cpu, breakpoint->sw.opcode);
257
258 if (debugger->setSoftwareBreakpoint) {
259 debugger->setSoftwareBreakpoint(debugger, breakpoint->d.address, breakpoint->sw.mode, &breakpoint->sw.opcode);
260 }
261 }
262 }
263 if (debugger->d.p->entered) {
264 debugger->d.p->entered(debugger->d.p, reason, info);
265 }
266}
267
268ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address, enum ExecutionMode mode) {
269 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
270 uint32_t opcode;
271 if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) {
272 return -1;
273 }
274
275 struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->swBreakpoints);
276 ssize_t id = debugger->nextId;
277 ++debugger->nextId;
278 breakpoint->d.id = id;
279 breakpoint->d.address = address & ~1; // Clear Thumb bit since it's not part of a valid address
280 breakpoint->d.segment = -1;
281 breakpoint->d.condition = NULL;
282 breakpoint->d.type = BREAKPOINT_SOFTWARE;
283 breakpoint->sw.opcode = opcode;
284 breakpoint->sw.mode = mode;
285
286 return id;
287}
288
289static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) {
290 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
291 struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints);
292 ssize_t id = debugger->nextId;
293 ++debugger->nextId;
294 breakpoint->d = *info;
295 breakpoint->d.address &= ~1; // Clear Thumb bit since it's not part of a valid address
296 breakpoint->d.id = id;
297 if (info->type == BREAKPOINT_SOFTWARE) {
298 // TODO
299 abort();
300 }
301 return id;
302}
303
304static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) {
305 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
306 size_t i;
307
308 struct ARMDebugBreakpointList* breakpoints = &debugger->breakpoints;
309 for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) {
310 if (ARMDebugBreakpointListGetPointer(breakpoints, i)->d.id == id) {
311 _destroyBreakpoint(ARMDebugBreakpointListGetPointer(breakpoints, i));
312 ARMDebugBreakpointListShift(breakpoints, i, 1);
313 return true;
314 }
315 }
316
317 struct ARMDebugBreakpointList* swBreakpoints = &debugger->swBreakpoints;
318 if (debugger->clearSoftwareBreakpoint) {
319 for (i = 0; i < ARMDebugBreakpointListSize(swBreakpoints); ++i) {
320 if (ARMDebugBreakpointListGetPointer(swBreakpoints, i)->d.id == id) {
321 debugger->clearSoftwareBreakpoint(debugger, ARMDebugBreakpointListGetPointer(swBreakpoints, i));
322 ARMDebugBreakpointListShift(swBreakpoints, i, 1);
323 return true;
324 }
325 }
326 }
327
328 struct mWatchpointList* watchpoints = &debugger->watchpoints;
329 for (i = 0; i < mWatchpointListSize(watchpoints); ++i) {
330 if (mWatchpointListGetPointer(watchpoints, i)->id == id) {
331 _destroyWatchpoint(mWatchpointListGetPointer(watchpoints, i));
332 mWatchpointListShift(watchpoints, i, 1);
333 if (!mWatchpointListSize(&debugger->watchpoints)) {
334 ARMDebuggerRemoveMemoryShim(debugger);
335 }
336 return true;
337 }
338 }
339 return false;
340}
341
342static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBreakpointList* list) {
343 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
344 mBreakpointListClear(list);
345 size_t i, s;
346 for (i = 0, s = 0; i < ARMDebugBreakpointListSize(&debugger->breakpoints) || s < ARMDebugBreakpointListSize(&debugger->swBreakpoints);) {
347 struct ARMDebugBreakpoint* hw = NULL;
348 struct ARMDebugBreakpoint* sw = NULL;
349 if (i < ARMDebugBreakpointListSize(&debugger->breakpoints)) {
350 hw = ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i);
351 }
352 if (s < ARMDebugBreakpointListSize(&debugger->swBreakpoints)) {
353 sw = ARMDebugBreakpointListGetPointer(&debugger->swBreakpoints, s);
354 }
355 struct mBreakpoint* b = mBreakpointListAppend(list);
356 if (hw && sw) {
357 if (hw->d.id < sw->d.id) {
358 *b = hw->d;
359 ++i;
360 } else {
361 *b = sw->d;
362 ++s;
363 }
364 } else if (hw) {
365 *b = hw->d;
366 ++i;
367 } else if (sw) {
368 *b = sw->d;
369 ++s;
370 } else {
371 abort(); // Should be unreachable
372 }
373 }
374}
375
376static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
377 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
378 return ARMDebugBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints) || debugger->stackTraceMode != STACK_TRACE_DISABLED;
379}
380
381static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) {
382 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
383 if (!mWatchpointListSize(&debugger->watchpoints)) {
384 ARMDebuggerInstallMemoryShim(debugger);
385 }
386 struct mWatchpoint* watchpoint = mWatchpointListAppend(&debugger->watchpoints);
387 ssize_t id = debugger->nextId;
388 ++debugger->nextId;
389 *watchpoint = *info;
390 watchpoint->id = id;
391 return id;
392}
393
394static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatchpointList* list) {
395 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
396 mWatchpointListClear(list);
397 mWatchpointListCopy(list, &debugger->watchpoints);
398}
399
400static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
401 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
402 struct ARMCore* cpu = debugger->cpu;
403
404 char disassembly[64];
405
406 struct ARMInstructionInfo info;
407 if (cpu->executionMode == MODE_ARM) {
408 uint32_t instruction = cpu->prefetch[0];
409 sprintf(disassembly, "%08X: ", instruction);
410 ARMDecodeARM(instruction, &info);
411 ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: "));
412 } else {
413 struct ARMInstructionInfo info2;
414 struct ARMInstructionInfo combined;
415 uint16_t instruction = cpu->prefetch[0];
416 uint16_t instruction2 = cpu->prefetch[1];
417 ARMDecodeThumb(instruction, &info);
418 ARMDecodeThumb(instruction2, &info2);
419 if (ARMDecodeThumbCombine(&info, &info2, &combined)) {
420 sprintf(disassembly, "%04X%04X: ", instruction, instruction2);
421 ARMDisassemble(&combined, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: "));
422 } else {
423 sprintf(disassembly, " %04X: ", instruction);
424 ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: "));
425 }
426 }
427
428 size_t regStringLen = *length;
429 ARMDebuggerFormatRegisters(&cpu->regs, out, ®StringLen);
430 regStringLen += snprintf(out + regStringLen, *length - regStringLen, " | %s", disassembly);
431 *length = regStringLen;
432}
433
434static void ARMDebuggerFormatRegisters(struct ARMRegisterFile* regs, char* out, size_t* length) {
435 *length = snprintf(out, *length, "%08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X cpsr: %08X",
436 regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3],
437 regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7],
438 regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11],
439 regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15],
440 regs->cpsr.packed);
441}
442
443static void ARMDebuggerFrameFormatRegisters(struct mStackFrame* frame, char* out, size_t* length) {
444 ARMDebuggerFormatRegisters(frame->regs, out, length);
445}
446
447bool ARMDebuggerGetRegister(struct mDebuggerPlatform* d, const char* name, int32_t* value) {
448 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
449 struct ARMCore* cpu = debugger->cpu;
450
451 if (strcmp(name, "sp") == 0) {
452 *value = cpu->gprs[ARM_SP];
453 return true;
454 }
455 if (strcmp(name, "lr") == 0) {
456 *value = cpu->gprs[ARM_LR];
457 return true;
458 }
459 if (strcmp(name, "pc") == 0) {
460 *value = cpu->gprs[ARM_PC];
461 return true;
462 }
463 if (strcmp(name, "cpsr") == 0) {
464 *value = cpu->cpsr.packed;
465 return true;
466 }
467 // TODO: test if mode has SPSR
468 if (strcmp(name, "spsr") == 0) {
469 *value = cpu->spsr.packed;
470 return true;
471 }
472 if (name[0] == 'r') {
473 char* end;
474 uint32_t reg = strtoul(&name[1], &end, 10);
475 if (reg <= ARM_PC) {
476 *value = cpu->gprs[reg];
477 return true;
478 }
479 }
480 return false;
481}
482
483bool ARMDebuggerSetRegister(struct mDebuggerPlatform* d, const char* name, int32_t value) {
484 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
485 struct ARMCore* cpu = debugger->cpu;
486
487 if (strcmp(name, "sp") == 0) {
488 cpu->gprs[ARM_SP] = value;
489 return true;
490 }
491 if (strcmp(name, "lr") == 0) {
492 cpu->gprs[ARM_LR] = value;
493 return true;
494 }
495 if (strcmp(name, "pc") == 0) {
496 cpu->gprs[ARM_PC] = value;
497 if (cpu->executionMode == MODE_ARM) {
498 ARMWritePC(cpu);
499 } else {
500 ThumbWritePC(cpu);
501 }
502 return true;
503 }
504 if (name[0] == 'r') {
505 char* end;
506 uint32_t reg = strtoul(&name[1], &end, 10);
507 if (reg > ARM_PC) {
508 return false;
509 }
510 cpu->gprs[reg] = value;
511 if (reg == ARM_PC) {
512 if (cpu->executionMode == MODE_ARM) {
513 ARMWritePC(cpu);
514 } else {
515 ThumbWritePC(cpu);
516 }
517 }
518 return true;
519 }
520 return false;
521}
522
523static uint32_t ARMDebuggerGetStackTraceMode(struct mDebuggerPlatform* d) {
524 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
525 return debugger->stackTraceMode;
526}
527
528static void ARMDebuggerSetStackTraceMode(struct mDebuggerPlatform* d, uint32_t mode) {
529 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
530 struct mStackTrace* stack = &d->p->stackTrace;
531 if (mode == STACK_TRACE_DISABLED && debugger->stackTraceMode != STACK_TRACE_DISABLED) {
532 mStackTraceClear(stack);
533 }
534 debugger->stackTraceMode = mode;
535}
536
537static bool ARMDebuggerUpdateStackTrace(struct mDebuggerPlatform* d) {
538 struct ARMDebugger* debugger = (struct ARMDebugger*) d;
539 int instructionLength = _ARMInstructionLength(debugger->cpu);
540 uint32_t pc = debugger->cpu->gprs[ARM_PC] - instructionLength;
541 if (debugger->stackTraceMode != STACK_TRACE_DISABLED) {
542 return ARMDebuggerUpdateStackTraceInternal(d, pc);
543 } else {
544 return false;
545 }
546}