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