all repos — mgba @ 74c4cbe33e5bc67ef2b0eb1cb6bd518270735e63

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