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