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