all repos — mgba @ c19d1117f18da6a407ae8332a904004e9edf0677

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#include "linenoise.h"
 14
 15struct DebugVector {
 16	struct DebugVector* next;
 17	enum DVType {
 18		ERROR_TYPE,
 19		INT_TYPE,
 20		CHAR_TYPE
 21	} type;
 22	union {
 23		int32_t intValue;
 24		const char* charValue;
 25	};
 26};
 27
 28static const char* ERROR_MISSING_ARGS = "Arguments missing";
 29
 30static struct ARMDebugger* _activeDebugger;
 31
 32typedef void (DebuggerComamnd)(struct ARMDebugger*, struct DebugVector*);
 33
 34static void _breakInto(struct ARMDebugger*, struct DebugVector*);
 35static void _continue(struct ARMDebugger*, struct DebugVector*);
 36static void _next(struct ARMDebugger*, struct DebugVector*);
 37static void _print(struct ARMDebugger*, struct DebugVector*);
 38static void _printHex(struct ARMDebugger*, struct DebugVector*);
 39static void _printStatus(struct ARMDebugger*, struct DebugVector*);
 40static void _quit(struct ARMDebugger*, struct DebugVector*);
 41static void _readByte(struct ARMDebugger*, struct DebugVector*);
 42static void _readHalfword(struct ARMDebugger*, struct DebugVector*);
 43static void _readWord(struct ARMDebugger*, struct DebugVector*);
 44static void _setBreakpoint(struct ARMDebugger*, struct DebugVector*);
 45static void _setWatchpoint(struct ARMDebugger*, struct DebugVector*);
 46
 47static void _breakIntoDefault(int signal);
 48
 49struct {
 50	const char* name;
 51	DebuggerComamnd* command;
 52} debuggerCommands[] = {
 53	{ "b", _setBreakpoint },
 54	{ "break", _setBreakpoint },
 55	{ "c", _continue },
 56	{ "continue", _continue },
 57	{ "i", _printStatus },
 58	{ "info", _printStatus },
 59	{ "n", _next },
 60	{ "p", _print },
 61	{ "print", _print },
 62	{ "p/x", _printHex },
 63	{ "print/x", _printHex },
 64	{ "q", _quit },
 65	{ "quit", _quit },
 66	{ "rb", _readByte },
 67	{ "rh", _readHalfword },
 68	{ "rw", _readWord },
 69	{ "status", _printStatus },
 70	{ "x", _breakInto },
 71	{ "w", _setWatchpoint },
 72	{ "watch", _setWatchpoint },
 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_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, 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) {
259	if (!string || !string[0]) {
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 (string[0] && string[0] != ' ' && state != PARSE_ERROR) {
268		char token = string[0];
269		++string;
270		switch (state) {
271		case PARSE_ROOT:
272			switch (token) {
273			case 'r':
274				state = PARSE_EXPECT_REGISTER;
275				break;
276			case 'p':
277				state = PARSE_EXPECT_PC;
278				break;
279			case 's':
280				state = PARSE_EXPECT_SP;
281				break;
282			case 'l':
283				state = PARSE_EXPECT_LR;
284				break;
285			case '1':
286			case '2':
287			case '3':
288			case '4':
289			case '5':
290			case '6':
291			case '7':
292			case '8':
293			case '9':
294				state = PARSE_EXPECT_DECIMAL;
295				current = token - '0';
296				break;
297			case '0':
298				state = PARSE_EXPECT_PREFIX;
299				break;
300			case '$':
301				state = PARSE_EXPECT_HEX;
302				current = 0;
303				break;
304			default:
305				state = PARSE_ERROR;
306				break;
307			};
308			break;
309		case PARSE_EXPECT_LR:
310			switch (token) {
311			case 'r':
312				current = debugger->cpu->gprs[ARM_LR];
313				state = PARSE_EXPECT_SUFFIX;
314				break;
315			default:
316				state = PARSE_ERROR;
317				break;
318			}
319			break;
320		case PARSE_EXPECT_PC:
321			switch (token) {
322			case 'c':
323				current = debugger->cpu->gprs[ARM_PC];
324				state = PARSE_EXPECT_SUFFIX;
325				break;
326			default:
327				state = PARSE_ERROR;
328				break;
329			}
330			break;
331		case PARSE_EXPECT_SP:
332			switch (token) {
333			case 'p':
334				current = debugger->cpu->gprs[ARM_SP];
335				state = PARSE_EXPECT_SUFFIX;
336				break;
337			default:
338				state = PARSE_ERROR;
339				break;
340			}
341			break;
342		case PARSE_EXPECT_REGISTER:
343			switch (token) {
344			case '0':
345			case '2':
346			case '3':
347			case '4':
348			case '5':
349			case '6':
350			case '7':
351			case '8':
352			case '9':
353				current = debugger->cpu->gprs[token - '0'];
354				state = PARSE_EXPECT_SUFFIX;
355				break;
356			case '1':
357				state = PARSE_EXPECT_REGISTER_2;
358				break;
359			default:
360				state = PARSE_ERROR;
361				break;
362			}
363			break;
364		case PARSE_EXPECT_REGISTER_2:
365			switch (token) {
366			case '0':
367			case '1':
368			case '2':
369			case '3':
370			case '4':
371			case '5':
372				current = debugger->cpu->gprs[token - '0' + 10];
373				state = PARSE_EXPECT_SUFFIX;
374				break;
375			default:
376				state = PARSE_ERROR;
377				break;
378			}
379			break;
380		case PARSE_EXPECT_DECIMAL:
381			switch (token) {
382			case '0':
383			case '1':
384			case '2':
385			case '3':
386			case '4':
387			case '5':
388			case '6':
389			case '7':
390			case '8':
391			case '9':
392				// TODO: handle overflow
393				current *= 10;
394				current += token - '0';
395				break;
396			default:
397				state = PARSE_ERROR;
398			}
399			break;
400		case PARSE_EXPECT_HEX:
401			switch (token) {
402			case '0':
403			case '1':
404			case '2':
405			case '3':
406			case '4':
407			case '5':
408			case '6':
409			case '7':
410			case '8':
411			case '9':
412				// TODO: handle overflow
413				current *= 16;
414				current += token - '0';
415				break;
416			case 'A':
417			case 'B':
418			case 'C':
419			case 'D':
420			case 'E':
421			case 'F':
422				// TODO: handle overflow
423				current *= 16;
424				current += token - 'A' + 10;
425				break;
426			case 'a':
427			case 'b':
428			case 'c':
429			case 'd':
430			case 'e':
431			case 'f':
432				// TODO: handle overflow
433				current *= 16;
434				current += token - 'a' + 10;
435				break;
436			default:
437				state = PARSE_ERROR;
438				break;
439			}
440			break;
441		case PARSE_EXPECT_PREFIX:
442			switch (token) {
443			case 'X':
444			case 'x':
445				current = 0;
446				state = PARSE_EXPECT_HEX;
447				break;
448			default:
449				state = PARSE_ERROR;
450				break;
451			}
452			break;
453		case PARSE_EXPECT_SUFFIX:
454			// TODO
455			state = PARSE_ERROR;
456			break;
457		case PARSE_ERROR:
458			// This shouldn't be reached
459			break;
460		}
461	}
462
463	struct DebugVector* dv = malloc(sizeof(struct DebugVector));
464	if (state == PARSE_ERROR) {
465		dv->type = ERROR_TYPE;
466		dv->next = 0;
467	} else {
468		dvTemp.intValue = current;
469		*dv = dvTemp;
470		if (string[0] == ' ') {
471			dv->next = _DVParse(debugger, string + 1);
472		}
473	}
474	return dv;
475}
476
477static void _DVFree(struct DebugVector* dv) {
478	struct DebugVector* next;
479	while (dv) {
480		next = dv->next;
481		free(dv);
482		dv = next;
483	}
484}
485
486static int _parse(struct ARMDebugger* debugger, const char* line) {
487	char* firstSpace = strchr(line, ' ');
488	size_t cmdLength;
489	struct DebugVector* dv = 0;
490	if (firstSpace) {
491		cmdLength = firstSpace - line;
492		dv = _DVParse(debugger, firstSpace + 1);
493		if (dv && dv->type == ERROR_TYPE) {
494			printf("Parse error\n");
495			_DVFree(dv);
496			return 0;
497		}
498	} else {
499		cmdLength = strlen(line);
500	}
501
502	int i;
503	const char* name;
504	for (i = 0; (name = debuggerCommands[i].name); ++i) {
505		if (strlen(name) != cmdLength) {
506			continue;
507		}
508		if (strncasecmp(name, line, cmdLength) == 0) {
509			debuggerCommands[i].command(debugger, dv);
510			_DVFree(dv);
511			return 1;
512		}
513	}
514	_DVFree(dv);
515	printf("Command not found\n");
516	return 0;
517}
518
519static void _commandLine(struct ARMDebugger* debugger) {
520	char* line;
521	_printStatus(debugger, 0);
522	while (debugger->state == DEBUGGER_PAUSED) {
523		line = linenoise("> ");
524		if (!line) {
525			debugger->state = DEBUGGER_EXITING;
526			return;
527		}
528		if (!line[0]) {
529			if (debugger->lastCommand) {
530				_parse(debugger, debugger->lastCommand);
531			}
532		} else {
533			linenoiseHistoryAdd(line);
534			if (_parse(debugger, line)) {
535				char* oldLine = debugger->lastCommand;
536				debugger->lastCommand = line;
537				free(oldLine);
538			} else {
539				free(line);
540			}
541		}
542	}
543}
544
545void ARMDebuggerInit(struct ARMDebugger* debugger, struct ARMCore* cpu) {
546	debugger->cpu = cpu;
547	debugger->state = DEBUGGER_PAUSED;
548	debugger->lastCommand = 0;
549	debugger->breakpoints = 0;
550	debugger->memoryShim.p = debugger;
551	debugger->memoryShim.watchpoints = 0;
552	_activeDebugger = debugger;
553	signal(SIGINT, _breakIntoDefault);
554}
555
556void ARMDebuggerRun(struct ARMDebugger* debugger) {
557	while (debugger->state != DEBUGGER_EXITING) {
558		if (!debugger->breakpoints) {
559			while (debugger->state == DEBUGGER_RUNNING) {
560				ARMRun(debugger->cpu);
561			}
562		} else {
563			while (debugger->state == DEBUGGER_RUNNING) {
564				ARMRun(debugger->cpu);
565				_checkBreakpoints(debugger);
566			}
567		}
568		switch (debugger->state) {
569		case DEBUGGER_PAUSED:
570			_commandLine(debugger);
571			break;
572		case DEBUGGER_EXITING:
573			return;
574		default:
575			// Should never be reached
576			break;
577		}
578	}
579}
580
581void ARMDebuggerEnter(struct ARMDebugger* debugger) {
582	debugger->state = DEBUGGER_PAUSED;
583}