all repos — mgba @ 6116f730e713585d5d2214ba0b89df836b40d8ff

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