all repos — mgba @ 7189d7f13a158563246d8277afc64e7c73db6d7d

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 <mgba/internal/debugger/cli-debugger.h>
  7
  8#include <mgba/internal/debugger/symbols.h>
  9
 10#include <mgba/core/core.h>
 11#include <mgba/core/version.h>
 12#include <mgba/internal/debugger/parser.h>
 13#include <mgba-util/string.h>
 14
 15#if ENABLE_SCRIPTING
 16#include <mgba/core/scripting.h>
 17#endif
 18
 19#if !defined(NDEBUG) && !defined(_WIN32)
 20#include <signal.h>
 21#endif
 22
 23#ifdef USE_PTHREADS
 24#include <pthread.h>
 25#endif
 26
 27const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
 28const char* ERROR_OVERFLOW = "Arguments overflow";
 29const char* ERROR_INVALID_ARGS = "Invalid arguments";
 30
 31#if !defined(NDEBUG) && !defined(_WIN32)
 32static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
 33#endif
 34static void _continue(struct CLIDebugger*, struct CLIDebugVector*);
 35static void _disassemble(struct CLIDebugger*, struct CLIDebugVector*);
 36static void _next(struct CLIDebugger*, struct CLIDebugVector*);
 37static void _print(struct CLIDebugger*, struct CLIDebugVector*);
 38static void _printBin(struct CLIDebugger*, struct CLIDebugVector*);
 39static void _printHex(struct CLIDebugger*, struct CLIDebugVector*);
 40static void _printStatus(struct CLIDebugger*, struct CLIDebugVector*);
 41static void _printHelp(struct CLIDebugger*, struct CLIDebugVector*);
 42static void _quit(struct CLIDebugger*, struct CLIDebugVector*);
 43static void _readByte(struct CLIDebugger*, struct CLIDebugVector*);
 44static void _reset(struct CLIDebugger*, struct CLIDebugVector*);
 45static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
 46static void _readWord(struct CLIDebugger*, struct CLIDebugVector*);
 47static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
 48static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
 49static void _listBreakpoints(struct CLIDebugger*, struct CLIDebugVector*);
 50static void _setReadWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
 51static void _setReadWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
 52static void _setWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
 53static void _setWriteChangedWatchpoint(struct CLIDebugger*, struct CLIDebugVector*);
 54static void _listWatchpoints(struct CLIDebugger*, struct CLIDebugVector*);
 55static void _trace(struct CLIDebugger*, struct CLIDebugVector*);
 56static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*);
 57static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*);
 58static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*);
 59static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*);
 60static void _dumpByte(struct CLIDebugger*, struct CLIDebugVector*);
 61static void _dumpHalfword(struct CLIDebugger*, struct CLIDebugVector*);
 62static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*);
 63#ifdef ENABLE_SCRIPTING
 64static void _source(struct CLIDebugger*, struct CLIDebugVector*);
 65#endif
 66
 67static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
 68	{ "b", _setBreakpoint, "Is", "Set a breakpoint" },
 69	{ "break", _setBreakpoint, "Is", "Set a breakpoint" },
 70	{ "c", _continue, "", "Continue execution" },
 71	{ "continue", _continue, "", "Continue execution" },
 72	{ "d", _clearBreakpoint, "I", "Delete a breakpoint or watchpoint" },
 73	{ "delete", _clearBreakpoint, "I", "Delete a breakpoint or watchpoint" },
 74	{ "dis", _disassemble, "Ii", "Disassemble instructions" },
 75	{ "disasm", _disassemble, "Ii", "Disassemble instructions" },
 76	{ "disassemble", _disassemble, "Ii", "Disassemble instructions" },
 77	{ "h", _printHelp, "S", "Print help" },
 78	{ "help", _printHelp, "S", "Print help" },
 79	{ "i", _printStatus, "", "Print the current status" },
 80	{ "info", _printStatus, "", "Print the current status" },
 81	{ "lb", _listBreakpoints, "", "List breakpoints" },
 82	{ "listb", _listBreakpoints, "", "List breakpoints" },
 83	{ "lw", _listWatchpoints, "", "List watchpoints" },
 84	{ "listw", _listWatchpoints, "", "List watchpoints" },
 85	{ "n", _next, "", "Execute next instruction" },
 86	{ "next", _next, "", "Execute next instruction" },
 87	{ "p", _print, "I", "Print a value" },
 88	{ "p/t", _printBin, "I", "Print a value as binary" },
 89	{ "p/x", _printHex, "I", "Print a value as hexadecimal" },
 90	{ "print", _print, "I", "Print a value" },
 91	{ "print/t", _printBin, "I", "Print a value as binary" },
 92	{ "print/x", _printHex, "I", "Print a value as hexadecimal" },
 93	{ "q", _quit, "", "Quit the emulator" },
 94	{ "quit", _quit, "", "Quit the emulator" },
 95	{ "reset", _reset, "", "Reset the emulation" },
 96	{ "r/1", _readByte, "I", "Read a byte from a specified offset" },
 97	{ "r/2", _readHalfword, "I", "Read a halfword from a specified offset" },
 98	{ "r/4", _readWord, "I", "Read a word from a specified offset" },
 99	{ "status", _printStatus, "", "Print the current status" },
100	{ "trace", _trace, "I", "Trace a fixed number of instructions" },
101	{ "w", _setReadWriteWatchpoint, "Is", "Set a watchpoint" },
102	{ "w/1", _writeByte, "II", "Write a byte at a specified offset" },
103	{ "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" },
104	{ "w/r", _writeRegister, "SI", "Write a register" },
105	{ "w/4", _writeWord, "II", "Write a word at a specified offset" },
106	{ "watch", _setReadWriteWatchpoint, "Is", "Set a watchpoint" },
107	{ "watch/c", _setWriteChangedWatchpoint, "Is", "Set a change watchpoint" },
108	{ "watch/r", _setReadWatchpoint, "Is", "Set a read watchpoint" },
109	{ "watch/w", _setWriteWatchpoint, "Is", "Set a write watchpoint" },
110	{ "x/1", _dumpByte, "Ii", "Examine bytes at a specified offset" },
111	{ "x/2", _dumpHalfword, "Ii", "Examine halfwords at a specified offset" },
112	{ "x/4", _dumpWord, "Ii", "Examine words at a specified offset" },
113#ifdef ENABLE_SCRIPTING
114	{ "source", _source, "S", "Load a script" },
115#endif
116#if !defined(NDEBUG) && !defined(_WIN32)
117	{ "!", _breakInto, "", "Break into attached debugger (for developers)" },
118#endif
119	{ 0, 0, 0, 0 }
120};
121
122#if !defined(NDEBUG) && !defined(_WIN32)
123static void _handleDeath(int sig) {
124	UNUSED(sig);
125	printf("No debugger attached!\n");
126}
127
128static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
129	UNUSED(debugger);
130	UNUSED(dv);
131	struct sigaction sa, osa;
132	sa.sa_handler = _handleDeath;
133	sigemptyset(&sa.sa_mask);
134	sigaddset(&sa.sa_mask, SIGTRAP);
135	sa.sa_flags = SA_RESTART;
136	sigaction(SIGTRAP, &sa, &osa);
137#ifdef USE_PTHREADS
138	pthread_kill(pthread_self(), SIGTRAP);
139#else
140	kill(getpid(), SIGTRAP);
141#endif
142	sigaction(SIGTRAP, &osa, 0);
143}
144#endif
145
146static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
147	UNUSED(dv);
148	debugger->d.state = DEBUGGER_RUNNING;
149}
150
151static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
152	UNUSED(dv);
153	debugger->d.core->step(debugger->d.core);
154	_printStatus(debugger, 0);
155}
156
157static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
158	debugger->system->disassemble(debugger->system, dv);
159}
160
161static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
162	for (; dv; dv = dv->next) {
163		if (dv->segmentValue >= 0) {
164			debugger->backend->printf(debugger->backend, " $%02X:%04X", dv->segmentValue, dv->intValue);
165			continue;
166		}
167		debugger->backend->printf(debugger->backend, " %u", dv->intValue);
168	}
169	debugger->backend->printf(debugger->backend, "\n");
170}
171
172static void _printBin(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
173	for (; dv; dv = dv->next) {
174		debugger->backend->printf(debugger->backend, " 0b");
175		int i = 32;
176		while (i--) {
177			debugger->backend->printf(debugger->backend, "%u", (dv->intValue >> i) & 1);
178		}
179	}
180	debugger->backend->printf(debugger->backend, "\n");
181}
182
183static void _printHex(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
184	for (; dv; dv = dv->next) {
185		debugger->backend->printf(debugger->backend, " 0x%08X", dv->intValue);
186	}
187	debugger->backend->printf(debugger->backend, "\n");
188}
189
190static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
191	UNUSED(dv);
192	if (!dv) {
193		debugger->backend->printf(debugger->backend, "Generic commands:\n");
194		int i;
195		for (i = 0; _debuggerCommands[i].name; ++i) {
196			debugger->backend->printf(debugger->backend, "%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary);
197		}
198		if (debugger->system) {
199			debugger->backend->printf(debugger->backend, "%s commands:\n", debugger->system->platformName);
200			for (i = 0; debugger->system->platformCommands[i].name; ++i) {
201				debugger->backend->printf(debugger->backend, "%-10s %s\n", debugger->system->platformCommands[i].name, debugger->system->platformCommands[i].summary);
202			}
203			debugger->backend->printf(debugger->backend, "%s commands:\n", debugger->system->name);
204			for (i = 0; debugger->system->commands[i].name; ++i) {
205				debugger->backend->printf(debugger->backend, "%-10s %s\n", debugger->system->commands[i].name, debugger->system->commands[i].summary);
206			}
207		}
208	} else {
209		int i;
210		for (i = 0; _debuggerCommands[i].name; ++i) {
211			if (strcmp(_debuggerCommands[i].name, dv->charValue) == 0) {
212				debugger->backend->printf(debugger->backend, " %s\n", _debuggerCommands[i].summary);
213			}
214		}
215		if (debugger->system) {
216			for (i = 0; debugger->system->platformCommands[i].name; ++i) {
217				if (strcmp(debugger->system->platformCommands[i].name, dv->charValue) == 0) {
218					debugger->backend->printf(debugger->backend, " %s\n", debugger->system->platformCommands[i].summary);
219				}
220			}
221			for (i = 0; debugger->system->commands[i].name; ++i) {
222				if (strcmp(debugger->system->commands[i].name, dv->charValue) == 0) {
223					debugger->backend->printf(debugger->backend, " %s\n", debugger->system->commands[i].summary);
224				}
225			}
226		}
227	}
228}
229
230static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
231	UNUSED(dv);
232	debugger->d.state = DEBUGGER_SHUTDOWN;
233}
234
235static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
236	if (!dv || dv->type != CLIDV_INT_TYPE) {
237		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
238		return;
239	}
240	uint32_t address = dv->intValue;
241	uint8_t value;
242	if (dv->segmentValue >= 0) {
243		value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue);
244	} else {
245		value = debugger->d.core->busRead8(debugger->d.core, address);
246	}
247	debugger->backend->printf(debugger->backend, " 0x%02X\n", value);
248}
249
250static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
251	UNUSED(dv);
252	debugger->d.core->reset(debugger->d.core);
253	_printStatus(debugger, 0);
254}
255
256static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
257	if (!dv || dv->type != CLIDV_INT_TYPE) {
258		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
259		return;
260	}
261	uint32_t address = dv->intValue;
262	uint16_t value;
263	if (dv->segmentValue >= 0) {
264		value = debugger->d.core->rawRead16(debugger->d.core, address & -1, dv->segmentValue);
265	} else {
266		value = debugger->d.core->busRead16(debugger->d.core, address & ~1);
267	}
268	debugger->backend->printf(debugger->backend, " 0x%04X\n", value);
269}
270
271static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
272	if (!dv || dv->type != CLIDV_INT_TYPE) {
273		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
274		return;
275	}
276	uint32_t address = dv->intValue;
277	uint32_t value;
278	if (dv->segmentValue >= 0) {
279		value = debugger->d.core->rawRead32(debugger->d.core, address & -3, dv->segmentValue);
280	} else {
281		value = debugger->d.core->busRead32(debugger->d.core, address & ~3);
282	}
283	debugger->backend->printf(debugger->backend, " 0x%08X\n", value);
284}
285
286static void _writeByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
287	if (!dv || !dv->next) {
288		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
289		return;
290	}
291	if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
292		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
293		return;
294	}
295	uint32_t address = dv->intValue;
296	uint32_t value = dv->next->intValue;
297	if (value > 0xFF) {
298		debugger->backend->printf(debugger->backend, "%s\n", ERROR_OVERFLOW);
299		return;
300	}
301	if (dv->segmentValue >= 0) {
302		debugger->d.core->rawWrite8(debugger->d.core, address, value, dv->segmentValue);
303	} else {
304		debugger->d.core->busWrite8(debugger->d.core, address, value);
305	}
306}
307
308static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
309	if (!dv || !dv->next) {
310		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
311		return;
312	}
313	if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
314		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
315		return;
316	}
317	uint32_t address = dv->intValue;
318	uint32_t value = dv->next->intValue;
319	if (value > 0xFFFF) {
320		debugger->backend->printf(debugger->backend, "%s\n", ERROR_OVERFLOW);
321		return;
322	}
323	if (dv->segmentValue >= 0) {
324		debugger->d.core->rawWrite16(debugger->d.core, address, value, dv->segmentValue);
325	} else {
326		debugger->d.core->busWrite16(debugger->d.core, address, value);
327	}
328}
329
330static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
331	if (!dv || !dv->next) {
332		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
333		return;
334	}
335	if (dv->type != CLIDV_CHAR_TYPE || dv->next->type != CLIDV_INT_TYPE) {
336		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
337		return;
338	}
339	if (!debugger->d.platform->setRegister(debugger->d.platform, dv->charValue, dv->next->intValue)) {
340		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
341	}
342}
343
344static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
345	if (!dv || !dv->next) {
346		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
347		return;
348	}
349	if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
350		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
351		return;
352	}
353	uint32_t address = dv->intValue;
354	uint32_t value = dv->next->intValue;
355	if (dv->segmentValue >= 0) {
356		debugger->d.core->rawWrite32(debugger->d.core, address, value, dv->segmentValue);
357	} else {
358		debugger->d.core->busWrite32(debugger->d.core, address, value);
359	}
360}
361
362static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
363	if (!dv || dv->type != CLIDV_INT_TYPE) {
364		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
365		return;
366	}
367	uint32_t address = dv->intValue;
368	uint32_t words = 16;
369	if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
370		words = dv->next->intValue;
371	}
372	while (words) {
373		uint32_t line = 16;
374		if (line > words) {
375			line = words;
376		}
377		debugger->backend->printf(debugger->backend, "0x%08X:", address);
378		for (; line > 0; --line, ++address, --words) {
379			uint32_t value;
380			if (dv->segmentValue >= 0) {
381				value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue);
382			} else {
383				value = debugger->d.core->busRead8(debugger->d.core, address);
384			}
385			debugger->backend->printf(debugger->backend, " %02X", value);
386		}
387		debugger->backend->printf(debugger->backend, "\n");
388	}
389}
390
391static void _dumpHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
392	if (!dv || dv->type != CLIDV_INT_TYPE) {
393		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
394		return;
395	}
396	uint32_t address = dv->intValue;
397	uint32_t words = 8;
398	if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
399		words = dv->next->intValue;
400	}
401	while (words) {
402		uint32_t line = 8;
403		if (line > words) {
404			line = words;
405		}
406		debugger->backend->printf(debugger->backend, "0x%08X:", address);
407		for (; line > 0; --line, address += 2, --words) {
408			uint32_t value;
409			if (dv->segmentValue >= 0) {
410				value = debugger->d.core->rawRead16(debugger->d.core, address, dv->segmentValue);
411			} else {
412				value = debugger->d.core->busRead16(debugger->d.core, address);
413			}
414			debugger->backend->printf(debugger->backend, " %04X", value);
415		}
416		debugger->backend->printf(debugger->backend, "\n");
417	}
418}
419
420static void _dumpWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
421	if (!dv || dv->type != CLIDV_INT_TYPE) {
422		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
423		return;
424	}
425	uint32_t address = dv->intValue;
426	uint32_t words = 4;
427	if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
428		words = dv->next->intValue;
429	}
430	while (words) {
431		uint32_t line = 4;
432		if (line > words) {
433			line = words;
434		}
435		debugger->backend->printf(debugger->backend, "0x%08X:", address);
436		for (; line > 0; --line, address += 4, --words) {
437			uint32_t value;
438			if (dv->segmentValue >= 0) {
439				value = debugger->d.core->rawRead32(debugger->d.core, address, dv->segmentValue);
440			} else {
441				value = debugger->d.core->busRead32(debugger->d.core, address);
442			}
443			debugger->backend->printf(debugger->backend, " %08X", value);
444		}
445		debugger->backend->printf(debugger->backend, "\n");
446	}
447}
448
449#ifdef ENABLE_SCRIPTING
450static void _source(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
451	if (!dv) {
452		debugger->backend->printf(debugger->backend, "Needs a filename\n");
453		return;
454	}
455	if (debugger->d.bridge && mScriptBridgeLoadScript(debugger->d.bridge, dv->charValue)) {
456		mScriptBridgeRun(debugger->d.bridge);
457	} else {
458		debugger->backend->printf(debugger->backend, "Failed to load script\n");
459	}
460}
461#endif
462
463static struct ParseTree* _parseTree(const char* string) {
464	struct LexVector lv;
465	bool error = false;
466	LexVectorInit(&lv, 0);
467	size_t length = strlen(string);
468	size_t adjusted = lexExpression(&lv, string, length, NULL);
469	struct ParseTree* tree = malloc(sizeof(*tree));
470	if (!adjusted) {
471		error = true;
472	} else {
473		parseLexedExpression(tree, &lv);
474
475		if (adjusted > length) {
476			error = true;
477		} else {
478			length -= adjusted;
479			string += adjusted;
480		}
481	}
482	lexFree(&lv);
483	LexVectorClear(&lv);
484	LexVectorDeinit(&lv);
485	if (error) {
486		parseFree(tree);
487		free(tree);
488		return NULL;
489	} else {
490		return tree;
491	}
492}
493
494static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
495	if (!dv || dv->type != CLIDV_INT_TYPE) {
496		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
497		return;
498	}
499	struct mBreakpoint breakpoint = {
500		.address = dv->intValue,
501		.segment = dv->segmentValue,
502		.type = BREAKPOINT_HARDWARE
503	};
504	if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
505		struct ParseTree* tree = _parseTree(dv->next->charValue);
506		if (tree) {
507			breakpoint.condition = tree;
508		} else {
509			debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
510			return;
511		}
512	}
513	debugger->d.platform->setBreakpoint(debugger->d.platform, &breakpoint);
514}
515
516static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum mWatchpointType type) {
517	if (!dv || dv->type != CLIDV_INT_TYPE) {
518		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
519		return;
520	}
521	if (!debugger->d.platform->setWatchpoint) {
522		debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
523		return;
524	}
525	struct mWatchpoint watchpoint = {
526		.address = dv->intValue,
527		.segment = dv->segmentValue,
528		.type = type
529	};
530	if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
531		struct ParseTree* tree = _parseTree(dv->next->charValue);
532		if (tree) {
533			watchpoint.condition = tree;
534		} else {
535			debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
536			return;
537		}
538	}
539	debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint);
540}
541
542static void _setReadWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
543	_setWatchpoint(debugger, dv, WATCHPOINT_RW);
544}
545
546static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
547	_setWatchpoint(debugger, dv, WATCHPOINT_READ);
548}
549
550static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
551	_setWatchpoint(debugger, dv, WATCHPOINT_WRITE);
552}
553
554static void _setWriteChangedWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
555	_setWatchpoint(debugger, dv, WATCHPOINT_WRITE_CHANGE);
556}
557
558static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
559	if (!dv || dv->type != CLIDV_INT_TYPE) {
560		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
561		return;
562	}
563	uint64_t id = dv->intValue;
564	debugger->d.platform->clearBreakpoint(debugger->d.platform, id);
565}
566
567static void _listBreakpoints(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
568	UNUSED(dv);
569	struct mBreakpointList breakpoints;
570	mBreakpointListInit(&breakpoints, 0);
571	debugger->d.platform->listBreakpoints(debugger->d.platform, &breakpoints);
572	size_t i;
573	for (i = 0; i < mBreakpointListSize(&breakpoints); ++i) {
574		struct mBreakpoint* breakpoint = mBreakpointListGetPointer(&breakpoints, i);
575		if (breakpoint->segment >= 0) {
576			debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", breakpoint->id, breakpoint->segment, breakpoint->address);
577		} else {
578			debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", breakpoint->id, breakpoint->address);
579		}
580	}
581	mBreakpointListDeinit(&breakpoints);
582}
583
584static void _listWatchpoints(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
585	UNUSED(dv);
586	struct mWatchpointList watchpoints;
587	mWatchpointListInit(&watchpoints, 0);
588	debugger->d.platform->listWatchpoints(debugger->d.platform, &watchpoints);
589	size_t i;
590	for (i = 0; i < mWatchpointListSize(&watchpoints); ++i) {
591		struct mWatchpoint* watchpoint = mWatchpointListGetPointer(&watchpoints, i);
592		if (watchpoint->segment >= 0) {
593			debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", watchpoint->id, watchpoint->segment, watchpoint->address);
594		} else {
595			debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", watchpoint->id, watchpoint->address);
596		}
597	}
598	mWatchpointListDeinit(&watchpoints);
599}
600
601static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
602	if (!dv || dv->type != CLIDV_INT_TYPE) {
603		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
604		return;
605	}
606
607	char trace[1024];
608	trace[sizeof(trace) - 1] = '\0';
609
610	int i;
611	for (i = 0; i < dv->intValue; ++i) {
612		debugger->d.core->step(debugger->d.core);
613		size_t traceSize = sizeof(trace) - 1;
614		debugger->d.platform->trace(debugger->d.platform, trace, &traceSize);
615		if (traceSize + 1 < sizeof(trace)) {
616			trace[traceSize + 1] = '\0';
617		}
618		debugger->backend->printf(debugger->backend, "%s\n", trace);
619	}
620}
621
622static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
623	UNUSED(dv);
624	debugger->system->printStatus(debugger->system);
625}
626
627struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* string, size_t length) {
628	if (!string || length < 1) {
629		return 0;
630	}
631
632	struct CLIDebugVector dvTemp = { .type = CLIDV_INT_TYPE, .segmentValue = -1 };
633
634	struct LexVector lv;
635	LexVectorInit(&lv, 0);
636	size_t adjusted = lexExpression(&lv, string, length, " ");
637	if (adjusted > length) {
638		dvTemp.type = CLIDV_ERROR_TYPE;
639	}
640
641	struct ParseTree tree;
642	parseLexedExpression(&tree, &lv);
643	if (tree.token.type == TOKEN_ERROR_TYPE) {
644		dvTemp.type = CLIDV_ERROR_TYPE;
645	} else {
646		if (!mDebuggerEvaluateParseTree(&debugger->d, &tree, &dvTemp.intValue, &dvTemp.segmentValue)) {
647			dvTemp.type = CLIDV_ERROR_TYPE;
648		}
649	}
650
651	parseFree(&tree);
652
653	lexFree(&lv);
654	LexVectorDeinit(&lv);
655
656	struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
657	if (dvTemp.type == CLIDV_ERROR_TYPE) {
658		dv->type = CLIDV_ERROR_TYPE;
659		dv->next = 0;
660	} else {
661		*dv = dvTemp;
662	}
663	return dv;
664}
665
666struct CLIDebugVector* CLIDVStringParse(struct CLIDebugger* debugger, const char* string, size_t length) {
667	UNUSED(debugger);
668	if (!string || length < 1) {
669		return 0;
670	}
671
672	struct CLIDebugVector dvTemp = { .type = CLIDV_CHAR_TYPE };
673
674	dvTemp.charValue = strndup(string, length);
675
676	struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
677	*dv = dvTemp;
678	return dv;
679}
680
681static void _DVFree(struct CLIDebugVector* dv) {
682	struct CLIDebugVector* next;
683	while (dv) {
684		next = dv->next;
685		if (dv->type == CLIDV_CHAR_TYPE) {
686			free(dv->charValue);
687		}
688		free(dv);
689		dv = next;
690	}
691}
692
693static struct CLIDebugVector* _parseArg(struct CLIDebugger* debugger, const char* args, size_t argsLen, char type) {
694	struct CLIDebugVector* dv = NULL;
695	switch (type) {
696	case 'I':
697	case 'i':
698		return CLIDVParse(debugger, args, argsLen);
699	case 'S':
700	case 's':
701		return CLIDVStringParse(debugger, args, argsLen);
702	case '*':
703		dv = _parseArg(debugger, args, argsLen, 'I');
704		if (!dv) {
705			dv = _parseArg(debugger, args, argsLen, 'S');
706		}
707		break;
708	}
709	return dv;
710}
711
712static int _tryCommands(struct CLIDebugger* debugger, struct CLIDebuggerCommandSummary* commands, const char* command, size_t commandLen, const char* args, size_t argsLen) {
713	struct CLIDebugVector* dv = NULL;
714	struct CLIDebugVector* dvLast = NULL;
715	int i;
716	const char* name;
717	for (i = 0; (name = commands[i].name); ++i) {
718		if (strlen(name) != commandLen) {
719			continue;
720		}
721		if (strncasecmp(name, command, commandLen) == 0) {
722			if (commands[i].format && args) {
723				char lastArg = '\0';
724				int arg;
725				for (arg = 0; commands[i].format[arg] && argsLen; ++arg) {
726					while (isspace(args[0]) && argsLen) {
727						++args;
728						--argsLen;
729					}
730					if (!args[0] || !argsLen) {
731						debugger->backend->printf(debugger->backend, "Wrong number of arguments\n");
732						_DVFree(dv);
733						return 0;
734					}
735
736					size_t adjusted;
737					const char* next = strchr(args, ' ');
738					if (next) {
739						adjusted = next - args;
740					} else {
741						adjusted = argsLen;
742					}
743
744					struct CLIDebugVector* dvNext = NULL;
745					bool nextArgMandatory = false;
746
747					if (commands[i].format[arg] == '+') {
748						dvNext = _parseArg(debugger, args, adjusted, lastArg);
749						--args;
750					} else {
751						nextArgMandatory = isupper(commands[i].format[arg]) || (commands[i].format[arg] == '*');
752						dvNext = _parseArg(debugger, args, adjusted, commands[i].format[arg]);
753					}
754
755					args += adjusted;
756					argsLen -= adjusted;
757
758					if (!dvNext) {
759						if (!nextArgMandatory) {
760							args = NULL;
761						}
762						break;
763					}
764					if (dvNext->type == CLIDV_ERROR_TYPE) {
765						debugger->backend->printf(debugger->backend, "Parse error\n");
766						_DVFree(dv);
767						return 0;
768					}
769
770					if (dvLast) {
771						dvLast->next = dvNext;
772						dvLast = dvNext;
773					} else {
774						dv = dvNext;
775						dvLast = dv;
776					}
777				}
778			}
779
780			if (args) {
781				while (isspace(args[0]) && argsLen) {
782					++args;
783					--argsLen;
784				}
785			}
786			if (args && argsLen) {
787				debugger->backend->printf(debugger->backend, "Wrong number of arguments\n");
788				_DVFree(dv);
789				return 0;
790			}
791			commands[i].command(debugger, dv);
792			_DVFree(dv);
793			return 1;
794		}
795	}
796	return -1;
797}
798
799static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count) {
800	const char* firstSpace = strchr(line, ' ');
801	size_t cmdLength;
802	if (firstSpace) {
803		cmdLength = firstSpace - line;
804	} else {
805		cmdLength = count;
806	}
807
808	const char* args = 0;
809	if (firstSpace) {
810		args = firstSpace + 1;
811	}
812	int result = _tryCommands(debugger, _debuggerCommands, line, cmdLength, args, count - cmdLength - 1);
813	if (result < 0 && debugger->system) {
814		result = _tryCommands(debugger, debugger->system->commands, line, cmdLength, args, count - cmdLength - 1);
815		if (result < 0) {
816			result = _tryCommands(debugger, debugger->system->platformCommands, line, cmdLength, args, count - cmdLength - 1);
817		}
818	}
819	if (result < 0) {
820		debugger->backend->printf(debugger->backend, "Command not found\n");
821	}
822	return false;
823}
824
825static void _commandLine(struct mDebugger* debugger) {
826	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
827	const char* line;
828		size_t len;
829	_printStatus(cliDebugger, 0);
830	while (debugger->state == DEBUGGER_PAUSED) {
831		line = cliDebugger->backend->readline(cliDebugger->backend, &len);
832		if (!line || len == 0) {
833			debugger->state = DEBUGGER_SHUTDOWN;
834			return;
835		}
836		if (line[0] == '\n') {
837			line = cliDebugger->backend->historyLast(cliDebugger->backend, &len);
838			if (line && len) {
839				_parse(cliDebugger, line, len);
840			}
841		} else {
842			_parse(cliDebugger, line, len);
843			cliDebugger->backend->historyAppend(cliDebugger->backend, line);
844		}
845	}
846}
847
848static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
849	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
850	switch (reason) {
851	case DEBUGGER_ENTER_MANUAL:
852	case DEBUGGER_ENTER_ATTACHED:
853		break;
854	case DEBUGGER_ENTER_BREAKPOINT:
855		if (info) {
856			cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint at 0x%08X\n", info->address);
857		} else {
858			cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint\n");
859		}
860		break;
861	case DEBUGGER_ENTER_WATCHPOINT:
862		if (info) {
863			if (info->type.wp.accessType & WATCHPOINT_WRITE) {
864				cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint at 0x%08X: (new value = 0x%08X, old value = 0x%08X)\n", info->address, info->type.wp.newValue, info->type.wp.oldValue);
865			} else {
866				cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint at 0x%08X: (value = 0x%08X)\n", info->address, info->type.wp.oldValue);
867			}
868		} else {
869			cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint\n");
870		}
871		break;
872	case DEBUGGER_ENTER_ILLEGAL_OP:
873		if (info) {
874			cliDebugger->backend->printf(cliDebugger->backend, "Hit illegal opcode at 0x%08X: 0x%08X\n", info->address, info->type.bp.opcode);
875		} else {
876			cliDebugger->backend->printf(cliDebugger->backend, "Hit illegal opcode\n");
877		}
878		break;
879	}
880}
881
882static void _cliDebuggerInit(struct mDebugger* debugger) {
883	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
884	cliDebugger->backend->init(cliDebugger->backend);
885}
886
887static void _cliDebuggerDeinit(struct mDebugger* debugger) {
888	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
889	if (cliDebugger->system) {
890		if (cliDebugger->system->deinit) {
891			cliDebugger->system->deinit(cliDebugger->system);
892		}
893		free(cliDebugger->system);
894		cliDebugger->system = NULL;
895	}
896	if (cliDebugger->backend && cliDebugger->backend->deinit) {
897		cliDebugger->backend->deinit(cliDebugger->backend);
898		cliDebugger->backend = NULL;
899	}
900}
901
902static void _cliDebuggerCustom(struct mDebugger* debugger) {
903	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
904	bool retain = false;
905	if (cliDebugger->system) {
906		retain = cliDebugger->system->custom(cliDebugger->system);
907	}
908	if (!retain && debugger->state == DEBUGGER_CUSTOM) {
909		debugger->state = DEBUGGER_RUNNING;
910	}
911}
912
913void CLIDebuggerCreate(struct CLIDebugger* debugger) {
914	debugger->d.init = _cliDebuggerInit;
915	debugger->d.deinit = _cliDebuggerDeinit;
916	debugger->d.custom = _cliDebuggerCustom;
917	debugger->d.paused = _commandLine;
918	debugger->d.entered = _reportEntry;
919	debugger->d.type = DEBUGGER_CLI;
920
921	debugger->system = NULL;
922	debugger->backend = NULL;
923}
924
925void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSystem* system) {
926	if (debugger->system) {
927		if (debugger->system->deinit) {
928			debugger->system->deinit(debugger->system);
929		}
930		free(debugger->system);
931	}
932
933	debugger->system = system;
934	system->p = debugger;
935}
936
937void CLIDebuggerAttachBackend(struct CLIDebugger* debugger, struct CLIDebuggerBackend* backend) {
938	if (debugger->backend == backend) {
939		return;
940	}
941	if (debugger->backend && debugger->backend->deinit) {
942		debugger->backend->deinit(debugger->backend);
943	}
944
945	debugger->backend = backend;
946	backend->p = debugger;
947}
948
949bool CLIDebuggerTabComplete(struct CLIDebugger* debugger, const char* token, bool initial, size_t tokenLen) {
950	size_t cmd = 0;
951	size_t len;
952	const char* name = 0;
953	for (len = 1; len <= tokenLen; ++len) {
954		for (; (name = _debuggerCommands[cmd].name); ++cmd) {
955			int cmp = strncasecmp(name, token, len);
956			if (cmp > 0) {
957				return false;
958			}
959			if (cmp == 0) {
960				break;
961			}
962		}
963	}
964	if (!name) {
965		return false;
966	}
967	if (_debuggerCommands[cmd + 1].name && strlen(_debuggerCommands[cmd + 1].name) >= len && name[len - 1] == _debuggerCommands[cmd + 1].name[len - 1]) {
968		--len;
969		const char* next = 0;
970		int i;
971		for (i = cmd + 1; _debuggerCommands[i].name; ++i) {
972			if (strncasecmp(name, _debuggerCommands[i].name, len)) {
973				break;
974			}
975			next = _debuggerCommands[i].name;
976		}
977		if (!next) {
978			return false;
979		}
980
981		for (; name[len]; ++len) {
982			if (name[len] != next[len]) {
983				break;
984			}
985			char out[2] = { name[len], '\0' };
986			debugger->backend->lineAppend(debugger->backend, out);
987		}
988		return true;
989	}
990	name += len - 1;
991	debugger->backend->lineAppend(debugger->backend, name);
992	debugger->backend->lineAppend(debugger->backend, " ");
993	return true;
994}