all repos — mgba @ 8741a374a54185418a47500122440c357a13f9e4

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