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