all repos — mgba @ e7fa65f876fda26e6ea9b223b83de929fdd2b6c5

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