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