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