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