all repos — mgba @ 510a539a504ea914d7ea6f30ece1e15d11c02b39

mGBA Game Boy Advance Emulator

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, &regStringLen);
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}