all repos — mgba @ 02c3ea80fd9a2020e2b10cbc5cb0e624c77f0940

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