all repos — mgba @ 4659635fb57e27c15bc2419130d5e0c9542d6fef

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
 14#ifdef USE_PTHREADS
 15#include <pthread.h>
 16#endif
 17
 18struct DebugVector {
 19	struct DebugVector* next;
 20	enum DVType {
 21		ERROR_TYPE,
 22		INT_TYPE,
 23		CHAR_TYPE
 24	} type;
 25	union {
 26		int32_t intValue;
 27		const char* charValue;
 28	};
 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*);
 48static void _setWatchpoint(struct ARMDebugger*, struct DebugVector*);
 49
 50static void _breakIntoDefault(int signal);
 51
 52static struct {
 53	const char* name;
 54	DebuggerComamnd* command;
 55} _debuggerCommands[] = {
 56	{ "b", _setBreakpoint },
 57	{ "break", _setBreakpoint },
 58	{ "c", _continue },
 59	{ "continue", _continue },
 60	{ "i", _printStatus },
 61	{ "info", _printStatus },
 62	{ "n", _next },
 63	{ "next", _next },
 64	{ "p", _print },
 65	{ "p/x", _printHex },
 66	{ "print", _print },
 67	{ "print/x", _printHex },
 68	{ "q", _quit },
 69	{ "quit", _quit },
 70	{ "rb", _readByte },
 71	{ "rh", _readHalfword },
 72	{ "rw", _readWord },
 73	{ "status", _printStatus },
 74	{ "w", _setWatchpoint },
 75	{ "watch", _setWatchpoint },
 76	{ "x", _breakInto },
 77	{ 0, 0 }
 78};
 79
 80static inline void _printPSR(union PSR psr) {
 81	printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed,
 82		psr.n ? 'N' : '-',
 83		psr.z ? 'Z' : '-',
 84		psr.c ? 'C' : '-',
 85		psr.v ? 'V' : '-',
 86		psr.i ? 'I' : '-',
 87		psr.f ? 'F' : '-',
 88		psr.t ? 'T' : '-');
 89}
 90
 91static void _handleDeath(int sig) {
 92	(void)(sig);
 93	printf("No debugger attached!\n");
 94}
 95
 96static void _breakInto(struct ARMDebugger* debugger, struct DebugVector* dv) {
 97	(void)(debugger);
 98	(void)(dv);
 99	struct sigaction sa, osa;
100	sa.sa_handler = _handleDeath;
101	sigemptyset(&sa.sa_mask);
102	sigaddset(&sa.sa_mask, SIGTRAP);
103	sa.sa_flags = SA_RESTART;
104	sigaction(SIGTRAP, &sa, &osa);
105#ifdef USE_PTHREADS
106	pthread_kill(pthread_self(), SIGTRAP);
107#else
108	kill(getpid(), SIGTRAP);
109#endif
110	sigaction(SIGTRAP, &osa, 0);
111}
112
113static void _continue(struct ARMDebugger* debugger, struct DebugVector* dv) {
114	(void)(dv);
115	debugger->state = DEBUGGER_RUNNING;
116}
117
118static void _next(struct ARMDebugger* debugger, struct DebugVector* dv) {
119	(void)(dv);
120	ARMRun(debugger->cpu);
121	_printStatus(debugger, 0);
122}
123
124static void _print(struct ARMDebugger* debugger, struct DebugVector* dv) {
125	(void)(debugger);
126	for ( ; dv; dv = dv->next) {
127		printf(" %u", dv->intValue);
128	}
129	printf("\n");
130}
131
132static void _printHex(struct ARMDebugger* debugger, struct DebugVector* dv) {
133	(void)(debugger);
134	for ( ; dv; dv = dv->next) {
135		printf(" 0x%08X", dv->intValue);
136	}
137	printf("\n");
138}
139
140static inline void _printLine(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
141	// TODO: write a disassembler
142	if (mode == MODE_ARM) {
143		uint32_t instruction = debugger->cpu->memory->load32(debugger->cpu->memory, address, 0);
144		printf("%08X\n", instruction);
145	} else {
146		uint16_t instruction = debugger->cpu->memory->loadU16(debugger->cpu->memory, address, 0);
147		printf("%04X\n", instruction);
148	}
149}
150
151static void _printStatus(struct ARMDebugger* debugger, struct DebugVector* dv) {
152	(void)(dv);
153	int r;
154	for (r = 0; r < 4; ++r) {
155		printf("%08X %08X %08X %08X\n",
156			debugger->cpu->gprs[r << 2],
157			debugger->cpu->gprs[(r << 2) + 1],
158			debugger->cpu->gprs[(r << 2) + 2],
159			debugger->cpu->gprs[(r << 2) + 3]);
160	}
161	_printPSR(debugger->cpu->cpsr);
162	int instructionLength;
163	enum ExecutionMode mode = debugger->cpu->cpsr.t;
164	if (mode == MODE_ARM) {
165		instructionLength = WORD_SIZE_ARM;
166	} else {
167		instructionLength = WORD_SIZE_THUMB;
168	}
169	_printLine(debugger, debugger->cpu->gprs[ARM_PC] - instructionLength, mode);
170}
171
172static void _quit(struct ARMDebugger* debugger, struct DebugVector* dv) {
173	(void)(dv);
174	debugger->state = DEBUGGER_SHUTDOWN;
175}
176
177static void _readByte(struct ARMDebugger* debugger, struct DebugVector* dv) {
178	if (!dv || dv->type != INT_TYPE) {
179		printf("%s\n", ERROR_MISSING_ARGS);
180		return;
181	}
182	uint32_t address = dv->intValue;
183	uint8_t value = debugger->cpu->memory->loadU8(debugger->cpu->memory, address, 0);
184	printf(" 0x%02X\n", value);
185}
186
187static void _readHalfword(struct ARMDebugger* debugger, struct DebugVector* dv) {
188	if (!dv || dv->type != INT_TYPE) {
189		printf("%s\n", ERROR_MISSING_ARGS);
190		return;
191	}
192	uint32_t address = dv->intValue;
193	uint16_t value = debugger->cpu->memory->loadU16(debugger->cpu->memory, address, 0);
194	printf(" 0x%04X\n", value);
195}
196
197static void _readWord(struct ARMDebugger* debugger, struct DebugVector* dv) {
198	if (!dv || dv->type != INT_TYPE) {
199		printf("%s\n", ERROR_MISSING_ARGS);
200		return;
201	}
202	uint32_t address = dv->intValue;
203	uint32_t value = debugger->cpu->memory->load32(debugger->cpu->memory, address, 0);
204	printf(" 0x%08X\n", value);
205}
206
207static void _setBreakpoint(struct ARMDebugger* debugger, struct DebugVector* dv) {
208	if (!dv || dv->type != INT_TYPE) {
209		printf("%s\n", ERROR_MISSING_ARGS);
210		return;
211	}
212	uint32_t address = dv->intValue;
213	struct DebugBreakpoint* breakpoint = malloc(sizeof(struct DebugBreakpoint));
214	breakpoint->address = address;
215	breakpoint->next = debugger->breakpoints;
216	debugger->breakpoints = breakpoint;
217}
218
219static void _setWatchpoint(struct ARMDebugger* debugger, struct DebugVector* dv) {
220	if (!dv || dv->type != INT_TYPE) {
221		printf("%s\n", ERROR_MISSING_ARGS);
222		return;
223	}
224	uint32_t address = dv->intValue;
225	if (debugger->cpu->memory != &debugger->memoryShim.d) {
226		ARMDebuggerInstallMemoryShim(debugger);
227	}
228	struct DebugBreakpoint* watchpoint = malloc(sizeof(struct DebugBreakpoint));
229	watchpoint->address = address;
230	watchpoint->next = debugger->memoryShim.watchpoints;
231	debugger->memoryShim.watchpoints = watchpoint;
232}
233
234static void _checkBreakpoints(struct ARMDebugger* debugger) {
235	struct DebugBreakpoint* breakpoint;
236	int instructionLength;
237	enum ExecutionMode mode = debugger->cpu->cpsr.t;
238	if (mode == MODE_ARM) {
239		instructionLength = WORD_SIZE_ARM;
240	} else {
241		instructionLength = WORD_SIZE_THUMB;
242	}
243	for (breakpoint = debugger->breakpoints; breakpoint; breakpoint = breakpoint->next) {
244		if (breakpoint->address + instructionLength == debugger->cpu->gprs[ARM_PC]) {
245			debugger->state = DEBUGGER_PAUSED;
246			printf("Hit breakpoint\n");
247			break;
248		}
249	}
250}
251
252static void _breakIntoDefault(int signal) {
253	(void)(signal);
254	_activeDebugger->state = DEBUGGER_PAUSED;
255}
256
257enum _DVParseState {
258	PARSE_ERROR = -1,
259	PARSE_ROOT = 0,
260	PARSE_EXPECT_REGISTER,
261	PARSE_EXPECT_REGISTER_2,
262	PARSE_EXPECT_LR,
263	PARSE_EXPECT_PC,
264	PARSE_EXPECT_SP,
265	PARSE_EXPECT_DECIMAL,
266	PARSE_EXPECT_HEX,
267	PARSE_EXPECT_PREFIX,
268	PARSE_EXPECT_SUFFIX,
269};
270
271static struct DebugVector* _DVParse(struct ARMDebugger* debugger, const char* string, size_t length) {
272	if (!string || length < 1) {
273		return 0;
274	}
275
276	enum _DVParseState state = PARSE_ROOT;
277	struct DebugVector dvTemp = { .type = INT_TYPE };
278	uint32_t current = 0;
279
280	while (length > 0 && string[0] && string[0] != ' ' && state != PARSE_ERROR) {
281		char token = string[0];
282		++string;
283		--length;
284		switch (state) {
285		case PARSE_ROOT:
286			switch (token) {
287			case 'r':
288				state = PARSE_EXPECT_REGISTER;
289				break;
290			case 'p':
291				state = PARSE_EXPECT_PC;
292				break;
293			case 's':
294				state = PARSE_EXPECT_SP;
295				break;
296			case 'l':
297				state = PARSE_EXPECT_LR;
298				break;
299			case '1':
300			case '2':
301			case '3':
302			case '4':
303			case '5':
304			case '6':
305			case '7':
306			case '8':
307			case '9':
308				state = PARSE_EXPECT_DECIMAL;
309				current = token - '0';
310				break;
311			case '0':
312				state = PARSE_EXPECT_PREFIX;
313				break;
314			case '$':
315				state = PARSE_EXPECT_HEX;
316				current = 0;
317				break;
318			default:
319				state = PARSE_ERROR;
320				break;
321			};
322			break;
323		case PARSE_EXPECT_LR:
324			switch (token) {
325			case 'r':
326				current = debugger->cpu->gprs[ARM_LR];
327				state = PARSE_EXPECT_SUFFIX;
328				break;
329			default:
330				state = PARSE_ERROR;
331				break;
332			}
333			break;
334		case PARSE_EXPECT_PC:
335			switch (token) {
336			case 'c':
337				current = debugger->cpu->gprs[ARM_PC];
338				state = PARSE_EXPECT_SUFFIX;
339				break;
340			default:
341				state = PARSE_ERROR;
342				break;
343			}
344			break;
345		case PARSE_EXPECT_SP:
346			switch (token) {
347			case 'p':
348				current = debugger->cpu->gprs[ARM_SP];
349				state = PARSE_EXPECT_SUFFIX;
350				break;
351			default:
352				state = PARSE_ERROR;
353				break;
354			}
355			break;
356		case PARSE_EXPECT_REGISTER:
357			switch (token) {
358			case '0':
359			case '2':
360			case '3':
361			case '4':
362			case '5':
363			case '6':
364			case '7':
365			case '8':
366			case '9':
367				current = debugger->cpu->gprs[token - '0'];
368				state = PARSE_EXPECT_SUFFIX;
369				break;
370			case '1':
371				state = PARSE_EXPECT_REGISTER_2;
372				break;
373			default:
374				state = PARSE_ERROR;
375				break;
376			}
377			break;
378		case PARSE_EXPECT_REGISTER_2:
379			switch (token) {
380			case '0':
381			case '1':
382			case '2':
383			case '3':
384			case '4':
385			case '5':
386				current = debugger->cpu->gprs[token - '0' + 10];
387				state = PARSE_EXPECT_SUFFIX;
388				break;
389			default:
390				state = PARSE_ERROR;
391				break;
392			}
393			break;
394		case PARSE_EXPECT_DECIMAL:
395			switch (token) {
396			case '0':
397			case '1':
398			case '2':
399			case '3':
400			case '4':
401			case '5':
402			case '6':
403			case '7':
404			case '8':
405			case '9':
406				// TODO: handle overflow
407				current *= 10;
408				current += token - '0';
409				break;
410			default:
411				state = PARSE_ERROR;
412			}
413			break;
414		case PARSE_EXPECT_HEX:
415			switch (token) {
416			case '0':
417			case '1':
418			case '2':
419			case '3':
420			case '4':
421			case '5':
422			case '6':
423			case '7':
424			case '8':
425			case '9':
426				// TODO: handle overflow
427				current *= 16;
428				current += token - '0';
429				break;
430			case 'A':
431			case 'B':
432			case 'C':
433			case 'D':
434			case 'E':
435			case 'F':
436				// TODO: handle overflow
437				current *= 16;
438				current += token - 'A' + 10;
439				break;
440			case 'a':
441			case 'b':
442			case 'c':
443			case 'd':
444			case 'e':
445			case 'f':
446				// TODO: handle overflow
447				current *= 16;
448				current += token - 'a' + 10;
449				break;
450			default:
451				state = PARSE_ERROR;
452				break;
453			}
454			break;
455		case PARSE_EXPECT_PREFIX:
456			switch (token) {
457			case 'X':
458			case 'x':
459				current = 0;
460				state = PARSE_EXPECT_HEX;
461				break;
462			default:
463				state = PARSE_ERROR;
464				break;
465			}
466			break;
467		case PARSE_EXPECT_SUFFIX:
468			// TODO
469			state = PARSE_ERROR;
470			break;
471		case PARSE_ERROR:
472			// This shouldn't be reached
473			break;
474		}
475	}
476
477	struct DebugVector* dv = malloc(sizeof(struct DebugVector));
478	if (state == PARSE_ERROR) {
479		dv->type = ERROR_TYPE;
480		dv->next = 0;
481	} else {
482		dvTemp.intValue = current;
483		*dv = dvTemp;
484		if (string[0] == ' ') {
485			dv->next = _DVParse(debugger, string + 1, length - 1);
486		}
487	}
488	return dv;
489}
490
491static void _DVFree(struct DebugVector* dv) {
492	struct DebugVector* next;
493	while (dv) {
494		next = dv->next;
495		free(dv);
496		dv = next;
497	}
498}
499
500static int _parse(struct ARMDebugger* debugger, const char* line, size_t count) {
501	const char* firstSpace = strchr(line, ' ');
502	size_t cmdLength;
503	struct DebugVector* dv = 0;
504	if (firstSpace) {
505		cmdLength = firstSpace - line;
506		dv = _DVParse(debugger, firstSpace + 1, count - cmdLength - 1);
507		if (dv && dv->type == ERROR_TYPE) {
508			printf("Parse error\n");
509			_DVFree(dv);
510			return 0;
511		}
512	} else {
513		cmdLength = count;
514	}
515
516	int i;
517	const char* name;
518	for (i = 0; (name = _debuggerCommands[i].name); ++i) {
519		if (strlen(name) != cmdLength) {
520			continue;
521		}
522		if (strncasecmp(name, line, cmdLength) == 0) {
523			_debuggerCommands[i].command(debugger, dv);
524			_DVFree(dv);
525			return 1;
526		}
527	}
528	_DVFree(dv);
529	printf("Command not found\n");
530	return 0;
531}
532
533static char* _prompt(EditLine* el) {
534	(void)(el);
535	return "> ";
536}
537
538static void _commandLine(struct ARMDebugger* debugger) {
539	const char* line;
540	_printStatus(debugger, 0);
541	int count = 0;
542	HistEvent ev;
543	while (debugger->state == DEBUGGER_PAUSED) {
544		line = el_gets(debugger->elstate, &count);
545		if (!line) {
546			debugger->state = DEBUGGER_EXITING;
547			return;
548		}
549		if (line[0] == '\n') {
550			if (history(debugger->histate, &ev, H_FIRST) >= 0) {
551				_parse(debugger, ev.str, strlen(ev.str) - 1);
552			}
553		} else {
554			if (_parse(debugger, line, count - 1)) {
555				history(debugger->histate, &ev, H_ENTER, line);
556			}
557		}
558	}
559}
560
561static unsigned char _tabComplete(EditLine* elstate, int ch) {
562	(void)(ch);
563	const LineInfo* li = el_line(elstate);
564	const char* commandPtr;
565	int cmd = 0, len = 0;
566	const char* name = 0;
567	for (commandPtr = li->buffer; commandPtr <= li->cursor; ++commandPtr, ++len) {
568		for (; (name = _debuggerCommands[cmd].name); ++cmd) {
569			int cmp = strncasecmp(name, li->buffer, len);
570			if (cmp > 0) {
571				return CC_ERROR;
572			}
573			if (cmp == 0) {
574				break;
575			}
576		}
577	}
578	if (_debuggerCommands[cmd + 1].name && strncasecmp(_debuggerCommands[cmd + 1].name, li->buffer, len - 1) == 0) {
579		return CC_ERROR;
580	}
581	name += len - 1;
582	el_insertstr(elstate, name);
583	el_insertstr(elstate, " ");
584	return CC_REDISPLAY;
585}
586
587void ARMDebuggerInit(struct ARMDebugger* debugger, struct ARMCore* cpu) {
588	debugger->cpu = cpu;
589	debugger->state = DEBUGGER_PAUSED;
590	debugger->breakpoints = 0;
591	// TODO: get argv[0]
592	debugger->elstate = el_init("gbac", stdin, stdout, stderr);
593	el_set(debugger->elstate, EL_PROMPT, _prompt);
594	el_set(debugger->elstate, EL_EDITOR, "emacs");
595
596	el_set(debugger->elstate, EL_CLIENTDATA, debugger);
597	el_set(debugger->elstate, EL_ADDFN, "tab-complete", "Tab completion", _tabComplete);
598	el_set(debugger->elstate, EL_BIND, "\t", "tab-complete", 0);
599	debugger->histate = history_init();
600	HistEvent ev;
601	history(debugger->histate, &ev, H_SETSIZE, 200);
602	el_set(debugger->elstate, EL_HIST, history, debugger->histate);
603	debugger->memoryShim.p = debugger;
604	debugger->memoryShim.watchpoints = 0;
605	_activeDebugger = debugger;
606	signal(SIGINT, _breakIntoDefault);
607}
608
609void ARMDebuggerDeinit(struct ARMDebugger* debugger) {
610	// TODO: actually call this
611	history_end(debugger->histate);
612	el_end(debugger->elstate);
613}
614
615void ARMDebuggerRun(struct ARMDebugger* debugger) {
616	if (debugger->state == DEBUGGER_EXITING) {
617		debugger->state = DEBUGGER_RUNNING;
618	}
619	while (debugger->state < DEBUGGER_EXITING) {
620		if (!debugger->breakpoints) {
621			while (debugger->state == DEBUGGER_RUNNING) {
622				ARMRun(debugger->cpu);
623			}
624		} else {
625			while (debugger->state == DEBUGGER_RUNNING) {
626				ARMRun(debugger->cpu);
627				_checkBreakpoints(debugger);
628			}
629		}
630		switch (debugger->state) {
631		case DEBUGGER_RUNNING:
632			break;
633		case DEBUGGER_PAUSED:
634			_commandLine(debugger);
635			break;
636		case DEBUGGER_EXITING:
637		case DEBUGGER_SHUTDOWN:
638			return;
639		}
640	}
641}
642
643void ARMDebuggerEnter(struct ARMDebugger* debugger) {
644	debugger->state = DEBUGGER_PAUSED;
645}