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