all repos — mgba @ 8c68d867e61f6227dad735390444ff8e41510f4f

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