all repos — mgba @ 47d945bf75c4a43307698393a57b015d7373e716

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