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#include "linenoise.h"
14
15struct DebugVector {
16 struct DebugVector* next;
17 enum DVType {
18 ERROR_TYPE,
19 INT_TYPE,
20 CHAR_TYPE
21 } type;
22 union {
23 int32_t intValue;
24 const char* charValue;
25 };
26};
27
28static const char* ERROR_MISSING_ARGS = "Arguments missing";
29
30static struct ARMDebugger* _activeDebugger;
31
32typedef void (DebuggerComamnd)(struct ARMDebugger*, struct DebugVector*);
33
34static void _breakInto(struct ARMDebugger*, struct DebugVector*);
35static void _continue(struct ARMDebugger*, struct DebugVector*);
36static void _next(struct ARMDebugger*, struct DebugVector*);
37static void _print(struct ARMDebugger*, struct DebugVector*);
38static void _printHex(struct ARMDebugger*, struct DebugVector*);
39static void _printStatus(struct ARMDebugger*, struct DebugVector*);
40static void _quit(struct ARMDebugger*, struct DebugVector*);
41static void _readByte(struct ARMDebugger*, struct DebugVector*);
42static void _readHalfword(struct ARMDebugger*, struct DebugVector*);
43static void _readWord(struct ARMDebugger*, struct DebugVector*);
44static void _setBreakpoint(struct ARMDebugger*, struct DebugVector*);
45static void _setWatchpoint(struct ARMDebugger*, struct DebugVector*);
46
47static void _breakIntoDefault(int signal);
48
49struct {
50 const char* name;
51 DebuggerComamnd* command;
52} debuggerCommands[] = {
53 { "b", _setBreakpoint },
54 { "break", _setBreakpoint },
55 { "c", _continue },
56 { "continue", _continue },
57 { "i", _printStatus },
58 { "info", _printStatus },
59 { "n", _next },
60 { "p", _print },
61 { "print", _print },
62 { "p/x", _printHex },
63 { "print/x", _printHex },
64 { "q", _quit },
65 { "quit", _quit },
66 { "rb", _readByte },
67 { "rh", _readHalfword },
68 { "rw", _readWord },
69 { "status", _printStatus },
70 { "x", _breakInto },
71 { "w", _setWatchpoint },
72 { "watch", _setWatchpoint },
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_EXITING;
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) {
259 if (!string || !string[0]) {
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 (string[0] && string[0] != ' ' && state != PARSE_ERROR) {
268 char token = string[0];
269 ++string;
270 switch (state) {
271 case PARSE_ROOT:
272 switch (token) {
273 case 'r':
274 state = PARSE_EXPECT_REGISTER;
275 break;
276 case 'p':
277 state = PARSE_EXPECT_PC;
278 break;
279 case 's':
280 state = PARSE_EXPECT_SP;
281 break;
282 case 'l':
283 state = PARSE_EXPECT_LR;
284 break;
285 case '1':
286 case '2':
287 case '3':
288 case '4':
289 case '5':
290 case '6':
291 case '7':
292 case '8':
293 case '9':
294 state = PARSE_EXPECT_DECIMAL;
295 current = token - '0';
296 break;
297 case '0':
298 state = PARSE_EXPECT_PREFIX;
299 break;
300 case '$':
301 state = PARSE_EXPECT_HEX;
302 current = 0;
303 break;
304 default:
305 state = PARSE_ERROR;
306 break;
307 };
308 break;
309 case PARSE_EXPECT_LR:
310 switch (token) {
311 case 'r':
312 current = debugger->cpu->gprs[ARM_LR];
313 state = PARSE_EXPECT_SUFFIX;
314 break;
315 default:
316 state = PARSE_ERROR;
317 break;
318 }
319 break;
320 case PARSE_EXPECT_PC:
321 switch (token) {
322 case 'c':
323 current = debugger->cpu->gprs[ARM_PC];
324 state = PARSE_EXPECT_SUFFIX;
325 break;
326 default:
327 state = PARSE_ERROR;
328 break;
329 }
330 break;
331 case PARSE_EXPECT_SP:
332 switch (token) {
333 case 'p':
334 current = debugger->cpu->gprs[ARM_SP];
335 state = PARSE_EXPECT_SUFFIX;
336 break;
337 default:
338 state = PARSE_ERROR;
339 break;
340 }
341 break;
342 case PARSE_EXPECT_REGISTER:
343 switch (token) {
344 case '0':
345 case '2':
346 case '3':
347 case '4':
348 case '5':
349 case '6':
350 case '7':
351 case '8':
352 case '9':
353 current = debugger->cpu->gprs[token - '0'];
354 state = PARSE_EXPECT_SUFFIX;
355 break;
356 case '1':
357 state = PARSE_EXPECT_REGISTER_2;
358 break;
359 default:
360 state = PARSE_ERROR;
361 break;
362 }
363 break;
364 case PARSE_EXPECT_REGISTER_2:
365 switch (token) {
366 case '0':
367 case '1':
368 case '2':
369 case '3':
370 case '4':
371 case '5':
372 current = debugger->cpu->gprs[token - '0' + 10];
373 state = PARSE_EXPECT_SUFFIX;
374 break;
375 default:
376 state = PARSE_ERROR;
377 break;
378 }
379 break;
380 case PARSE_EXPECT_DECIMAL:
381 switch (token) {
382 case '0':
383 case '1':
384 case '2':
385 case '3':
386 case '4':
387 case '5':
388 case '6':
389 case '7':
390 case '8':
391 case '9':
392 // TODO: handle overflow
393 current *= 10;
394 current += token - '0';
395 break;
396 default:
397 state = PARSE_ERROR;
398 }
399 break;
400 case PARSE_EXPECT_HEX:
401 switch (token) {
402 case '0':
403 case '1':
404 case '2':
405 case '3':
406 case '4':
407 case '5':
408 case '6':
409 case '7':
410 case '8':
411 case '9':
412 // TODO: handle overflow
413 current *= 16;
414 current += token - '0';
415 break;
416 case 'A':
417 case 'B':
418 case 'C':
419 case 'D':
420 case 'E':
421 case 'F':
422 // TODO: handle overflow
423 current *= 16;
424 current += token - 'A' + 10;
425 break;
426 case 'a':
427 case 'b':
428 case 'c':
429 case 'd':
430 case 'e':
431 case 'f':
432 // TODO: handle overflow
433 current *= 16;
434 current += token - 'a' + 10;
435 break;
436 default:
437 state = PARSE_ERROR;
438 break;
439 }
440 break;
441 case PARSE_EXPECT_PREFIX:
442 switch (token) {
443 case 'X':
444 case 'x':
445 current = 0;
446 state = PARSE_EXPECT_HEX;
447 break;
448 default:
449 state = PARSE_ERROR;
450 break;
451 }
452 break;
453 case PARSE_EXPECT_SUFFIX:
454 // TODO
455 state = PARSE_ERROR;
456 break;
457 case PARSE_ERROR:
458 // This shouldn't be reached
459 break;
460 }
461 }
462
463 struct DebugVector* dv = malloc(sizeof(struct DebugVector));
464 if (state == PARSE_ERROR) {
465 dv->type = ERROR_TYPE;
466 dv->next = 0;
467 } else {
468 dvTemp.intValue = current;
469 *dv = dvTemp;
470 if (string[0] == ' ') {
471 dv->next = _DVParse(debugger, string + 1);
472 }
473 }
474 return dv;
475}
476
477static void _DVFree(struct DebugVector* dv) {
478 struct DebugVector* next;
479 while (dv) {
480 next = dv->next;
481 free(dv);
482 dv = next;
483 }
484}
485
486static int _parse(struct ARMDebugger* debugger, const char* line) {
487 char* firstSpace = strchr(line, ' ');
488 size_t cmdLength;
489 struct DebugVector* dv = 0;
490 if (firstSpace) {
491 cmdLength = firstSpace - line;
492 dv = _DVParse(debugger, firstSpace + 1);
493 if (dv && dv->type == ERROR_TYPE) {
494 printf("Parse error\n");
495 _DVFree(dv);
496 return 0;
497 }
498 } else {
499 cmdLength = strlen(line);
500 }
501
502 int i;
503 const char* name;
504 for (i = 0; (name = debuggerCommands[i].name); ++i) {
505 if (strlen(name) != cmdLength) {
506 continue;
507 }
508 if (strncasecmp(name, line, cmdLength) == 0) {
509 debuggerCommands[i].command(debugger, dv);
510 _DVFree(dv);
511 return 1;
512 }
513 }
514 _DVFree(dv);
515 printf("Command not found\n");
516 return 0;
517}
518
519static void _commandLine(struct ARMDebugger* debugger) {
520 char* line;
521 _printStatus(debugger, 0);
522 while (debugger->state == DEBUGGER_PAUSED) {
523 line = linenoise("> ");
524 if (!line) {
525 debugger->state = DEBUGGER_EXITING;
526 return;
527 }
528 if (!line[0]) {
529 if (debugger->lastCommand) {
530 _parse(debugger, debugger->lastCommand);
531 }
532 } else {
533 linenoiseHistoryAdd(line);
534 if (_parse(debugger, line)) {
535 char* oldLine = debugger->lastCommand;
536 debugger->lastCommand = line;
537 free(oldLine);
538 } else {
539 free(line);
540 }
541 }
542 }
543}
544
545void ARMDebuggerInit(struct ARMDebugger* debugger, struct ARMCore* cpu) {
546 debugger->cpu = cpu;
547 debugger->state = DEBUGGER_PAUSED;
548 debugger->lastCommand = 0;
549 debugger->breakpoints = 0;
550 debugger->memoryShim.p = debugger;
551 debugger->memoryShim.watchpoints = 0;
552 _activeDebugger = debugger;
553 signal(SIGINT, _breakIntoDefault);
554}
555
556void ARMDebuggerRun(struct ARMDebugger* debugger) {
557 while (debugger->state != DEBUGGER_EXITING) {
558 if (!debugger->breakpoints) {
559 while (debugger->state == DEBUGGER_RUNNING) {
560 ARMRun(debugger->cpu);
561 }
562 } else {
563 while (debugger->state == DEBUGGER_RUNNING) {
564 ARMRun(debugger->cpu);
565 _checkBreakpoints(debugger);
566 }
567 }
568 switch (debugger->state) {
569 case DEBUGGER_PAUSED:
570 _commandLine(debugger);
571 break;
572 case DEBUGGER_EXITING:
573 return;
574 default:
575 // Should never be reached
576 break;
577 }
578 }
579}
580
581void ARMDebuggerEnter(struct ARMDebugger* debugger) {
582 debugger->state = DEBUGGER_PAUSED;
583}