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