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