all repos — mgba @ dce49ea99022187e3798e484580d9a4624ed02bd

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