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