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 size_t traceSize = sizeof(trace) - 2;
713 debugger->d.platform->trace(debugger->d.platform, trace, &traceSize);
714 if (traceSize + 1 <= sizeof(trace)) {
715 trace[traceSize] = '\n';
716 trace[traceSize + 1] = '\0';
717 }
718 if (debugger->traceVf) {
719 debugger->traceVf->write(debugger->traceVf, trace, traceSize + 1);
720 } else {
721 debugger->backend->printf(debugger->backend, "%s", trace);
722 }
723 if (debugger->traceRemaining > 0) {
724 --debugger->traceRemaining;
725 }
726 return debugger->traceRemaining != 0;
727}
728
729static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
730 UNUSED(dv);
731 debugger->system->printStatus(debugger->system);
732}
733
734struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* string, size_t length) {
735 if (!string || length < 1) {
736 return 0;
737 }
738
739 struct CLIDebugVector dvTemp = { .type = CLIDV_INT_TYPE, .segmentValue = -1 };
740
741 struct LexVector lv;
742 LexVectorInit(&lv, 0);
743 size_t adjusted = lexExpression(&lv, string, length, " ");
744 if (adjusted > length) {
745 dvTemp.type = CLIDV_ERROR_TYPE;
746 }
747
748 struct ParseTree tree;
749 parseLexedExpression(&tree, &lv);
750 if (tree.token.type == TOKEN_ERROR_TYPE) {
751 dvTemp.type = CLIDV_ERROR_TYPE;
752 } else {
753 if (!mDebuggerEvaluateParseTree(&debugger->d, &tree, &dvTemp.intValue, &dvTemp.segmentValue)) {
754 dvTemp.type = CLIDV_ERROR_TYPE;
755 }
756 }
757
758 parseFree(&tree);
759
760 lexFree(&lv);
761 LexVectorDeinit(&lv);
762
763 struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
764 if (dvTemp.type == CLIDV_ERROR_TYPE) {
765 dv->type = CLIDV_ERROR_TYPE;
766 dv->next = 0;
767 } else {
768 *dv = dvTemp;
769 }
770 return dv;
771}
772
773struct CLIDebugVector* CLIDVStringParse(struct CLIDebugger* debugger, const char* string, size_t length) {
774 UNUSED(debugger);
775 if (!string || length < 1) {
776 return 0;
777 }
778
779 struct CLIDebugVector dvTemp = { .type = CLIDV_CHAR_TYPE };
780
781 dvTemp.charValue = strndup(string, length);
782
783 struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
784 *dv = dvTemp;
785 return dv;
786}
787
788static void _DVFree(struct CLIDebugVector* dv) {
789 struct CLIDebugVector* next;
790 while (dv) {
791 next = dv->next;
792 if (dv->type == CLIDV_CHAR_TYPE) {
793 free(dv->charValue);
794 }
795 free(dv);
796 dv = next;
797 }
798}
799
800static struct CLIDebugVector* _parseArg(struct CLIDebugger* debugger, const char* args, size_t argsLen, char type) {
801 struct CLIDebugVector* dv = NULL;
802 switch (type) {
803 case 'I':
804 case 'i':
805 return CLIDVParse(debugger, args, argsLen);
806 case 'S':
807 case 's':
808 return CLIDVStringParse(debugger, args, argsLen);
809 case '*':
810 dv = _parseArg(debugger, args, argsLen, 'I');
811 if (!dv) {
812 dv = _parseArg(debugger, args, argsLen, 'S');
813 }
814 break;
815 }
816 return dv;
817}
818
819static int _tryCommands(struct CLIDebugger* debugger, struct CLIDebuggerCommandSummary* commands, struct CLIDebuggerCommandAlias* aliases, const char* command, size_t commandLen, const char* args, size_t argsLen) {
820 struct CLIDebugVector* dv = NULL;
821 struct CLIDebugVector* dvLast = NULL;
822 int i;
823 const char* name;
824 if (aliases) {
825 for (i = 0; (name = aliases[i].name); ++i) {
826 if (strlen(name) != commandLen) {
827 continue;
828 }
829 if (strncasecmp(name, command, commandLen) == 0) {
830 command = aliases[i].original;
831 commandLen = strlen(aliases[i].original);
832 }
833 }
834 }
835 for (i = 0; (name = commands[i].name); ++i) {
836 if (strlen(name) != commandLen) {
837 continue;
838 }
839 if (strncasecmp(name, command, commandLen) == 0) {
840 if (commands[i].format && args) {
841 char lastArg = '\0';
842 int arg;
843 for (arg = 0; commands[i].format[arg] && argsLen; ++arg) {
844 while (isspace(args[0]) && argsLen) {
845 ++args;
846 --argsLen;
847 }
848 if (!args[0] || !argsLen) {
849 debugger->backend->printf(debugger->backend, "Wrong number of arguments\n");
850 _DVFree(dv);
851 return 0;
852 }
853
854 size_t adjusted;
855 const char* next = strchr(args, ' ');
856 if (next) {
857 adjusted = next - args;
858 } else {
859 adjusted = argsLen;
860 }
861
862 struct CLIDebugVector* dvNext = NULL;
863 bool nextArgMandatory = false;
864
865 if (commands[i].format[arg] == '+') {
866 dvNext = _parseArg(debugger, args, adjusted, lastArg);
867 --arg;
868 } else {
869 nextArgMandatory = isupper(commands[i].format[arg]) || (commands[i].format[arg] == '*');
870 dvNext = _parseArg(debugger, args, adjusted, commands[i].format[arg]);
871 lastArg = commands[i].format[arg];
872 }
873
874 args += adjusted;
875 argsLen -= adjusted;
876
877 if (!dvNext) {
878 if (!nextArgMandatory) {
879 args = NULL;
880 }
881 break;
882 }
883 if (dvNext->type == CLIDV_ERROR_TYPE) {
884 debugger->backend->printf(debugger->backend, "Parse error\n");
885 _DVFree(dv);
886 return 0;
887 }
888
889 if (dvLast) {
890 dvLast->next = dvNext;
891 dvLast = dvNext;
892 } else {
893 dv = dvNext;
894 dvLast = dv;
895 }
896 }
897 }
898
899 if (args) {
900 while (isspace(args[0]) && argsLen) {
901 ++args;
902 --argsLen;
903 }
904 }
905 if (args && argsLen) {
906 debugger->backend->printf(debugger->backend, "Wrong number of arguments\n");
907 _DVFree(dv);
908 return 0;
909 }
910 commands[i].command(debugger, dv);
911 _DVFree(dv);
912 return 1;
913 }
914 }
915 return -1;
916}
917
918static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count) {
919 const char* firstSpace = strchr(line, ' ');
920 size_t cmdLength;
921 if (firstSpace) {
922 cmdLength = firstSpace - line;
923 } else {
924 cmdLength = count;
925 }
926
927 const char* args = 0;
928 if (firstSpace) {
929 args = firstSpace + 1;
930 }
931 int result = _tryCommands(debugger, _debuggerCommands, _debuggerCommandAliases, line, cmdLength, args, count - cmdLength - 1);
932 if (result < 0 && debugger->system) {
933 result = _tryCommands(debugger, debugger->system->commands, debugger->system->commandAliases, line, cmdLength, args, count - cmdLength - 1);
934 if (result < 0) {
935 result = _tryCommands(debugger, debugger->system->platformCommands, debugger->system->platformCommandAliases, line, cmdLength, args, count - cmdLength - 1);
936 }
937 }
938 if (result < 0) {
939 debugger->backend->printf(debugger->backend, "Command not found\n");
940 }
941 return false;
942}
943
944static void _commandLine(struct mDebugger* debugger) {
945 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
946 const char* line;
947 size_t len;
948 _printStatus(cliDebugger, 0);
949 while (debugger->state == DEBUGGER_PAUSED) {
950 line = cliDebugger->backend->readline(cliDebugger->backend, &len);
951 if (!line || len == 0) {
952 debugger->state = DEBUGGER_SHUTDOWN;
953 return;
954 }
955 if (line[0] == '\n') {
956 line = cliDebugger->backend->historyLast(cliDebugger->backend, &len);
957 if (line && len) {
958 _parse(cliDebugger, line, len);
959 }
960 } else {
961 _parse(cliDebugger, line, len);
962 cliDebugger->backend->historyAppend(cliDebugger->backend, line);
963 }
964 }
965}
966
967static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
968 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
969 if (cliDebugger->traceRemaining > 0) {
970 cliDebugger->traceRemaining = 0;
971 }
972 switch (reason) {
973 case DEBUGGER_ENTER_MANUAL:
974 case DEBUGGER_ENTER_ATTACHED:
975 break;
976 case DEBUGGER_ENTER_BREAKPOINT:
977 if (info) {
978 if (info->pointId > 0) {
979 cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint %zi at 0x%08X\n", info->pointId, info->address);
980 } else {
981 cliDebugger->backend->printf(cliDebugger->backend, "Hit unknown breakpoint at 0x%08X\n", info->address);
982 }
983 } else {
984 cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint\n");
985 }
986 break;
987 case DEBUGGER_ENTER_WATCHPOINT:
988 if (info) {
989 if (info->type.wp.accessType & WATCHPOINT_WRITE) {
990 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);
991 } else {
992 cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint %zi at 0x%08X: (value = 0x%08X)\n", info->pointId, info->address, info->type.wp.oldValue);
993 }
994 } else {
995 cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint\n");
996 }
997 break;
998 case DEBUGGER_ENTER_ILLEGAL_OP:
999 if (info) {
1000 cliDebugger->backend->printf(cliDebugger->backend, "Hit illegal opcode at 0x%08X: 0x%08X\n", info->address, info->type.bp.opcode);
1001 } else {
1002 cliDebugger->backend->printf(cliDebugger->backend, "Hit illegal opcode\n");
1003 }
1004 break;
1005 }
1006}
1007
1008static void _cliDebuggerInit(struct mDebugger* debugger) {
1009 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1010 cliDebugger->traceRemaining = 0;
1011 cliDebugger->traceVf = NULL;
1012 cliDebugger->backend->init(cliDebugger->backend);
1013}
1014
1015static void _cliDebuggerDeinit(struct mDebugger* debugger) {
1016 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1017 if (cliDebugger->traceVf) {
1018 cliDebugger->traceVf->close(cliDebugger->traceVf);
1019 cliDebugger->traceVf = NULL;
1020 }
1021
1022 if (cliDebugger->system) {
1023 if (cliDebugger->system->deinit) {
1024 cliDebugger->system->deinit(cliDebugger->system);
1025 }
1026 free(cliDebugger->system);
1027 cliDebugger->system = NULL;
1028 }
1029 if (cliDebugger->backend && cliDebugger->backend->deinit) {
1030 cliDebugger->backend->deinit(cliDebugger->backend);
1031 cliDebugger->backend = NULL;
1032 }
1033}
1034
1035static void _cliDebuggerCustom(struct mDebugger* debugger) {
1036 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1037 bool retain = true;
1038 enum mDebuggerState next = DEBUGGER_RUNNING;
1039 if (cliDebugger->traceRemaining) {
1040 retain = _doTrace(cliDebugger) && retain;
1041 next = DEBUGGER_PAUSED;
1042 }
1043 if (cliDebugger->system) {
1044 retain = cliDebugger->system->custom(cliDebugger->system) && retain;
1045 }
1046 if (!retain && debugger->state == DEBUGGER_CUSTOM) {
1047 debugger->state = next;
1048 }
1049}
1050
1051void CLIDebuggerCreate(struct CLIDebugger* debugger) {
1052 debugger->d.init = _cliDebuggerInit;
1053 debugger->d.deinit = _cliDebuggerDeinit;
1054 debugger->d.custom = _cliDebuggerCustom;
1055 debugger->d.paused = _commandLine;
1056 debugger->d.entered = _reportEntry;
1057 debugger->d.type = DEBUGGER_CLI;
1058
1059 debugger->system = NULL;
1060 debugger->backend = NULL;
1061}
1062
1063void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSystem* system) {
1064 if (debugger->system) {
1065 if (debugger->system->deinit) {
1066 debugger->system->deinit(debugger->system);
1067 }
1068 free(debugger->system);
1069 }
1070
1071 debugger->system = system;
1072 system->p = debugger;
1073}
1074
1075void CLIDebuggerAttachBackend(struct CLIDebugger* debugger, struct CLIDebuggerBackend* backend) {
1076 if (debugger->backend == backend) {
1077 return;
1078 }
1079 if (debugger->backend && debugger->backend->deinit) {
1080 debugger->backend->deinit(debugger->backend);
1081 }
1082
1083 debugger->backend = backend;
1084 backend->p = debugger;
1085}
1086
1087bool CLIDebuggerTabComplete(struct CLIDebugger* debugger, const char* token, bool initial, size_t tokenLen) {
1088 size_t cmd = 0;
1089 size_t len;
1090 const char* name = 0;
1091 for (len = 1; len <= tokenLen; ++len) {
1092 for (; (name = _debuggerCommands[cmd].name); ++cmd) {
1093 int cmp = strncasecmp(name, token, len);
1094 if (cmp > 0) {
1095 return false;
1096 }
1097 if (cmp == 0) {
1098 break;
1099 }
1100 }
1101 }
1102 if (!name) {
1103 return false;
1104 }
1105 if (_debuggerCommands[cmd + 1].name && strlen(_debuggerCommands[cmd + 1].name) >= len && name[len - 1] == _debuggerCommands[cmd + 1].name[len - 1]) {
1106 --len;
1107 const char* next = 0;
1108 int i;
1109 for (i = cmd + 1; _debuggerCommands[i].name; ++i) {
1110 if (strncasecmp(name, _debuggerCommands[i].name, len)) {
1111 break;
1112 }
1113 next = _debuggerCommands[i].name;
1114 }
1115 if (!next) {
1116 return false;
1117 }
1118
1119 for (; name[len]; ++len) {
1120 if (name[len] != next[len]) {
1121 break;
1122 }
1123 char out[2] = { name[len], '\0' };
1124 debugger->backend->lineAppend(debugger->backend, out);
1125 }
1126 return true;
1127 }
1128 name += len - 1;
1129 debugger->backend->lineAppend(debugger->backend, name);
1130 debugger->backend->lineAppend(debugger->backend, " ");
1131 return true;
1132}