all repos — mgba @ 1ca648715166fbca34ec4bef3ac591d9ce3a0869

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