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