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