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