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}