all repos — mgba @ 9aed9754d025d103d298ce2aaa816d5650e98f77

mGBA Game Boy Advance Emulator

src/debugger/cli-debugger.c (view raw)

  1/* Copyright (c) 2013-2014 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "cli-debugger.h"
  7#include "decoder.h"
  8#include "parser.h"
  9
 10#include <signal.h>
 11
 12#ifdef USE_PTHREADS
 13#include <pthread.h>
 14#endif
 15
 16static const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
 17
 18static struct CLIDebugger* _activeDebugger;
 19
 20static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
 21static void _continue(struct CLIDebugger*, struct CLIDebugVector*);
 22static void _disassemble(struct CLIDebugger*, struct CLIDebugVector*);
 23static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*);
 24static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*);
 25static void _next(struct CLIDebugger*, struct CLIDebugVector*);
 26static void _print(struct CLIDebugger*, struct CLIDebugVector*);
 27static void _printBin(struct CLIDebugger*, struct CLIDebugVector*);
 28static void _printHex(struct CLIDebugger*, struct CLIDebugVector*);
 29static void _printStatus(struct CLIDebugger*, struct CLIDebugVector*);
 30static void _printHelp(struct CLIDebugger*, struct CLIDebugVector*);
 31static void _quit(struct CLIDebugger*, struct CLIDebugVector*);
 32static void _readByte(struct CLIDebugger*, struct CLIDebugVector*);
 33static void _reset(struct CLIDebugger*, struct CLIDebugVector*);
 34static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
 35static void _readWord(struct CLIDebugger*, struct CLIDebugVector*);
 36static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
 37static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
 38static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
 39
 40static void _breakIntoDefault(int signal);
 41static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode);
 42static void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
 43
 44static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
 45	{ "b", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
 46	{ "break", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
 47	{ "c", _continue, 0, "Continue execution" },
 48	{ "continue", _continue, 0, "Continue execution" },
 49	{ "d", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
 50	{ "delete", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
 51	{ "dis", _disassemble, CLIDVParse, "Disassemble instructions" },
 52	{ "dis/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
 53	{ "dis/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
 54	{ "disasm", _disassemble, CLIDVParse, "Disassemble instructions" },
 55	{ "disasm/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
 56	{ "disasm/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
 57	{ "disassemble", _disassemble, CLIDVParse, "Disassemble instructions" },
 58	{ "disassemble/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
 59	{ "disassemble/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
 60	{ "h", _printHelp, CLIDVStringParse, "Print help" },
 61	{ "help", _printHelp, CLIDVStringParse, "Print help" },
 62	{ "i", _printStatus, 0, "Print the current status" },
 63	{ "info", _printStatus, 0, "Print the current status" },
 64	{ "n", _next, 0, "Execute next instruction" },
 65	{ "next", _next, 0, "Execute next instruction" },
 66	{ "p", _print, CLIDVParse, "Print a value" },
 67	{ "p/t", _printBin, CLIDVParse, "Print a value as binary" },
 68	{ "p/x", _printHex, CLIDVParse, "Print a value as hexadecimal" },
 69	{ "print", _print, CLIDVParse, "Print a value" },
 70	{ "print/t", _printBin, CLIDVParse, "Print a value as binary" },
 71	{ "print/x", _printHex, CLIDVParse, "Print a value as hexadecimal" },
 72	{ "q", _quit, 0, "Quit the emulator" },
 73	{ "quit", _quit, 0, "Quit the emulator"  },
 74	{ "rb", _readByte, CLIDVParse, "Read a byte from a specified offset" },
 75	{ "reset", _reset, 0, "Reset the emulation" },
 76	{ "rh", _readHalfword, CLIDVParse, "Read a halfword from a specified offset" },
 77	{ "rw", _readWord, CLIDVParse, "Read a word from a specified offset" },
 78	{ "status", _printStatus, 0, "Print the current status" },
 79	{ "w", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
 80	{ "watch", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
 81	{ "x", _breakInto, 0, "Break into attached debugger (for developers)" },
 82	{ 0, 0, 0, 0 }
 83};
 84
 85static inline void _printPSR(union PSR psr) {
 86	printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed,
 87		psr.n ? 'N' : '-',
 88		psr.z ? 'Z' : '-',
 89		psr.c ? 'C' : '-',
 90		psr.v ? 'V' : '-',
 91		psr.i ? 'I' : '-',
 92		psr.f ? 'F' : '-',
 93		psr.t ? 'T' : '-');
 94}
 95
 96static void _handleDeath(int sig) {
 97	UNUSED(sig);
 98	printf("No debugger attached!\n");
 99}
100
101static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
102	UNUSED(debugger);
103	UNUSED(dv);
104	struct sigaction sa, osa;
105	sa.sa_handler = _handleDeath;
106	sigemptyset(&sa.sa_mask);
107	sigaddset(&sa.sa_mask, SIGTRAP);
108	sa.sa_flags = SA_RESTART;
109	sigaction(SIGTRAP, &sa, &osa);
110#ifdef USE_PTHREADS
111	pthread_kill(pthread_self(), SIGTRAP);
112#else
113	kill(getpid(), SIGTRAP);
114#endif
115	sigaction(SIGTRAP, &osa, 0);
116}
117
118static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
119	UNUSED(dv);
120	debugger->d.state = DEBUGGER_RUNNING;
121}
122
123static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
124	UNUSED(dv);
125	ARMRun(debugger->d.cpu);
126	_printStatus(debugger, 0);
127}
128
129static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
130	_disassembleMode(debugger, dv, debugger->d.cpu->executionMode);
131}
132
133static void _disassembleArm(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
134	_disassembleMode(debugger, dv, MODE_ARM);
135}
136
137static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
138	_disassembleMode(debugger, dv, MODE_THUMB);
139}
140
141static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) {
142	uint32_t address;
143	int size;
144	int wordSize;
145
146	if (mode == MODE_ARM) {
147		wordSize = WORD_SIZE_ARM;
148	} else {
149		wordSize = WORD_SIZE_THUMB;
150	}
151
152	if (!dv || dv->type != CLIDV_INT_TYPE) {
153		address = debugger->d.cpu->gprs[ARM_PC] - wordSize;
154	} else {
155		address = dv->intValue;
156		dv = dv->next;
157	}
158
159	if (!dv || dv->type != CLIDV_INT_TYPE) {
160		size = 1;
161	} else {
162		size = dv->intValue;
163		dv = dv->next; // TODO: Check for excess args
164	}
165
166	int i;
167	for (i = 0; i < size; ++i) {
168		_printLine(debugger, address, mode);
169		address += wordSize;
170	}
171}
172
173static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
174	UNUSED(debugger);
175	for ( ; dv; dv = dv->next) {
176		printf(" %u", dv->intValue);
177	}
178	printf("\n");
179}
180
181static void _printBin(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
182	UNUSED(debugger);
183	for ( ; dv; dv = dv->next) {
184		printf(" 0b");
185		int i = 32;
186		while (i--) {
187			printf(" %u", (dv->intValue >> i) & 1);
188		}
189	}
190	printf("\n");
191}
192
193static void _printHex(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
194	UNUSED(debugger);
195	for ( ; dv; dv = dv->next) {
196		printf(" 0x%08X", dv->intValue);
197	}
198	printf("\n");
199}
200
201static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
202	UNUSED(debugger);
203	UNUSED(dv);
204	if (!dv) {
205		puts("ARM commands:");
206		int i;
207		for (i = 0; _debuggerCommands[i].name; ++i) {
208			printf("%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary);
209		}
210		if (debugger->system) {
211			printf("%s commands:\n", debugger->system->name);
212			for (i = 0; debugger->system->commands[i].name; ++i) {
213				printf("%-10s %s\n", debugger->system->commands[i].name, debugger->system->commands[i].summary);
214			}
215		}
216	} else {
217		int i;
218		for (i = 0; _debuggerCommands[i].name; ++i) {
219			if (strcmp(_debuggerCommands[i].name, dv->charValue) == 0) {
220				printf(" %s\n", _debuggerCommands[i].summary);
221			}
222		}
223		if (debugger->system) {
224			printf("\n%s commands:\n", debugger->system->name);
225			for (i = 0; debugger->system->commands[i].name; ++i) {
226				if (strcmp(debugger->system->commands[i].name, dv->charValue) == 0) {
227					printf(" %s\n", debugger->system->commands[i].summary);
228				}
229			}
230		}
231	}
232}
233
234static inline void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
235	char disassembly[48];
236	struct ARMInstructionInfo info;
237	printf("%08X:  ", address);
238	if (mode == MODE_ARM) {
239		uint32_t instruction = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
240		ARMDecodeARM(instruction, &info);
241		ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
242		printf("%08X\t%s\n", instruction, disassembly);
243	} else {
244		uint16_t instruction = debugger->d.cpu->memory.loadU16(debugger->d.cpu, address, 0);
245		ARMDecodeThumb(instruction, &info);
246		ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
247		printf("%04X\t%s\n", instruction, disassembly);
248	}
249}
250
251static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
252	UNUSED(dv);
253	int r;
254	for (r = 0; r < 4; ++r) {
255		printf("%08X %08X %08X %08X\n",
256			debugger->d.cpu->gprs[r << 2],
257			debugger->d.cpu->gprs[(r << 2) + 1],
258			debugger->d.cpu->gprs[(r << 2) + 2],
259			debugger->d.cpu->gprs[(r << 2) + 3]);
260	}
261	_printPSR(debugger->d.cpu->cpsr);
262	int instructionLength;
263	enum ExecutionMode mode = debugger->d.cpu->cpsr.t;
264	if (mode == MODE_ARM) {
265		instructionLength = WORD_SIZE_ARM;
266	} else {
267		instructionLength = WORD_SIZE_THUMB;
268	}
269	_printLine(debugger, debugger->d.cpu->gprs[ARM_PC] - instructionLength, mode);
270}
271
272static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
273	UNUSED(dv);
274	debugger->d.state = DEBUGGER_SHUTDOWN;
275}
276
277static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
278	if (!dv || dv->type != CLIDV_INT_TYPE) {
279		printf("%s\n", ERROR_MISSING_ARGS);
280		return;
281	}
282	uint32_t address = dv->intValue;
283	uint8_t value = debugger->d.cpu->memory.loadU8(debugger->d.cpu, address, 0);
284	printf(" 0x%02X\n", value);
285}
286
287static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
288	UNUSED(dv);
289	ARMReset(debugger->d.cpu);
290	_printStatus(debugger, 0);
291}
292
293static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
294	if (!dv || dv->type != CLIDV_INT_TYPE) {
295		printf("%s\n", ERROR_MISSING_ARGS);
296		return;
297	}
298	uint32_t address = dv->intValue;
299	uint16_t value = debugger->d.cpu->memory.loadU16(debugger->d.cpu, address, 0);
300	printf(" 0x%04X\n", value);
301}
302
303static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
304	if (!dv || dv->type != CLIDV_INT_TYPE) {
305		printf("%s\n", ERROR_MISSING_ARGS);
306		return;
307	}
308	uint32_t address = dv->intValue;
309	uint32_t value = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
310	printf(" 0x%08X\n", value);
311}
312
313static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
314	if (!dv || dv->type != CLIDV_INT_TYPE) {
315		printf("%s\n", ERROR_MISSING_ARGS);
316		return;
317	}
318	uint32_t address = dv->intValue;
319	ARMDebuggerSetBreakpoint(&debugger->d, address);
320}
321
322static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
323	if (!dv || dv->type != CLIDV_INT_TYPE) {
324		printf("%s\n", ERROR_MISSING_ARGS);
325		return;
326	}
327	uint32_t address = dv->intValue;
328	ARMDebuggerClearBreakpoint(&debugger->d, address);
329}
330
331static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
332	if (!dv || dv->type != CLIDV_INT_TYPE) {
333		printf("%s\n", ERROR_MISSING_ARGS);
334		return;
335	}
336	uint32_t address = dv->intValue;
337	ARMDebuggerSetWatchpoint(&debugger->d, address);
338}
339
340static void _breakIntoDefault(int signal) {
341	UNUSED(signal);
342	ARMDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL);
343}
344
345static uint32_t _performOperation(enum Operation operation, uint32_t current, uint32_t next, struct CLIDebugVector* dv) {
346	switch (operation) {
347	case OP_ASSIGN:
348		current = next;
349		break;
350	case OP_ADD:
351		current += next;
352		break;
353	case OP_SUBTRACT:
354		current -= next;
355		break;
356	case OP_MULTIPLY:
357		current *= next;
358		break;
359	case OP_DIVIDE:
360		if (next != 0) {
361			current /= next;
362		} else {
363			dv->type = CLIDV_ERROR_TYPE;
364			return 0;
365		}
366		break;
367	}
368	return current;
369}
370
371static uint32_t _lookupIdentifier(struct ARMDebugger* debugger, const char* name, struct CLIDebugVector* dv) {
372	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
373	if (strcmp(name, "sp") == 0) {
374		return debugger->cpu->gprs[ARM_SP];
375	}
376	if (strcmp(name, "lr") == 0) {
377		return debugger->cpu->gprs[ARM_LR];
378	}
379	if (strcmp(name, "pc") == 0) {
380		return debugger->cpu->gprs[ARM_PC];
381	}
382	if (strcmp(name, "cpsr") == 0) {
383		return debugger->cpu->cpsr.packed;
384	}
385	// TODO: test if mode has SPSR
386	if (strcmp(name, "spsr") == 0) {
387		return debugger->cpu->spsr.packed;
388	}
389	if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') {
390		int reg = atoi(&name[1]);
391		if (reg < 16) {
392			return debugger->cpu->gprs[reg];
393		}
394	}
395	if (cliDebugger->system) {
396		uint32_t value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv);
397		if (dv->type != CLIDV_ERROR_TYPE) {
398			return value;
399		}
400	} else {
401		dv->type = CLIDV_ERROR_TYPE;
402	}
403	return 0;
404}
405
406static uint32_t _evaluateParseTree(struct ARMDebugger* debugger, struct ParseTree* tree, struct CLIDebugVector* dv) {
407	switch (tree->token.type) {
408	case TOKEN_UINT_TYPE:
409		return tree->token.uintValue;
410	case TOKEN_OPERATOR_TYPE:
411		return _performOperation(tree->token.operatorValue, _evaluateParseTree(debugger, tree->lhs, dv), _evaluateParseTree(debugger, tree->rhs, dv), dv);
412	case TOKEN_IDENTIFIER_TYPE:
413		return _lookupIdentifier(debugger, tree->token.identifierValue, dv);
414	case TOKEN_ERROR_TYPE:
415	default:
416		dv->type = CLIDV_ERROR_TYPE;
417	}
418	return 0;
419}
420
421struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* string, size_t length) {
422	if (!string || length < 1) {
423		return 0;
424	}
425
426	struct CLIDebugVector dvTemp = { .type = CLIDV_INT_TYPE };
427
428	struct LexVector lv = { .next = 0 };
429	size_t adjusted = lexExpression(&lv, string, length);
430	if (adjusted > length) {
431		dvTemp.type = CLIDV_ERROR_TYPE;
432		lexFree(lv.next);
433	}
434
435	struct ParseTree tree;
436	parseLexedExpression(&tree, &lv);
437	if (tree.token.type == TOKEN_ERROR_TYPE) {
438		dvTemp.type = CLIDV_ERROR_TYPE;
439	} else {
440		dvTemp.intValue = _evaluateParseTree(&debugger->d, &tree, &dvTemp);
441	}
442
443	parseFree(tree.lhs);
444	parseFree(tree.rhs);
445
446	length -= adjusted;
447	string += adjusted;
448
449	struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
450	if (dvTemp.type == CLIDV_ERROR_TYPE) {
451		dv->type = CLIDV_ERROR_TYPE;
452		dv->next = 0;
453	} else {
454		*dv = dvTemp;
455		if (string[0] == ' ') {
456			dv->next = CLIDVParse(debugger, string + 1, length - 1);
457			if (dv->next && dv->next->type == CLIDV_ERROR_TYPE) {
458				dv->type = CLIDV_ERROR_TYPE;
459			}
460		}
461	}
462	return dv;
463}
464
465struct CLIDebugVector* CLIDVStringParse(struct CLIDebugger* debugger, const char* string, size_t length) {
466	if (!string || length < 1) {
467		return 0;
468	}
469
470	struct CLIDebugVector dvTemp = { .type = CLIDV_CHAR_TYPE };
471
472	size_t adjusted;
473	const char* next = strchr(string, ' ');
474	if (next) {
475		adjusted = next - string;
476	} else {
477		adjusted = length;
478	}
479	dvTemp.charValue = malloc(adjusted);
480	strncpy(dvTemp.charValue, string, adjusted);
481
482	length -= adjusted;
483	string += adjusted;
484
485	struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
486	*dv = dvTemp;
487	if (string[0] == ' ') {
488		dv->next = CLIDVStringParse(debugger, string + 1, length - 1);
489		if (dv->next && dv->next->type == CLIDV_ERROR_TYPE) {
490			dv->type = CLIDV_ERROR_TYPE;
491		}
492	}
493	return dv;
494}
495
496static void _DVFree(struct CLIDebugVector* dv) {
497	struct CLIDebugVector* next;
498	while (dv) {
499		next = dv->next;
500		if (dv->type == CLIDV_CHAR_TYPE) {
501			free(dv->charValue);
502		}
503		free(dv);
504		dv = next;
505	}
506}
507
508static int _tryCommands(struct CLIDebugger* debugger, struct CLIDebuggerCommandSummary* commands, const char* command, size_t commandLen, const char* args, size_t argsLen) {
509	struct CLIDebugVector* dv = 0;
510	int i;
511	const char* name;
512	for (i = 0; (name = commands[i].name); ++i) {
513		if (strlen(name) != commandLen) {
514			continue;
515		}
516		if (strncasecmp(name, command, commandLen) == 0) {
517			if (commands[i].parser) {
518				if (args) {
519					dv = commands[i].parser(debugger, args, argsLen);
520					if (dv && dv->type == CLIDV_ERROR_TYPE) {
521						printf("Parse error\n");
522						_DVFree(dv);
523						return false;
524					}
525				}
526			} else if (args) {
527				printf("Wrong number of arguments\n");
528				return false;
529			}
530			commands[i].command(debugger, dv);
531			_DVFree(dv);
532			return true;
533		}
534	}
535	return -1;
536}
537
538static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count) {
539	const char* firstSpace = strchr(line, ' ');
540	size_t cmdLength;
541	if (firstSpace) {
542		cmdLength = firstSpace - line;
543	} else {
544		cmdLength = count;
545	}
546
547	const char* args = 0;
548	if (firstSpace) {
549		args = firstSpace + 1;
550	}
551	int result = _tryCommands(debugger, _debuggerCommands, line, cmdLength, args, count - cmdLength - 1);
552	if (result < 0 && debugger->system) {
553		result = _tryCommands(debugger, debugger->system->commands, line, cmdLength, args, count - cmdLength - 1);
554	}
555	if (result < 0) {
556		printf("Command not found\n");
557	}
558	return false;
559}
560
561static char* _prompt(EditLine* el) {
562	UNUSED(el);
563	return "> ";
564}
565
566static void _commandLine(struct ARMDebugger* debugger) {
567	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
568	const char* line;
569	_printStatus(cliDebugger, 0);
570	int count = 0;
571	HistEvent ev;
572	while (debugger->state == DEBUGGER_PAUSED) {
573		line = el_gets(cliDebugger->elstate, &count);
574		if (!line) {
575			debugger->state = DEBUGGER_EXITING;
576			return;
577		}
578		if (line[0] == '\n') {
579			if (history(cliDebugger->histate, &ev, H_FIRST) >= 0) {
580				_parse(cliDebugger, ev.str, strlen(ev.str) - 1);
581			}
582		} else {
583			_parse(cliDebugger, line, count - 1);
584			history(cliDebugger->histate, &ev, H_ENTER, line);
585		}
586	}
587}
588
589static void _reportEntry(struct ARMDebugger* debugger, enum DebuggerEntryReason reason) {
590	UNUSED(debugger);
591	switch (reason) {
592	case DEBUGGER_ENTER_MANUAL:
593	case DEBUGGER_ENTER_ATTACHED:
594		break;
595	case DEBUGGER_ENTER_BREAKPOINT:
596		printf("Hit breakpoint\n");
597		break;
598	case DEBUGGER_ENTER_WATCHPOINT:
599		printf("Hit watchpoint\n");
600		break;
601	case DEBUGGER_ENTER_ILLEGAL_OP:
602		printf("Hit illegal opcode\n");
603		break;
604	}
605}
606
607static unsigned char _tabComplete(EditLine* elstate, int ch) {
608	UNUSED(ch);
609	const LineInfo* li = el_line(elstate);
610	if (!li->buffer[0]) {
611		return CC_ERROR;
612	}
613
614	const char* commandPtr;
615	int cmd = 0, len = 0;
616	const char* name = 0;
617	for (commandPtr = li->buffer; commandPtr <= li->cursor; ++commandPtr, ++len) {
618		for (; (name = _debuggerCommands[cmd].name); ++cmd) {
619			int cmp = strncasecmp(name, li->buffer, len);
620			if (cmp > 0) {
621				return CC_ERROR;
622			}
623			if (cmp == 0) {
624				break;
625			}
626		}
627	}
628	if (!name) {
629		return CC_ERROR;
630	}
631	if (_debuggerCommands[cmd + 1].name && name[len - 2] == _debuggerCommands[cmd + 1].name[len - 2]) {
632		--len;
633		const char* next = 0;
634		int i;
635		for (i = cmd + 1; _debuggerCommands[i].name; ++i) {
636			if (strncasecmp(name, _debuggerCommands[i].name, len)) {
637				break;
638			}
639			next = _debuggerCommands[i].name;
640		}
641
642		for (; name[len]; ++len) {
643			if (name[len] != next[len]) {
644				break;
645			}
646			char out[2] = { name[len], '\0' };
647			el_insertstr(elstate, out);
648		}
649		return CC_REDISPLAY;
650	}
651	name += len - 1;
652	el_insertstr(elstate, name);
653	el_insertstr(elstate, " ");
654	return CC_REDISPLAY;
655}
656
657static void _cliDebuggerInit(struct ARMDebugger* debugger) {
658	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
659	// TODO: get argv[0]
660	cliDebugger->elstate = el_init(BINARY_NAME, stdin, stdout, stderr);
661	el_set(cliDebugger->elstate, EL_PROMPT, _prompt);
662	el_set(cliDebugger->elstate, EL_EDITOR, "emacs");
663
664	el_set(cliDebugger->elstate, EL_CLIENTDATA, cliDebugger);
665	el_set(cliDebugger->elstate, EL_ADDFN, "tab-complete", "Tab completion", _tabComplete);
666	el_set(cliDebugger->elstate, EL_BIND, "\t", "tab-complete", 0);
667	cliDebugger->histate = history_init();
668	HistEvent ev;
669	history(cliDebugger->histate, &ev, H_SETSIZE, 200);
670	el_set(cliDebugger->elstate, EL_HIST, history, cliDebugger->histate);
671	_activeDebugger = cliDebugger;
672	signal(SIGINT, _breakIntoDefault);
673}
674
675static void _cliDebuggerDeinit(struct ARMDebugger* debugger) {
676	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
677	history_end(cliDebugger->histate);
678	el_end(cliDebugger->elstate);
679
680	if (cliDebugger->system) {
681		cliDebugger->system->deinit(cliDebugger->system);
682		free(cliDebugger->system);
683		cliDebugger->system = 0;
684	}
685}
686
687void CLIDebuggerCreate(struct CLIDebugger* debugger) {
688	ARMDebuggerCreate(&debugger->d);
689	debugger->d.init = _cliDebuggerInit;
690	debugger->d.deinit = _cliDebuggerDeinit;
691	debugger->d.paused = _commandLine;
692	debugger->d.entered = _reportEntry;
693
694	debugger->system = 0;
695}
696
697void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSystem* system) {
698	if (debugger->system) {
699		debugger->system->deinit(debugger->system);
700		free(debugger->system);
701	}
702
703	debugger->system = system;
704	system->p = debugger;
705}