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 uint32_t _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 address += _printLine(debugger, address, mode);;
176 }
177}
178
179static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
180 UNUSED(debugger);
181 for ( ; dv; dv = dv->next) {
182 printf(" %u", dv->intValue);
183 }
184 printf("\n");
185}
186
187static void _printBin(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
188 UNUSED(debugger);
189 for ( ; dv; dv = dv->next) {
190 printf(" 0b");
191 int i = 32;
192 while (i--) {
193 printf("%u", (dv->intValue >> i) & 1);
194 }
195 }
196 printf("\n");
197}
198
199static void _printHex(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
200 UNUSED(debugger);
201 for ( ; dv; dv = dv->next) {
202 printf(" 0x%08X", dv->intValue);
203 }
204 printf("\n");
205}
206
207static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
208 UNUSED(debugger);
209 UNUSED(dv);
210 if (!dv) {
211 puts("ARM commands:");
212 int i;
213 for (i = 0; _debuggerCommands[i].name; ++i) {
214 printf("%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary);
215 }
216 if (debugger->system) {
217 printf("%s commands:\n", debugger->system->name);
218 for (i = 0; debugger->system->commands[i].name; ++i) {
219 printf("%-10s %s\n", debugger->system->commands[i].name, debugger->system->commands[i].summary);
220 }
221 }
222 } else {
223 int i;
224 for (i = 0; _debuggerCommands[i].name; ++i) {
225 if (strcmp(_debuggerCommands[i].name, dv->charValue) == 0) {
226 printf(" %s\n", _debuggerCommands[i].summary);
227 }
228 }
229 if (debugger->system) {
230 printf("\n%s commands:\n", debugger->system->name);
231 for (i = 0; debugger->system->commands[i].name; ++i) {
232 if (strcmp(debugger->system->commands[i].name, dv->charValue) == 0) {
233 printf(" %s\n", debugger->system->commands[i].summary);
234 }
235 }
236 }
237 }
238}
239
240static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
241 char disassembly[48];
242 struct ARMInstructionInfo info;
243 printf("%08X: ", address);
244 if (mode == MODE_ARM) {
245 uint32_t instruction = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
246 ARMDecodeARM(instruction, &info);
247 ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
248 printf("%08X\t%s\n", instruction, disassembly);
249 return WORD_SIZE_ARM;
250 } else {
251 struct ARMInstructionInfo info2;
252 struct ARMInstructionInfo combined;
253 uint16_t instruction = debugger->d.cpu->memory.load16(debugger->d.cpu, address, 0);
254 uint16_t instruction2 = debugger->d.cpu->memory.load16(debugger->d.cpu, address + WORD_SIZE_THUMB, 0);
255 ARMDecodeThumb(instruction, &info);
256 ARMDecodeThumb(instruction2, &info2);
257 if (ARMDecodeThumbCombine(&info, &info2, &combined)) {
258 ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
259 printf("%04X %04X\t%s\n", instruction, instruction2, disassembly);
260 return WORD_SIZE_THUMB * 2;
261 } else {
262 ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
263 printf("%04X \t%s\n", instruction, disassembly);
264 return WORD_SIZE_THUMB;
265 }
266 }
267}
268
269static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
270 UNUSED(dv);
271 int r;
272 for (r = 0; r < 4; ++r) {
273 printf("%08X %08X %08X %08X\n",
274 debugger->d.cpu->gprs[r << 2],
275 debugger->d.cpu->gprs[(r << 2) + 1],
276 debugger->d.cpu->gprs[(r << 2) + 2],
277 debugger->d.cpu->gprs[(r << 2) + 3]);
278 }
279 _printPSR(debugger->d.cpu->cpsr);
280 int instructionLength;
281 enum ExecutionMode mode = debugger->d.cpu->cpsr.t;
282 if (mode == MODE_ARM) {
283 instructionLength = WORD_SIZE_ARM;
284 } else {
285 instructionLength = WORD_SIZE_THUMB;
286 }
287 _printLine(debugger, debugger->d.cpu->gprs[ARM_PC] - instructionLength, mode);
288}
289
290static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
291 UNUSED(dv);
292 debugger->d.state = DEBUGGER_SHUTDOWN;
293}
294
295static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
296 if (!dv || dv->type != CLIDV_INT_TYPE) {
297 printf("%s\n", ERROR_MISSING_ARGS);
298 return;
299 }
300 uint32_t address = dv->intValue;
301 uint8_t value = debugger->d.cpu->memory.load8(debugger->d.cpu, address, 0);
302 printf(" 0x%02X\n", value);
303}
304
305static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
306 UNUSED(dv);
307 ARMReset(debugger->d.cpu);
308 _printStatus(debugger, 0);
309}
310
311static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
312 if (!dv || dv->type != CLIDV_INT_TYPE) {
313 printf("%s\n", ERROR_MISSING_ARGS);
314 return;
315 }
316 uint32_t address = dv->intValue;
317 uint16_t value = debugger->d.cpu->memory.load16(debugger->d.cpu, address & ~1, 0);
318 printf(" 0x%04X\n", value);
319}
320
321static void _readWord(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 uint32_t value = debugger->d.cpu->memory.load32(debugger->d.cpu, address & ~3, 0);
328 printf(" 0x%08X\n", value);
329}
330
331static void _writeByte(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 if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
337 printf("%s\n", ERROR_MISSING_ARGS);
338 return;
339 }
340 uint32_t address = dv->intValue;
341 uint32_t value = dv->next->intValue;
342 if (value > 0xFF) {
343 printf("%s\n", ERROR_OVERFLOW);
344 return;
345 }
346 debugger->d.cpu->memory.store8(debugger->d.cpu, address, value, 0);
347}
348
349static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
350 if (!dv || dv->type != CLIDV_INT_TYPE) {
351 printf("%s\n", ERROR_MISSING_ARGS);
352 return;
353 }
354 if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
355 printf("%s\n", ERROR_MISSING_ARGS);
356 return;
357 }
358 uint32_t address = dv->intValue;
359 uint32_t value = dv->next->intValue;
360 if (value > 0xFFFF) {
361 printf("%s\n", ERROR_OVERFLOW);
362 return;
363 }
364 debugger->d.cpu->memory.store16(debugger->d.cpu, address, value, 0);
365}
366
367static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
368 if (!dv || dv->type != CLIDV_INT_TYPE) {
369 printf("%s\n", ERROR_MISSING_ARGS);
370 return;
371 }
372 if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
373 printf("%s\n", ERROR_MISSING_ARGS);
374 return;
375 }
376 uint32_t address = dv->intValue;
377 uint32_t value = dv->next->intValue;
378 debugger->d.cpu->memory.store32(debugger->d.cpu, address, value, 0);
379}
380
381static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
382 if (!dv || dv->type != CLIDV_INT_TYPE) {
383 printf("%s\n", ERROR_MISSING_ARGS);
384 return;
385 }
386 uint32_t address = dv->intValue;
387 ARMDebuggerSetBreakpoint(&debugger->d, address);
388}
389
390static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
391 if (!dv || dv->type != CLIDV_INT_TYPE) {
392 printf("%s\n", ERROR_MISSING_ARGS);
393 return;
394 }
395 uint32_t address = dv->intValue;
396 ARMDebuggerClearBreakpoint(&debugger->d, address);
397}
398
399static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
400 if (!dv || dv->type != CLIDV_INT_TYPE) {
401 printf("%s\n", ERROR_MISSING_ARGS);
402 return;
403 }
404 uint32_t address = dv->intValue;
405 ARMDebuggerSetWatchpoint(&debugger->d, address);
406}
407
408static void _breakIntoDefault(int signal) {
409 UNUSED(signal);
410 ARMDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL, 0);
411}
412
413static uint32_t _performOperation(enum Operation operation, uint32_t current, uint32_t next, struct CLIDebugVector* dv) {
414 switch (operation) {
415 case OP_ASSIGN:
416 current = next;
417 break;
418 case OP_ADD:
419 current += next;
420 break;
421 case OP_SUBTRACT:
422 current -= next;
423 break;
424 case OP_MULTIPLY:
425 current *= next;
426 break;
427 case OP_DIVIDE:
428 if (next != 0) {
429 current /= next;
430 } else {
431 dv->type = CLIDV_ERROR_TYPE;
432 return 0;
433 }
434 break;
435 }
436 return current;
437}
438
439static uint32_t _lookupIdentifier(struct ARMDebugger* debugger, const char* name, struct CLIDebugVector* dv) {
440 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
441 if (strcmp(name, "sp") == 0) {
442 return debugger->cpu->gprs[ARM_SP];
443 }
444 if (strcmp(name, "lr") == 0) {
445 return debugger->cpu->gprs[ARM_LR];
446 }
447 if (strcmp(name, "pc") == 0) {
448 return debugger->cpu->gprs[ARM_PC];
449 }
450 if (strcmp(name, "cpsr") == 0) {
451 return debugger->cpu->cpsr.packed;
452 }
453 // TODO: test if mode has SPSR
454 if (strcmp(name, "spsr") == 0) {
455 return debugger->cpu->spsr.packed;
456 }
457 if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') {
458 int reg = atoi(&name[1]);
459 if (reg < 16) {
460 return debugger->cpu->gprs[reg];
461 }
462 }
463 if (cliDebugger->system) {
464 uint32_t value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv);
465 if (dv->type != CLIDV_ERROR_TYPE) {
466 return value;
467 }
468 } else {
469 dv->type = CLIDV_ERROR_TYPE;
470 }
471 return 0;
472}
473
474static uint32_t _evaluateParseTree(struct ARMDebugger* debugger, struct ParseTree* tree, struct CLIDebugVector* dv) {
475 switch (tree->token.type) {
476 case TOKEN_UINT_TYPE:
477 return tree->token.uintValue;
478 case TOKEN_OPERATOR_TYPE:
479 return _performOperation(tree->token.operatorValue, _evaluateParseTree(debugger, tree->lhs, dv), _evaluateParseTree(debugger, tree->rhs, dv), dv);
480 case TOKEN_IDENTIFIER_TYPE:
481 return _lookupIdentifier(debugger, tree->token.identifierValue, dv);
482 case TOKEN_ERROR_TYPE:
483 default:
484 dv->type = CLIDV_ERROR_TYPE;
485 }
486 return 0;
487}
488
489struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* string, size_t length) {
490 if (!string || length < 1) {
491 return 0;
492 }
493
494 struct CLIDebugVector dvTemp = { .type = CLIDV_INT_TYPE };
495
496 struct LexVector lv = { .next = 0 };
497 size_t adjusted = lexExpression(&lv, string, length);
498 if (adjusted > length) {
499 dvTemp.type = CLIDV_ERROR_TYPE;
500 lexFree(lv.next);
501 }
502
503 struct ParseTree tree;
504 parseLexedExpression(&tree, &lv);
505 if (tree.token.type == TOKEN_ERROR_TYPE) {
506 dvTemp.type = CLIDV_ERROR_TYPE;
507 } else {
508 dvTemp.intValue = _evaluateParseTree(&debugger->d, &tree, &dvTemp);
509 }
510
511 parseFree(tree.lhs);
512 parseFree(tree.rhs);
513
514 length -= adjusted;
515 string += adjusted;
516
517 struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
518 if (dvTemp.type == CLIDV_ERROR_TYPE) {
519 dv->type = CLIDV_ERROR_TYPE;
520 dv->next = 0;
521 } else {
522 *dv = dvTemp;
523 if (string[0] == ' ') {
524 dv->next = CLIDVParse(debugger, string + 1, length - 1);
525 if (dv->next && dv->next->type == CLIDV_ERROR_TYPE) {
526 dv->type = CLIDV_ERROR_TYPE;
527 }
528 }
529 }
530 return dv;
531}
532
533struct CLIDebugVector* CLIDVStringParse(struct CLIDebugger* debugger, const char* string, size_t length) {
534 if (!string || length < 1) {
535 return 0;
536 }
537
538 struct CLIDebugVector dvTemp = { .type = CLIDV_CHAR_TYPE };
539
540 size_t adjusted;
541 const char* next = strchr(string, ' ');
542 if (next) {
543 adjusted = next - string;
544 } else {
545 adjusted = length;
546 }
547 dvTemp.charValue = malloc(adjusted);
548 strncpy(dvTemp.charValue, string, adjusted);
549
550 length -= adjusted;
551 string += adjusted;
552
553 struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
554 *dv = dvTemp;
555 if (string[0] == ' ') {
556 dv->next = CLIDVStringParse(debugger, string + 1, length - 1);
557 if (dv->next && dv->next->type == CLIDV_ERROR_TYPE) {
558 dv->type = CLIDV_ERROR_TYPE;
559 }
560 }
561 return dv;
562}
563
564static void _DVFree(struct CLIDebugVector* dv) {
565 struct CLIDebugVector* next;
566 while (dv) {
567 next = dv->next;
568 if (dv->type == CLIDV_CHAR_TYPE) {
569 free(dv->charValue);
570 }
571 free(dv);
572 dv = next;
573 }
574}
575
576static int _tryCommands(struct CLIDebugger* debugger, struct CLIDebuggerCommandSummary* commands, const char* command, size_t commandLen, const char* args, size_t argsLen) {
577 struct CLIDebugVector* dv = 0;
578 int i;
579 const char* name;
580 for (i = 0; (name = commands[i].name); ++i) {
581 if (strlen(name) != commandLen) {
582 continue;
583 }
584 if (strncasecmp(name, command, commandLen) == 0) {
585 if (commands[i].parser) {
586 if (args) {
587 dv = commands[i].parser(debugger, args, argsLen);
588 if (dv && dv->type == CLIDV_ERROR_TYPE) {
589 printf("Parse error\n");
590 _DVFree(dv);
591 return false;
592 }
593 }
594 } else if (args) {
595 printf("Wrong number of arguments\n");
596 return false;
597 }
598 commands[i].command(debugger, dv);
599 _DVFree(dv);
600 return true;
601 }
602 }
603 return -1;
604}
605
606static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count) {
607 const char* firstSpace = strchr(line, ' ');
608 size_t cmdLength;
609 if (firstSpace) {
610 cmdLength = firstSpace - line;
611 } else {
612 cmdLength = count;
613 }
614
615 const char* args = 0;
616 if (firstSpace) {
617 args = firstSpace + 1;
618 }
619 int result = _tryCommands(debugger, _debuggerCommands, line, cmdLength, args, count - cmdLength - 1);
620 if (result < 0 && debugger->system) {
621 result = _tryCommands(debugger, debugger->system->commands, line, cmdLength, args, count - cmdLength - 1);
622 }
623 if (result < 0) {
624 printf("Command not found\n");
625 }
626 return false;
627}
628
629static char* _prompt(EditLine* el) {
630 UNUSED(el);
631 return "> ";
632}
633
634static void _commandLine(struct ARMDebugger* debugger) {
635 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
636 const char* line;
637 _printStatus(cliDebugger, 0);
638 int count = 0;
639 HistEvent ev;
640 while (debugger->state == DEBUGGER_PAUSED) {
641 line = el_gets(cliDebugger->elstate, &count);
642 if (!line) {
643 return;
644 }
645 if (line[0] == '\n') {
646 if (history(cliDebugger->histate, &ev, H_FIRST) >= 0) {
647 _parse(cliDebugger, ev.str, strlen(ev.str) - 1);
648 }
649 } else {
650 _parse(cliDebugger, line, count - 1);
651 history(cliDebugger->histate, &ev, H_ENTER, line);
652 }
653 }
654}
655
656static void _reportEntry(struct ARMDebugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) {
657 UNUSED(debugger);
658 switch (reason) {
659 case DEBUGGER_ENTER_MANUAL:
660 case DEBUGGER_ENTER_ATTACHED:
661 break;
662 case DEBUGGER_ENTER_BREAKPOINT:
663 if (info) {
664 printf("Hit breakpoint at 0x%08X\n", info->address);
665 } else {
666 printf("Hit breakpoint\n");
667 }
668 break;
669 case DEBUGGER_ENTER_WATCHPOINT:
670 if (info) {
671 printf("Hit watchpoint at 0x%08X: (old value = 0x%08X)\n", info->address, info->oldValue);
672 } else {
673 printf("Hit watchpoint\n");
674 }
675 break;
676 case DEBUGGER_ENTER_ILLEGAL_OP:
677 if (info) {
678 printf("Hit illegal opcode at 0x%08X: 0x%08X\n", info->address, info->opcode);
679 } else {
680 printf("Hit illegal opcode\n");
681 }
682 break;
683 }
684}
685
686static unsigned char _tabComplete(EditLine* elstate, int ch) {
687 UNUSED(ch);
688 const LineInfo* li = el_line(elstate);
689 if (!li->buffer[0]) {
690 return CC_ERROR;
691 }
692
693 const char* commandPtr;
694 int cmd = 0, len = 0;
695 const char* name = 0;
696 for (commandPtr = li->buffer; commandPtr <= li->cursor; ++commandPtr, ++len) {
697 for (; (name = _debuggerCommands[cmd].name); ++cmd) {
698 int cmp = strncasecmp(name, li->buffer, len);
699 if (cmp > 0) {
700 return CC_ERROR;
701 }
702 if (cmp == 0) {
703 break;
704 }
705 }
706 }
707 if (!name) {
708 return CC_ERROR;
709 }
710 if (_debuggerCommands[cmd + 1].name && name[len - 2] == _debuggerCommands[cmd + 1].name[len - 2]) {
711 --len;
712 const char* next = 0;
713 int i;
714 for (i = cmd + 1; _debuggerCommands[i].name; ++i) {
715 if (strncasecmp(name, _debuggerCommands[i].name, len)) {
716 break;
717 }
718 next = _debuggerCommands[i].name;
719 }
720
721 for (; name[len]; ++len) {
722 if (name[len] != next[len]) {
723 break;
724 }
725 char out[2] = { name[len], '\0' };
726 el_insertstr(elstate, out);
727 }
728 return CC_REDISPLAY;
729 }
730 name += len - 1;
731 el_insertstr(elstate, name);
732 el_insertstr(elstate, " ");
733 return CC_REDISPLAY;
734}
735
736static void _cliDebuggerInit(struct ARMDebugger* debugger) {
737 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
738 // TODO: get argv[0]
739 cliDebugger->elstate = el_init(BINARY_NAME, stdin, stdout, stderr);
740 el_set(cliDebugger->elstate, EL_PROMPT, _prompt);
741 el_set(cliDebugger->elstate, EL_EDITOR, "emacs");
742
743 el_set(cliDebugger->elstate, EL_CLIENTDATA, cliDebugger);
744 el_set(cliDebugger->elstate, EL_ADDFN, "tab-complete", "Tab completion", _tabComplete);
745 el_set(cliDebugger->elstate, EL_BIND, "\t", "tab-complete", 0);
746 cliDebugger->histate = history_init();
747 HistEvent ev;
748 history(cliDebugger->histate, &ev, H_SETSIZE, 200);
749 el_set(cliDebugger->elstate, EL_HIST, history, cliDebugger->histate);
750 _activeDebugger = cliDebugger;
751 signal(SIGINT, _breakIntoDefault);
752}
753
754static void _cliDebuggerDeinit(struct ARMDebugger* debugger) {
755 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
756 history_end(cliDebugger->histate);
757 el_end(cliDebugger->elstate);
758
759 if (cliDebugger->system) {
760 cliDebugger->system->deinit(cliDebugger->system);
761 free(cliDebugger->system);
762 cliDebugger->system = 0;
763 }
764}
765
766static void _cliDebuggerCustom(struct ARMDebugger* debugger) {
767 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
768 bool retain = false;
769 if (cliDebugger->system) {
770 retain = cliDebugger->system->custom(cliDebugger->system);
771 }
772 if (!retain && debugger->state == DEBUGGER_CUSTOM) {
773 debugger->state = DEBUGGER_RUNNING;
774 }
775}
776
777void CLIDebuggerCreate(struct CLIDebugger* debugger) {
778 ARMDebuggerCreate(&debugger->d);
779 debugger->d.init = _cliDebuggerInit;
780 debugger->d.deinit = _cliDebuggerDeinit;
781 debugger->d.custom = _cliDebuggerCustom;
782 debugger->d.paused = _commandLine;
783 debugger->d.entered = _reportEntry;
784
785 debugger->system = 0;
786}
787
788void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSystem* system) {
789 if (debugger->system) {
790 debugger->system->deinit(debugger->system);
791 free(debugger->system);
792 }
793
794 debugger->system = system;
795 system->p = debugger;
796}