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