src/debugger/cli-debugger.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/debugger/cli-debugger.h>
7
8#include <mgba/internal/debugger/symbols.h>
9
10#include <mgba/core/core.h>
11#include <mgba/core/version.h>
12#include <mgba/internal/debugger/parser.h>
13#include <mgba-util/string.h>
14
15#if ENABLE_SCRIPTING
16#include <mgba/core/scripting.h>
17#endif
18
19#if !defined(NDEBUG) && !defined(_WIN32)
20#include <signal.h>
21#endif
22
23#ifdef USE_PTHREADS
24#include <pthread.h>
25#endif
26
27const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
28const char* ERROR_OVERFLOW = "Arguments overflow";
29const char* ERROR_INVALID_ARGS = "Invalid arguments";
30
31#if !defined(NDEBUG) && !defined(_WIN32)
32static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
33#endif
34static void _continue(struct CLIDebugger*, struct CLIDebugVector*);
35static void _disassemble(struct CLIDebugger*, struct CLIDebugVector*);
36static void _next(struct CLIDebugger*, struct CLIDebugVector*);
37static void _print(struct CLIDebugger*, struct CLIDebugVector*);
38static void _printBin(struct CLIDebugger*, struct CLIDebugVector*);
39static void _printHex(struct CLIDebugger*, struct CLIDebugVector*);
40static void _printStatus(struct CLIDebugger*, struct CLIDebugVector*);
41static void _printHelp(struct CLIDebugger*, struct CLIDebugVector*);
42static void _quit(struct CLIDebugger*, struct CLIDebugVector*);
43static void _readByte(struct CLIDebugger*, struct CLIDebugVector*);
44static void _reset(struct CLIDebugger*, struct CLIDebugVector*);
45static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
46static void _readWord(struct CLIDebugger*, struct CLIDebugVector*);
47static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
48static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
49static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
50static void _setReadWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
51static void _setWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
52static void _trace(struct CLIDebugger*, struct CLIDebugVector*);
53static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*);
54static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*);
55static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*);
56static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*);
57static void _dumpByte(struct CLIDebugger*, struct CLIDebugVector*);
58static void _dumpHalfword(struct CLIDebugger*, struct CLIDebugVector*);
59static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*);
60#ifdef ENABLE_SCRIPTING
61static void _source(struct CLIDebugger*, struct CLIDebugVector*);
62#endif
63
64static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
65 { "b", _setBreakpoint, "I", "Set a breakpoint" },
66 { "break", _setBreakpoint, "I", "Set a breakpoint" },
67 { "c", _continue, "", "Continue execution" },
68 { "continue", _continue, "", "Continue execution" },
69 { "d", _clearBreakpoint, "I", "Delete a breakpoint" },
70 { "delete", _clearBreakpoint, "I", "Delete a breakpoint" },
71 { "dis", _disassemble, "Ii", "Disassemble instructions" },
72 { "disasm", _disassemble, "Ii", "Disassemble instructions" },
73 { "disassemble", _disassemble, "Ii", "Disassemble instructions" },
74 { "h", _printHelp, "S", "Print help" },
75 { "help", _printHelp, "S", "Print help" },
76 { "i", _printStatus, "", "Print the current status" },
77 { "info", _printStatus, "", "Print the current status" },
78 { "n", _next, "", "Execute next instruction" },
79 { "next", _next, "", "Execute next instruction" },
80 { "p", _print, "I", "Print a value" },
81 { "p/t", _printBin, "I", "Print a value as binary" },
82 { "p/x", _printHex, "I", "Print a value as hexadecimal" },
83 { "print", _print, "I", "Print a value" },
84 { "print/t", _printBin, "I", "Print a value as binary" },
85 { "print/x", _printHex, "I", "Print a value as hexadecimal" },
86 { "q", _quit, "", "Quit the emulator" },
87 { "quit", _quit, "", "Quit the emulator" },
88 { "reset", _reset, "", "Reset the emulation" },
89 { "r/1", _readByte, "I", "Read a byte from a specified offset" },
90 { "r/2", _readHalfword, "I", "Read a halfword from a specified offset" },
91 { "r/4", _readWord, "I", "Read a word from a specified offset" },
92 { "status", _printStatus, "", "Print the current status" },
93 { "trace", _trace, "I", "Trace a fixed number of instructions" },
94 { "w", _setWatchpoint, "I", "Set a watchpoint" },
95 { "w/1", _writeByte, "II", "Write a byte at a specified offset" },
96 { "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" },
97 { "w/r", _writeRegister, "SI", "Write a register" },
98 { "w/4", _writeWord, "II", "Write a word at a specified offset" },
99 { "watch", _setWatchpoint, "I", "Set a watchpoint" },
100 { "watch/r", _setReadWatchpoint, "I", "Set a read watchpoint" },
101 { "watch/w", _setWriteWatchpoint, "I", "Set a write watchpoint" },
102 { "x/1", _dumpByte, "Ii", "Examine bytes at a specified offset" },
103 { "x/2", _dumpHalfword, "Ii", "Examine halfwords at a specified offset" },
104 { "x/4", _dumpWord, "Ii", "Examine words at a specified offset" },
105#ifdef ENABLE_SCRIPTING
106 { "source", _source, "S", "Load a script" },
107#endif
108#if !defined(NDEBUG) && !defined(_WIN32)
109 { "!", _breakInto, "", "Break into attached debugger (for developers)" },
110#endif
111 { 0, 0, 0, 0 }
112};
113
114#if !defined(NDEBUG) && !defined(_WIN32)
115static void _handleDeath(int sig) {
116 UNUSED(sig);
117 printf("No debugger attached!\n");
118}
119
120static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
121 UNUSED(debugger);
122 UNUSED(dv);
123 struct sigaction sa, osa;
124 sa.sa_handler = _handleDeath;
125 sigemptyset(&sa.sa_mask);
126 sigaddset(&sa.sa_mask, SIGTRAP);
127 sa.sa_flags = SA_RESTART;
128 sigaction(SIGTRAP, &sa, &osa);
129#ifdef USE_PTHREADS
130 pthread_kill(pthread_self(), SIGTRAP);
131#else
132 kill(getpid(), SIGTRAP);
133#endif
134 sigaction(SIGTRAP, &osa, 0);
135}
136#endif
137
138static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
139 UNUSED(dv);
140 debugger->d.state = DEBUGGER_RUNNING;
141}
142
143static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
144 UNUSED(dv);
145 debugger->d.core->step(debugger->d.core);
146 _printStatus(debugger, 0);
147}
148
149static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
150 debugger->system->disassemble(debugger->system, dv);
151}
152
153static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
154 for (; dv; dv = dv->next) {
155 if (dv->segmentValue >= 0) {
156 debugger->backend->printf(debugger->backend, " $%02X:%04X", dv->segmentValue, dv->intValue);
157 continue;
158 }
159 debugger->backend->printf(debugger->backend, " %u", dv->intValue);
160 }
161 debugger->backend->printf(debugger->backend, "\n");
162}
163
164static void _printBin(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
165 for (; dv; dv = dv->next) {
166 debugger->backend->printf(debugger->backend, " 0b");
167 int i = 32;
168 while (i--) {
169 debugger->backend->printf(debugger->backend, "%u", (dv->intValue >> i) & 1);
170 }
171 }
172 debugger->backend->printf(debugger->backend, "\n");
173}
174
175static void _printHex(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
176 for (; dv; dv = dv->next) {
177 debugger->backend->printf(debugger->backend, " 0x%08X", dv->intValue);
178 }
179 debugger->backend->printf(debugger->backend, "\n");
180}
181
182static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
183 UNUSED(dv);
184 if (!dv) {
185 debugger->backend->printf(debugger->backend, "Generic commands:\n");
186 int i;
187 for (i = 0; _debuggerCommands[i].name; ++i) {
188 debugger->backend->printf(debugger->backend, "%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary);
189 }
190 if (debugger->system) {
191 debugger->backend->printf(debugger->backend, "%s commands:\n", debugger->system->platformName);
192 for (i = 0; debugger->system->platformCommands[i].name; ++i) {
193 debugger->backend->printf(debugger->backend, "%-10s %s\n", debugger->system->platformCommands[i].name, debugger->system->platformCommands[i].summary);
194 }
195 debugger->backend->printf(debugger->backend, "%s commands:\n", debugger->system->name);
196 for (i = 0; debugger->system->commands[i].name; ++i) {
197 debugger->backend->printf(debugger->backend, "%-10s %s\n", debugger->system->commands[i].name, debugger->system->commands[i].summary);
198 }
199 }
200 } else {
201 int i;
202 for (i = 0; _debuggerCommands[i].name; ++i) {
203 if (strcmp(_debuggerCommands[i].name, dv->charValue) == 0) {
204 debugger->backend->printf(debugger->backend, " %s\n", _debuggerCommands[i].summary);
205 }
206 }
207 if (debugger->system) {
208 for (i = 0; debugger->system->platformCommands[i].name; ++i) {
209 if (strcmp(debugger->system->platformCommands[i].name, dv->charValue) == 0) {
210 debugger->backend->printf(debugger->backend, " %s\n", debugger->system->platformCommands[i].summary);
211 }
212 }
213 for (i = 0; debugger->system->commands[i].name; ++i) {
214 if (strcmp(debugger->system->commands[i].name, dv->charValue) == 0) {
215 debugger->backend->printf(debugger->backend, " %s\n", debugger->system->commands[i].summary);
216 }
217 }
218 }
219 }
220}
221
222static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
223 UNUSED(dv);
224 debugger->d.state = DEBUGGER_SHUTDOWN;
225}
226
227static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
228 if (!dv || dv->type != CLIDV_INT_TYPE) {
229 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
230 return;
231 }
232 uint32_t address = dv->intValue;
233 uint8_t value;
234 if (dv->segmentValue >= 0) {
235 value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue);
236 } else {
237 value = debugger->d.core->busRead8(debugger->d.core, address);
238 }
239 debugger->backend->printf(debugger->backend, " 0x%02X\n", value);
240}
241
242static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
243 UNUSED(dv);
244 debugger->d.core->reset(debugger->d.core);
245 _printStatus(debugger, 0);
246}
247
248static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
249 if (!dv || dv->type != CLIDV_INT_TYPE) {
250 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
251 return;
252 }
253 uint32_t address = dv->intValue;
254 uint16_t value;
255 if (dv->segmentValue >= 0) {
256 value = debugger->d.core->rawRead16(debugger->d.core, address & -1, dv->segmentValue);
257 } else {
258 value = debugger->d.core->busRead16(debugger->d.core, address & ~1);
259 }
260 debugger->backend->printf(debugger->backend, " 0x%04X\n", value);
261}
262
263static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
264 if (!dv || dv->type != CLIDV_INT_TYPE) {
265 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
266 return;
267 }
268 uint32_t address = dv->intValue;
269 uint32_t value;
270 if (dv->segmentValue >= 0) {
271 value = debugger->d.core->rawRead32(debugger->d.core, address & -3, dv->segmentValue);
272 } else {
273 value = debugger->d.core->busRead32(debugger->d.core, address & ~3);
274 }
275 debugger->backend->printf(debugger->backend, " 0x%08X\n", value);
276}
277
278static void _writeByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
279 if (!dv || !dv->next) {
280 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
281 return;
282 }
283 if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
284 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
285 return;
286 }
287 uint32_t address = dv->intValue;
288 uint32_t value = dv->next->intValue;
289 if (value > 0xFF) {
290 debugger->backend->printf(debugger->backend, "%s\n", ERROR_OVERFLOW);
291 return;
292 }
293 if (dv->segmentValue >= 0) {
294 debugger->d.core->rawWrite8(debugger->d.core, address, value, dv->segmentValue);
295 } else {
296 debugger->d.core->busWrite8(debugger->d.core, address, value);
297 }
298}
299
300static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
301 if (!dv || !dv->next) {
302 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
303 return;
304 }
305 if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
306 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
307 return;
308 }
309 uint32_t address = dv->intValue;
310 uint32_t value = dv->next->intValue;
311 if (value > 0xFFFF) {
312 debugger->backend->printf(debugger->backend, "%s\n", ERROR_OVERFLOW);
313 return;
314 }
315 if (dv->segmentValue >= 0) {
316 debugger->d.core->rawWrite16(debugger->d.core, address, value, dv->segmentValue);
317 } else {
318 debugger->d.core->busWrite16(debugger->d.core, address, value);
319 }
320}
321
322static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
323 if (!dv || !dv->next) {
324 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
325 return;
326 }
327 if (dv->type != CLIDV_CHAR_TYPE || dv->next->type != CLIDV_INT_TYPE) {
328 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
329 return;
330 }
331 if (!debugger->d.platform->setRegister(debugger->d.platform, dv->charValue, dv->next->intValue)) {
332 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
333 }
334}
335
336static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
337 if (!dv || !dv->next) {
338 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
339 return;
340 }
341 if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
342 debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
343 return;
344 }
345 uint32_t address = dv->intValue;
346 uint32_t value = dv->next->intValue;
347 if (dv->segmentValue >= 0) {
348 debugger->d.core->rawWrite32(debugger->d.core, address, value, dv->segmentValue);
349 } else {
350 debugger->d.core->busWrite32(debugger->d.core, address, value);
351 }
352}
353
354static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
355 if (!dv || dv->type != CLIDV_INT_TYPE) {
356 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
357 return;
358 }
359 uint32_t address = dv->intValue;
360 uint32_t words = 16;
361 if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
362 words = dv->next->intValue;
363 }
364 while (words) {
365 uint32_t line = 16;
366 if (line > words) {
367 line = words;
368 }
369 debugger->backend->printf(debugger->backend, "0x%08X:", address);
370 for (; line > 0; --line, ++address, --words) {
371 uint32_t value;
372 if (dv->segmentValue >= 0) {
373 value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue);
374 } else {
375 value = debugger->d.core->busRead8(debugger->d.core, address);
376 }
377 debugger->backend->printf(debugger->backend, " %02X", value);
378 }
379 debugger->backend->printf(debugger->backend, "\n");
380 }
381}
382
383static void _dumpHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
384 if (!dv || dv->type != CLIDV_INT_TYPE) {
385 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
386 return;
387 }
388 uint32_t address = dv->intValue;
389 uint32_t words = 8;
390 if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
391 words = dv->next->intValue;
392 }
393 while (words) {
394 uint32_t line = 8;
395 if (line > words) {
396 line = words;
397 }
398 debugger->backend->printf(debugger->backend, "0x%08X:", address);
399 for (; line > 0; --line, address += 2, --words) {
400 uint32_t value;
401 if (dv->segmentValue >= 0) {
402 value = debugger->d.core->rawRead16(debugger->d.core, address, dv->segmentValue);
403 } else {
404 value = debugger->d.core->busRead16(debugger->d.core, address);
405 }
406 debugger->backend->printf(debugger->backend, " %04X", value);
407 }
408 debugger->backend->printf(debugger->backend, "\n");
409 }
410}
411
412static void _dumpWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
413 if (!dv || dv->type != CLIDV_INT_TYPE) {
414 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
415 return;
416 }
417 uint32_t address = dv->intValue;
418 uint32_t words = 4;
419 if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
420 words = dv->next->intValue;
421 }
422 while (words) {
423 uint32_t line = 4;
424 if (line > words) {
425 line = words;
426 }
427 debugger->backend->printf(debugger->backend, "0x%08X:", address);
428 for (; line > 0; --line, address += 4, --words) {
429 uint32_t value;
430 if (dv->segmentValue >= 0) {
431 value = debugger->d.core->rawRead32(debugger->d.core, address, dv->segmentValue);
432 } else {
433 value = debugger->d.core->busRead32(debugger->d.core, address);
434 }
435 debugger->backend->printf(debugger->backend, " %08X", value);
436 }
437 debugger->backend->printf(debugger->backend, "\n");
438 }
439}
440
441#ifdef ENABLE_SCRIPTING
442static void _source(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
443 if (!dv) {
444 debugger->backend->printf(debugger->backend, "Needs a filename\n");
445 return;
446 }
447 if (debugger->d.bridge && mScriptBridgeLoadScript(debugger->d.bridge, dv->charValue)) {
448 mScriptBridgeRun(debugger->d.bridge);
449 } else {
450 debugger->backend->printf(debugger->backend, "Failed to load script\n");
451 }
452}
453#endif
454
455static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
456 if (!dv || dv->type != CLIDV_INT_TYPE) {
457 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
458 return;
459 }
460 uint32_t address = dv->intValue;
461 debugger->d.platform->setBreakpoint(debugger->d.platform, address, dv->segmentValue);
462}
463
464static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
465 if (!dv || dv->type != CLIDV_INT_TYPE) {
466 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
467 return;
468 }
469 if (!debugger->d.platform->setWatchpoint) {
470 debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
471 return;
472 }
473 uint32_t address = dv->intValue;
474 debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_RW);
475}
476
477static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
478 if (!dv || dv->type != CLIDV_INT_TYPE) {
479 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
480 return;
481 }
482 if (!debugger->d.platform->setWatchpoint) {
483 debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
484 return;
485 }
486 uint32_t address = dv->intValue;
487 debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_READ);
488}
489
490static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
491 if (!dv || dv->type != CLIDV_INT_TYPE) {
492 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
493 return;
494 }
495 if (!debugger->d.platform->setWatchpoint) {
496 debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
497 return;
498 }
499 uint32_t address = dv->intValue;
500 debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_WRITE);
501}
502
503static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
504 if (!dv || dv->type != CLIDV_INT_TYPE) {
505 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
506 return;
507 }
508 uint32_t address = dv->intValue;
509 debugger->d.platform->clearBreakpoint(debugger->d.platform, address, dv->segmentValue);
510 if (debugger->d.platform->clearWatchpoint) {
511 debugger->d.platform->clearWatchpoint(debugger->d.platform, address, dv->segmentValue);
512 }
513}
514
515static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
516 if (!dv || dv->type != CLIDV_INT_TYPE) {
517 debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
518 return;
519 }
520
521 char trace[1024];
522 trace[sizeof(trace) - 1] = '\0';
523
524 int i;
525 for (i = 0; i < dv->intValue; ++i) {
526 debugger->d.core->step(debugger->d.core);
527 size_t traceSize = sizeof(trace) - 1;
528 debugger->d.platform->trace(debugger->d.platform, trace, &traceSize);
529 if (traceSize + 1 < sizeof(trace)) {
530 trace[traceSize + 1] = '\0';
531 }
532 debugger->backend->printf(debugger->backend, "%s\n", trace);
533 }
534}
535
536static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
537 UNUSED(dv);
538 debugger->system->printStatus(debugger->system);
539}
540
541static uint32_t _performOperation(enum Operation operation, uint32_t current, uint32_t next, struct CLIDebugVector* dv) {
542 switch (operation) {
543 case OP_ASSIGN:
544 current = next;
545 break;
546 case OP_ADD:
547 current += next;
548 break;
549 case OP_SUBTRACT:
550 current -= next;
551 break;
552 case OP_MULTIPLY:
553 current *= next;
554 break;
555 case OP_DIVIDE:
556 if (next != 0) {
557 current /= next;
558 } else {
559 dv->type = CLIDV_ERROR_TYPE;
560 return 0;
561 }
562 break;
563 case OP_AND:
564 current &= next;
565 break;
566 case OP_OR:
567 current |= next;
568 break;
569 case OP_XOR:
570 current ^= next;
571 break;
572 case OP_LESS:
573 current = current < next;
574 break;
575 case OP_GREATER:
576 current = current > next;
577 break;
578 case OP_EQUAL:
579 current = current == next;
580 break;
581 case OP_LE:
582 current = current <= next;
583 break;
584 case OP_GE:
585 current = current >= next;
586 break;
587 }
588 return current;
589}
590
591static void _lookupIdentifier(struct mDebugger* debugger, const char* name, struct CLIDebugVector* dv) {
592 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
593 if (cliDebugger->system) {
594 uint32_t value;
595#ifdef ENABLE_SCRIPTING
596 if (debugger->bridge && mScriptBridgeLookupSymbol(debugger->bridge, name, &dv->intValue)) {
597 return;
598 }
599#endif
600 if (debugger->core->symbolTable && mDebuggerSymbolLookup(debugger->core->symbolTable, name, &dv->intValue, &dv->segmentValue)) {
601 return;
602 }
603 dv->type = CLIDV_INT_TYPE;
604 if (debugger->platform->getRegister(debugger->platform, name, &dv->intValue)) {
605 return;
606 }
607 value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv);
608 if (dv->type != CLIDV_ERROR_TYPE) {
609 dv->intValue = value;
610 return;
611 }
612 }
613 dv->type = CLIDV_ERROR_TYPE;
614}
615
616static void _evaluateParseTree(struct mDebugger* debugger, struct ParseTree* tree, struct CLIDebugVector* dv) {
617 int32_t lhs, rhs;
618 switch (tree->token.type) {
619 case TOKEN_UINT_TYPE:
620 dv->intValue = tree->token.uintValue;
621 break;
622 case TOKEN_SEGMENT_TYPE:
623 _evaluateParseTree(debugger, tree->lhs, dv);
624 dv->segmentValue = dv->intValue;
625 _evaluateParseTree(debugger, tree->rhs, dv);
626 break;
627 case TOKEN_OPERATOR_TYPE:
628 _evaluateParseTree(debugger, tree->lhs, dv);
629 lhs = dv->intValue;
630 _evaluateParseTree(debugger, tree->rhs, dv);
631 rhs = dv->intValue;
632 dv->intValue = _performOperation(tree->token.operatorValue, lhs, rhs, dv);
633 break;
634 case TOKEN_IDENTIFIER_TYPE:
635 _lookupIdentifier(debugger, tree->token.identifierValue, dv);
636 break;
637 case TOKEN_ERROR_TYPE:
638 default:
639 dv->type = CLIDV_ERROR_TYPE;
640 }
641}
642
643struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* string, size_t length) {
644 if (!string || length < 1) {
645 return 0;
646 }
647
648 struct CLIDebugVector dvTemp = { .type = CLIDV_INT_TYPE, .segmentValue = -1 };
649
650 struct LexVector lv = { .next = 0 };
651 size_t adjusted = lexExpression(&lv, string, length);
652 if (adjusted > length) {
653 dvTemp.type = CLIDV_ERROR_TYPE;
654 lexFree(lv.next);
655 }
656
657 struct ParseTree tree;
658 parseLexedExpression(&tree, &lv);
659 if (tree.token.type == TOKEN_ERROR_TYPE) {
660 dvTemp.type = CLIDV_ERROR_TYPE;
661 } else {
662 _evaluateParseTree(&debugger->d, &tree, &dvTemp);
663 }
664
665 parseFree(tree.lhs);
666 parseFree(tree.rhs);
667
668 struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
669 if (dvTemp.type == CLIDV_ERROR_TYPE) {
670 dv->type = CLIDV_ERROR_TYPE;
671 dv->next = 0;
672 } else {
673 *dv = dvTemp;
674 }
675 return dv;
676}
677
678struct CLIDebugVector* CLIDVStringParse(struct CLIDebugger* debugger, const char* string, size_t length) {
679 UNUSED(debugger);
680 if (!string || length < 1) {
681 return 0;
682 }
683
684 struct CLIDebugVector dvTemp = { .type = CLIDV_CHAR_TYPE };
685
686 dvTemp.charValue = strndup(string, length);
687
688 struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
689 *dv = dvTemp;
690 return dv;
691}
692
693static void _DVFree(struct CLIDebugVector* dv) {
694 struct CLIDebugVector* next;
695 while (dv) {
696 next = dv->next;
697 if (dv->type == CLIDV_CHAR_TYPE) {
698 free(dv->charValue);
699 }
700 free(dv);
701 dv = next;
702 }
703}
704
705static struct CLIDebugVector* _parseArg(struct CLIDebugger* debugger, const char* args, size_t argsLen, char type) {
706 struct CLIDebugVector* dv = NULL;
707 switch (type) {
708 case 'I':
709 case 'i':
710 return CLIDVParse(debugger, args, argsLen);
711 case 'S':
712 case 's':
713 return CLIDVStringParse(debugger, args, argsLen);
714 case '*':
715 dv = _parseArg(debugger, args, argsLen, 'I');
716 if (!dv) {
717 dv = _parseArg(debugger, args, argsLen, 'S');
718 }
719 break;
720 }
721 return dv;
722}
723
724static int _tryCommands(struct CLIDebugger* debugger, struct CLIDebuggerCommandSummary* commands, const char* command, size_t commandLen, const char* args, size_t argsLen) {
725 struct CLIDebugVector* dv = NULL;
726 struct CLIDebugVector* dvLast = NULL;
727 int i;
728 const char* name;
729 for (i = 0; (name = commands[i].name); ++i) {
730 if (strlen(name) != commandLen) {
731 continue;
732 }
733 if (strncasecmp(name, command, commandLen) == 0) {
734 if (commands[i].format && args) {
735 char lastArg = '\0';
736 int arg;
737 for (arg = 0; commands[i].format[arg] && argsLen; ++arg) {
738 while (isspace(args[0]) && argsLen) {
739 ++args;
740 --argsLen;
741 }
742 if (!args[0] || !argsLen) {
743 debugger->backend->printf(debugger->backend, "Wrong number of arguments\n");
744 _DVFree(dv);
745 return 0;
746 }
747
748 size_t adjusted;
749 const char* next = strchr(args, ' ');
750 if (next) {
751 adjusted = next - args;
752 } else {
753 adjusted = argsLen;
754 }
755
756 struct CLIDebugVector* dvNext = NULL;
757 bool nextArgMandatory = false;
758
759 if (commands[i].format[arg] == '+') {
760 dvNext = _parseArg(debugger, args, adjusted, lastArg);
761 --args;
762 } else {
763 nextArgMandatory = isupper(commands[i].format[arg]) || (commands[i].format[arg] == '*');
764 dvNext = _parseArg(debugger, args, adjusted, commands[i].format[arg]);
765 }
766
767 args += adjusted;
768 argsLen -= adjusted;
769
770 if (!dvNext) {
771 if (!nextArgMandatory) {
772 args = NULL;
773 }
774 break;
775 }
776 if (dvNext->type == CLIDV_ERROR_TYPE) {
777 debugger->backend->printf(debugger->backend, "Parse error\n");
778 _DVFree(dv);
779 return 0;
780 }
781
782 if (dvLast) {
783 dvLast->next = dvNext;
784 dvLast = dvNext;
785 } else {
786 dv = dvNext;
787 dvLast = dv;
788 }
789 }
790 }
791
792 if (args) {
793 while (isspace(args[0]) && argsLen) {
794 ++args;
795 --argsLen;
796 }
797 }
798 if (args && argsLen) {
799 debugger->backend->printf(debugger->backend, "Wrong number of arguments\n");
800 _DVFree(dv);
801 return 0;
802 }
803 commands[i].command(debugger, dv);
804 _DVFree(dv);
805 return 1;
806 }
807 }
808 return -1;
809}
810
811static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count) {
812 const char* firstSpace = strchr(line, ' ');
813 size_t cmdLength;
814 if (firstSpace) {
815 cmdLength = firstSpace - line;
816 } else {
817 cmdLength = count;
818 }
819
820 const char* args = 0;
821 if (firstSpace) {
822 args = firstSpace + 1;
823 }
824 int result = _tryCommands(debugger, _debuggerCommands, line, cmdLength, args, count - cmdLength - 1);
825 if (result < 0 && debugger->system) {
826 result = _tryCommands(debugger, debugger->system->commands, line, cmdLength, args, count - cmdLength - 1);
827 if (result < 0) {
828 result = _tryCommands(debugger, debugger->system->platformCommands, line, cmdLength, args, count - cmdLength - 1);
829 }
830 }
831 if (result < 0) {
832 debugger->backend->printf(debugger->backend, "Command not found\n");
833 }
834 return false;
835}
836
837static void _commandLine(struct mDebugger* debugger) {
838 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
839 const char* line;
840 size_t len;
841 _printStatus(cliDebugger, 0);
842 while (debugger->state == DEBUGGER_PAUSED) {
843 line = cliDebugger->backend->readline(cliDebugger->backend, &len);
844 if (!line || len == 0) {
845 debugger->state = DEBUGGER_SHUTDOWN;
846 return;
847 }
848 if (line[0] == '\n') {
849 line = cliDebugger->backend->historyLast(cliDebugger->backend, &len);
850 if (line && len) {
851 _parse(cliDebugger, line, len);
852 }
853 } else {
854 _parse(cliDebugger, line, len);
855 cliDebugger->backend->historyAppend(cliDebugger->backend, line);
856 }
857 }
858}
859
860static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
861 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
862 switch (reason) {
863 case DEBUGGER_ENTER_MANUAL:
864 case DEBUGGER_ENTER_ATTACHED:
865 break;
866 case DEBUGGER_ENTER_BREAKPOINT:
867 if (info) {
868 cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint at 0x%08X\n", info->address);
869 } else {
870 cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint\n");
871 }
872 break;
873 case DEBUGGER_ENTER_WATCHPOINT:
874 if (info) {
875 if (info->type.wp.accessType & WATCHPOINT_WRITE) {
876 cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint at 0x%08X: (new value = 0x%08x, old value = 0x%08X)\n", info->address, info->type.wp.newValue, info->type.wp.oldValue);
877 } else {
878 cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint at 0x%08X: (value = 0x%08x)\n", info->address, info->type.wp.oldValue);
879 }
880 } else {
881 cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint\n");
882 }
883 break;
884 case DEBUGGER_ENTER_ILLEGAL_OP:
885 if (info) {
886 cliDebugger->backend->printf(cliDebugger->backend, "Hit illegal opcode at 0x%08X: 0x%08X\n", info->address, info->type.bp.opcode);
887 } else {
888 cliDebugger->backend->printf(cliDebugger->backend, "Hit illegal opcode\n");
889 }
890 break;
891 }
892}
893
894static void _cliDebuggerInit(struct mDebugger* debugger) {
895 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
896 cliDebugger->backend->init(cliDebugger->backend);
897}
898
899static void _cliDebuggerDeinit(struct mDebugger* debugger) {
900 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
901 if (cliDebugger->system) {
902 if (cliDebugger->system->deinit) {
903 cliDebugger->system->deinit(cliDebugger->system);
904 }
905 free(cliDebugger->system);
906 cliDebugger->system = NULL;
907 }
908 if (cliDebugger->backend && cliDebugger->backend->deinit) {
909 cliDebugger->backend->deinit(cliDebugger->backend);
910 cliDebugger->backend = NULL;
911 }
912}
913
914static void _cliDebuggerCustom(struct mDebugger* debugger) {
915 struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
916 bool retain = false;
917 if (cliDebugger->system) {
918 retain = cliDebugger->system->custom(cliDebugger->system);
919 }
920 if (!retain && debugger->state == DEBUGGER_CUSTOM) {
921 debugger->state = DEBUGGER_RUNNING;
922 }
923}
924
925void CLIDebuggerCreate(struct CLIDebugger* debugger) {
926 debugger->d.init = _cliDebuggerInit;
927 debugger->d.deinit = _cliDebuggerDeinit;
928 debugger->d.custom = _cliDebuggerCustom;
929 debugger->d.paused = _commandLine;
930 debugger->d.entered = _reportEntry;
931 debugger->d.type = DEBUGGER_CLI;
932
933 debugger->system = NULL;
934 debugger->backend = NULL;
935}
936
937void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSystem* system) {
938 if (debugger->system) {
939 if (debugger->system->deinit) {
940 debugger->system->deinit(debugger->system);
941 }
942 free(debugger->system);
943 }
944
945 debugger->system = system;
946 system->p = debugger;
947}
948
949void CLIDebuggerAttachBackend(struct CLIDebugger* debugger, struct CLIDebuggerBackend* backend) {
950 if (debugger->backend == backend) {
951 return;
952 }
953 if (debugger->backend && debugger->backend->deinit) {
954 debugger->backend->deinit(debugger->backend);
955 }
956
957 debugger->backend = backend;
958 backend->p = debugger;
959}
960
961bool CLIDebuggerTabComplete(struct CLIDebugger* debugger, const char* token, bool initial, size_t tokenLen) {
962 size_t cmd = 0;
963 size_t len;
964 const char* name = 0;
965 for (len = 1; len <= tokenLen; ++len) {
966 for (; (name = _debuggerCommands[cmd].name); ++cmd) {
967 int cmp = strncasecmp(name, token, len);
968 if (cmp > 0) {
969 return false;
970 }
971 if (cmp == 0) {
972 break;
973 }
974 }
975 }
976 if (!name) {
977 return false;
978 }
979 if (_debuggerCommands[cmd + 1].name && strlen(_debuggerCommands[cmd + 1].name) >= len && name[len - 1] == _debuggerCommands[cmd + 1].name[len - 1]) {
980 --len;
981 const char* next = 0;
982 int i;
983 for (i = cmd + 1; _debuggerCommands[i].name; ++i) {
984 if (strncasecmp(name, _debuggerCommands[i].name, len)) {
985 break;
986 }
987 next = _debuggerCommands[i].name;
988 }
989 if (!next) {
990 return false;
991 }
992
993 for (; name[len]; ++len) {
994 if (name[len] != next[len]) {
995 break;
996 }
997 char out[2] = { name[len], '\0' };
998 debugger->backend->lineAppend(debugger->backend, out);
999 }
1000 return true;
1001 }
1002 name += len - 1;
1003 debugger->backend->lineAppend(debugger->backend, name);
1004 debugger->backend->lineAppend(debugger->backend, " ");
1005 return true;
1006}