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