all repos — mgba @ 8ec961d2e84b6042d0c621ac2983f8b72986a7b2

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