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