src/debugger/cli-debugger.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/debugger/cli-debugger.h>
7
8#include <mgba/internal/debugger/symbols.h>
9
10#include <mgba/core/core.h>
11#include <mgba/core/version.h>
12#include <mgba/internal/debugger/parser.h>
13#include <mgba-util/string.h>
14#include <mgba-util/vfs.h>
15
16#if ENABLE_SCRIPTING
17#include <mgba/core/scripting.h>
18#endif
19
20#if !defined(NDEBUG) && !defined(_WIN32)
21#include <signal.h>
22#endif
23
24#ifdef USE_PTHREADS
25#include <pthread.h>
26#endif
27
28const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
29const char* ERROR_OVERFLOW = "Arguments overflow";
30const char* ERROR_INVALID_ARGS = "Invalid arguments";
31const char* INFO_BREAKPOINT_ADDED = "Added breakpoint #%" PRIz "i\n";
32const char* INFO_WATCHPOINT_ADDED = "Added watchpoint #%" PRIz "i\n";
33
34static struct ParseTree* _parseTree(const char** string);
35static bool _doTrace(struct CLIDebugger* debugger);
36
37#if !defined(NDEBUG) && !defined(_WIN32)
38static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
39#endif
40static void _continue(struct CLIDebugger*, struct CLIDebugVector*);
41static void _disassemble(struct CLIDebugger*, struct CLIDebugVector*);
42static void _next(struct CLIDebugger*, struct CLIDebugVector*);
43static void _print(struct CLIDebugger*, struct CLIDebugVector*);
44static void _printBin(struct CLIDebugger*, struct CLIDebugVector*);
45static void _printHex(struct CLIDebugger*, struct CLIDebugVector*);
46static void _printStatus(struct CLIDebugger*, struct CLIDebugVector*);
47static void _printHelp(struct CLIDebugger*, struct CLIDebugVector*);
48static void _quit(struct CLIDebugger*, struct CLIDebugVector*);
49static void _readByte(struct CLIDebugger*, struct CLIDebugVector*);
50static void _reset(struct CLIDebugger*, struct CLIDebugVector*);
51static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
52static void _readWord(struct CLIDebugger*, struct CLIDebugVector*);
53static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
54static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
55static void _listBreakpoints(struct CLIDebugger*, struct CLIDebugVector*);
56static void _setReadWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
57static void _setReadWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
58static void _setWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
59static void _setWriteChangedWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
60static void _listWatchpoints(struct CLIDebugger*, struct CLIDebugVector*);
61static void _trace(struct CLIDebugger*, struct CLIDebugVector*);
62static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*);
63static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*);
64static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*);
65static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*);
66static void _dumpByte(struct CLIDebugger*, struct CLIDebugVector*);
67static void _dumpHalfword(struct CLIDebugger*, struct CLIDebugVector*);
68static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*);
69#ifdef ENABLE_SCRIPTING
70static void _source(struct CLIDebugger*, struct CLIDebugVector*);
71#endif
72
73static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
74 { "break", _setBreakpoint, "Is", "Set a breakpoint" },
75 { "continue", _continue, "", "Continue execution" },
76 { "delete", _clearBreakpoint, "I", "Delete a breakpoint or watchpoint" },
77 { "disassemble", _disassemble, "Ii", "Disassemble instructions" },
78 { "help", _printHelp, "S", "Print help" },
79 { "listb", _listBreakpoints, "", "List breakpoints" },
80 { "listw", _listWatchpoints, "", "List watchpoints" },
81 { "next", _next, "", "Execute next instruction" },
82 { "print", _print, "S+", "Print a value" },
83 { "print/t", _printBin, "S+", "Print a value as binary" },
84 { "print/x", _printHex, "S+", "Print a value as hexadecimal" },
85 { "quit", _quit, "", "Quit the emulator" },
86 { "reset", _reset, "", "Reset the emulation" },
87 { "r/1", _readByte, "I", "Read a byte from a specified offset" },
88 { "r/2", _readHalfword, "I", "Read a halfword from a specified offset" },
89 { "r/4", _readWord, "I", "Read a word from a specified offset" },
90 { "status", _printStatus, "", "Print the current status" },
91 { "trace", _trace, "Is", "Trace a number of instructions" },
92 { "w/1", _writeByte, "II", "Write a byte at a specified offset" },
93 { "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" },
94 { "w/r", _writeRegister, "SI", "Write a register" },
95 { "w/4", _writeWord, "II", "Write a word at a specified offset" },
96 { "watch", _setReadWriteWatchpoint, "Is", "Set a watchpoint" },
97 { "watch/c", _setWriteChangedWatchpoint, "Is", "Set a change watchpoint" },
98 { "watch/r", _setReadWatchpoint, "Is", "Set a read watchpoint" },
99 { "watch/w", _setWriteWatchpoint, "Is", "Set a write watchpoint" },
100 { "x/1", _dumpByte, "Ii", "Examine bytes at a specified offset" },
101 { "x/2", _dumpHalfword, "Ii", "Examine halfwords at a specified offset" },
102 { "x/4", _dumpWord, "Ii", "Examine words at a specified offset" },
103#ifdef ENABLE_SCRIPTING
104 { "source", _source, "S", "Load a script" },
105#endif
106#if !defined(NDEBUG) && !defined(_WIN32)
107 { "!", _breakInto, "", "Break into attached debugger (for developers)" },
108#endif
109 { 0, 0, 0, 0 }
110};
111
112static struct CLIDebuggerCommandAlias _debuggerCommandAliases[] = {
113 { "b", "break" },
114 { "c", "continue" },
115 { "d", "delete" },
116 { "dis", "disassemble" },
117 { "disasm", "disassemble" },
118 { "h", "help" },
119 { "i", "status" },
120 { "info", "status" },
121 { "lb", "listb" },
122 { "lw", "listw" },
123 { "n", "next" },
124 { "p", "print" },
125 { "p/t", "print/t" },
126 { "p/x", "print/x" },
127 { "q", "quit" },
128 { "w", "watch" },
129 { 0, 0 }
130};
131
132#if !defined(NDEBUG) && !defined(_WIN32)
133static void _handleDeath(int sig) {
134 UNUSED(sig);
135 printf("No debugger attached!\n");
136}
137
138static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
139 UNUSED(debugger);
140 UNUSED(dv);
141 struct sigaction sa, osa;
142 sa.sa_handler = _handleDeath;
143 sigemptyset(&sa.sa_mask);
144 sigaddset(&sa.sa_mask, SIGTRAP);
145 sa.sa_flags = SA_RESTART;
146 sigaction(SIGTRAP, &sa, &osa);
147#ifdef USE_PTHREADS
148 pthread_kill(pthread_self(), SIGTRAP);
149#else
150 kill(getpid(), SIGTRAP);
151#endif
152 sigaction(SIGTRAP, &osa, 0);
153}
154#endif
155
156static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
157 UNUSED(dv);
158 debugger->d.state = debugger->traceRemaining != 0 ? DEBUGGER_CUSTOM : DEBUGGER_RUNNING;
159}
160
161static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
162 UNUSED(dv);
163 debugger->d.core->step(debugger->d.core);
164 _printStatus(debugger, 0);
165}
166
167static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
168 debugger->system->disassemble(debugger->system, dv);
169}
170
171static bool _parseExpression(struct mDebugger* debugger, struct CLIDebugVector* dv, int32_t* intValue, int* segmentValue) {
172 size_t args = 0;
173 struct CLIDebugVector* accum;
174 for (accum = dv; accum; accum = accum->next) {
175 ++args;
176 }
177 const char** arglist = malloc(sizeof(const char*) * (args + 1));
178 args = 0;
179 for (accum = dv; accum; accum = accum->next) {
180 arglist[args] = accum->charValue;
181 ++args;
182 }
183 arglist[args] = NULL;
184 struct ParseTree* tree = _parseTree(arglist);
185 free(arglist);
186
187 if (!tree) {
188 return false;
189 }
190 if (!mDebuggerEvaluateParseTree(debugger, tree, intValue, segmentValue)) {
191 parseFree(tree);
192 free(tree);
193 return false;
194 }
195 parseFree(tree);
196 free(tree);
197 return true;
198}
199
200static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
201 int32_t intValue = 0;
202 int segmentValue = -1;
203 if (!_parseExpression(&debugger->d, dv, &intValue, &segmentValue)) {
204 debugger->backend->printf(debugger->backend, "Parse error\n");
205 return;
206 }
207 if (segmentValue >= 0) {
208 debugger->backend->printf(debugger->backend, " $%02X:%04X\n", segmentValue, intValue);
209 } else {
210 debugger->backend->printf(debugger->backend, " %u\n", intValue);
211 }
212}
213
214static void _printBin(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
215 int32_t intValue = 0;
216 int segmentValue = -1;
217 if (!_parseExpression(&debugger->d, dv, &intValue, &segmentValue)) {
218 debugger->backend->printf(debugger->backend, "Parse error\n");
219 return;
220 }
221 debugger->backend->printf(debugger->backend, " 0b");
222 int i = 32;
223 while (i--) {
224 debugger->backend->printf(debugger->backend, "%u", (intValue >> i) & 1);
225 }
226 debugger->backend->printf(debugger->backend, "\n");
227}
228
229static void _printHex(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
230 int32_t intValue = 0;
231 int segmentValue = -1;
232 if (!_parseExpression(&debugger->d, dv, &intValue, &segmentValue)) {
233 debugger->backend->printf(debugger->backend, "Parse error\n");
234 return;
235 }
236 debugger->backend->printf(debugger->backend, " 0x%08X\n", intValue);
237}
238
239static void _printCommands(struct CLIDebugger* debugger, struct CLIDebuggerCommandSummary* commands, struct CLIDebuggerCommandAlias* aliases) {
240 int i;
241 for (i = 0; commands[i].name; ++i) {
242 debugger->backend->printf(debugger->backend, "%-15s %s\n", commands[i].name, commands[i].summary);
243 if (aliases) {
244 bool printedAlias = false;
245 int j;
246 for (j = 0; aliases[j].name; ++j) {
247 if (strcmp(aliases[j].original, commands[i].name) == 0) {
248 if (!printedAlias) {
249 debugger->backend->printf(debugger->backend, " Aliases:");
250 printedAlias = true;
251 }
252 debugger->backend->printf(debugger->backend, " %s", aliases[j].name);
253 }
254 }
255 if (printedAlias) {
256 debugger->backend->printf(debugger->backend, "\n");
257 }
258 }
259 }
260}
261
262static void _printCommandSummary(struct CLIDebugger* debugger, const char* name, struct CLIDebuggerCommandSummary* commands, struct CLIDebuggerCommandAlias* aliases) {
263 int i;
264 for (i = 0; commands[i].name; ++i) {
265 if (strcmp(commands[i].name, name) == 0) {
266 debugger->backend->printf(debugger->backend, " %s\n", commands[i].summary);
267 if (aliases) {
268 bool printedAlias = false;
269 int j;
270 for (j = 0; aliases[j].name; ++j) {
271 if (strcmp(aliases[j].original, commands[i].name) == 0) {
272 if (!printedAlias) {
273 debugger->backend->printf(debugger->backend, " Aliases:");
274 printedAlias = true;
275 }
276 debugger->backend->printf(debugger->backend, " %s", aliases[j].name);
277 }
278 }
279 if (printedAlias) {
280 debugger->backend->printf(debugger->backend, "\n");
281 }
282 }
283 return;
284 }
285 }
286}
287
288static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
289 UNUSED(dv);
290 if (!dv) {
291 debugger->backend->printf(debugger->backend, "Generic commands:\n");
292 _printCommands(debugger, _debuggerCommands, _debuggerCommandAliases);
293 if (debugger->system) {
294 debugger->backend->printf(debugger->backend, "\n%s commands:\n", debugger->system->platformName);
295 _printCommands(debugger, debugger->system->platformCommands, debugger->system->platformCommandAliases);
296 debugger->backend->printf(debugger->backend, "\n%s commands:\n", debugger->system->name);
297 _printCommands(debugger, debugger->system->commands, debugger->system->commandAliases);
298 }
299 } else {
300 _printCommandSummary(debugger, dv->charValue, _debuggerCommands, _debuggerCommandAliases);
301 if (debugger->system) {
302 _printCommandSummary(debugger, dv->charValue, debugger->system->platformCommands, debugger->system->platformCommandAliases);
303 _printCommandSummary(debugger, dv->charValue, debugger->system->commands, debugger->system->commandAliases);
304 }
305 }
306}
307
308static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
309 UNUSED(dv);
310 debugger->d.state = DEBUGGER_SHUTDOWN;
311}
312
313static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
314 if (!dv || dv->type != CLIDV_INT_TYPE) {
315 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
316 return;
317 }
318 uint32_t address = dv->intValue;
319 uint8_t value;
320 if (dv->segmentValue >= 0) {
321 value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue);
322 } else {
323 value = debugger->d.core->busRead8(debugger->d.core, address);
324 }
325 debugger->backend->printf(debugger->backend, " 0x%02X\n", value);
326}
327
328static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
329 UNUSED(dv);
330 debugger->d.core->reset(debugger->d.core);
331 _printStatus(debugger, 0);
332}
333
334static void _readHalfword(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 uint16_t value;
341 if (dv->segmentValue >= 0) {
342 value = debugger->d.core->rawRead16(debugger->d.core, address & -1, dv->segmentValue);
343 } else {
344 value = debugger->d.core->busRead16(debugger->d.core, address & ~1);
345 }
346 debugger->backend->printf(debugger->backend, " 0x%04X\n", value);
347}
348
349static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
350 if (!dv || dv->type != CLIDV_INT_TYPE) {
351 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
352 return;
353 }
354 uint32_t address = dv->intValue;
355 uint32_t value;
356 if (dv->segmentValue >= 0) {
357 value = debugger->d.core->rawRead32(debugger->d.core, address & -3, dv->segmentValue);
358 } else {
359 value = debugger->d.core->busRead32(debugger->d.core, address & ~3);
360 }
361 debugger->backend->printf(debugger->backend, " 0x%08X\n", value);
362}
363
364static void _writeByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
365 if (!dv || !dv->next) {
366 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
367 return;
368 }
369 if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
370 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
371 return;
372 }
373 uint32_t address = dv->intValue;
374 uint32_t value = dv->next->intValue;
375 if (value > 0xFF) {
376 debugger->backend->printf(debugger->backend, "%s\n", ERROR_OVERFLOW);
377 return;
378 }
379 if (dv->segmentValue >= 0) {
380 debugger->d.core->rawWrite8(debugger->d.core, address, value, dv->segmentValue);
381 } else {
382 debugger->d.core->busWrite8(debugger->d.core, address, value);
383 }
384}
385
386static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
387 if (!dv || !dv->next) {
388 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
389 return;
390 }
391 if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
392 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
393 return;
394 }
395 uint32_t address = dv->intValue;
396 uint32_t value = dv->next->intValue;
397 if (value > 0xFFFF) {
398 debugger->backend->printf(debugger->backend, "%s\n", ERROR_OVERFLOW);
399 return;
400 }
401 if (dv->segmentValue >= 0) {
402 debugger->d.core->rawWrite16(debugger->d.core, address, value, dv->segmentValue);
403 } else {
404 debugger->d.core->busWrite16(debugger->d.core, address, value);
405 }
406}
407
408static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
409 if (!dv || !dv->next) {
410 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
411 return;
412 }
413 if (dv->type != CLIDV_CHAR_TYPE || dv->next->type != CLIDV_INT_TYPE) {
414 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
415 return;
416 }
417 if (!debugger->d.platform->setRegister(debugger->d.platform, dv->charValue, dv->next->intValue)) {
418 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
419 }
420}
421
422static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
423 if (!dv || !dv->next) {
424 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
425 return;
426 }
427 if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
428 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
429 return;
430 }
431 uint32_t address = dv->intValue;
432 uint32_t value = dv->next->intValue;
433 if (dv->segmentValue >= 0) {
434 debugger->d.core->rawWrite32(debugger->d.core, address, value, dv->segmentValue);
435 } else {
436 debugger->d.core->busWrite32(debugger->d.core, address, value);
437 }
438}
439
440static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
441 if (!dv || dv->type != CLIDV_INT_TYPE) {
442 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
443 return;
444 }
445 uint32_t address = dv->intValue;
446 uint32_t words = 16;
447 if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
448 words = dv->next->intValue;
449 }
450 while (words) {
451 uint32_t line = 16;
452 if (line > words) {
453 line = words;
454 }
455 debugger->backend->printf(debugger->backend, "0x%08X:", address);
456 for (; line > 0; --line, ++address, --words) {
457 uint32_t value;
458 if (dv->segmentValue >= 0) {
459 value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue);
460 } else {
461 value = debugger->d.core->busRead8(debugger->d.core, address);
462 }
463 debugger->backend->printf(debugger->backend, " %02X", value);
464 }
465 debugger->backend->printf(debugger->backend, "\n");
466 }
467}
468
469static void _dumpHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
470 if (!dv || dv->type != CLIDV_INT_TYPE) {
471 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
472 return;
473 }
474 uint32_t address = dv->intValue;
475 uint32_t words = 8;
476 if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
477 words = dv->next->intValue;
478 }
479 while (words) {
480 uint32_t line = 8;
481 if (line > words) {
482 line = words;
483 }
484 debugger->backend->printf(debugger->backend, "0x%08X:", address);
485 for (; line > 0; --line, address += 2, --words) {
486 uint32_t value;
487 if (dv->segmentValue >= 0) {
488 value = debugger->d.core->rawRead16(debugger->d.core, address, dv->segmentValue);
489 } else {
490 value = debugger->d.core->busRead16(debugger->d.core, address);
491 }
492 debugger->backend->printf(debugger->backend, " %04X", value);
493 }
494 debugger->backend->printf(debugger->backend, "\n");
495 }
496}
497
498static void _dumpWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
499 if (!dv || dv->type != CLIDV_INT_TYPE) {
500 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
501 return;
502 }
503 uint32_t address = dv->intValue;
504 uint32_t words = 4;
505 if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
506 words = dv->next->intValue;
507 }
508 while (words) {
509 uint32_t line = 4;
510 if (line > words) {
511 line = words;
512 }
513 debugger->backend->printf(debugger->backend, "0x%08X:", address);
514 for (; line > 0; --line, address += 4, --words) {
515 uint32_t value;
516 if (dv->segmentValue >= 0) {
517 value = debugger->d.core->rawRead32(debugger->d.core, address, dv->segmentValue);
518 } else {
519 value = debugger->d.core->busRead32(debugger->d.core, address);
520 }
521 debugger->backend->printf(debugger->backend, " %08X", value);
522 }
523 debugger->backend->printf(debugger->backend, "\n");
524 }
525}
526
527#ifdef ENABLE_SCRIPTING
528static void _source(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
529 if (!dv) {
530 debugger->backend->printf(debugger->backend, "Needs a filename\n");
531 return;
532 }
533 if (debugger->d.bridge && mScriptBridgeLoadScript(debugger->d.bridge, dv->charValue)) {
534 mScriptBridgeRun(debugger->d.bridge);
535 } else {
536 debugger->backend->printf(debugger->backend, "Failed to load script\n");
537 }
538}
539#endif
540
541static struct ParseTree* _parseTree(const char** string) {
542 struct LexVector lv;
543 bool error = false;
544 LexVectorInit(&lv, 0);
545 size_t i;
546 for (i = 0; string[i]; ++i) {
547 size_t length = strlen(string[i]);
548 size_t adjusted = lexExpression(&lv, string[i], length, NULL);
549 if (!adjusted || adjusted > length) {
550 error = true;
551 }
552 }
553 struct ParseTree* tree = NULL;
554 if (!error) {
555 tree = malloc(sizeof(*tree));
556 parseLexedExpression(tree, &lv);
557 }
558 lexFree(&lv);
559 LexVectorClear(&lv);
560 LexVectorDeinit(&lv);
561 if (error) {
562 if (tree) {
563 parseFree(tree);
564 free(tree);
565 }
566 return NULL;
567 } else {
568 return tree;
569 }
570}
571
572static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
573 if (!dv || dv->type != CLIDV_INT_TYPE) {
574 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
575 return;
576 }
577 struct mBreakpoint breakpoint = {
578 .address = dv->intValue,
579 .segment = dv->segmentValue,
580 .type = BREAKPOINT_HARDWARE
581 };
582 if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
583 struct ParseTree* tree = _parseTree((const char*[]) { dv->next->charValue, NULL });
584 if (tree) {
585 breakpoint.condition = tree;
586 } else {
587 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
588 return;
589 }
590 }
591 ssize_t id = debugger->d.platform->setBreakpoint(debugger->d.platform, &breakpoint);
592 if (id > 0) {
593 debugger->backend->printf(debugger->backend, INFO_BREAKPOINT_ADDED, id);
594 }
595}
596
597static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum mWatchpointType type) {
598 if (!dv || dv->type != CLIDV_INT_TYPE) {
599 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
600 return;
601 }
602 if (!debugger->d.platform->setWatchpoint) {
603 debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
604 return;
605 }
606 struct mWatchpoint watchpoint = {
607 .address = dv->intValue,
608 .segment = dv->segmentValue,
609 .type = type
610 };
611 if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
612 struct ParseTree* tree = _parseTree((const char*[]) { dv->next->charValue, NULL });
613 if (tree) {
614 watchpoint.condition = tree;
615 } else {
616 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
617 return;
618 }
619 }
620 ssize_t id = debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint);
621 if (id > 0) {
622 debugger->backend->printf(debugger->backend, INFO_WATCHPOINT_ADDED, id);
623 }
624}
625
626static void _setReadWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
627 _setWatchpoint(debugger, dv, WATCHPOINT_RW);
628}
629
630static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
631 _setWatchpoint(debugger, dv, WATCHPOINT_READ);
632}
633
634static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
635 _setWatchpoint(debugger, dv, WATCHPOINT_WRITE);
636}
637
638static void _setWriteChangedWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
639 _setWatchpoint(debugger, dv, WATCHPOINT_WRITE_CHANGE);
640}
641
642static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
643 if (!dv || dv->type != CLIDV_INT_TYPE) {
644 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
645 return;
646 }
647 uint64_t id = dv->intValue;
648 debugger->d.platform->clearBreakpoint(debugger->d.platform, id);
649}
650
651static void _listBreakpoints(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
652 UNUSED(dv);
653 struct mBreakpointList breakpoints;
654 mBreakpointListInit(&breakpoints, 0);
655 debugger->d.platform->listBreakpoints(debugger->d.platform, &breakpoints);
656 size_t i;
657 for (i = 0; i < mBreakpointListSize(&breakpoints); ++i) {
658 struct mBreakpoint* breakpoint = mBreakpointListGetPointer(&breakpoints, i);
659 if (breakpoint->segment >= 0) {
660 debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", breakpoint->id, breakpoint->segment, breakpoint->address);
661 } else {
662 debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", breakpoint->id, breakpoint->address);
663 }
664 }
665 mBreakpointListDeinit(&breakpoints);
666}
667
668static void _listWatchpoints(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
669 UNUSED(dv);
670 struct mWatchpointList watchpoints;
671 mWatchpointListInit(&watchpoints, 0);
672 debugger->d.platform->listWatchpoints(debugger->d.platform, &watchpoints);
673 size_t i;
674 for (i = 0; i < mWatchpointListSize(&watchpoints); ++i) {
675 struct mWatchpoint* watchpoint = mWatchpointListGetPointer(&watchpoints, i);
676 if (watchpoint->segment >= 0) {
677 debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", watchpoint->id, watchpoint->segment, watchpoint->address);
678 } else {
679 debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", watchpoint->id, watchpoint->address);
680 }
681 }
682 mWatchpointListDeinit(&watchpoints);
683}
684
685static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
686 if (!dv || dv->type != CLIDV_INT_TYPE) {
687 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
688 return;
689 }
690
691 debugger->traceRemaining = dv->intValue;
692 if (debugger->traceVf) {
693 debugger->traceVf->close(debugger->traceVf);
694 debugger->traceVf = NULL;
695 }
696 if (debugger->traceRemaining == 0) {
697 return;
698 }
699 if (dv->next && dv->next->charValue) {
700 debugger->traceVf = VFileOpen(dv->next->charValue, O_CREAT | O_WRONLY | O_APPEND);
701 }
702 if (_doTrace(debugger)) {
703 debugger->d.state = DEBUGGER_CUSTOM;
704 } else {
705 debugger->system->printStatus(debugger->system);
706 }
707}
708
709static bool _doTrace(struct CLIDebugger* debugger) {
710 char trace[1024];
711 trace[sizeof(trace) - 1] = '\0';
712 debugger->d.core->step(debugger->d.core);
713 size_t traceSize = sizeof(trace) - 2;
714 debugger->d.platform->trace(debugger->d.platform, trace, &traceSize);
715 if (traceSize + 1 <= sizeof(trace)) {
716 trace[traceSize] = '\n';
717 trace[traceSize + 1] = '\0';
718 }
719 if (debugger->traceVf) {
720 debugger->traceVf->write(debugger->traceVf, trace, traceSize + 1);
721 } else {
722 debugger->backend->printf(debugger->backend, "%s", trace);
723 }
724 if (debugger->traceRemaining > 0) {
725 --debugger->traceRemaining;
726 }
727 return debugger->traceRemaining != 0;
728}
729
730static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
731 UNUSED(dv);
732 debugger->system->printStatus(debugger->system);
733}
734
735struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* string, size_t length) {
736 if (!string || length < 1) {
737 return 0;
738 }
739
740 struct CLIDebugVector dvTemp = { .type = CLIDV_INT_TYPE, .segmentValue = -1 };
741
742 struct LexVector lv;
743 LexVectorInit(&lv, 0);
744 size_t adjusted = lexExpression(&lv, string, length, " ");
745 if (adjusted > length) {
746 dvTemp.type = CLIDV_ERROR_TYPE;
747 }
748
749 struct ParseTree tree;
750 parseLexedExpression(&tree, &lv);
751 if (tree.token.type == TOKEN_ERROR_TYPE) {
752 dvTemp.type = CLIDV_ERROR_TYPE;
753 } else {
754 if (!mDebuggerEvaluateParseTree(&debugger->d, &tree, &dvTemp.intValue, &dvTemp.segmentValue)) {
755 dvTemp.type = CLIDV_ERROR_TYPE;
756 }
757 }
758
759 parseFree(&tree);
760
761 lexFree(&lv);
762 LexVectorDeinit(&lv);
763
764 struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
765 if (dvTemp.type == CLIDV_ERROR_TYPE) {
766 dv->type = CLIDV_ERROR_TYPE;
767 dv->next = 0;
768 } else {
769 *dv = dvTemp;
770 }
771 return dv;
772}
773
774struct CLIDebugVector* CLIDVStringParse(struct CLIDebugger* debugger, const char* string, size_t length) {
775 UNUSED(debugger);
776 if (!string || length < 1) {
777 return 0;
778 }
779
780 struct CLIDebugVector dvTemp = { .type = CLIDV_CHAR_TYPE };
781
782 dvTemp.charValue = strndup(string, length);
783
784 struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
785 *dv = dvTemp;
786 return dv;
787}
788
789static void _DVFree(struct CLIDebugVector* dv) {
790 struct CLIDebugVector* next;
791 while (dv) {
792 next = dv->next;
793 if (dv->type == CLIDV_CHAR_TYPE) {
794 free(dv->charValue);
795 }
796 free(dv);
797 dv = next;
798 }
799}
800
801static struct CLIDebugVector* _parseArg(struct CLIDebugger* debugger, const char* args, size_t argsLen, char type) {
802 struct CLIDebugVector* dv = NULL;
803 switch (type) {
804 case 'I':
805 case 'i':
806 return CLIDVParse(debugger, args, argsLen);
807 case 'S':
808 case 's':
809 return CLIDVStringParse(debugger, args, argsLen);
810 case '*':
811 dv = _parseArg(debugger, args, argsLen, 'I');
812 if (!dv) {
813 dv = _parseArg(debugger, args, argsLen, 'S');
814 }
815 break;
816 }
817 return dv;
818}
819
820static int _tryCommands(struct CLIDebugger* debugger, struct CLIDebuggerCommandSummary* commands, struct CLIDebuggerCommandAlias* aliases, const char* command, size_t commandLen, const char* args, size_t argsLen) {
821 struct CLIDebugVector* dv = NULL;
822 struct CLIDebugVector* dvLast = NULL;
823 int i;
824 const char* name;
825 if (aliases) {
826 for (i = 0; (name = aliases[i].name); ++i) {
827 if (strlen(name) != commandLen) {
828 continue;
829 }
830 if (strncasecmp(name, command, commandLen) == 0) {
831 command = aliases[i].original;
832 commandLen = strlen(aliases[i].original);
833 }
834 }
835 }
836 for (i = 0; (name = commands[i].name); ++i) {
837 if (strlen(name) != commandLen) {
838 continue;
839 }
840 if (strncasecmp(name, command, commandLen) == 0) {
841 if (commands[i].format && args) {
842 char lastArg = '\0';
843 int arg;
844 for (arg = 0; commands[i].format[arg] && argsLen; ++arg) {
845 while (isspace(args[0]) && argsLen) {
846 ++args;
847 --argsLen;
848 }
849 if (!args[0] || !argsLen) {
850 debugger->backend->printf(debugger->backend, "Wrong number of arguments\n");
851 _DVFree(dv);
852 return 0;
853 }
854
855 size_t adjusted;
856 const char* next = strchr(args, ' ');
857 if (next) {
858 adjusted = next - args;
859 } else {
860 adjusted = argsLen;
861 }
862
863 struct CLIDebugVector* dvNext = NULL;
864 bool nextArgMandatory = false;
865
866 if (commands[i].format[arg] == '+') {
867 dvNext = _parseArg(debugger, args, adjusted, lastArg);
868 --arg;
869 } else {
870 nextArgMandatory = isupper(commands[i].format[arg]) || (commands[i].format[arg] == '*');
871 dvNext = _parseArg(debugger, args, adjusted, commands[i].format[arg]);
872 lastArg = commands[i].format[arg];
873 }
874
875 args += adjusted;
876 argsLen -= adjusted;
877
878 if (!dvNext) {
879 if (!nextArgMandatory) {
880 args = NULL;
881 }
882 break;
883 }
884 if (dvNext->type == CLIDV_ERROR_TYPE) {
885 debugger->backend->printf(debugger->backend, "Parse error\n");
886 _DVFree(dv);
887 return 0;
888 }
889
890 if (dvLast) {
891 dvLast->next = dvNext;
892 dvLast = dvNext;
893 } else {
894 dv = dvNext;
895 dvLast = dv;
896 }
897 }
898 }
899
900 if (args) {
901 while (isspace(args[0]) && argsLen) {
902 ++args;
903 --argsLen;
904 }
905 }
906 if (args && argsLen) {
907 debugger->backend->printf(debugger->backend, "Wrong number of arguments\n");
908 _DVFree(dv);
909 return 0;
910 }
911 commands[i].command(debugger, dv);
912 _DVFree(dv);
913 return 1;
914 }
915 }
916 return -1;
917}
918
919static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count) {
920 const char* firstSpace = strchr(line, ' ');
921 size_t cmdLength;
922 if (firstSpace) {
923 cmdLength = firstSpace - line;
924 } else {
925 cmdLength = count;
926 }
927
928 const char* args = 0;
929 if (firstSpace) {
930 args = firstSpace + 1;
931 }
932 int result = _tryCommands(debugger, _debuggerCommands, _debuggerCommandAliases, line, cmdLength, args, count - cmdLength - 1);
933 if (result < 0 && debugger->system) {
934 result = _tryCommands(debugger, debugger->system->commands, debugger->system->commandAliases, line, cmdLength, args, count - cmdLength - 1);
935 if (result < 0) {
936 result = _tryCommands(debugger, debugger->system->platformCommands, debugger->system->platformCommandAliases, line, cmdLength, args, count - cmdLength - 1);
937 }
938 }
939 if (result < 0) {
940 debugger->backend->printf(debugger->backend, "Command not found\n");
941 }
942 return false;
943}
944
945static void _commandLine(struct mDebugger* debugger) {
946 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
947 const char* line;
948 size_t len;
949 _printStatus(cliDebugger, 0);
950 while (debugger->state == DEBUGGER_PAUSED) {
951 line = cliDebugger->backend->readline(cliDebugger->backend, &len);
952 if (!line || len == 0) {
953 debugger->state = DEBUGGER_SHUTDOWN;
954 return;
955 }
956 if (line[0] == '\n') {
957 line = cliDebugger->backend->historyLast(cliDebugger->backend, &len);
958 if (line && len) {
959 _parse(cliDebugger, line, len);
960 }
961 } else {
962 _parse(cliDebugger, line, len);
963 cliDebugger->backend->historyAppend(cliDebugger->backend, line);
964 }
965 }
966}
967
968static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
969 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
970 if (cliDebugger->traceRemaining > 0) {
971 cliDebugger->traceRemaining = 0;
972 }
973 switch (reason) {
974 case DEBUGGER_ENTER_MANUAL:
975 case DEBUGGER_ENTER_ATTACHED:
976 break;
977 case DEBUGGER_ENTER_BREAKPOINT:
978 if (info) {
979 if (info->pointId > 0) {
980 cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint %zi at 0x%08X\n", info->pointId, info->address);
981 } else {
982 cliDebugger->backend->printf(cliDebugger->backend, "Hit unknown breakpoint at 0x%08X\n", info->address);
983 }
984 } else {
985 cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint\n");
986 }
987 break;
988 case DEBUGGER_ENTER_WATCHPOINT:
989 if (info) {
990 if (info->type.wp.accessType & WATCHPOINT_WRITE) {
991 cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint %zi at 0x%08X: (new value = 0x%08X, old value = 0x%08X)\n", info->pointId, info->address, info->type.wp.newValue, info->type.wp.oldValue);
992 } else {
993 cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint %zi at 0x%08X: (value = 0x%08X)\n", info->pointId, info->address, info->type.wp.oldValue);
994 }
995 } else {
996 cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint\n");
997 }
998 break;
999 case DEBUGGER_ENTER_ILLEGAL_OP:
1000 if (info) {
1001 cliDebugger->backend->printf(cliDebugger->backend, "Hit illegal opcode at 0x%08X: 0x%08X\n", info->address, info->type.bp.opcode);
1002 } else {
1003 cliDebugger->backend->printf(cliDebugger->backend, "Hit illegal opcode\n");
1004 }
1005 break;
1006 }
1007}
1008
1009static void _cliDebuggerInit(struct mDebugger* debugger) {
1010 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1011 cliDebugger->traceRemaining = 0;
1012 cliDebugger->traceVf = NULL;
1013 cliDebugger->backend->init(cliDebugger->backend);
1014}
1015
1016static void _cliDebuggerDeinit(struct mDebugger* debugger) {
1017 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1018 if (cliDebugger->traceVf) {
1019 cliDebugger->traceVf->close(cliDebugger->traceVf);
1020 cliDebugger->traceVf = NULL;
1021 }
1022
1023 if (cliDebugger->system) {
1024 if (cliDebugger->system->deinit) {
1025 cliDebugger->system->deinit(cliDebugger->system);
1026 }
1027 free(cliDebugger->system);
1028 cliDebugger->system = NULL;
1029 }
1030 if (cliDebugger->backend && cliDebugger->backend->deinit) {
1031 cliDebugger->backend->deinit(cliDebugger->backend);
1032 cliDebugger->backend = NULL;
1033 }
1034}
1035
1036static void _cliDebuggerCustom(struct mDebugger* debugger) {
1037 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1038 bool retain = true;
1039 enum mDebuggerState next = DEBUGGER_RUNNING;
1040 if (cliDebugger->traceRemaining) {
1041 retain = _doTrace(cliDebugger) && retain;
1042 next = DEBUGGER_PAUSED;
1043 }
1044 if (cliDebugger->system) {
1045 retain = cliDebugger->system->custom(cliDebugger->system) && retain;
1046 }
1047 if (!retain && debugger->state == DEBUGGER_CUSTOM) {
1048 debugger->state = next;
1049 }
1050}
1051
1052void CLIDebuggerCreate(struct CLIDebugger* debugger) {
1053 debugger->d.init = _cliDebuggerInit;
1054 debugger->d.deinit = _cliDebuggerDeinit;
1055 debugger->d.custom = _cliDebuggerCustom;
1056 debugger->d.paused = _commandLine;
1057 debugger->d.entered = _reportEntry;
1058 debugger->d.type = DEBUGGER_CLI;
1059
1060 debugger->system = NULL;
1061 debugger->backend = NULL;
1062}
1063
1064void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSystem* system) {
1065 if (debugger->system) {
1066 if (debugger->system->deinit) {
1067 debugger->system->deinit(debugger->system);
1068 }
1069 free(debugger->system);
1070 }
1071
1072 debugger->system = system;
1073 system->p = debugger;
1074}
1075
1076void CLIDebuggerAttachBackend(struct CLIDebugger* debugger, struct CLIDebuggerBackend* backend) {
1077 if (debugger->backend == backend) {
1078 return;
1079 }
1080 if (debugger->backend && debugger->backend->deinit) {
1081 debugger->backend->deinit(debugger->backend);
1082 }
1083
1084 debugger->backend = backend;
1085 backend->p = debugger;
1086}
1087
1088bool CLIDebuggerTabComplete(struct CLIDebugger* debugger, const char* token, bool initial, size_t tokenLen) {
1089 size_t cmd = 0;
1090 size_t len;
1091 const char* name = 0;
1092 for (len = 1; len <= tokenLen; ++len) {
1093 for (; (name = _debuggerCommands[cmd].name); ++cmd) {
1094 int cmp = strncasecmp(name, token, len);
1095 if (cmp > 0) {
1096 return false;
1097 }
1098 if (cmp == 0) {
1099 break;
1100 }
1101 }
1102 }
1103 if (!name) {
1104 return false;
1105 }
1106 if (_debuggerCommands[cmd + 1].name && strlen(_debuggerCommands[cmd + 1].name) >= len && name[len - 1] == _debuggerCommands[cmd + 1].name[len - 1]) {
1107 --len;
1108 const char* next = 0;
1109 int i;
1110 for (i = cmd + 1; _debuggerCommands[i].name; ++i) {
1111 if (strncasecmp(name, _debuggerCommands[i].name, len)) {
1112 break;
1113 }
1114 next = _debuggerCommands[i].name;
1115 }
1116 if (!next) {
1117 return false;
1118 }
1119
1120 for (; name[len]; ++len) {
1121 if (name[len] != next[len]) {
1122 break;
1123 }
1124 char out[2] = { name[len], '\0' };
1125 debugger->backend->lineAppend(debugger->backend, out);
1126 }
1127 return true;
1128 }
1129 name += len - 1;
1130 debugger->backend->lineAppend(debugger->backend, name);
1131 debugger->backend->lineAppend(debugger->backend, " ");
1132 return true;
1133}