src/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 <strings.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
33typedef void (DebuggerComamnd)(struct ARMDebugger*, struct DebugVector*);
34
35static void _breakInto(struct ARMDebugger*, struct DebugVector*);
36static void _continue(struct ARMDebugger*, struct DebugVector*);
37static void _next(struct ARMDebugger*, struct DebugVector*);
38static void _print(struct ARMDebugger*, struct DebugVector*);
39static void _printHex(struct ARMDebugger*, struct DebugVector*);
40static void _printStatus(struct ARMDebugger*, struct DebugVector*);
41static void _quit(struct ARMDebugger*, struct DebugVector*);
42static void _readByte(struct ARMDebugger*, struct DebugVector*);
43static void _readHalfword(struct ARMDebugger*, struct DebugVector*);
44static void _readWord(struct ARMDebugger*, struct DebugVector*);
45static void _setBreakpoint(struct ARMDebugger*, struct DebugVector*);
46
47struct {
48 const char* name;
49 DebuggerComamnd* command;
50} debuggerCommands[] = {
51 { "b", _setBreakpoint },
52 { "break", _setBreakpoint },
53 { "c", _continue },
54 { "continue", _continue },
55 { "i", _printStatus },
56 { "info", _printStatus },
57 { "n", _next },
58 { "p", _print },
59 { "print", _print },
60 { "p/x", _printHex },
61 { "print/x", _printHex },
62 { "q", _quit },
63 { "quit", _quit },
64 { "rb", _readByte },
65 { "rh", _readHalfword },
66 { "rw", _readWord },
67 { "status", _printStatus },
68 { "x", _breakInto },
69 { 0, 0 }
70};
71
72static inline void _printPSR(union PSR psr) {
73 printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed,
74 psr.n ? 'N' : '-',
75 psr.z ? 'Z' : '-',
76 psr.c ? 'C' : '-',
77 psr.v ? 'V' : '-',
78 psr.i ? 'I' : '-',
79 psr.f ? 'F' : '-',
80 psr.t ? 'T' : '-');
81}
82
83static void _handleDeath(int sig) {
84 (void)(sig);
85 printf("No debugger attached!\n");
86}
87
88static void _breakInto(struct ARMDebugger* debugger, struct DebugVector* dv) {
89 (void)(debugger);
90 (void)(dv);
91 sig_t oldSignal = signal(SIGTRAP, _handleDeath);
92 kill(getpid(), SIGTRAP);
93 signal(SIGTRAP, oldSignal);
94}
95
96static void _continue(struct ARMDebugger* debugger, struct DebugVector* dv) {
97 (void)(dv);
98 debugger->state = DEBUGGER_RUNNING;
99}
100
101static void _next(struct ARMDebugger* debugger, struct DebugVector* dv) {
102 (void)(dv);
103 ARMRun(debugger->cpu);
104 _printStatus(debugger, 0);
105}
106
107static void _print(struct ARMDebugger* debugger, struct DebugVector* dv) {
108 (void)(debugger);
109 for ( ; dv; dv = dv->next) {
110 printf(" %u", dv->intValue);
111 }
112 printf("\n");
113}
114
115static void _printHex(struct ARMDebugger* debugger, struct DebugVector* dv) {
116 (void)(debugger);
117 for ( ; dv; dv = dv->next) {
118 printf(" 0x%08X", dv->intValue);
119 }
120 printf("\n");
121}
122
123static inline void _printLine(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
124 // TODO: write a disassembler
125 if (mode == MODE_ARM) {
126 uint32_t instruction = debugger->cpu->memory->load32(debugger->cpu->memory, address);
127 printf("%08X\n", instruction);
128 } else {
129 uint16_t instruction = debugger->cpu->memory->loadU16(debugger->cpu->memory, address);
130 printf("%04X\n", instruction);
131 }
132}
133
134static void _printStatus(struct ARMDebugger* debugger, struct DebugVector* dv) {
135 (void)(dv);
136 int r;
137 for (r = 0; r < 4; ++r) {
138 printf("%08X %08X %08X %08X\n",
139 debugger->cpu->gprs[r << 2],
140 debugger->cpu->gprs[(r << 2) + 1],
141 debugger->cpu->gprs[(r << 2) + 2],
142 debugger->cpu->gprs[(r << 2) + 3]);
143 }
144 _printPSR(debugger->cpu->cpsr);
145 int instructionLength;
146 enum ExecutionMode mode = debugger->cpu->cpsr.t;
147 if (mode == MODE_ARM) {
148 instructionLength = WORD_SIZE_ARM;
149 } else {
150 instructionLength = WORD_SIZE_THUMB;
151 }
152 _printLine(debugger, debugger->cpu->gprs[ARM_PC] - instructionLength, mode);
153}
154
155static void _quit(struct ARMDebugger* debugger, struct DebugVector* dv) {
156 (void)(dv);
157 debugger->state = DEBUGGER_EXITING;
158}
159
160static void _readByte(struct ARMDebugger* debugger, struct DebugVector* dv) {
161 if (!dv || dv->type != INT_TYPE) {
162 printf("%s\n", ERROR_MISSING_ARGS);
163 return;
164 }
165 uint32_t address = dv->intValue;
166 uint8_t value = debugger->cpu->memory->loadU8(debugger->cpu->memory, address);
167 printf(" 0x%02X\n", value);
168}
169
170static void _readHalfword(struct ARMDebugger* debugger, struct DebugVector* dv) {
171 if (!dv || dv->type != INT_TYPE) {
172 printf("%s\n", ERROR_MISSING_ARGS);
173 return;
174 }
175 uint32_t address = dv->intValue;
176 uint16_t value = debugger->cpu->memory->loadU16(debugger->cpu->memory, address);
177 printf(" 0x%04X\n", value);
178}
179
180static void _readWord(struct ARMDebugger* debugger, struct DebugVector* dv) {
181 if (!dv || dv->type != INT_TYPE) {
182 printf("%s\n", ERROR_MISSING_ARGS);
183 return;
184 }
185 uint32_t address = dv->intValue;
186 uint32_t value = debugger->cpu->memory->load32(debugger->cpu->memory, address);
187 printf(" 0x%08X\n", value);
188}
189
190static void _setBreakpoint(struct ARMDebugger* debugger, struct DebugVector* dv) {
191 if (!dv || dv->type != INT_TYPE) {
192 printf("%s\n", ERROR_MISSING_ARGS);
193 return;
194 }
195 uint32_t address = dv->intValue;
196 struct DebugBreakpoint* breakpoint = malloc(sizeof(struct DebugBreakpoint));
197 breakpoint->address = address;
198 breakpoint->next = debugger->breakpoints;
199 debugger->breakpoints = breakpoint;
200}
201
202static void _checkBreakpoints(struct ARMDebugger* debugger) {
203 struct DebugBreakpoint* breakpoint;
204 int instructionLength;
205 enum ExecutionMode mode = debugger->cpu->cpsr.t;
206 if (mode == MODE_ARM) {
207 instructionLength = WORD_SIZE_ARM;
208 } else {
209 instructionLength = WORD_SIZE_THUMB;
210 }
211 for (breakpoint = debugger->breakpoints; breakpoint; breakpoint = breakpoint->next) {
212 if (breakpoint->address + instructionLength == debugger->cpu->gprs[ARM_PC]) {
213 debugger->state = DEBUGGER_PAUSED;
214 printf("Hit breakpoint\n");
215 break;
216 }
217 }
218}
219
220enum _DVParseState {
221 PARSE_ERROR = -1,
222 PARSE_ROOT = 0,
223 PARSE_EXPECT_REGISTER,
224 PARSE_EXPECT_REGISTER_2,
225 PARSE_EXPECT_LR,
226 PARSE_EXPECT_PC,
227 PARSE_EXPECT_SP,
228 PARSE_EXPECT_DECIMAL,
229 PARSE_EXPECT_HEX,
230 PARSE_EXPECT_PREFIX,
231 PARSE_EXPECT_SUFFIX,
232};
233
234static struct DebugVector* _DVParse(struct ARMDebugger* debugger, const char* string) {
235 if (!string || !string[0]) {
236 return 0;
237 }
238
239 enum _DVParseState state = PARSE_ROOT;
240 struct DebugVector dvTemp = { .type = INT_TYPE };
241 uint32_t current = 0;
242
243 while (string[0] && string[0] != ' ' && state != PARSE_ERROR) {
244 char token = string[0];
245 ++string;
246 switch (state) {
247 case PARSE_ROOT:
248 switch (token) {
249 case 'r':
250 state = PARSE_EXPECT_REGISTER;
251 break;
252 case 'p':
253 state = PARSE_EXPECT_PC;
254 break;
255 case 's':
256 state = PARSE_EXPECT_SP;
257 break;
258 case 'l':
259 state = PARSE_EXPECT_LR;
260 break;
261 case '1':
262 case '2':
263 case '3':
264 case '4':
265 case '5':
266 case '6':
267 case '7':
268 case '8':
269 case '9':
270 state = PARSE_EXPECT_DECIMAL;
271 current = token - '0';
272 break;
273 case '0':
274 state = PARSE_EXPECT_PREFIX;
275 break;
276 case '$':
277 state = PARSE_EXPECT_HEX;
278 current = 0;
279 break;
280 default:
281 state = PARSE_ERROR;
282 break;
283 };
284 break;
285 case PARSE_EXPECT_LR:
286 switch (token) {
287 case 'r':
288 current = debugger->cpu->gprs[ARM_LR];
289 state = PARSE_EXPECT_SUFFIX;
290 break;
291 default:
292 state = PARSE_ERROR;
293 break;
294 }
295 break;
296 case PARSE_EXPECT_PC:
297 switch (token) {
298 case 'c':
299 current = debugger->cpu->gprs[ARM_PC];
300 state = PARSE_EXPECT_SUFFIX;
301 break;
302 default:
303 state = PARSE_ERROR;
304 break;
305 }
306 break;
307 case PARSE_EXPECT_SP:
308 switch (token) {
309 case 'p':
310 current = debugger->cpu->gprs[ARM_SP];
311 state = PARSE_EXPECT_SUFFIX;
312 break;
313 default:
314 state = PARSE_ERROR;
315 break;
316 }
317 break;
318 case PARSE_EXPECT_REGISTER:
319 switch (token) {
320 case '0':
321 case '2':
322 case '3':
323 case '4':
324 case '5':
325 case '6':
326 case '7':
327 case '8':
328 case '9':
329 current = debugger->cpu->gprs[token - '0'];
330 state = PARSE_EXPECT_SUFFIX;
331 break;
332 case '1':
333 state = PARSE_EXPECT_REGISTER_2;
334 break;
335 default:
336 state = PARSE_ERROR;
337 break;
338 }
339 break;
340 case PARSE_EXPECT_REGISTER_2:
341 switch (token) {
342 case '0':
343 case '1':
344 case '2':
345 case '3':
346 case '4':
347 case '5':
348 current = debugger->cpu->gprs[token - '0' + 10];
349 state = PARSE_EXPECT_SUFFIX;
350 break;
351 default:
352 state = PARSE_ERROR;
353 break;
354 }
355 break;
356 case PARSE_EXPECT_DECIMAL:
357 switch (token) {
358 case '0':
359 case '1':
360 case '2':
361 case '3':
362 case '4':
363 case '5':
364 case '6':
365 case '7':
366 case '8':
367 case '9':
368 // TODO: handle overflow
369 current *= 10;
370 current += token - '0';
371 break;
372 default:
373 state = PARSE_ERROR;
374 }
375 break;
376 case PARSE_EXPECT_HEX:
377 switch (token) {
378 case '0':
379 case '1':
380 case '2':
381 case '3':
382 case '4':
383 case '5':
384 case '6':
385 case '7':
386 case '8':
387 case '9':
388 // TODO: handle overflow
389 current *= 16;
390 current += token - '0';
391 break;
392 case 'A':
393 case 'B':
394 case 'C':
395 case 'D':
396 case 'E':
397 case 'F':
398 // TODO: handle overflow
399 current *= 16;
400 current += token - 'A' + 10;
401 break;
402 case 'a':
403 case 'b':
404 case 'c':
405 case 'd':
406 case 'e':
407 case 'f':
408 // TODO: handle overflow
409 current *= 16;
410 current += token - 'a' + 10;
411 break;
412 default:
413 state = PARSE_ERROR;
414 break;
415 }
416 break;
417 case PARSE_EXPECT_PREFIX:
418 switch (token) {
419 case 'X':
420 case 'x':
421 current = 0;
422 state = PARSE_EXPECT_HEX;
423 break;
424 default:
425 state = PARSE_ERROR;
426 break;
427 }
428 break;
429 case PARSE_EXPECT_SUFFIX:
430 // TODO
431 state = PARSE_ERROR;
432 break;
433 case PARSE_ERROR:
434 // This shouldn't be reached
435 break;
436 }
437 }
438
439 struct DebugVector* dv = malloc(sizeof(struct DebugVector));
440 if (state == PARSE_ERROR) {
441 dv->type = ERROR_TYPE;
442 dv->next = 0;
443 } else {
444 dvTemp.intValue = current;
445 *dv = dvTemp;
446 if (string[0] == ' ') {
447 dv->next = _DVParse(debugger, string + 1);
448 }
449 }
450 return dv;
451}
452
453static void _DVFree(struct DebugVector* dv) {
454 struct DebugVector* next;
455 while (dv) {
456 next = dv->next;
457 free(dv);
458 dv = next;
459 }
460}
461
462static int _parse(struct ARMDebugger* debugger, const char* line) {
463 char* firstSpace = strchr(line, ' ');
464 size_t cmdLength;
465 struct DebugVector* dv = 0;
466 if (firstSpace) {
467 cmdLength = firstSpace - line;
468 dv = _DVParse(debugger, firstSpace + 1);
469 if (dv->type == ERROR_TYPE) {
470 printf("Parse error\n");
471 _DVFree(dv);
472 return 0;
473 }
474 } else {
475 cmdLength = strlen(line);
476 }
477
478 int i;
479 const char* name;
480 for (i = 0; (name = debuggerCommands[i].name); ++i) {
481 if (strlen(name) != cmdLength) {
482 continue;
483 }
484 if (strncasecmp(name, line, cmdLength) == 0) {
485 debuggerCommands[i].command(debugger, dv);
486 _DVFree(dv);
487 return 1;
488 }
489 }
490 _DVFree(dv);
491 printf("Command not found\n");
492 return 0;
493}
494
495static void _commandLine(struct ARMDebugger* debugger) {
496 char* line;
497 _printStatus(debugger, 0);
498 while (debugger->state == DEBUGGER_PAUSED) {
499 line = linenoise("> ");
500 if (!line) {
501 debugger->state = DEBUGGER_EXITING;
502 return;
503 }
504 if (!line[0]) {
505 if (debugger->lastCommand) {
506 _parse(debugger, debugger->lastCommand);
507 }
508 } else {
509 linenoiseHistoryAdd(line);
510 if (_parse(debugger, line)) {
511 char* oldLine = debugger->lastCommand;
512 debugger->lastCommand = line;
513 free(oldLine);
514 } else {
515 free(line);
516 }
517 }
518 }
519}
520
521void ARMDebuggerInit(struct ARMDebugger* debugger, struct ARMCore* cpu) {
522 debugger->cpu = cpu;
523 debugger->state = DEBUGGER_PAUSED;
524 debugger->lastCommand = 0;
525 debugger->breakpoints = 0;
526}
527
528void ARMDebuggerRun(struct ARMDebugger* debugger) {
529 while (debugger->state != DEBUGGER_EXITING) {
530 if (!debugger->breakpoints) {
531 while (debugger->state == DEBUGGER_RUNNING) {
532 ARMRun(debugger->cpu);
533 }
534 } else {
535 while (debugger->state == DEBUGGER_RUNNING) {
536 ARMRun(debugger->cpu);
537 _checkBreakpoints(debugger);
538 }
539 }
540 switch (debugger->state) {
541 case DEBUGGER_PAUSED:
542 _commandLine(debugger);
543 break;
544 case DEBUGGER_EXITING:
545 return;
546 default:
547 // Should never be reached
548 break;
549 }
550 }
551}
552
553void ARMDebuggerEnter(struct ARMDebugger* debugger) {
554 debugger->state = DEBUGGER_PAUSED;
555}