all repos — mgba @ 0458184a5e2ab6a852525c894a3a7d6a08595764

mGBA Game Boy Advance Emulator

src/debugger/debugger.c (view raw)

  1#include "debugger.h"
  2
  3#include "memory-debugger.h"
  4
  5#include "arm.h"
  6
  7#include <signal.h>
  8#include <stdio.h>
  9#include <stdarg.h>
 10#include <stdlib.h>
 11#include <string.h>
 12#include <unistd.h>
 13
 14struct DebugVector {
 15	struct DebugVector* next;
 16	enum DVType {
 17		ERROR_TYPE,
 18		INT_TYPE,
 19		CHAR_TYPE
 20	} type;
 21	union {
 22		int32_t intValue;
 23		const char* charValue;
 24	};
 25};
 26
 27static const char* ERROR_MISSING_ARGS = "Arguments missing";
 28
 29static struct ARMDebugger* _activeDebugger;
 30
 31typedef void (DebuggerComamnd)(struct ARMDebugger*, struct DebugVector*);
 32
 33static void _breakInto(struct ARMDebugger*, struct DebugVector*);
 34static void _continue(struct ARMDebugger*, struct DebugVector*);
 35static void _next(struct ARMDebugger*, struct DebugVector*);
 36static void _print(struct ARMDebugger*, struct DebugVector*);
 37static void _printHex(struct ARMDebugger*, struct DebugVector*);
 38static void _printStatus(struct ARMDebugger*, struct DebugVector*);
 39static void _quit(struct ARMDebugger*, struct DebugVector*);
 40static void _readByte(struct ARMDebugger*, struct DebugVector*);
 41static void _readHalfword(struct ARMDebugger*, struct DebugVector*);
 42static void _readWord(struct ARMDebugger*, struct DebugVector*);
 43static void _setBreakpoint(struct ARMDebugger*, struct DebugVector*);
 44static void _setWatchpoint(struct ARMDebugger*, struct DebugVector*);
 45
 46static void _breakIntoDefault(int signal);
 47
 48static struct {
 49	const char* name;
 50	DebuggerComamnd* command;
 51} _debuggerCommands[] = {
 52	{ "b", _setBreakpoint },
 53	{ "break", _setBreakpoint },
 54	{ "c", _continue },
 55	{ "continue", _continue },
 56	{ "i", _printStatus },
 57	{ "info", _printStatus },
 58	{ "n", _next },
 59	{ "next", _next },
 60	{ "p", _print },
 61	{ "p/x", _printHex },
 62	{ "print", _print },
 63	{ "print/x", _printHex },
 64	{ "q", _quit },
 65	{ "quit", _quit },
 66	{ "rb", _readByte },
 67	{ "rh", _readHalfword },
 68	{ "rw", _readWord },
 69	{ "status", _printStatus },
 70	{ "w", _setWatchpoint },
 71	{ "watch", _setWatchpoint },
 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, 0);
131		printf("%08X\n", instruction);
132	} else {
133		uint16_t instruction = debugger->cpu->memory->loadU16(debugger->cpu->memory, address, 0);
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_SHUTDOWN;
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, 0);
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, 0);
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, 0);
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 _setWatchpoint(struct ARMDebugger* debugger, struct DebugVector* dv) {
207	if (!dv || dv->type != INT_TYPE) {
208		printf("%s\n", ERROR_MISSING_ARGS);
209		return;
210	}
211	uint32_t address = dv->intValue;
212	if (debugger->cpu->memory != &debugger->memoryShim.d) {
213		ARMDebuggerInstallMemoryShim(debugger);
214	}
215	struct DebugBreakpoint* watchpoint = malloc(sizeof(struct DebugBreakpoint));
216	watchpoint->address = address;
217	watchpoint->next = debugger->memoryShim.watchpoints;
218	debugger->memoryShim.watchpoints = watchpoint;
219}
220
221static void _checkBreakpoints(struct ARMDebugger* debugger) {
222	struct DebugBreakpoint* breakpoint;
223	int instructionLength;
224	enum ExecutionMode mode = debugger->cpu->cpsr.t;
225	if (mode == MODE_ARM) {
226		instructionLength = WORD_SIZE_ARM;
227	} else {
228		instructionLength = WORD_SIZE_THUMB;
229	}
230	for (breakpoint = debugger->breakpoints; breakpoint; breakpoint = breakpoint->next) {
231		if (breakpoint->address + instructionLength == debugger->cpu->gprs[ARM_PC]) {
232			debugger->state = DEBUGGER_PAUSED;
233			printf("Hit breakpoint\n");
234			break;
235		}
236	}
237}
238
239static void _breakIntoDefault(int signal) {
240	(void)(signal);
241	_activeDebugger->state = DEBUGGER_PAUSED;
242}
243
244enum _DVParseState {
245	PARSE_ERROR = -1,
246	PARSE_ROOT = 0,
247	PARSE_EXPECT_REGISTER,
248	PARSE_EXPECT_REGISTER_2,
249	PARSE_EXPECT_LR,
250	PARSE_EXPECT_PC,
251	PARSE_EXPECT_SP,
252	PARSE_EXPECT_DECIMAL,
253	PARSE_EXPECT_HEX,
254	PARSE_EXPECT_PREFIX,
255	PARSE_EXPECT_SUFFIX,
256};
257
258static struct DebugVector* _DVParse(struct ARMDebugger* debugger, const char* string, size_t length) {
259	if (!string || length < 1) {
260		return 0;
261	}
262
263	enum _DVParseState state = PARSE_ROOT;
264	struct DebugVector dvTemp = { .type = INT_TYPE };
265	uint32_t current = 0;
266
267	while (length > 0 && string[0] && string[0] != ' ' && state != PARSE_ERROR) {
268		char token = string[0];
269		++string;
270		--length;
271		switch (state) {
272		case PARSE_ROOT:
273			switch (token) {
274			case 'r':
275				state = PARSE_EXPECT_REGISTER;
276				break;
277			case 'p':
278				state = PARSE_EXPECT_PC;
279				break;
280			case 's':
281				state = PARSE_EXPECT_SP;
282				break;
283			case 'l':
284				state = PARSE_EXPECT_LR;
285				break;
286			case '1':
287			case '2':
288			case '3':
289			case '4':
290			case '5':
291			case '6':
292			case '7':
293			case '8':
294			case '9':
295				state = PARSE_EXPECT_DECIMAL;
296				current = token - '0';
297				break;
298			case '0':
299				state = PARSE_EXPECT_PREFIX;
300				break;
301			case '$':
302				state = PARSE_EXPECT_HEX;
303				current = 0;
304				break;
305			default:
306				state = PARSE_ERROR;
307				break;
308			};
309			break;
310		case PARSE_EXPECT_LR:
311			switch (token) {
312			case 'r':
313				current = debugger->cpu->gprs[ARM_LR];
314				state = PARSE_EXPECT_SUFFIX;
315				break;
316			default:
317				state = PARSE_ERROR;
318				break;
319			}
320			break;
321		case PARSE_EXPECT_PC:
322			switch (token) {
323			case 'c':
324				current = debugger->cpu->gprs[ARM_PC];
325				state = PARSE_EXPECT_SUFFIX;
326				break;
327			default:
328				state = PARSE_ERROR;
329				break;
330			}
331			break;
332		case PARSE_EXPECT_SP:
333			switch (token) {
334			case 'p':
335				current = debugger->cpu->gprs[ARM_SP];
336				state = PARSE_EXPECT_SUFFIX;
337				break;
338			default:
339				state = PARSE_ERROR;
340				break;
341			}
342			break;
343		case PARSE_EXPECT_REGISTER:
344			switch (token) {
345			case '0':
346			case '2':
347			case '3':
348			case '4':
349			case '5':
350			case '6':
351			case '7':
352			case '8':
353			case '9':
354				current = debugger->cpu->gprs[token - '0'];
355				state = PARSE_EXPECT_SUFFIX;
356				break;
357			case '1':
358				state = PARSE_EXPECT_REGISTER_2;
359				break;
360			default:
361				state = PARSE_ERROR;
362				break;
363			}
364			break;
365		case PARSE_EXPECT_REGISTER_2:
366			switch (token) {
367			case '0':
368			case '1':
369			case '2':
370			case '3':
371			case '4':
372			case '5':
373				current = debugger->cpu->gprs[token - '0' + 10];
374				state = PARSE_EXPECT_SUFFIX;
375				break;
376			default:
377				state = PARSE_ERROR;
378				break;
379			}
380			break;
381		case PARSE_EXPECT_DECIMAL:
382			switch (token) {
383			case '0':
384			case '1':
385			case '2':
386			case '3':
387			case '4':
388			case '5':
389			case '6':
390			case '7':
391			case '8':
392			case '9':
393				// TODO: handle overflow
394				current *= 10;
395				current += token - '0';
396				break;
397			default:
398				state = PARSE_ERROR;
399			}
400			break;
401		case PARSE_EXPECT_HEX:
402			switch (token) {
403			case '0':
404			case '1':
405			case '2':
406			case '3':
407			case '4':
408			case '5':
409			case '6':
410			case '7':
411			case '8':
412			case '9':
413				// TODO: handle overflow
414				current *= 16;
415				current += token - '0';
416				break;
417			case 'A':
418			case 'B':
419			case 'C':
420			case 'D':
421			case 'E':
422			case 'F':
423				// TODO: handle overflow
424				current *= 16;
425				current += token - 'A' + 10;
426				break;
427			case 'a':
428			case 'b':
429			case 'c':
430			case 'd':
431			case 'e':
432			case 'f':
433				// TODO: handle overflow
434				current *= 16;
435				current += token - 'a' + 10;
436				break;
437			default:
438				state = PARSE_ERROR;
439				break;
440			}
441			break;
442		case PARSE_EXPECT_PREFIX:
443			switch (token) {
444			case 'X':
445			case 'x':
446				current = 0;
447				state = PARSE_EXPECT_HEX;
448				break;
449			default:
450				state = PARSE_ERROR;
451				break;
452			}
453			break;
454		case PARSE_EXPECT_SUFFIX:
455			// TODO
456			state = PARSE_ERROR;
457			break;
458		case PARSE_ERROR:
459			// This shouldn't be reached
460			break;
461		}
462	}
463
464	struct DebugVector* dv = malloc(sizeof(struct DebugVector));
465	if (state == PARSE_ERROR) {
466		dv->type = ERROR_TYPE;
467		dv->next = 0;
468	} else {
469		dvTemp.intValue = current;
470		*dv = dvTemp;
471		if (string[0] == ' ') {
472			dv->next = _DVParse(debugger, string + 1, length - 1);
473		}
474	}
475	return dv;
476}
477
478static void _DVFree(struct DebugVector* dv) {
479	struct DebugVector* next;
480	while (dv) {
481		next = dv->next;
482		free(dv);
483		dv = next;
484	}
485}
486
487static int _parse(struct ARMDebugger* debugger, const char* line, size_t count) {
488	const char* firstSpace = strchr(line, ' ');
489	size_t cmdLength;
490	struct DebugVector* dv = 0;
491	if (firstSpace) {
492		cmdLength = firstSpace - line;
493		dv = _DVParse(debugger, firstSpace + 1, count - cmdLength - 1);
494		if (dv && dv->type == ERROR_TYPE) {
495			printf("Parse error\n");
496			_DVFree(dv);
497			return 0;
498		}
499	} else {
500		cmdLength = count;
501	}
502
503	int i;
504	const char* name;
505	for (i = 0; (name = _debuggerCommands[i].name); ++i) {
506		if (strlen(name) != cmdLength) {
507			continue;
508		}
509		if (strncasecmp(name, line, cmdLength) == 0) {
510			_debuggerCommands[i].command(debugger, dv);
511			_DVFree(dv);
512			return 1;
513		}
514	}
515	_DVFree(dv);
516	printf("Command not found\n");
517	return 0;
518}
519
520static char* _prompt(EditLine* el) {
521	(void)(el);
522	return "> ";
523}
524
525static void _commandLine(struct ARMDebugger* debugger) {
526	const char* line;
527	_printStatus(debugger, 0);
528	int count = 0;
529	HistEvent ev;
530	while (debugger->state == DEBUGGER_PAUSED) {
531		line = el_gets(debugger->elstate, &count);
532		if (!line) {
533			debugger->state = DEBUGGER_EXITING;
534			return;
535		}
536		if (line[0] == '\n') {
537			if (history(debugger->histate, &ev, H_FIRST) >= 0) {
538				_parse(debugger, ev.str, strlen(ev.str) - 1);
539			}
540		} else {
541			if (_parse(debugger, line, count - 1)) {
542				history(debugger->histate, &ev, H_ENTER, line);
543			}
544		}
545	}
546}
547
548static unsigned char _tabComplete(EditLine* elstate, int ch) {
549	(void)(ch);
550	const LineInfo* li = el_line(elstate);
551	const char* commandPtr;
552	int cmd = 0, len = 0;
553	const char* name = 0;
554	for (commandPtr = li->buffer; commandPtr <= li->cursor; ++commandPtr, ++len) {
555		for (; (name = _debuggerCommands[cmd].name); ++cmd) {
556			int cmp = strncasecmp(name, li->buffer, len);
557			if (cmp > 0) {
558				return CC_ERROR;
559			}
560			if (cmp == 0) {
561				break;
562			}
563		}
564	}
565	if (_debuggerCommands[cmd + 1].name && strncasecmp(_debuggerCommands[cmd + 1].name, li->buffer, len - 1) == 0) {
566		return CC_ERROR;
567	}
568	name += len - 1;
569	el_insertstr(elstate, name);
570	el_insertstr(elstate, " ");
571	return CC_REDISPLAY;
572}
573
574void ARMDebuggerInit(struct ARMDebugger* debugger, struct ARMCore* cpu) {
575	debugger->cpu = cpu;
576	debugger->state = DEBUGGER_PAUSED;
577	debugger->breakpoints = 0;
578	// TODO: get argv[0]
579	debugger->elstate = el_init("gbac", stdin, stdout, stderr);
580	el_set(debugger->elstate, EL_PROMPT, _prompt);
581	el_set(debugger->elstate, EL_EDITOR, "emacs");
582
583	el_set(debugger->elstate, EL_CLIENTDATA, debugger);
584	el_set(debugger->elstate, EL_ADDFN, "tab-complete", "Tab completion", _tabComplete);
585	el_set(debugger->elstate, EL_BIND, "\t", "tab-complete", 0);
586	debugger->histate = history_init();
587	HistEvent ev;
588	history(debugger->histate, &ev, H_SETSIZE, 200);
589	el_set(debugger->elstate, EL_HIST, history, debugger->histate);
590	debugger->memoryShim.p = debugger;
591	debugger->memoryShim.watchpoints = 0;
592	_activeDebugger = debugger;
593	signal(SIGINT, _breakIntoDefault);
594}
595
596void ARMDebuggerDeinit(struct ARMDebugger* debugger) {
597	// TODO: actually call this
598	history_end(debugger->histate);
599	el_end(debugger->elstate);
600}
601
602void ARMDebuggerRun(struct ARMDebugger* debugger) {
603	if (debugger->state == DEBUGGER_EXITING) {
604		debugger->state = DEBUGGER_RUNNING;
605	}
606	while (debugger->state < DEBUGGER_EXITING) {
607		if (!debugger->breakpoints) {
608			while (debugger->state == DEBUGGER_RUNNING) {
609				ARMRun(debugger->cpu);
610			}
611		} else {
612			while (debugger->state == DEBUGGER_RUNNING) {
613				ARMRun(debugger->cpu);
614				_checkBreakpoints(debugger);
615			}
616		}
617		switch (debugger->state) {
618		case DEBUGGER_RUNNING:
619			break;
620		case DEBUGGER_PAUSED:
621			_commandLine(debugger);
622			break;
623		case DEBUGGER_EXITING:
624		case DEBUGGER_SHUTDOWN:
625			return;
626		}
627	}
628}
629
630void ARMDebuggerEnter(struct ARMDebugger* debugger) {
631	debugger->state = DEBUGGER_PAUSED;
632}