all repos — mgba @ 821c8988a385025f2f5c741d279ea0e745f47c0c

mGBA Game Boy Advance Emulator

src/debugger/cli-debugger.c (view raw)

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