all repos — mgba @ 738b3dc44e1d8f7eb3179b0b07c85bae7dc4123b

mGBA Game Boy Advance Emulator

src/debugger/debugger.c (view raw)

  1#include "debugger.h"
  2
  3#include "arm.h"
  4
  5#include <signal.h>
  6#include <stdio.h>
  7#include <stdarg.h>
  8#include <stdlib.h>
  9#include <string.h>
 10#include <unistd.h>
 11#include "linenoise.h"
 12
 13struct DebugVector {
 14	struct DebugVector* next;
 15	enum DVType {
 16		ERROR_TYPE,
 17		INT_TYPE,
 18		CHAR_TYPE
 19	} type;
 20	union {
 21		int32_t intValue;
 22		const char* charValue;
 23	};
 24};
 25
 26struct DebugBreakpoint {
 27	struct DebugBreakpoint* next;
 28	int32_t address;
 29};
 30
 31static const char* ERROR_MISSING_ARGS = "Arguments missing";
 32
 33static struct ARMDebugger* _activeDebugger;
 34
 35typedef void (DebuggerComamnd)(struct ARMDebugger*, struct DebugVector*);
 36
 37static void _breakInto(struct ARMDebugger*, struct DebugVector*);
 38static void _continue(struct ARMDebugger*, struct DebugVector*);
 39static void _next(struct ARMDebugger*, struct DebugVector*);
 40static void _print(struct ARMDebugger*, struct DebugVector*);
 41static void _printHex(struct ARMDebugger*, struct DebugVector*);
 42static void _printStatus(struct ARMDebugger*, struct DebugVector*);
 43static void _quit(struct ARMDebugger*, struct DebugVector*);
 44static void _readByte(struct ARMDebugger*, struct DebugVector*);
 45static void _readHalfword(struct ARMDebugger*, struct DebugVector*);
 46static void _readWord(struct ARMDebugger*, struct DebugVector*);
 47static void _setBreakpoint(struct ARMDebugger*, struct DebugVector*);
 48
 49static void _breakIntoDefault(int signal);
 50
 51struct {
 52	const char* name;
 53	DebuggerComamnd* command;
 54} debuggerCommands[] = {
 55	{ "b", _setBreakpoint },
 56	{ "break", _setBreakpoint },
 57	{ "c", _continue },
 58	{ "continue", _continue },
 59	{ "i", _printStatus },
 60	{ "info", _printStatus },
 61	{ "n", _next },
 62	{ "p", _print },
 63	{ "print", _print },
 64	{ "p/x", _printHex },
 65	{ "print/x", _printHex },
 66	{ "q", _quit },
 67	{ "quit", _quit },
 68	{ "rb", _readByte },
 69	{ "rh", _readHalfword },
 70	{ "rw", _readWord },
 71	{ "status", _printStatus },
 72	{ "x", _breakInto },
 73	{ 0, 0 }
 74};
 75
 76static inline void _printPSR(union PSR psr) {
 77	printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed,
 78		psr.n ? 'N' : '-',
 79		psr.z ? 'Z' : '-',
 80		psr.c ? 'C' : '-',
 81		psr.v ? 'V' : '-',
 82		psr.i ? 'I' : '-',
 83		psr.f ? 'F' : '-',
 84		psr.t ? 'T' : '-');
 85}
 86
 87static void _handleDeath(int sig) {
 88	(void)(sig);
 89	printf("No debugger attached!\n");
 90}
 91
 92static void _breakInto(struct ARMDebugger* debugger, struct DebugVector* dv) {
 93	(void)(debugger);
 94	(void)(dv);
 95	sig_t oldSignal = signal(SIGTRAP, _handleDeath);
 96	kill(getpid(), SIGTRAP);
 97	signal(SIGTRAP, oldSignal);
 98}
 99
100static void _continue(struct ARMDebugger* debugger, struct DebugVector* dv) {
101	(void)(dv);
102	debugger->state = DEBUGGER_RUNNING;
103}
104
105static void _next(struct ARMDebugger* debugger, struct DebugVector* dv) {
106	(void)(dv);
107	ARMRun(debugger->cpu);
108	_printStatus(debugger, 0);
109}
110
111static void _print(struct ARMDebugger* debugger, struct DebugVector* dv) {
112	(void)(debugger);
113	for ( ; dv; dv = dv->next) {
114		printf(" %u", dv->intValue);
115	}
116	printf("\n");
117}
118
119static void _printHex(struct ARMDebugger* debugger, struct DebugVector* dv) {
120	(void)(debugger);
121	for ( ; dv; dv = dv->next) {
122		printf(" 0x%08X", dv->intValue);
123	}
124	printf("\n");
125}
126
127static inline void _printLine(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
128	// TODO: write a disassembler
129	if (mode == MODE_ARM) {
130		uint32_t instruction = debugger->cpu->memory->load32(debugger->cpu->memory, address);
131		printf("%08X\n", instruction);
132	} else {
133		uint16_t instruction = debugger->cpu->memory->loadU16(debugger->cpu->memory, address);
134		printf("%04X\n", instruction);
135	}
136}
137
138static void _printStatus(struct ARMDebugger* debugger, struct DebugVector* dv) {
139	(void)(dv);
140	int r;
141	for (r = 0; r < 4; ++r) {
142		printf("%08X %08X %08X %08X\n",
143			debugger->cpu->gprs[r << 2],
144			debugger->cpu->gprs[(r << 2) + 1],
145			debugger->cpu->gprs[(r << 2) + 2],
146			debugger->cpu->gprs[(r << 2) + 3]);
147	}
148	_printPSR(debugger->cpu->cpsr);
149	int instructionLength;
150	enum ExecutionMode mode = debugger->cpu->cpsr.t;
151	if (mode == MODE_ARM) {
152		instructionLength = WORD_SIZE_ARM;
153	} else {
154		instructionLength = WORD_SIZE_THUMB;
155	}
156	_printLine(debugger, debugger->cpu->gprs[ARM_PC] - instructionLength, mode);
157}
158
159static void _quit(struct ARMDebugger* debugger, struct DebugVector* dv) {
160	(void)(dv);
161	debugger->state = DEBUGGER_EXITING;
162}
163
164static void _readByte(struct ARMDebugger* debugger, struct DebugVector* dv) {
165	if (!dv || dv->type != INT_TYPE) {
166		printf("%s\n", ERROR_MISSING_ARGS);
167		return;
168	}
169	uint32_t address = dv->intValue;
170	uint8_t value = debugger->cpu->memory->loadU8(debugger->cpu->memory, address);
171	printf(" 0x%02X\n", value);
172}
173
174static void _readHalfword(struct ARMDebugger* debugger, struct DebugVector* dv) {
175	if (!dv || dv->type != INT_TYPE) {
176		printf("%s\n", ERROR_MISSING_ARGS);
177		return;
178	}
179	uint32_t address = dv->intValue;
180	uint16_t value = debugger->cpu->memory->loadU16(debugger->cpu->memory, address);
181	printf(" 0x%04X\n", value);
182}
183
184static void _readWord(struct ARMDebugger* debugger, struct DebugVector* dv) {
185	if (!dv || dv->type != INT_TYPE) {
186		printf("%s\n", ERROR_MISSING_ARGS);
187		return;
188	}
189	uint32_t address = dv->intValue;
190	uint32_t value = debugger->cpu->memory->load32(debugger->cpu->memory, address);
191	printf(" 0x%08X\n", value);
192}
193
194static void _setBreakpoint(struct ARMDebugger* debugger, struct DebugVector* dv) {
195	if (!dv || dv->type != INT_TYPE) {
196		printf("%s\n", ERROR_MISSING_ARGS);
197		return;
198	}
199	uint32_t address = dv->intValue;
200	struct DebugBreakpoint* breakpoint = malloc(sizeof(struct DebugBreakpoint));
201	breakpoint->address = address;
202	breakpoint->next = debugger->breakpoints;
203	debugger->breakpoints = breakpoint;
204}
205
206static void _checkBreakpoints(struct ARMDebugger* debugger) {
207	struct DebugBreakpoint* breakpoint;
208	int instructionLength;
209	enum ExecutionMode mode = debugger->cpu->cpsr.t;
210	if (mode == MODE_ARM) {
211		instructionLength = WORD_SIZE_ARM;
212	} else {
213		instructionLength = WORD_SIZE_THUMB;
214	}
215	for (breakpoint = debugger->breakpoints; breakpoint; breakpoint = breakpoint->next) {
216		if (breakpoint->address + instructionLength == debugger->cpu->gprs[ARM_PC]) {
217			debugger->state = DEBUGGER_PAUSED;
218			printf("Hit breakpoint\n");
219			break;
220		}
221	}
222}
223
224static void _breakIntoDefault(int signal) {
225	(void)(signal);
226	_activeDebugger->state = DEBUGGER_PAUSED;
227}
228
229enum _DVParseState {
230	PARSE_ERROR = -1,
231	PARSE_ROOT = 0,
232	PARSE_EXPECT_REGISTER,
233	PARSE_EXPECT_REGISTER_2,
234	PARSE_EXPECT_LR,
235	PARSE_EXPECT_PC,
236	PARSE_EXPECT_SP,
237	PARSE_EXPECT_DECIMAL,
238	PARSE_EXPECT_HEX,
239	PARSE_EXPECT_PREFIX,
240	PARSE_EXPECT_SUFFIX,
241};
242
243static struct DebugVector* _DVParse(struct ARMDebugger* debugger, const char* string) {
244	if (!string || !string[0]) {
245		return 0;
246	}
247
248	enum _DVParseState state = PARSE_ROOT;
249	struct DebugVector dvTemp = { .type = INT_TYPE };
250	uint32_t current = 0;
251
252	while (string[0] && string[0] != ' ' && state != PARSE_ERROR) {
253		char token = string[0];
254		++string;
255		switch (state) {
256		case PARSE_ROOT:
257			switch (token) {
258			case 'r':
259				state = PARSE_EXPECT_REGISTER;
260				break;
261			case 'p':
262				state = PARSE_EXPECT_PC;
263				break;
264			case 's':
265				state = PARSE_EXPECT_SP;
266				break;
267			case 'l':
268				state = PARSE_EXPECT_LR;
269				break;
270			case '1':
271			case '2':
272			case '3':
273			case '4':
274			case '5':
275			case '6':
276			case '7':
277			case '8':
278			case '9':
279				state = PARSE_EXPECT_DECIMAL;
280				current = token - '0';
281				break;
282			case '0':
283				state = PARSE_EXPECT_PREFIX;
284				break;
285			case '$':
286				state = PARSE_EXPECT_HEX;
287				current = 0;
288				break;
289			default:
290				state = PARSE_ERROR;
291				break;
292			};
293			break;
294		case PARSE_EXPECT_LR:
295			switch (token) {
296			case 'r':
297				current = debugger->cpu->gprs[ARM_LR];
298				state = PARSE_EXPECT_SUFFIX;
299				break;
300			default:
301				state = PARSE_ERROR;
302				break;
303			}
304			break;
305		case PARSE_EXPECT_PC:
306			switch (token) {
307			case 'c':
308				current = debugger->cpu->gprs[ARM_PC];
309				state = PARSE_EXPECT_SUFFIX;
310				break;
311			default:
312				state = PARSE_ERROR;
313				break;
314			}
315			break;
316		case PARSE_EXPECT_SP:
317			switch (token) {
318			case 'p':
319				current = debugger->cpu->gprs[ARM_SP];
320				state = PARSE_EXPECT_SUFFIX;
321				break;
322			default:
323				state = PARSE_ERROR;
324				break;
325			}
326			break;
327		case PARSE_EXPECT_REGISTER:
328			switch (token) {
329			case '0':
330			case '2':
331			case '3':
332			case '4':
333			case '5':
334			case '6':
335			case '7':
336			case '8':
337			case '9':
338				current = debugger->cpu->gprs[token - '0'];
339				state = PARSE_EXPECT_SUFFIX;
340				break;
341			case '1':
342				state = PARSE_EXPECT_REGISTER_2;
343				break;
344			default:
345				state = PARSE_ERROR;
346				break;
347			}
348			break;
349		case PARSE_EXPECT_REGISTER_2:
350			switch (token) {
351			case '0':
352			case '1':
353			case '2':
354			case '3':
355			case '4':
356			case '5':
357				current = debugger->cpu->gprs[token - '0' + 10];
358				state = PARSE_EXPECT_SUFFIX;
359				break;
360			default:
361				state = PARSE_ERROR;
362				break;
363			}
364			break;
365		case PARSE_EXPECT_DECIMAL:
366			switch (token) {
367			case '0':
368			case '1':
369			case '2':
370			case '3':
371			case '4':
372			case '5':
373			case '6':
374			case '7':
375			case '8':
376			case '9':
377				// TODO: handle overflow
378				current *= 10;
379				current += token - '0';
380				break;
381			default:
382				state = PARSE_ERROR;
383			}
384			break;
385		case PARSE_EXPECT_HEX:
386			switch (token) {
387			case '0':
388			case '1':
389			case '2':
390			case '3':
391			case '4':
392			case '5':
393			case '6':
394			case '7':
395			case '8':
396			case '9':
397				// TODO: handle overflow
398				current *= 16;
399				current += token - '0';
400				break;
401			case 'A':
402			case 'B':
403			case 'C':
404			case 'D':
405			case 'E':
406			case 'F':
407				// TODO: handle overflow
408				current *= 16;
409				current += token - 'A' + 10;
410				break;
411			case 'a':
412			case 'b':
413			case 'c':
414			case 'd':
415			case 'e':
416			case 'f':
417				// TODO: handle overflow
418				current *= 16;
419				current += token - 'a' + 10;
420				break;
421			default:
422				state = PARSE_ERROR;
423				break;
424			}
425			break;
426		case PARSE_EXPECT_PREFIX:
427			switch (token) {
428			case 'X':
429			case 'x':
430				current = 0;
431				state = PARSE_EXPECT_HEX;
432				break;
433			default:
434				state = PARSE_ERROR;
435				break;
436			}
437			break;
438		case PARSE_EXPECT_SUFFIX:
439			// TODO
440			state = PARSE_ERROR;
441			break;
442		case PARSE_ERROR:
443			// This shouldn't be reached
444			break;
445		}
446	}
447
448	struct DebugVector* dv = malloc(sizeof(struct DebugVector));
449	if (state == PARSE_ERROR) {
450		dv->type = ERROR_TYPE;
451		dv->next = 0;
452	} else {
453		dvTemp.intValue = current;
454		*dv = dvTemp;
455		if (string[0] == ' ') {
456			dv->next = _DVParse(debugger, string + 1);
457		}
458	}
459	return dv;
460}
461
462static void _DVFree(struct DebugVector* dv) {
463	struct DebugVector* next;
464	while (dv) {
465		next = dv->next;
466		free(dv);
467		dv = next;
468	}
469}
470
471static int _parse(struct ARMDebugger* debugger, const char* line) {
472	char* firstSpace = strchr(line, ' ');
473	size_t cmdLength;
474	struct DebugVector* dv = 0;
475	if (firstSpace) {
476		cmdLength = firstSpace - line;
477		dv = _DVParse(debugger, firstSpace + 1);
478		if (dv && dv->type == ERROR_TYPE) {
479			printf("Parse error\n");
480			_DVFree(dv);
481			return 0;
482		}
483	} else {
484		cmdLength = strlen(line);
485	}
486
487	int i;
488	const char* name;
489	for (i = 0; (name = debuggerCommands[i].name); ++i) {
490		if (strlen(name) != cmdLength) {
491			continue;
492		}
493		if (strncasecmp(name, line, cmdLength) == 0) {
494			debuggerCommands[i].command(debugger, dv);
495			_DVFree(dv);
496			return 1;
497		}
498	}
499	_DVFree(dv);
500	printf("Command not found\n");
501	return 0;
502}
503
504static void _commandLine(struct ARMDebugger* debugger) {
505	char* line;
506	_printStatus(debugger, 0);
507	while (debugger->state == DEBUGGER_PAUSED) {
508		line = linenoise("> ");
509		if (!line) {
510			debugger->state = DEBUGGER_EXITING;
511			return;
512		}
513		if (!line[0]) {
514			if (debugger->lastCommand) {
515				_parse(debugger, debugger->lastCommand);
516			}
517		} else {
518			linenoiseHistoryAdd(line);
519			if (_parse(debugger, line)) {
520				char* oldLine = debugger->lastCommand;
521				debugger->lastCommand = line;
522				free(oldLine);
523			} else {
524				free(line);
525			}
526		}
527	}
528}
529
530void ARMDebuggerInit(struct ARMDebugger* debugger, struct ARMCore* cpu) {
531	debugger->cpu = cpu;
532	debugger->state = DEBUGGER_PAUSED;
533	debugger->lastCommand = 0;
534	debugger->breakpoints = 0;
535	_activeDebugger = debugger;
536	signal(SIGINT, _breakIntoDefault);
537}
538
539void ARMDebuggerRun(struct ARMDebugger* debugger) {
540	while (debugger->state != DEBUGGER_EXITING) {
541		if (!debugger->breakpoints) {
542			while (debugger->state == DEBUGGER_RUNNING) {
543				ARMRun(debugger->cpu);
544			}
545		} else {
546			while (debugger->state == DEBUGGER_RUNNING) {
547				ARMRun(debugger->cpu);
548				_checkBreakpoints(debugger);
549			}
550		}
551		switch (debugger->state) {
552		case DEBUGGER_PAUSED:
553			_commandLine(debugger);
554			break;
555		case DEBUGGER_EXITING:
556			return;
557		default:
558			// Should never be reached
559			break;
560		}
561	}
562}
563
564void ARMDebuggerEnter(struct ARMDebugger* debugger) {
565	debugger->state = DEBUGGER_PAUSED;
566}