all repos — mgba @ 16ba5bd05ff423ba9bc98cb7615140b01ff49bd2

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