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