all repos — mgba @ fa884d071ecaa3e05ff20b45a67bf9500dd3d6b6

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