src/debugger/cli-debugger.c (view raw)
1#include "cli-debugger.h"
2#include "decoder.h"
3#include "parser.h"
4
5#include <signal.h>
6
7#ifdef USE_PTHREADS
8#include <pthread.h>
9#endif
10
11struct DebugVector {
12 struct DebugVector* next;
13 enum DVType {
14 DV_ERROR_TYPE,
15 DV_INT_TYPE,
16 DV_CHAR_TYPE
17 } type;
18 union {
19 int32_t intValue;
20 const char* charValue;
21 };
22};
23
24static const char* ERROR_MISSING_ARGS = "Arguments missing";
25
26static struct CLIDebugger* _activeDebugger;
27
28typedef void (DebuggerCommand)(struct CLIDebugger*, struct DebugVector*);
29
30static void _breakInto(struct CLIDebugger*, struct DebugVector*);
31static void _continue(struct CLIDebugger*, struct DebugVector*);
32static void _disassemble(struct CLIDebugger*, struct DebugVector*);
33static void _next(struct CLIDebugger*, struct DebugVector*);
34static void _print(struct CLIDebugger*, struct DebugVector*);
35static void _printHex(struct CLIDebugger*, struct DebugVector*);
36static void _printStatus(struct CLIDebugger*, struct DebugVector*);
37static void _quit(struct CLIDebugger*, struct DebugVector*);
38static void _readByte(struct CLIDebugger*, struct DebugVector*);
39static void _readHalfword(struct CLIDebugger*, struct DebugVector*);
40static void _readWord(struct CLIDebugger*, struct DebugVector*);
41static void _setBreakpoint(struct CLIDebugger*, struct DebugVector*);
42static void _clearBreakpoint(struct CLIDebugger*, struct DebugVector*);
43static void _setWatchpoint(struct CLIDebugger*, struct DebugVector*);
44
45static void _breakIntoDefault(int signal);
46static void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
47
48static struct {
49 const char* name;
50 DebuggerCommand* command;
51} _debuggerCommands[] = {
52 { "b", _setBreakpoint },
53 { "break", _setBreakpoint },
54 { "c", _continue },
55 { "continue", _continue },
56 { "d", _clearBreakpoint },
57 { "delete", _clearBreakpoint },
58 { "dis", _disassemble },
59 { "disasm", _disassemble },
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 UNUSED(sig);
93 printf("No debugger attached!\n");
94}
95
96static void _breakInto(struct CLIDebugger* debugger, struct DebugVector* dv) {
97 UNUSED(debugger);
98 UNUSED(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 CLIDebugger* debugger, struct DebugVector* dv) {
114 UNUSED(dv);
115 debugger->d.state = DEBUGGER_RUNNING;
116}
117
118static void _next(struct CLIDebugger* debugger, struct DebugVector* dv) {
119 UNUSED(dv);
120 ARMRun(debugger->d.cpu);
121 _printStatus(debugger, 0);
122}
123
124static void _disassemble(struct CLIDebugger* debugger, struct DebugVector* dv) {
125 uint32_t address;
126 int size;
127 int wordSize;
128 enum ExecutionMode mode = debugger->d.cpu->executionMode;
129
130 if (mode == MODE_ARM) {
131 wordSize = WORD_SIZE_ARM;
132 } else {
133 wordSize = WORD_SIZE_THUMB;
134 }
135
136 if (!dv || dv->type != DV_INT_TYPE) {
137 address = debugger->d.cpu->gprs[ARM_PC] - wordSize;
138 } else {
139 address = dv->intValue;
140 dv = dv->next;
141 }
142
143 if (!dv || dv->type != DV_INT_TYPE) {
144 size = 1;
145 } else {
146 size = dv->intValue;
147 dv = dv->next; // TODO: Check for excess args
148 }
149
150 int i;
151 for (i = 0; i < size; ++i) {
152 _printLine(debugger, address, mode);
153 address += wordSize;
154 }
155}
156
157static void _print(struct CLIDebugger* debugger, struct DebugVector* dv) {
158 UNUSED(debugger);
159 for ( ; dv; dv = dv->next) {
160 printf(" %u", dv->intValue);
161 }
162 printf("\n");
163}
164
165static void _printHex(struct CLIDebugger* debugger, struct DebugVector* dv) {
166 UNUSED(debugger);
167 for ( ; dv; dv = dv->next) {
168 printf(" 0x%08X", dv->intValue);
169 }
170 printf("\n");
171}
172
173static inline void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
174 char disassembly[48];
175 struct ARMInstructionInfo info;
176 if (mode == MODE_ARM) {
177 uint32_t instruction = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
178 ARMDecodeARM(instruction, &info);
179 ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
180 printf("%08X: %s\n", instruction, disassembly);
181 } else {
182 uint16_t instruction = debugger->d.cpu->memory.loadU16(debugger->d.cpu, address, 0);
183 ARMDecodeThumb(instruction, &info);
184 ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
185 printf("%04X: %s\n", instruction, disassembly);
186 }
187}
188
189static void _printStatus(struct CLIDebugger* debugger, struct DebugVector* dv) {
190 UNUSED(dv);
191 int r;
192 for (r = 0; r < 4; ++r) {
193 printf("%08X %08X %08X %08X\n",
194 debugger->d.cpu->gprs[r << 2],
195 debugger->d.cpu->gprs[(r << 2) + 1],
196 debugger->d.cpu->gprs[(r << 2) + 2],
197 debugger->d.cpu->gprs[(r << 2) + 3]);
198 }
199 _printPSR(debugger->d.cpu->cpsr);
200 int instructionLength;
201 enum ExecutionMode mode = debugger->d.cpu->cpsr.t;
202 if (mode == MODE_ARM) {
203 instructionLength = WORD_SIZE_ARM;
204 } else {
205 instructionLength = WORD_SIZE_THUMB;
206 }
207 _printLine(debugger, debugger->d.cpu->gprs[ARM_PC] - instructionLength, mode);
208}
209
210static void _quit(struct CLIDebugger* debugger, struct DebugVector* dv) {
211 UNUSED(dv);
212 debugger->d.state = DEBUGGER_SHUTDOWN;
213}
214
215static void _readByte(struct CLIDebugger* debugger, struct DebugVector* dv) {
216 if (!dv || dv->type != DV_INT_TYPE) {
217 printf("%s\n", ERROR_MISSING_ARGS);
218 return;
219 }
220 uint32_t address = dv->intValue;
221 uint8_t value = debugger->d.cpu->memory.loadU8(debugger->d.cpu, address, 0);
222 printf(" 0x%02X\n", value);
223}
224
225static void _readHalfword(struct CLIDebugger* debugger, struct DebugVector* dv) {
226 if (!dv || dv->type != DV_INT_TYPE) {
227 printf("%s\n", ERROR_MISSING_ARGS);
228 return;
229 }
230 uint32_t address = dv->intValue;
231 uint16_t value = debugger->d.cpu->memory.loadU16(debugger->d.cpu, address, 0);
232 printf(" 0x%04X\n", value);
233}
234
235static void _readWord(struct CLIDebugger* debugger, struct DebugVector* dv) {
236 if (!dv || dv->type != DV_INT_TYPE) {
237 printf("%s\n", ERROR_MISSING_ARGS);
238 return;
239 }
240 uint32_t address = dv->intValue;
241 uint32_t value = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
242 printf(" 0x%08X\n", value);
243}
244
245static void _setBreakpoint(struct CLIDebugger* debugger, struct DebugVector* dv) {
246 if (!dv || dv->type != DV_INT_TYPE) {
247 printf("%s\n", ERROR_MISSING_ARGS);
248 return;
249 }
250 uint32_t address = dv->intValue;
251 ARMDebuggerSetBreakpoint(&debugger->d, address);
252}
253
254static void _clearBreakpoint(struct CLIDebugger* debugger, struct DebugVector* dv) {
255 if (!dv || dv->type != DV_INT_TYPE) {
256 printf("%s\n", ERROR_MISSING_ARGS);
257 return;
258 }
259 uint32_t address = dv->intValue;
260 ARMDebuggerClearBreakpoint(&debugger->d, address);
261}
262
263static void _setWatchpoint(struct CLIDebugger* debugger, struct DebugVector* dv) {
264 if (!dv || dv->type != DV_INT_TYPE) {
265 printf("%s\n", ERROR_MISSING_ARGS);
266 return;
267 }
268 uint32_t address = dv->intValue;
269 ARMDebuggerSetWatchpoint(&debugger->d, address);
270}
271
272static void _breakIntoDefault(int signal) {
273 UNUSED(signal);
274 ARMDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL);
275}
276
277static uint32_t _performOperation(enum Operation operation, uint32_t current, uint32_t next, struct DebugVector* dv) {
278 switch (operation) {
279 case OP_ASSIGN:
280 current = next;
281 break;
282 case OP_ADD:
283 current += next;
284 break;
285 case OP_SUBTRACT:
286 current -= next;
287 break;
288 case OP_MULTIPLY:
289 current *= next;
290 break;
291 case OP_DIVIDE:
292 if (next != 0) {
293 current /= next;
294 } else {
295 dv->type = DV_ERROR_TYPE;
296 return 0;
297 }
298 break;
299 }
300 return current;
301}
302
303static uint32_t _lookupIdentifier(struct ARMDebugger* debugger, const char* name, struct DebugVector* dv) {
304 if (strcmp(name, "sp") == 0) {
305 return debugger->cpu->gprs[ARM_SP];
306 }
307 if (strcmp(name, "lr") == 0) {
308 return debugger->cpu->gprs[ARM_LR];
309 }
310 if (strcmp(name, "pc") == 0) {
311 return debugger->cpu->gprs[ARM_PC];
312 }
313 if (strcmp(name, "cpsr") == 0) {
314 return debugger->cpu->cpsr.packed;
315 }
316 // TODO: test if mode has SPSR
317 if (strcmp(name, "spsr") == 0) {
318 return debugger->cpu->spsr.packed;
319 }
320 if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') {
321 int reg = atoi(&name[1]);
322 if (reg < 16) {
323 return debugger->cpu->gprs[reg];
324 }
325 }
326 dv->type = DV_ERROR_TYPE;
327 return 0;
328}
329
330static uint32_t _evaluateParseTree(struct ARMDebugger* debugger, struct ParseTree* tree, struct DebugVector* dv) {
331 switch (tree->token.type) {
332 case TOKEN_UINT_TYPE:
333 return tree->token.uintValue;
334 case TOKEN_OPERATOR_TYPE:
335 return _performOperation(tree->token.operatorValue, _evaluateParseTree(debugger, tree->lhs, dv), _evaluateParseTree(debugger, tree->rhs, dv), dv);
336 case TOKEN_IDENTIFIER_TYPE:
337 return _lookupIdentifier(debugger, tree->token.identifierValue, dv);
338 case TOKEN_ERROR_TYPE:
339 default:
340 dv->type = DV_ERROR_TYPE;
341 }
342 return 0;
343}
344
345static struct DebugVector* _DVParse(struct CLIDebugger* debugger, const char* string, size_t length) {
346 if (!string || length < 1) {
347 return 0;
348 }
349
350 struct DebugVector dvTemp = { .type = DV_INT_TYPE };
351
352 struct LexVector lv = { .next = 0 };
353 size_t adjusted = lexExpression(&lv, string, length);
354 if (adjusted > length) {
355 dvTemp.type = DV_ERROR_TYPE;
356 lexFree(lv.next);
357 }
358
359 struct ParseTree tree;
360 parseLexedExpression(&tree, &lv);
361 if (tree.token.type == TOKEN_ERROR_TYPE) {
362 dvTemp.type = DV_ERROR_TYPE;
363 } else {
364 dvTemp.intValue = _evaluateParseTree(&debugger->d, &tree, &dvTemp);
365 }
366
367 parseFree(tree.lhs);
368 parseFree(tree.rhs);
369
370 length -= adjusted;
371 string += adjusted;
372
373 struct DebugVector* dv = malloc(sizeof(struct DebugVector));
374 if (dvTemp.type == DV_ERROR_TYPE) {
375 dv->type = DV_ERROR_TYPE;
376 dv->next = 0;
377 } else {
378 *dv = dvTemp;
379 if (string[0] == ' ') {
380 dv->next = _DVParse(debugger, string + 1, length - 1);
381 if (dv->next && dv->next->type == DV_ERROR_TYPE) {
382 dv->type = DV_ERROR_TYPE;
383 }
384 }
385 }
386 return dv;
387}
388
389static void _DVFree(struct DebugVector* dv) {
390 struct DebugVector* next;
391 while (dv) {
392 next = dv->next;
393 free(dv);
394 dv = next;
395 }
396}
397
398static int _parse(struct CLIDebugger* debugger, const char* line, size_t count) {
399 const char* firstSpace = strchr(line, ' ');
400 size_t cmdLength;
401 struct DebugVector* dv = 0;
402 if (firstSpace) {
403 cmdLength = firstSpace - line;
404 dv = _DVParse(debugger, firstSpace + 1, count - cmdLength - 1);
405 if (dv && dv->type == DV_ERROR_TYPE) {
406 printf("Parse error\n");
407 _DVFree(dv);
408 return 0;
409 }
410 } else {
411 cmdLength = count;
412 }
413
414 int i;
415 const char* name;
416 for (i = 0; (name = _debuggerCommands[i].name); ++i) {
417 if (strlen(name) != cmdLength) {
418 continue;
419 }
420 if (strncasecmp(name, line, cmdLength) == 0) {
421 _debuggerCommands[i].command(debugger, dv);
422 _DVFree(dv);
423 return 1;
424 }
425 }
426 _DVFree(dv);
427 printf("Command not found\n");
428 return 0;
429}
430
431static char* _prompt(EditLine* el) {
432 UNUSED(el);
433 return "> ";
434}
435
436static void _commandLine(struct ARMDebugger* debugger) {
437 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
438 const char* line;
439 _printStatus(cliDebugger, 0);
440 int count = 0;
441 HistEvent ev;
442 while (debugger->state == DEBUGGER_PAUSED) {
443 line = el_gets(cliDebugger->elstate, &count);
444 if (!line) {
445 debugger->state = DEBUGGER_EXITING;
446 return;
447 }
448 if (line[0] == '\n') {
449 if (history(cliDebugger->histate, &ev, H_FIRST) >= 0) {
450 _parse(cliDebugger, ev.str, strlen(ev.str) - 1);
451 }
452 } else {
453 if (_parse(cliDebugger, line, count - 1)) {
454 history(cliDebugger->histate, &ev, H_ENTER, line);
455 }
456 }
457 }
458}
459
460static void _reportEntry(struct ARMDebugger* debugger, enum DebuggerEntryReason reason) {
461 UNUSED(debugger);
462 switch (reason) {
463 case DEBUGGER_ENTER_MANUAL:
464 case DEBUGGER_ENTER_ATTACHED:
465 break;
466 case DEBUGGER_ENTER_BREAKPOINT:
467 printf("Hit breakpoint\n");
468 break;
469 case DEBUGGER_ENTER_WATCHPOINT:
470 printf("Hit watchpoint\n");
471 break;
472 case DEBUGGER_ENTER_ILLEGAL_OP:
473 printf("Hit illegal opcode\n");
474 break;
475 }
476}
477
478static unsigned char _tabComplete(EditLine* elstate, int ch) {
479 UNUSED(ch);
480 const LineInfo* li = el_line(elstate);
481 const char* commandPtr;
482 int cmd = 0, len = 0;
483 const char* name = 0;
484 for (commandPtr = li->buffer; commandPtr <= li->cursor; ++commandPtr, ++len) {
485 for (; (name = _debuggerCommands[cmd].name); ++cmd) {
486 int cmp = strncasecmp(name, li->buffer, len);
487 if (cmp > 0) {
488 return CC_ERROR;
489 }
490 if (cmp == 0) {
491 break;
492 }
493 }
494 }
495 if (_debuggerCommands[cmd + 1].name && strncasecmp(_debuggerCommands[cmd + 1].name, li->buffer, len - 1) == 0) {
496 return CC_ERROR;
497 }
498 name += len - 1;
499 el_insertstr(elstate, name);
500 el_insertstr(elstate, " ");
501 return CC_REDISPLAY;
502}
503
504static void _cliDebuggerInit(struct ARMDebugger* debugger) {
505 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
506 // TODO: get argv[0]
507 cliDebugger->elstate = el_init(BINARY_NAME, stdin, stdout, stderr);
508 el_set(cliDebugger->elstate, EL_PROMPT, _prompt);
509 el_set(cliDebugger->elstate, EL_EDITOR, "emacs");
510
511 el_set(cliDebugger->elstate, EL_CLIENTDATA, cliDebugger);
512 el_set(cliDebugger->elstate, EL_ADDFN, "tab-complete", "Tab completion", _tabComplete);
513 el_set(cliDebugger->elstate, EL_BIND, "\t", "tab-complete", 0);
514 cliDebugger->histate = history_init();
515 HistEvent ev;
516 history(cliDebugger->histate, &ev, H_SETSIZE, 200);
517 el_set(cliDebugger->elstate, EL_HIST, history, cliDebugger->histate);
518 _activeDebugger = cliDebugger;
519 signal(SIGINT, _breakIntoDefault);
520}
521
522static void _cliDebuggerDeinit(struct ARMDebugger* debugger) {
523 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
524 history_end(cliDebugger->histate);
525 el_end(cliDebugger->elstate);
526}
527
528void CLIDebuggerCreate(struct CLIDebugger* debugger) {
529 ARMDebuggerCreate(&debugger->d);
530 debugger->d.init = _cliDebuggerInit;
531 debugger->d.deinit = _cliDebuggerDeinit;
532 debugger->d.paused = _commandLine;
533 debugger->d.entered = _reportEntry;
534}