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