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
29 const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
30 const char* ERROR_OVERFLOW = "Arguments overflow";
31 const char* ERROR_INVALID_ARGS = "Invalid arguments";
32 const char* INFO_BREAKPOINT_ADDED = "Added breakpoint #%" PRIz "i\n";
33 const char* INFO_WATCHPOINT_ADDED = "Added watchpoint #%" PRIz "i\n";
34
35 static struct ParseTree* _parseTree(const char** string);
36 static bool _doTrace(struct CLIDebugger* debugger);
37
38 #if !defined(NDEBUG) && !defined(_WIN32)
39 static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
40 #endif
41 static void _continue(struct CLIDebugger*, struct CLIDebugVector*);
42 static void _disassemble(struct CLIDebugger*, struct CLIDebugVector*);
43 static void _next(struct CLIDebugger*, struct CLIDebugVector*);
44 static void _print(struct CLIDebugger*, struct CLIDebugVector*);
45 static void _printBin(struct CLIDebugger*, struct CLIDebugVector*);
46 static void _printHex(struct CLIDebugger*, struct CLIDebugVector*);
47 static void _printStatus(struct CLIDebugger*, struct CLIDebugVector*);
48 static void _printHelp(struct CLIDebugger*, struct CLIDebugVector*);
49 static void _quit(struct CLIDebugger*, struct CLIDebugVector*);
50 static void _readByte(struct CLIDebugger*, struct CLIDebugVector*);
51 static void _reset(struct CLIDebugger*, struct CLIDebugVector*);
52 static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
53 static void _readWord(struct CLIDebugger*, struct CLIDebugVector*);
54 static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
55 static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
56 static void _listBreakpoints(struct CLIDebugger*, struct CLIDebugVector*);
57 static void _setReadWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
58 static void _setReadWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
59 static void _setWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
60 static void _setWriteChangedWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
61 static void _listWatchpoints(struct CLIDebugger*, struct CLIDebugVector*);
62 static void _trace(struct CLIDebugger*, struct CLIDebugVector*);
63 static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*);
64 static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*);
65 static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*);
66 static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*);
67 static void _dumpByte(struct CLIDebugger*, struct CLIDebugVector*);
68 static void _dumpHalfword(struct CLIDebugger*, struct CLIDebugVector*);
69 static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*);
70 static void _events(struct CLIDebugger*, struct CLIDebugVector*);
71 #ifdef ENABLE_SCRIPTING
72 static void _source(struct CLIDebugger*, struct CLIDebugVector*);
73 #endif
74 static void _backtrace(struct CLIDebugger*, struct CLIDebugVector*);
75 static void _finish(struct CLIDebugger*, struct CLIDebugVector*);
76 static void _setStackTraceMode(struct CLIDebugger*, struct CLIDebugVector*);
77 static void _setSymbol(struct CLIDebugger*, struct CLIDebugVector*);
78 static void _findSymbol(struct CLIDebugger*, struct CLIDebugVector*);
79
80 static 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
125 static 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)
_handleDeath(int sig)149 static void _handleDeath(int sig) {
150 UNUSED(sig);
151 printf("No debugger attached!\n");
152 }
153
_breakInto(struct CLIDebugger * debugger,struct CLIDebugVector * dv)154 static 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
CLIDebuggerCheckTraceMode(struct CLIDebugger * debugger,bool requireEnabled)172 static 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
_continue(struct CLIDebugger * debugger,struct CLIDebugVector * dv)184 static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
185 UNUSED(dv);
186 debugger->d.state = debugger->traceRemaining != 0 ? DEBUGGER_CALLBACK : DEBUGGER_RUNNING;
187 }
188
_next(struct CLIDebugger * debugger,struct CLIDebugVector * dv)189 static 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
_disassemble(struct CLIDebugger * debugger,struct CLIDebugVector * dv)199 static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
200 debugger->system->disassemble(debugger->system, dv);
201 }
202
_parseExpression(struct mDebugger * debugger,struct CLIDebugVector * dv,int32_t * intValue,int * segmentValue)203 static 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
_print(struct CLIDebugger * debugger,struct CLIDebugVector * dv)232 static 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
_printBin(struct CLIDebugger * debugger,struct CLIDebugVector * dv)246 static 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
_printHex(struct CLIDebugger * debugger,struct CLIDebugVector * dv)261 static 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
_printCommands(struct CLIDebugger * debugger,struct CLIDebuggerCommandSummary * commands,struct CLIDebuggerCommandAlias * aliases)271 static 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
_printCommandSummary(struct CLIDebugger * debugger,const char * name,struct CLIDebuggerCommandSummary * commands,struct CLIDebuggerCommandAlias * aliases)294 static 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
_printHelp(struct CLIDebugger * debugger,struct CLIDebugVector * dv)320 static 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
_quit(struct CLIDebugger * debugger,struct CLIDebugVector * dv)340 static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
341 UNUSED(dv);
342 debugger->d.state = DEBUGGER_SHUTDOWN;
343 }
344
_readByte(struct CLIDebugger * debugger,struct CLIDebugVector * dv)345 static 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
_reset(struct CLIDebugger * debugger,struct CLIDebugVector * dv)360 static 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
_readHalfword(struct CLIDebugger * debugger,struct CLIDebugVector * dv)367 static 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
_readWord(struct CLIDebugger * debugger,struct CLIDebugVector * dv)382 static 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
_writeByte(struct CLIDebugger * debugger,struct CLIDebugVector * dv)397 static 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
_writeHalfword(struct CLIDebugger * debugger,struct CLIDebugVector * dv)419 static 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
_writeRegister(struct CLIDebugger * debugger,struct CLIDebugVector * dv)441 static 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
_writeWord(struct CLIDebugger * debugger,struct CLIDebugVector * dv)455 static 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
_dumpByte(struct CLIDebugger * debugger,struct CLIDebugVector * dv)473 static 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
_dumpHalfword(struct CLIDebugger * debugger,struct CLIDebugVector * dv)502 static 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
_dumpWord(struct CLIDebugger * debugger,struct CLIDebugVector * dv)531 static 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
_source(struct CLIDebugger * debugger,struct CLIDebugVector * dv)561 static 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
_parseTree(const char ** string)574 static 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
_setBreakpoint(struct CLIDebugger * debugger,struct CLIDebugVector * dv)605 static 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
_setWatchpoint(struct CLIDebugger * debugger,struct CLIDebugVector * dv,enum mWatchpointType type)630 static 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
_setReadWriteWatchpoint(struct CLIDebugger * debugger,struct CLIDebugVector * dv)659 static void _setReadWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
660 _setWatchpoint(debugger, dv, WATCHPOINT_RW);
661 }
662
_setReadWatchpoint(struct CLIDebugger * debugger,struct CLIDebugVector * dv)663 static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
664 _setWatchpoint(debugger, dv, WATCHPOINT_READ);
665 }
666
_setWriteWatchpoint(struct CLIDebugger * debugger,struct CLIDebugVector * dv)667 static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
668 _setWatchpoint(debugger, dv, WATCHPOINT_WRITE);
669 }
670
_setWriteChangedWatchpoint(struct CLIDebugger * debugger,struct CLIDebugVector * dv)671 static void _setWriteChangedWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
672 _setWatchpoint(debugger, dv, WATCHPOINT_WRITE_CHANGE);
673 }
674
_clearBreakpoint(struct CLIDebugger * debugger,struct CLIDebugVector * dv)675 static 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
_listBreakpoints(struct CLIDebugger * debugger,struct CLIDebugVector * dv)684 static 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
_listWatchpoints(struct CLIDebugger * debugger,struct CLIDebugVector * dv)701 static 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
_trace(struct CLIDebugger * debugger,struct CLIDebugVector * dv)718 static 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
_doTrace(struct CLIDebugger * debugger)742 static 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
_printStatus(struct CLIDebugger * debugger,struct CLIDebugVector * dv)769 static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
770 UNUSED(dv);
771 debugger->system->printStatus(debugger->system);
772 }
773
_events(struct CLIDebugger * debugger,struct CLIDebugVector * dv)774 static 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
CLIDVParse(struct CLIDebugger * debugger,const char * string,size_t length)783 struct 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
CLIDVStringParse(struct CLIDebugger * debugger,const char * string,size_t length)822 struct 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
_DVFree(struct CLIDebugVector * dv)837 static 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
_parseArg(struct CLIDebugger * debugger,const char * args,size_t argsLen,char type)849 static 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
_tryCommands(struct CLIDebugger * debugger,struct CLIDebuggerCommandSummary * commands,struct CLIDebuggerCommandAlias * aliases,const char * command,size_t commandLen,const char * args,size_t argsLen)868 static 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
CLIDebuggerRunCommand(struct CLIDebugger * debugger,const char * line,size_t count)968 bool 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
_commandLine(struct mDebugger * debugger)994 static 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
_reportEntry(struct mDebugger * debugger,enum mDebuggerEntryReason reason,struct mDebuggerEntryInfo * info)1017 static 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
_cliDebuggerInit(struct mDebugger * debugger)1076 static 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 if (cliDebugger->system && cliDebugger->system->init) {
1082 cliDebugger->system->init(cliDebugger->system);
1083 }
1084 }
1085
_cliDebuggerDeinit(struct mDebugger * debugger)1086 static void _cliDebuggerDeinit(struct mDebugger* debugger) {
1087 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1088 if (cliDebugger->traceVf) {
1089 cliDebugger->traceVf->close(cliDebugger->traceVf);
1090 cliDebugger->traceVf = NULL;
1091 }
1092
1093 if (cliDebugger->system) {
1094 if (cliDebugger->system->deinit) {
1095 cliDebugger->system->deinit(cliDebugger->system);
1096 }
1097 free(cliDebugger->system);
1098 cliDebugger->system = NULL;
1099 }
1100 if (cliDebugger->backend && cliDebugger->backend->deinit) {
1101 cliDebugger->backend->deinit(cliDebugger->backend);
1102 cliDebugger->backend = NULL;
1103 }
1104 }
1105
_cliDebuggerCustom(struct mDebugger * debugger)1106 static void _cliDebuggerCustom(struct mDebugger* debugger) {
1107 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1108 bool retain = true;
1109 enum mDebuggerState next = DEBUGGER_RUNNING;
1110 if (cliDebugger->traceRemaining) {
1111 retain = _doTrace(cliDebugger) && retain;
1112 next = DEBUGGER_PAUSED;
1113 }
1114 if (cliDebugger->system) {
1115 retain = cliDebugger->system->custom(cliDebugger->system) && retain;
1116 }
1117 if (!retain && debugger->state == DEBUGGER_CALLBACK) {
1118 debugger->state = next;
1119 }
1120 }
1121
CLIDebuggerCreate(struct CLIDebugger * debugger)1122 void CLIDebuggerCreate(struct CLIDebugger* debugger) {
1123 debugger->d.init = _cliDebuggerInit;
1124 debugger->d.deinit = _cliDebuggerDeinit;
1125 debugger->d.custom = _cliDebuggerCustom;
1126 debugger->d.paused = _commandLine;
1127 debugger->d.entered = _reportEntry;
1128 debugger->d.type = DEBUGGER_CLI;
1129
1130 debugger->system = NULL;
1131 debugger->backend = NULL;
1132 }
1133
CLIDebuggerAttachSystem(struct CLIDebugger * debugger,struct CLIDebuggerSystem * system)1134 void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSystem* system) {
1135 if (debugger->system) {
1136 if (debugger->system->deinit) {
1137 debugger->system->deinit(debugger->system);
1138 }
1139 free(debugger->system);
1140 }
1141
1142 debugger->system = system;
1143 system->p = debugger;
1144 }
1145
CLIDebuggerAttachBackend(struct CLIDebugger * debugger,struct CLIDebuggerBackend * backend)1146 void CLIDebuggerAttachBackend(struct CLIDebugger* debugger, struct CLIDebuggerBackend* backend) {
1147 if (debugger->backend == backend) {
1148 return;
1149 }
1150 if (debugger->backend && debugger->backend->deinit) {
1151 debugger->backend->deinit(debugger->backend);
1152 }
1153
1154 debugger->backend = backend;
1155 backend->p = debugger;
1156 }
1157
CLIDebuggerTabComplete(struct CLIDebugger * debugger,const char * token,bool initial,size_t tokenLen)1158 bool CLIDebuggerTabComplete(struct CLIDebugger* debugger, const char* token, bool initial, size_t tokenLen) {
1159 size_t cmd = 0;
1160 size_t len;
1161 const char* name = 0;
1162 for (len = 1; len <= tokenLen; ++len) {
1163 for (; (name = _debuggerCommands[cmd].name); ++cmd) {
1164 int cmp = strncasecmp(name, token, len);
1165 if (cmp > 0) {
1166 return false;
1167 }
1168 if (cmp == 0) {
1169 break;
1170 }
1171 }
1172 }
1173 if (!name) {
1174 return false;
1175 }
1176 if (_debuggerCommands[cmd + 1].name && strlen(_debuggerCommands[cmd + 1].name) >= len && name[len - 1] == _debuggerCommands[cmd + 1].name[len - 1]) {
1177 --len;
1178 const char* next = 0;
1179 int i;
1180 for (i = cmd + 1; _debuggerCommands[i].name; ++i) {
1181 if (strncasecmp(name, _debuggerCommands[i].name, len)) {
1182 break;
1183 }
1184 next = _debuggerCommands[i].name;
1185 }
1186 if (!next) {
1187 return false;
1188 }
1189
1190 for (; name[len]; ++len) {
1191 if (name[len] != next[len]) {
1192 break;
1193 }
1194 char out[2] = { name[len], '\0' };
1195 debugger->backend->lineAppend(debugger->backend, out);
1196 }
1197 return true;
1198 }
1199 name += len - 1;
1200 debugger->backend->lineAppend(debugger->backend, name);
1201 debugger->backend->lineAppend(debugger->backend, " ");
1202 return true;
1203 }
1204
_backtrace(struct CLIDebugger * debugger,struct CLIDebugVector * dv)1205 static void _backtrace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
1206 if (!CLIDebuggerCheckTraceMode(debugger, true)) {
1207 return;
1208 }
1209 struct mStackTrace* stack = &debugger->d.stackTrace;
1210 ssize_t frames = mStackTraceGetDepth(stack);
1211 if (dv && dv->type == CLIDV_INT_TYPE && dv->intValue < frames) {
1212 frames = dv->intValue;
1213 }
1214 ssize_t i;
1215 struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
1216 for (i = 0; i < frames; ++i) {
1217 char trace[1024];
1218 size_t traceSize = sizeof(trace) - 2;
1219 mStackTraceFormatFrame(stack, symbolTable, i, trace, &traceSize);
1220 debugger->backend->printf(debugger->backend, "%s", trace);
1221 }
1222 }
1223
_finish(struct CLIDebugger * debugger,struct CLIDebugVector * dv)1224 static void _finish(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
1225 UNUSED(dv);
1226 if (!CLIDebuggerCheckTraceMode(debugger, true)) {
1227 return;
1228 }
1229 struct mStackTrace* stack = &debugger->d.stackTrace;
1230 struct mStackFrame* frame = mStackTraceGetFrame(stack, 0);
1231 if (!frame) {
1232 debugger->backend->printf(debugger->backend, "No current stack frame.\n");
1233 return;
1234 }
1235 frame->breakWhenFinished = true;
1236 _continue(debugger, dv);
1237 }
1238
_setStackTraceMode(struct CLIDebugger * debugger,struct CLIDebugVector * dv)1239 static void _setStackTraceMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
1240 if (!CLIDebuggerCheckTraceMode(debugger, false)) {
1241 return;
1242 }
1243 if (!dv) {
1244 debugger->backend->printf(debugger->backend, "off disable stack tracing (default)\n");
1245 debugger->backend->printf(debugger->backend, "trace-only enable stack tracing\n");
1246 debugger->backend->printf(debugger->backend, "break-call break on function calls\n");
1247 debugger->backend->printf(debugger->backend, "break-return break on function returns\n");
1248 debugger->backend->printf(debugger->backend, "break-all break on function calls and returns\n");
1249 return;
1250 }
1251 if (dv->type != CLIDV_CHAR_TYPE) {
1252 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
1253 return;
1254 }
1255 struct mDebuggerPlatform* platform = debugger->d.platform;
1256 if (strcmp(dv->charValue, "off") == 0) {
1257 platform->setStackTraceMode(platform, STACK_TRACE_DISABLED);
1258 } else if (strcmp(dv->charValue, "trace-only") == 0) {
1259 platform->setStackTraceMode(platform, STACK_TRACE_ENABLED);
1260 } else if (strcmp(dv->charValue, "break-call") == 0) {
1261 platform->setStackTraceMode(platform, STACK_TRACE_BREAK_ON_CALL);
1262 } else if (strcmp(dv->charValue, "break-return") == 0) {
1263 platform->setStackTraceMode(platform, STACK_TRACE_BREAK_ON_RETURN);
1264 } else if (strcmp(dv->charValue, "break-all") == 0) {
1265 platform->setStackTraceMode(platform, STACK_TRACE_BREAK_ON_BOTH);
1266 } else {
1267 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
1268 }
1269 }
1270
_setSymbol(struct CLIDebugger * debugger,struct CLIDebugVector * dv)1271 static void _setSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
1272 struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
1273 if (!symbolTable) {
1274 debugger->backend->printf(debugger->backend, "No symbol table available.\n");
1275 return;
1276 }
1277 if (!dv || !dv->next) {
1278 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
1279 return;
1280 }
1281 if (dv->type != CLIDV_CHAR_TYPE || dv->next->type != CLIDV_INT_TYPE) {
1282 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
1283 return;
1284 }
1285 mDebuggerSymbolAdd(symbolTable, dv->charValue, dv->next->intValue, dv->next->segmentValue);
1286 }
1287
_findSymbol(struct CLIDebugger * debugger,struct CLIDebugVector * dv)1288 static void _findSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
1289 struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
1290 if (!symbolTable) {
1291 debugger->backend->printf(debugger->backend, "No symbol table available.\n");
1292 return;
1293 }
1294 if (!dv) {
1295 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
1296 return;
1297 }
1298 if (dv->type != CLIDV_INT_TYPE) {
1299 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
1300 return;
1301 }
1302 const char* name = mDebuggerSymbolReverseLookup(symbolTable, dv->intValue, dv->segmentValue);
1303 if (name) {
1304 if (dv->segmentValue >= 0) {
1305 debugger->backend->printf(debugger->backend, " 0x%02X:%08X = %s\n", dv->segmentValue, dv->intValue, name);
1306 } else {
1307 debugger->backend->printf(debugger->backend, " 0x%08X = %s\n", dv->intValue, name);
1308 }
1309 } else {
1310 debugger->backend->printf(debugger->backend, "Not found.\n");
1311 }
1312 }
1313