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