src/debugger/cli-debugger.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "cli-debugger.h"
7#include "decoder.h"
8#include "parser.h"
9
10#include <signal.h>
11
12#ifdef USE_PTHREADS
13#include <pthread.h>
14#endif
15
16static const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
17static const char* ERROR_OVERFLOW = "Arguments overflow";
18
19static struct CLIDebugger* _activeDebugger;
20
21static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
22static void _continue(struct CLIDebugger*, struct CLIDebugVector*);
23static void _disassemble(struct CLIDebugger*, struct CLIDebugVector*);
24static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*);
25static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*);
26static void _next(struct CLIDebugger*, struct CLIDebugVector*);
27static void _print(struct CLIDebugger*, struct CLIDebugVector*);
28static void _printBin(struct CLIDebugger*, struct CLIDebugVector*);
29static void _printHex(struct CLIDebugger*, struct CLIDebugVector*);
30static void _printStatus(struct CLIDebugger*, struct CLIDebugVector*);
31static void _printHelp(struct CLIDebugger*, struct CLIDebugVector*);
32static void _quit(struct CLIDebugger*, struct CLIDebugVector*);
33static void _readByte(struct CLIDebugger*, struct CLIDebugVector*);
34static void _reset(struct CLIDebugger*, struct CLIDebugVector*);
35static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
36static void _readWord(struct CLIDebugger*, struct CLIDebugVector*);
37static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
38static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
39static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
40static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*);
41static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*);
42static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*);
43
44static void _breakIntoDefault(int signal);
45static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode);
46static void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
47
48static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
49 { "b", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
50 { "break", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
51 { "c", _continue, 0, "Continue execution" },
52 { "continue", _continue, 0, "Continue execution" },
53 { "d", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
54 { "delete", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
55 { "dis", _disassemble, CLIDVParse, "Disassemble instructions" },
56 { "dis/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
57 { "dis/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
58 { "disasm", _disassemble, CLIDVParse, "Disassemble instructions" },
59 { "disasm/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
60 { "disasm/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
61 { "disassemble", _disassemble, CLIDVParse, "Disassemble instructions" },
62 { "disassemble/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
63 { "disassemble/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
64 { "h", _printHelp, CLIDVStringParse, "Print help" },
65 { "help", _printHelp, CLIDVStringParse, "Print help" },
66 { "i", _printStatus, 0, "Print the current status" },
67 { "info", _printStatus, 0, "Print the current status" },
68 { "n", _next, 0, "Execute next instruction" },
69 { "next", _next, 0, "Execute next instruction" },
70 { "p", _print, CLIDVParse, "Print a value" },
71 { "p/t", _printBin, CLIDVParse, "Print a value as binary" },
72 { "p/x", _printHex, CLIDVParse, "Print a value as hexadecimal" },
73 { "print", _print, CLIDVParse, "Print a value" },
74 { "print/t", _printBin, CLIDVParse, "Print a value as binary" },
75 { "print/x", _printHex, CLIDVParse, "Print a value as hexadecimal" },
76 { "q", _quit, 0, "Quit the emulator" },
77 { "quit", _quit, 0, "Quit the emulator" },
78 { "rb", _readByte, CLIDVParse, "Read a byte from a specified offset" },
79 { "reset", _reset, 0, "Reset the emulation" },
80 { "rh", _readHalfword, CLIDVParse, "Read a halfword from a specified offset" },
81 { "rw", _readWord, CLIDVParse, "Read a word from a specified offset" },
82 { "status", _printStatus, 0, "Print the current status" },
83 { "w", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
84 { "watch", _setWatchpoint, CLIDVParse, "Set a watchpoint" },
85 { "wb", _writeByte, CLIDVParse, "Write a byte at a specified offset" },
86 { "wh", _writeHalfword, CLIDVParse, "Write a halfword at a specified offset" },
87 { "ww", _writeWord, CLIDVParse, "Write a word at a specified offset" },
88 { "x", _breakInto, 0, "Break into attached debugger (for developers)" },
89 { 0, 0, 0, 0 }
90};
91
92static inline void _printPSR(union PSR psr) {
93 printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed,
94 psr.n ? 'N' : '-',
95 psr.z ? 'Z' : '-',
96 psr.c ? 'C' : '-',
97 psr.v ? 'V' : '-',
98 psr.i ? 'I' : '-',
99 psr.f ? 'F' : '-',
100 psr.t ? 'T' : '-');
101}
102
103static void _handleDeath(int sig) {
104 UNUSED(sig);
105 printf("No debugger attached!\n");
106}
107
108static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
109 UNUSED(debugger);
110 UNUSED(dv);
111 struct sigaction sa, osa;
112 sa.sa_handler = _handleDeath;
113 sigemptyset(&sa.sa_mask);
114 sigaddset(&sa.sa_mask, SIGTRAP);
115 sa.sa_flags = SA_RESTART;
116 sigaction(SIGTRAP, &sa, &osa);
117#ifdef USE_PTHREADS
118 pthread_kill(pthread_self(), SIGTRAP);
119#else
120 kill(getpid(), SIGTRAP);
121#endif
122 sigaction(SIGTRAP, &osa, 0);
123}
124
125static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
126 UNUSED(dv);
127 debugger->d.state = DEBUGGER_RUNNING;
128}
129
130static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
131 UNUSED(dv);
132 ARMRun(debugger->d.cpu);
133 _printStatus(debugger, 0);
134}
135
136static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
137 _disassembleMode(debugger, dv, debugger->d.cpu->executionMode);
138}
139
140static void _disassembleArm(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
141 _disassembleMode(debugger, dv, MODE_ARM);
142}
143
144static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
145 _disassembleMode(debugger, dv, MODE_THUMB);
146}
147
148static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) {
149 uint32_t address;
150 int size;
151 int wordSize;
152
153 if (mode == MODE_ARM) {
154 wordSize = WORD_SIZE_ARM;
155 } else {
156 wordSize = WORD_SIZE_THUMB;
157 }
158
159 if (!dv || dv->type != CLIDV_INT_TYPE) {
160 address = debugger->d.cpu->gprs[ARM_PC] - wordSize;
161 } else {
162 address = dv->intValue;
163 dv = dv->next;
164 }
165
166 if (!dv || dv->type != CLIDV_INT_TYPE) {
167 size = 1;
168 } else {
169 size = dv->intValue;
170 dv = dv->next; // TODO: Check for excess args
171 }
172
173 int i;
174 for (i = 0; i < size; ++i) {
175 _printLine(debugger, address, mode);
176 address += wordSize;
177 }
178}
179
180static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
181 UNUSED(debugger);
182 for ( ; dv; dv = dv->next) {
183 printf(" %u", dv->intValue);
184 }
185 printf("\n");
186}
187
188static void _printBin(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
189 UNUSED(debugger);
190 for ( ; dv; dv = dv->next) {
191 printf(" 0b");
192 int i = 32;
193 while (i--) {
194 printf("%u", (dv->intValue >> i) & 1);
195 }
196 }
197 printf("\n");
198}
199
200static void _printHex(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
201 UNUSED(debugger);
202 for ( ; dv; dv = dv->next) {
203 printf(" 0x%08X", dv->intValue);
204 }
205 printf("\n");
206}
207
208static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
209 UNUSED(debugger);
210 UNUSED(dv);
211 if (!dv) {
212 puts("ARM commands:");
213 int i;
214 for (i = 0; _debuggerCommands[i].name; ++i) {
215 printf("%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary);
216 }
217 if (debugger->system) {
218 printf("%s commands:\n", debugger->system->name);
219 for (i = 0; debugger->system->commands[i].name; ++i) {
220 printf("%-10s %s\n", debugger->system->commands[i].name, debugger->system->commands[i].summary);
221 }
222 }
223 } else {
224 int i;
225 for (i = 0; _debuggerCommands[i].name; ++i) {
226 if (strcmp(_debuggerCommands[i].name, dv->charValue) == 0) {
227 printf(" %s\n", _debuggerCommands[i].summary);
228 }
229 }
230 if (debugger->system) {
231 printf("\n%s commands:\n", debugger->system->name);
232 for (i = 0; debugger->system->commands[i].name; ++i) {
233 if (strcmp(debugger->system->commands[i].name, dv->charValue) == 0) {
234 printf(" %s\n", debugger->system->commands[i].summary);
235 }
236 }
237 }
238 }
239}
240
241static inline void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
242 char disassembly[48];
243 struct ARMInstructionInfo info;
244 printf("%08X: ", address);
245 if (mode == MODE_ARM) {
246 uint32_t instruction = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
247 ARMDecodeARM(instruction, &info);
248 ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
249 printf("%08X\t%s\n", instruction, disassembly);
250 } else {
251 uint16_t instruction = debugger->d.cpu->memory.loadU16(debugger->d.cpu, address, 0);
252 ARMDecodeThumb(instruction, &info);
253 ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
254 printf("%04X\t%s\n", instruction, disassembly);
255 }
256}
257
258static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
259 UNUSED(dv);
260 int r;
261 for (r = 0; r < 4; ++r) {
262 printf("%08X %08X %08X %08X\n",
263 debugger->d.cpu->gprs[r << 2],
264 debugger->d.cpu->gprs[(r << 2) + 1],
265 debugger->d.cpu->gprs[(r << 2) + 2],
266 debugger->d.cpu->gprs[(r << 2) + 3]);
267 }
268 _printPSR(debugger->d.cpu->cpsr);
269 int instructionLength;
270 enum ExecutionMode mode = debugger->d.cpu->cpsr.t;
271 if (mode == MODE_ARM) {
272 instructionLength = WORD_SIZE_ARM;
273 } else {
274 instructionLength = WORD_SIZE_THUMB;
275 }
276 _printLine(debugger, debugger->d.cpu->gprs[ARM_PC] - instructionLength, mode);
277}
278
279static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
280 UNUSED(dv);
281 debugger->d.state = DEBUGGER_SHUTDOWN;
282}
283
284static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
285 if (!dv || dv->type != CLIDV_INT_TYPE) {
286 printf("%s\n", ERROR_MISSING_ARGS);
287 return;
288 }
289 uint32_t address = dv->intValue;
290 uint8_t value = debugger->d.cpu->memory.loadU8(debugger->d.cpu, address, 0);
291 printf(" 0x%02X\n", value);
292}
293
294static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
295 UNUSED(dv);
296 ARMReset(debugger->d.cpu);
297 _printStatus(debugger, 0);
298}
299
300static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
301 if (!dv || dv->type != CLIDV_INT_TYPE) {
302 printf("%s\n", ERROR_MISSING_ARGS);
303 return;
304 }
305 uint32_t address = dv->intValue;
306 uint16_t value = debugger->d.cpu->memory.loadU16(debugger->d.cpu, address, 0);
307 printf(" 0x%04X\n", value);
308}
309
310static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
311 if (!dv || dv->type != CLIDV_INT_TYPE) {
312 printf("%s\n", ERROR_MISSING_ARGS);
313 return;
314 }
315 uint32_t address = dv->intValue;
316 uint32_t value = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
317 printf(" 0x%08X\n", value);
318}
319
320static void _writeByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
321 if (!dv || dv->type != CLIDV_INT_TYPE) {
322 printf("%s\n", ERROR_MISSING_ARGS);
323 return;
324 }
325 if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
326 printf("%s\n", ERROR_MISSING_ARGS);
327 return;
328 }
329 uint32_t address = dv->intValue;
330 uint32_t value = dv->next->intValue;
331 if (value > 0xFF) {
332 printf("%s\n", ERROR_OVERFLOW);
333 return;
334 }
335 debugger->d.cpu->memory.store8(debugger->d.cpu, address, value, 0);
336}
337
338static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
339 if (!dv || dv->type != CLIDV_INT_TYPE) {
340 printf("%s\n", ERROR_MISSING_ARGS);
341 return;
342 }
343 if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
344 printf("%s\n", ERROR_MISSING_ARGS);
345 return;
346 }
347 uint32_t address = dv->intValue;
348 uint32_t value = dv->next->intValue;
349 if (value > 0xFFFF) {
350 printf("%s\n", ERROR_OVERFLOW);
351 return;
352 }
353 debugger->d.cpu->memory.store16(debugger->d.cpu, address, value, 0);
354}
355
356static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
357 if (!dv || dv->type != CLIDV_INT_TYPE) {
358 printf("%s\n", ERROR_MISSING_ARGS);
359 return;
360 }
361 if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
362 printf("%s\n", ERROR_MISSING_ARGS);
363 return;
364 }
365 uint32_t address = dv->intValue;
366 uint32_t value = dv->next->intValue;
367 debugger->d.cpu->memory.store32(debugger->d.cpu, address, value, 0);
368}
369
370static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
371 if (!dv || dv->type != CLIDV_INT_TYPE) {
372 printf("%s\n", ERROR_MISSING_ARGS);
373 return;
374 }
375 uint32_t address = dv->intValue;
376 ARMDebuggerSetBreakpoint(&debugger->d, address);
377}
378
379static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
380 if (!dv || dv->type != CLIDV_INT_TYPE) {
381 printf("%s\n", ERROR_MISSING_ARGS);
382 return;
383 }
384 uint32_t address = dv->intValue;
385 ARMDebuggerClearBreakpoint(&debugger->d, address);
386}
387
388static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
389 if (!dv || dv->type != CLIDV_INT_TYPE) {
390 printf("%s\n", ERROR_MISSING_ARGS);
391 return;
392 }
393 uint32_t address = dv->intValue;
394 ARMDebuggerSetWatchpoint(&debugger->d, address);
395}
396
397static void _breakIntoDefault(int signal) {
398 UNUSED(signal);
399 ARMDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL);
400}
401
402static uint32_t _performOperation(enum Operation operation, uint32_t current, uint32_t next, struct CLIDebugVector* dv) {
403 switch (operation) {
404 case OP_ASSIGN:
405 current = next;
406 break;
407 case OP_ADD:
408 current += next;
409 break;
410 case OP_SUBTRACT:
411 current -= next;
412 break;
413 case OP_MULTIPLY:
414 current *= next;
415 break;
416 case OP_DIVIDE:
417 if (next != 0) {
418 current /= next;
419 } else {
420 dv->type = CLIDV_ERROR_TYPE;
421 return 0;
422 }
423 break;
424 }
425 return current;
426}
427
428static uint32_t _lookupIdentifier(struct ARMDebugger* debugger, const char* name, struct CLIDebugVector* dv) {
429 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
430 if (strcmp(name, "sp") == 0) {
431 return debugger->cpu->gprs[ARM_SP];
432 }
433 if (strcmp(name, "lr") == 0) {
434 return debugger->cpu->gprs[ARM_LR];
435 }
436 if (strcmp(name, "pc") == 0) {
437 return debugger->cpu->gprs[ARM_PC];
438 }
439 if (strcmp(name, "cpsr") == 0) {
440 return debugger->cpu->cpsr.packed;
441 }
442 // TODO: test if mode has SPSR
443 if (strcmp(name, "spsr") == 0) {
444 return debugger->cpu->spsr.packed;
445 }
446 if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') {
447 int reg = atoi(&name[1]);
448 if (reg < 16) {
449 return debugger->cpu->gprs[reg];
450 }
451 }
452 if (cliDebugger->system) {
453 uint32_t value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv);
454 if (dv->type != CLIDV_ERROR_TYPE) {
455 return value;
456 }
457 } else {
458 dv->type = CLIDV_ERROR_TYPE;
459 }
460 return 0;
461}
462
463static uint32_t _evaluateParseTree(struct ARMDebugger* debugger, struct ParseTree* tree, struct CLIDebugVector* dv) {
464 switch (tree->token.type) {
465 case TOKEN_UINT_TYPE:
466 return tree->token.uintValue;
467 case TOKEN_OPERATOR_TYPE:
468 return _performOperation(tree->token.operatorValue, _evaluateParseTree(debugger, tree->lhs, dv), _evaluateParseTree(debugger, tree->rhs, dv), dv);
469 case TOKEN_IDENTIFIER_TYPE:
470 return _lookupIdentifier(debugger, tree->token.identifierValue, dv);
471 case TOKEN_ERROR_TYPE:
472 default:
473 dv->type = CLIDV_ERROR_TYPE;
474 }
475 return 0;
476}
477
478struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* string, size_t length) {
479 if (!string || length < 1) {
480 return 0;
481 }
482
483 struct CLIDebugVector dvTemp = { .type = CLIDV_INT_TYPE };
484
485 struct LexVector lv = { .next = 0 };
486 size_t adjusted = lexExpression(&lv, string, length);
487 if (adjusted > length) {
488 dvTemp.type = CLIDV_ERROR_TYPE;
489 lexFree(lv.next);
490 }
491
492 struct ParseTree tree;
493 parseLexedExpression(&tree, &lv);
494 if (tree.token.type == TOKEN_ERROR_TYPE) {
495 dvTemp.type = CLIDV_ERROR_TYPE;
496 } else {
497 dvTemp.intValue = _evaluateParseTree(&debugger->d, &tree, &dvTemp);
498 }
499
500 parseFree(tree.lhs);
501 parseFree(tree.rhs);
502
503 length -= adjusted;
504 string += adjusted;
505
506 struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
507 if (dvTemp.type == CLIDV_ERROR_TYPE) {
508 dv->type = CLIDV_ERROR_TYPE;
509 dv->next = 0;
510 } else {
511 *dv = dvTemp;
512 if (string[0] == ' ') {
513 dv->next = CLIDVParse(debugger, string + 1, length - 1);
514 if (dv->next && dv->next->type == CLIDV_ERROR_TYPE) {
515 dv->type = CLIDV_ERROR_TYPE;
516 }
517 }
518 }
519 return dv;
520}
521
522struct CLIDebugVector* CLIDVStringParse(struct CLIDebugger* debugger, const char* string, size_t length) {
523 if (!string || length < 1) {
524 return 0;
525 }
526
527 struct CLIDebugVector dvTemp = { .type = CLIDV_CHAR_TYPE };
528
529 size_t adjusted;
530 const char* next = strchr(string, ' ');
531 if (next) {
532 adjusted = next - string;
533 } else {
534 adjusted = length;
535 }
536 dvTemp.charValue = malloc(adjusted);
537 strncpy(dvTemp.charValue, string, adjusted);
538
539 length -= adjusted;
540 string += adjusted;
541
542 struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
543 *dv = dvTemp;
544 if (string[0] == ' ') {
545 dv->next = CLIDVStringParse(debugger, string + 1, length - 1);
546 if (dv->next && dv->next->type == CLIDV_ERROR_TYPE) {
547 dv->type = CLIDV_ERROR_TYPE;
548 }
549 }
550 return dv;
551}
552
553static void _DVFree(struct CLIDebugVector* dv) {
554 struct CLIDebugVector* next;
555 while (dv) {
556 next = dv->next;
557 if (dv->type == CLIDV_CHAR_TYPE) {
558 free(dv->charValue);
559 }
560 free(dv);
561 dv = next;
562 }
563}
564
565static int _tryCommands(struct CLIDebugger* debugger, struct CLIDebuggerCommandSummary* commands, const char* command, size_t commandLen, const char* args, size_t argsLen) {
566 struct CLIDebugVector* dv = 0;
567 int i;
568 const char* name;
569 for (i = 0; (name = commands[i].name); ++i) {
570 if (strlen(name) != commandLen) {
571 continue;
572 }
573 if (strncasecmp(name, command, commandLen) == 0) {
574 if (commands[i].parser) {
575 if (args) {
576 dv = commands[i].parser(debugger, args, argsLen);
577 if (dv && dv->type == CLIDV_ERROR_TYPE) {
578 printf("Parse error\n");
579 _DVFree(dv);
580 return false;
581 }
582 }
583 } else if (args) {
584 printf("Wrong number of arguments\n");
585 return false;
586 }
587 commands[i].command(debugger, dv);
588 _DVFree(dv);
589 return true;
590 }
591 }
592 return -1;
593}
594
595static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count) {
596 const char* firstSpace = strchr(line, ' ');
597 size_t cmdLength;
598 if (firstSpace) {
599 cmdLength = firstSpace - line;
600 } else {
601 cmdLength = count;
602 }
603
604 const char* args = 0;
605 if (firstSpace) {
606 args = firstSpace + 1;
607 }
608 int result = _tryCommands(debugger, _debuggerCommands, line, cmdLength, args, count - cmdLength - 1);
609 if (result < 0 && debugger->system) {
610 result = _tryCommands(debugger, debugger->system->commands, line, cmdLength, args, count - cmdLength - 1);
611 }
612 if (result < 0) {
613 printf("Command not found\n");
614 }
615 return false;
616}
617
618static char* _prompt(EditLine* el) {
619 UNUSED(el);
620 return "> ";
621}
622
623static void _commandLine(struct ARMDebugger* debugger) {
624 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
625 const char* line;
626 _printStatus(cliDebugger, 0);
627 int count = 0;
628 HistEvent ev;
629 while (debugger->state == DEBUGGER_PAUSED) {
630 line = el_gets(cliDebugger->elstate, &count);
631 if (!line) {
632 debugger->state = DEBUGGER_EXITING;
633 return;
634 }
635 if (line[0] == '\n') {
636 if (history(cliDebugger->histate, &ev, H_FIRST) >= 0) {
637 _parse(cliDebugger, ev.str, strlen(ev.str) - 1);
638 }
639 } else {
640 _parse(cliDebugger, line, count - 1);
641 history(cliDebugger->histate, &ev, H_ENTER, line);
642 }
643 }
644}
645
646static void _reportEntry(struct ARMDebugger* debugger, enum DebuggerEntryReason reason) {
647 UNUSED(debugger);
648 switch (reason) {
649 case DEBUGGER_ENTER_MANUAL:
650 case DEBUGGER_ENTER_ATTACHED:
651 break;
652 case DEBUGGER_ENTER_BREAKPOINT:
653 printf("Hit breakpoint\n");
654 break;
655 case DEBUGGER_ENTER_WATCHPOINT:
656 printf("Hit watchpoint\n");
657 break;
658 case DEBUGGER_ENTER_ILLEGAL_OP:
659 printf("Hit illegal opcode\n");
660 break;
661 }
662}
663
664static unsigned char _tabComplete(EditLine* elstate, int ch) {
665 UNUSED(ch);
666 const LineInfo* li = el_line(elstate);
667 if (!li->buffer[0]) {
668 return CC_ERROR;
669 }
670
671 const char* commandPtr;
672 int cmd = 0, len = 0;
673 const char* name = 0;
674 for (commandPtr = li->buffer; commandPtr <= li->cursor; ++commandPtr, ++len) {
675 for (; (name = _debuggerCommands[cmd].name); ++cmd) {
676 int cmp = strncasecmp(name, li->buffer, len);
677 if (cmp > 0) {
678 return CC_ERROR;
679 }
680 if (cmp == 0) {
681 break;
682 }
683 }
684 }
685 if (!name) {
686 return CC_ERROR;
687 }
688 if (_debuggerCommands[cmd + 1].name && name[len - 2] == _debuggerCommands[cmd + 1].name[len - 2]) {
689 --len;
690 const char* next = 0;
691 int i;
692 for (i = cmd + 1; _debuggerCommands[i].name; ++i) {
693 if (strncasecmp(name, _debuggerCommands[i].name, len)) {
694 break;
695 }
696 next = _debuggerCommands[i].name;
697 }
698
699 for (; name[len]; ++len) {
700 if (name[len] != next[len]) {
701 break;
702 }
703 char out[2] = { name[len], '\0' };
704 el_insertstr(elstate, out);
705 }
706 return CC_REDISPLAY;
707 }
708 name += len - 1;
709 el_insertstr(elstate, name);
710 el_insertstr(elstate, " ");
711 return CC_REDISPLAY;
712}
713
714static void _cliDebuggerInit(struct ARMDebugger* debugger) {
715 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
716 // TODO: get argv[0]
717 cliDebugger->elstate = el_init(BINARY_NAME, stdin, stdout, stderr);
718 el_set(cliDebugger->elstate, EL_PROMPT, _prompt);
719 el_set(cliDebugger->elstate, EL_EDITOR, "emacs");
720
721 el_set(cliDebugger->elstate, EL_CLIENTDATA, cliDebugger);
722 el_set(cliDebugger->elstate, EL_ADDFN, "tab-complete", "Tab completion", _tabComplete);
723 el_set(cliDebugger->elstate, EL_BIND, "\t", "tab-complete", 0);
724 cliDebugger->histate = history_init();
725 HistEvent ev;
726 history(cliDebugger->histate, &ev, H_SETSIZE, 200);
727 el_set(cliDebugger->elstate, EL_HIST, history, cliDebugger->histate);
728 _activeDebugger = cliDebugger;
729 signal(SIGINT, _breakIntoDefault);
730}
731
732static void _cliDebuggerDeinit(struct ARMDebugger* debugger) {
733 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
734 history_end(cliDebugger->histate);
735 el_end(cliDebugger->elstate);
736
737 if (cliDebugger->system) {
738 cliDebugger->system->deinit(cliDebugger->system);
739 free(cliDebugger->system);
740 cliDebugger->system = 0;
741 }
742}
743
744static void _cliDebuggerCustom(struct ARMDebugger* debugger) {
745 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
746 bool retain = false;
747 if (cliDebugger->system) {
748 retain = cliDebugger->system->custom(cliDebugger->system);
749 }
750 if (!retain && debugger->state == DEBUGGER_CUSTOM) {
751 debugger->state = DEBUGGER_RUNNING;
752 }
753}
754
755void CLIDebuggerCreate(struct CLIDebugger* debugger) {
756 ARMDebuggerCreate(&debugger->d);
757 debugger->d.init = _cliDebuggerInit;
758 debugger->d.deinit = _cliDebuggerDeinit;
759 debugger->d.custom = _cliDebuggerCustom;
760 debugger->d.paused = _commandLine;
761 debugger->d.entered = _reportEntry;
762
763 debugger->system = 0;
764}
765
766void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSystem* system) {
767 if (debugger->system) {
768 debugger->system->deinit(debugger->system);
769 free(debugger->system);
770 }
771
772 debugger->system = system;
773 system->p = debugger;
774}