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