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