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}