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