all repos — mgba @ 57894955a2741b2a96d91fc40d31cc9c87b41d05

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