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