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