all repos — mgba @ c937529d4ab5bb328923cc7654de5518ce8c111e

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