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