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