all repos — mgba @ dae68c2182a8daa5c1770ade38726ed4b7a37193

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