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