all repos — mgba @ 834395d5d92b614795088a789d2bdf97eb24375e

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