all repos — mgba @ 90e57c027b05e9f58873e3ca7f4186b01ece4672

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