all repos — mgba @ c4175846d88345d203153b64e8eb57559b9301ab

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