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