src/debugger/debugger.c (view raw)
1#include "debugger.h"
2
3#include "arm.h"
4
5#include <signal.h>
6#include <stdio.h>
7#include <stdarg.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11#include "linenoise.h"
12
13struct DebugVector {
14 struct DebugVector* next;
15 enum DVType {
16 ERROR_TYPE,
17 INT_TYPE,
18 CHAR_TYPE
19 } type;
20 union {
21 int32_t intValue;
22 const char* charValue;
23 };
24};
25
26struct DebugBreakpoint {
27 struct DebugBreakpoint* next;
28 int32_t address;
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*);
48
49static void _breakIntoDefault(int signal);
50
51struct {
52 const char* name;
53 DebuggerComamnd* command;
54} debuggerCommands[] = {
55 { "b", _setBreakpoint },
56 { "break", _setBreakpoint },
57 { "c", _continue },
58 { "continue", _continue },
59 { "i", _printStatus },
60 { "info", _printStatus },
61 { "n", _next },
62 { "p", _print },
63 { "print", _print },
64 { "p/x", _printHex },
65 { "print/x", _printHex },
66 { "q", _quit },
67 { "quit", _quit },
68 { "rb", _readByte },
69 { "rh", _readHalfword },
70 { "rw", _readWord },
71 { "status", _printStatus },
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);
131 printf("%08X\n", instruction);
132 } else {
133 uint16_t instruction = debugger->cpu->memory->loadU16(debugger->cpu->memory, address);
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);
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);
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);
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 _checkBreakpoints(struct ARMDebugger* debugger) {
207 struct DebugBreakpoint* breakpoint;
208 int instructionLength;
209 enum ExecutionMode mode = debugger->cpu->cpsr.t;
210 if (mode == MODE_ARM) {
211 instructionLength = WORD_SIZE_ARM;
212 } else {
213 instructionLength = WORD_SIZE_THUMB;
214 }
215 for (breakpoint = debugger->breakpoints; breakpoint; breakpoint = breakpoint->next) {
216 if (breakpoint->address + instructionLength == debugger->cpu->gprs[ARM_PC]) {
217 debugger->state = DEBUGGER_PAUSED;
218 printf("Hit breakpoint\n");
219 break;
220 }
221 }
222}
223
224static void _breakIntoDefault(int signal) {
225 (void)(signal);
226 _activeDebugger->state = DEBUGGER_PAUSED;
227}
228
229enum _DVParseState {
230 PARSE_ERROR = -1,
231 PARSE_ROOT = 0,
232 PARSE_EXPECT_REGISTER,
233 PARSE_EXPECT_REGISTER_2,
234 PARSE_EXPECT_LR,
235 PARSE_EXPECT_PC,
236 PARSE_EXPECT_SP,
237 PARSE_EXPECT_DECIMAL,
238 PARSE_EXPECT_HEX,
239 PARSE_EXPECT_PREFIX,
240 PARSE_EXPECT_SUFFIX,
241};
242
243static struct DebugVector* _DVParse(struct ARMDebugger* debugger, const char* string) {
244 if (!string || !string[0]) {
245 return 0;
246 }
247
248 enum _DVParseState state = PARSE_ROOT;
249 struct DebugVector dvTemp = { .type = INT_TYPE };
250 uint32_t current = 0;
251
252 while (string[0] && string[0] != ' ' && state != PARSE_ERROR) {
253 char token = string[0];
254 ++string;
255 switch (state) {
256 case PARSE_ROOT:
257 switch (token) {
258 case 'r':
259 state = PARSE_EXPECT_REGISTER;
260 break;
261 case 'p':
262 state = PARSE_EXPECT_PC;
263 break;
264 case 's':
265 state = PARSE_EXPECT_SP;
266 break;
267 case 'l':
268 state = PARSE_EXPECT_LR;
269 break;
270 case '1':
271 case '2':
272 case '3':
273 case '4':
274 case '5':
275 case '6':
276 case '7':
277 case '8':
278 case '9':
279 state = PARSE_EXPECT_DECIMAL;
280 current = token - '0';
281 break;
282 case '0':
283 state = PARSE_EXPECT_PREFIX;
284 break;
285 case '$':
286 state = PARSE_EXPECT_HEX;
287 current = 0;
288 break;
289 default:
290 state = PARSE_ERROR;
291 break;
292 };
293 break;
294 case PARSE_EXPECT_LR:
295 switch (token) {
296 case 'r':
297 current = debugger->cpu->gprs[ARM_LR];
298 state = PARSE_EXPECT_SUFFIX;
299 break;
300 default:
301 state = PARSE_ERROR;
302 break;
303 }
304 break;
305 case PARSE_EXPECT_PC:
306 switch (token) {
307 case 'c':
308 current = debugger->cpu->gprs[ARM_PC];
309 state = PARSE_EXPECT_SUFFIX;
310 break;
311 default:
312 state = PARSE_ERROR;
313 break;
314 }
315 break;
316 case PARSE_EXPECT_SP:
317 switch (token) {
318 case 'p':
319 current = debugger->cpu->gprs[ARM_SP];
320 state = PARSE_EXPECT_SUFFIX;
321 break;
322 default:
323 state = PARSE_ERROR;
324 break;
325 }
326 break;
327 case PARSE_EXPECT_REGISTER:
328 switch (token) {
329 case '0':
330 case '2':
331 case '3':
332 case '4':
333 case '5':
334 case '6':
335 case '7':
336 case '8':
337 case '9':
338 current = debugger->cpu->gprs[token - '0'];
339 state = PARSE_EXPECT_SUFFIX;
340 break;
341 case '1':
342 state = PARSE_EXPECT_REGISTER_2;
343 break;
344 default:
345 state = PARSE_ERROR;
346 break;
347 }
348 break;
349 case PARSE_EXPECT_REGISTER_2:
350 switch (token) {
351 case '0':
352 case '1':
353 case '2':
354 case '3':
355 case '4':
356 case '5':
357 current = debugger->cpu->gprs[token - '0' + 10];
358 state = PARSE_EXPECT_SUFFIX;
359 break;
360 default:
361 state = PARSE_ERROR;
362 break;
363 }
364 break;
365 case PARSE_EXPECT_DECIMAL:
366 switch (token) {
367 case '0':
368 case '1':
369 case '2':
370 case '3':
371 case '4':
372 case '5':
373 case '6':
374 case '7':
375 case '8':
376 case '9':
377 // TODO: handle overflow
378 current *= 10;
379 current += token - '0';
380 break;
381 default:
382 state = PARSE_ERROR;
383 }
384 break;
385 case PARSE_EXPECT_HEX:
386 switch (token) {
387 case '0':
388 case '1':
389 case '2':
390 case '3':
391 case '4':
392 case '5':
393 case '6':
394 case '7':
395 case '8':
396 case '9':
397 // TODO: handle overflow
398 current *= 16;
399 current += token - '0';
400 break;
401 case 'A':
402 case 'B':
403 case 'C':
404 case 'D':
405 case 'E':
406 case 'F':
407 // TODO: handle overflow
408 current *= 16;
409 current += token - 'A' + 10;
410 break;
411 case 'a':
412 case 'b':
413 case 'c':
414 case 'd':
415 case 'e':
416 case 'f':
417 // TODO: handle overflow
418 current *= 16;
419 current += token - 'a' + 10;
420 break;
421 default:
422 state = PARSE_ERROR;
423 break;
424 }
425 break;
426 case PARSE_EXPECT_PREFIX:
427 switch (token) {
428 case 'X':
429 case 'x':
430 current = 0;
431 state = PARSE_EXPECT_HEX;
432 break;
433 default:
434 state = PARSE_ERROR;
435 break;
436 }
437 break;
438 case PARSE_EXPECT_SUFFIX:
439 // TODO
440 state = PARSE_ERROR;
441 break;
442 case PARSE_ERROR:
443 // This shouldn't be reached
444 break;
445 }
446 }
447
448 struct DebugVector* dv = malloc(sizeof(struct DebugVector));
449 if (state == PARSE_ERROR) {
450 dv->type = ERROR_TYPE;
451 dv->next = 0;
452 } else {
453 dvTemp.intValue = current;
454 *dv = dvTemp;
455 if (string[0] == ' ') {
456 dv->next = _DVParse(debugger, string + 1);
457 }
458 }
459 return dv;
460}
461
462static void _DVFree(struct DebugVector* dv) {
463 struct DebugVector* next;
464 while (dv) {
465 next = dv->next;
466 free(dv);
467 dv = next;
468 }
469}
470
471static int _parse(struct ARMDebugger* debugger, const char* line) {
472 char* firstSpace = strchr(line, ' ');
473 size_t cmdLength;
474 struct DebugVector* dv = 0;
475 if (firstSpace) {
476 cmdLength = firstSpace - line;
477 dv = _DVParse(debugger, firstSpace + 1);
478 if (dv && dv->type == ERROR_TYPE) {
479 printf("Parse error\n");
480 _DVFree(dv);
481 return 0;
482 }
483 } else {
484 cmdLength = strlen(line);
485 }
486
487 int i;
488 const char* name;
489 for (i = 0; (name = debuggerCommands[i].name); ++i) {
490 if (strlen(name) != cmdLength) {
491 continue;
492 }
493 if (strncasecmp(name, line, cmdLength) == 0) {
494 debuggerCommands[i].command(debugger, dv);
495 _DVFree(dv);
496 return 1;
497 }
498 }
499 _DVFree(dv);
500 printf("Command not found\n");
501 return 0;
502}
503
504static void _commandLine(struct ARMDebugger* debugger) {
505 char* line;
506 _printStatus(debugger, 0);
507 while (debugger->state == DEBUGGER_PAUSED) {
508 line = linenoise("> ");
509 if (!line) {
510 debugger->state = DEBUGGER_EXITING;
511 return;
512 }
513 if (!line[0]) {
514 if (debugger->lastCommand) {
515 _parse(debugger, debugger->lastCommand);
516 }
517 } else {
518 linenoiseHistoryAdd(line);
519 if (_parse(debugger, line)) {
520 char* oldLine = debugger->lastCommand;
521 debugger->lastCommand = line;
522 free(oldLine);
523 } else {
524 free(line);
525 }
526 }
527 }
528}
529
530void ARMDebuggerInit(struct ARMDebugger* debugger, struct ARMCore* cpu) {
531 debugger->cpu = cpu;
532 debugger->state = DEBUGGER_PAUSED;
533 debugger->lastCommand = 0;
534 debugger->breakpoints = 0;
535 _activeDebugger = debugger;
536 signal(SIGINT, _breakIntoDefault);
537}
538
539void ARMDebuggerRun(struct ARMDebugger* debugger) {
540 while (debugger->state != DEBUGGER_EXITING) {
541 if (!debugger->breakpoints) {
542 while (debugger->state == DEBUGGER_RUNNING) {
543 ARMRun(debugger->cpu);
544 }
545 } else {
546 while (debugger->state == DEBUGGER_RUNNING) {
547 ARMRun(debugger->cpu);
548 _checkBreakpoints(debugger);
549 }
550 }
551 switch (debugger->state) {
552 case DEBUGGER_PAUSED:
553 _commandLine(debugger);
554 break;
555 case DEBUGGER_EXITING:
556 return;
557 default:
558 // Should never be reached
559 break;
560 }
561 }
562}
563
564void ARMDebuggerEnter(struct ARMDebugger* debugger) {
565 debugger->state = DEBUGGER_PAUSED;
566}