all repos — mgba @ a0af0ce1419eca9cc03f4b7a66638603898f66c7

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