all repos — mgba @ 15ef638f9506694bfb48a73f6861d9fdd21ae36e

mGBA Game Boy Advance Emulator

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

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