all repos — mgba @ e27e3333052238777f4acdb029f02f1fee90626c

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#ifdef 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
  72static void _backtrace(struct CLIDebugger*, struct CLIDebugVector*);
  73static void _finish(struct CLIDebugger*, struct CLIDebugVector*);
  74static void _setStackTraceMode(struct CLIDebugger*, struct CLIDebugVector*);
  75static void _setSymbol(struct CLIDebugger*, struct CLIDebugVector*);
  76static void _findSymbol(struct CLIDebugger*, struct CLIDebugVector*);
  77
  78static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
  79	{ "backtrace", _backtrace, "i", "Print backtrace of all or specified frames" },
  80	{ "break", _setBreakpoint, "Is", "Set a breakpoint" },
  81	{ "continue", _continue, "", "Continue execution" },
  82	{ "delete", _clearBreakpoint, "I", "Delete a breakpoint or watchpoint" },
  83	{ "disassemble", _disassemble, "Ii", "Disassemble instructions" },
  84	{ "finish", _finish, "", "Execute until current stack frame returns" },
  85	{ "help", _printHelp, "S", "Print help" },
  86	{ "listb", _listBreakpoints, "", "List breakpoints" },
  87	{ "listw", _listWatchpoints, "", "List watchpoints" },
  88	{ "next", _next, "", "Execute next instruction" },
  89	{ "print", _print, "S+", "Print a value" },
  90	{ "print/t", _printBin, "S+", "Print a value as binary" },
  91	{ "print/x", _printHex, "S+", "Print a value as hexadecimal" },
  92	{ "quit", _quit, "", "Quit the emulator" },
  93	{ "reset", _reset, "", "Reset the emulation" },
  94	{ "r/1", _readByte, "I", "Read a byte from a specified offset" },
  95	{ "r/2", _readHalfword, "I", "Read a halfword from a specified offset" },
  96	{ "r/4", _readWord, "I", "Read a word from a specified offset" },
  97	{ "set", _setSymbol, "SI", "Assign a symbol to an address" },
  98	{ "stack", _setStackTraceMode, "S", "Change the stack tracing mode" },
  99	{ "status", _printStatus, "", "Print the current status" },
 100	{ "symbol", _findSymbol, "I", "Find the symbol name for an address" },
 101	{ "trace", _trace, "Is", "Trace a number of instructions" },
 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
 122static struct CLIDebuggerCommandAlias _debuggerCommandAliases[] = {
 123	{ "b", "break" },
 124	{ "bt", "backtrace" },
 125	{ "c", "continue" },
 126	{ "d", "delete" },
 127	{ "dis", "disassemble" },
 128	{ "disasm", "disassemble" },
 129	{ "fin", "finish" },
 130	{ "h", "help" },
 131	{ "i", "status" },
 132	{ "info", "status" },
 133	{ "lb", "listb" },
 134	{ "lw", "listw" },
 135	{ "n", "next" },
 136	{ "p", "print" },
 137	{ "p/t", "print/t" },
 138	{ "p/x", "print/x" },
 139	{ "q", "quit" },
 140	{ "w", "watch" },
 141	{ ".", "source" },
 142	{ 0, 0 }
 143};
 144
 145#if !defined(NDEBUG) && !defined(_WIN32)
 146static void _handleDeath(int sig) {
 147	UNUSED(sig);
 148	printf("No debugger attached!\n");
 149}
 150
 151static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 152	UNUSED(debugger);
 153	UNUSED(dv);
 154	struct sigaction sa, osa;
 155	sa.sa_handler = _handleDeath;
 156	sigemptyset(&sa.sa_mask);
 157	sigaddset(&sa.sa_mask, SIGTRAP);
 158	sa.sa_flags = SA_RESTART;
 159	sigaction(SIGTRAP, &sa, &osa);
 160#ifdef USE_PTHREADS
 161	pthread_kill(pthread_self(), SIGTRAP);
 162#else
 163	kill(getpid(), SIGTRAP);
 164#endif
 165	sigaction(SIGTRAP, &osa, 0);
 166}
 167#endif
 168
 169static bool CLIDebuggerCheckTraceMode(struct CLIDebugger* debugger, bool requireEnabled) {
 170	struct mDebuggerPlatform* platform = debugger->d.platform;
 171	if (!platform->getStackTraceMode) {
 172		debugger->backend->printf(debugger->backend, "Stack tracing is not supported by this platform.\n");
 173		return false;
 174	} else if (requireEnabled && platform->getStackTraceMode(platform) == STACK_TRACE_DISABLED) {
 175		debugger->backend->printf(debugger->backend, "Stack tracing is not enabled.\n");
 176		return false;
 177	}
 178	return true;
 179}
 180
 181static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 182	UNUSED(dv);
 183	debugger->d.state = debugger->traceRemaining != 0 ? DEBUGGER_CALLBACK : DEBUGGER_RUNNING;
 184}
 185
 186static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 187	UNUSED(dv);
 188	struct mDebuggerPlatform* platform = debugger->d.platform;
 189	debugger->d.core->step(debugger->d.core);
 190	if (platform->getStackTraceMode && platform->getStackTraceMode(platform) != STACK_TRACE_DISABLED) {
 191		platform->updateStackTrace(platform);
 192	}
 193	_printStatus(debugger, 0);
 194}
 195
 196static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 197	debugger->system->disassemble(debugger->system, dv);
 198}
 199
 200static bool _parseExpression(struct mDebugger* debugger, struct CLIDebugVector* dv, int32_t* intValue, int* segmentValue) {
 201	size_t args = 0;
 202	struct CLIDebugVector* accum;
 203	for (accum = dv; accum; accum = accum->next) {
 204		++args;
 205	}
 206	const char** arglist = calloc(args + 1, sizeof(const char*));
 207	args = 0;
 208	for (accum = dv; accum; accum = accum->next) {
 209		arglist[args] = accum->charValue;
 210		++args;
 211	}
 212	arglist[args] = NULL;
 213	struct ParseTree* tree = _parseTree(arglist);
 214	free(arglist);
 215
 216	if (!tree) {
 217		return false;
 218	}
 219	if (!mDebuggerEvaluateParseTree(debugger, tree, intValue, segmentValue)) {
 220		parseFree(tree);
 221		free(tree);
 222		return false;
 223	}
 224	parseFree(tree);
 225	free(tree);
 226	return true;
 227}
 228
 229static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 230	int32_t intValue = 0;
 231	int segmentValue = -1;
 232	if (!_parseExpression(&debugger->d, dv, &intValue, &segmentValue)) {
 233		debugger->backend->printf(debugger->backend, "Parse error\n");
 234		return;
 235	}
 236	if (segmentValue >= 0) {
 237		debugger->backend->printf(debugger->backend, " $%02X:%04X\n", segmentValue, intValue);
 238	} else {
 239		debugger->backend->printf(debugger->backend, " %u\n", intValue);
 240	}
 241}
 242
 243static void _printBin(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 244	int32_t intValue = 0;
 245	int segmentValue = -1;
 246	if (!_parseExpression(&debugger->d, dv, &intValue, &segmentValue)) {
 247		debugger->backend->printf(debugger->backend, "Parse error\n");
 248		return;
 249	}
 250	debugger->backend->printf(debugger->backend, " 0b");
 251	int i = 32;
 252	while (i--) {
 253		debugger->backend->printf(debugger->backend, "%u", (intValue >> i) & 1);
 254	}
 255	debugger->backend->printf(debugger->backend, "\n");
 256}
 257
 258static void _printHex(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 259	int32_t intValue = 0;
 260	int segmentValue = -1;
 261	if (!_parseExpression(&debugger->d, dv, &intValue, &segmentValue)) {
 262		debugger->backend->printf(debugger->backend, "Parse error\n");
 263		return;
 264	}
 265	debugger->backend->printf(debugger->backend, " 0x%08X\n", intValue);
 266}
 267
 268static void _printCommands(struct CLIDebugger* debugger, struct CLIDebuggerCommandSummary* commands, struct CLIDebuggerCommandAlias* aliases) {
 269	int i;
 270	for (i = 0; commands[i].name; ++i) {
 271		debugger->backend->printf(debugger->backend, "%-15s  %s\n", commands[i].name, commands[i].summary);
 272		if (aliases) {
 273			bool printedAlias = false;
 274			int j;
 275			for (j = 0; aliases[j].name; ++j) {
 276				if (strcmp(aliases[j].original, commands[i].name) == 0) {
 277					if (!printedAlias) {
 278						debugger->backend->printf(debugger->backend, "                 Aliases:");
 279						printedAlias = true;
 280					}
 281					debugger->backend->printf(debugger->backend, " %s", aliases[j].name);
 282				}
 283			}
 284			if (printedAlias) {
 285				debugger->backend->printf(debugger->backend, "\n");
 286			}
 287		}
 288	}
 289}
 290
 291static void _printCommandSummary(struct CLIDebugger* debugger, const char* name, struct CLIDebuggerCommandSummary* commands, struct CLIDebuggerCommandAlias* aliases) {
 292	int i;
 293	for (i = 0; commands[i].name; ++i) {
 294		if (strcmp(commands[i].name, name) == 0) {
 295			debugger->backend->printf(debugger->backend, " %s\n", commands[i].summary);
 296			if (aliases) {
 297				bool printedAlias = false;
 298				int j;
 299				for (j = 0; aliases[j].name; ++j) {
 300					if (strcmp(aliases[j].original, commands[i].name) == 0) {
 301						if (!printedAlias) {
 302							debugger->backend->printf(debugger->backend, " Aliases:");
 303							printedAlias = true;
 304						}
 305						debugger->backend->printf(debugger->backend, " %s", aliases[j].name);
 306					}
 307				}
 308				if (printedAlias) {
 309					debugger->backend->printf(debugger->backend, "\n");
 310				}
 311			}
 312			return;
 313		}
 314	}
 315}
 316
 317static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 318	UNUSED(dv);
 319	if (!dv) {
 320		debugger->backend->printf(debugger->backend, "Generic commands:\n");
 321		_printCommands(debugger, _debuggerCommands, _debuggerCommandAliases);
 322		if (debugger->system) {
 323			debugger->backend->printf(debugger->backend, "\n%s commands:\n", debugger->system->platformName);
 324			_printCommands(debugger, debugger->system->platformCommands, debugger->system->platformCommandAliases);
 325			debugger->backend->printf(debugger->backend, "\n%s commands:\n", debugger->system->name);
 326			_printCommands(debugger, debugger->system->commands, debugger->system->commandAliases);
 327		}
 328	} else {
 329		_printCommandSummary(debugger, dv->charValue, _debuggerCommands, _debuggerCommandAliases);
 330		if (debugger->system) {
 331			_printCommandSummary(debugger, dv->charValue, debugger->system->platformCommands, debugger->system->platformCommandAliases);
 332			_printCommandSummary(debugger, dv->charValue, debugger->system->commands, debugger->system->commandAliases);
 333		}
 334	}
 335}
 336
 337static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 338	UNUSED(dv);
 339	debugger->d.state = DEBUGGER_SHUTDOWN;
 340}
 341
 342static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 343	if (!dv || dv->type != CLIDV_INT_TYPE) {
 344		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 345		return;
 346	}
 347	uint32_t address = dv->intValue;
 348	uint8_t value;
 349	if (dv->segmentValue >= 0) {
 350		value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue);
 351	} else {
 352		value = debugger->d.core->busRead8(debugger->d.core, address);
 353	}
 354	debugger->backend->printf(debugger->backend, " 0x%02X\n", value);
 355}
 356
 357static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 358	UNUSED(dv);
 359	mStackTraceClear(&debugger->d.stackTrace);
 360	debugger->d.core->reset(debugger->d.core);
 361	_printStatus(debugger, 0);
 362}
 363
 364static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 365	if (!dv || dv->type != CLIDV_INT_TYPE) {
 366		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 367		return;
 368	}
 369	uint32_t address = dv->intValue;
 370	uint16_t value;
 371	if (dv->segmentValue >= 0) {
 372		value = debugger->d.core->rawRead16(debugger->d.core, address & -1, dv->segmentValue);
 373	} else {
 374		value = debugger->d.core->busRead16(debugger->d.core, address & ~1);
 375	}
 376	debugger->backend->printf(debugger->backend, " 0x%04X\n", value);
 377}
 378
 379static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 380	if (!dv || dv->type != CLIDV_INT_TYPE) {
 381		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 382		return;
 383	}
 384	uint32_t address = dv->intValue;
 385	uint32_t value;
 386	if (dv->segmentValue >= 0) {
 387		value = debugger->d.core->rawRead32(debugger->d.core, address & -3, dv->segmentValue);
 388	} else {
 389		value = debugger->d.core->busRead32(debugger->d.core, address & ~3);
 390	}
 391	debugger->backend->printf(debugger->backend, " 0x%08X\n", value);
 392}
 393
 394static void _writeByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 395	if (!dv || !dv->next) {
 396		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 397		return;
 398	}
 399	if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
 400		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
 401		return;
 402	}
 403	uint32_t address = dv->intValue;
 404	uint32_t value = dv->next->intValue;
 405	if (value > 0xFF) {
 406		debugger->backend->printf(debugger->backend, "%s\n", ERROR_OVERFLOW);
 407		return;
 408	}
 409	if (dv->segmentValue >= 0) {
 410		debugger->d.core->rawWrite8(debugger->d.core, address, value, dv->segmentValue);
 411	} else {
 412		debugger->d.core->busWrite8(debugger->d.core, address, value);
 413	}
 414}
 415
 416static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 417	if (!dv || !dv->next) {
 418		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 419		return;
 420	}
 421	if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
 422		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
 423		return;
 424	}
 425	uint32_t address = dv->intValue;
 426	uint32_t value = dv->next->intValue;
 427	if (value > 0xFFFF) {
 428		debugger->backend->printf(debugger->backend, "%s\n", ERROR_OVERFLOW);
 429		return;
 430	}
 431	if (dv->segmentValue >= 0) {
 432		debugger->d.core->rawWrite16(debugger->d.core, address, value, dv->segmentValue);
 433	} else {
 434		debugger->d.core->busWrite16(debugger->d.core, address, value);
 435	}
 436}
 437
 438static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 439	if (!dv || !dv->next) {
 440		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 441		return;
 442	}
 443	if (dv->type != CLIDV_CHAR_TYPE || dv->next->type != CLIDV_INT_TYPE) {
 444		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
 445		return;
 446	}
 447	if (!debugger->d.platform->setRegister(debugger->d.platform, dv->charValue, dv->next->intValue)) {
 448		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
 449	}
 450}
 451
 452static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 453	if (!dv || !dv->next) {
 454		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 455		return;
 456	}
 457	if (dv->type != CLIDV_INT_TYPE || dv->next->type != CLIDV_INT_TYPE) {
 458		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
 459		return;
 460	}
 461	uint32_t address = dv->intValue;
 462	uint32_t value = dv->next->intValue;
 463	if (dv->segmentValue >= 0) {
 464		debugger->d.core->rawWrite32(debugger->d.core, address, value, dv->segmentValue);
 465	} else {
 466		debugger->d.core->busWrite32(debugger->d.core, address, value);
 467	}
 468}
 469
 470static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 471	if (!dv || dv->type != CLIDV_INT_TYPE) {
 472		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 473		return;
 474	}
 475	uint32_t address = dv->intValue;
 476	uint32_t words = 16;
 477	if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
 478		words = dv->next->intValue;
 479	}
 480	while (words) {
 481		uint32_t line = 16;
 482		if (line > words) {
 483			line = words;
 484		}
 485		debugger->backend->printf(debugger->backend, "0x%08X:", address);
 486		for (; line > 0; --line, ++address, --words) {
 487			uint32_t value;
 488			if (dv->segmentValue >= 0) {
 489				value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue);
 490			} else {
 491				value = debugger->d.core->busRead8(debugger->d.core, address);
 492			}
 493			debugger->backend->printf(debugger->backend, " %02X", value);
 494		}
 495		debugger->backend->printf(debugger->backend, "\n");
 496	}
 497}
 498
 499static void _dumpHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 500	if (!dv || dv->type != CLIDV_INT_TYPE) {
 501		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 502		return;
 503	}
 504	uint32_t address = dv->intValue;
 505	uint32_t words = 8;
 506	if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
 507		words = dv->next->intValue;
 508	}
 509	while (words) {
 510		uint32_t line = 8;
 511		if (line > words) {
 512			line = words;
 513		}
 514		debugger->backend->printf(debugger->backend, "0x%08X:", address);
 515		for (; line > 0; --line, address += 2, --words) {
 516			uint32_t value;
 517			if (dv->segmentValue >= 0) {
 518				value = debugger->d.core->rawRead16(debugger->d.core, address, dv->segmentValue);
 519			} else {
 520				value = debugger->d.core->busRead16(debugger->d.core, address);
 521			}
 522			debugger->backend->printf(debugger->backend, " %04X", value);
 523		}
 524		debugger->backend->printf(debugger->backend, "\n");
 525	}
 526}
 527
 528static void _dumpWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 529	if (!dv || dv->type != CLIDV_INT_TYPE) {
 530		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 531		return;
 532	}
 533	uint32_t address = dv->intValue;
 534	uint32_t words = 4;
 535	if (dv->next && dv->next->type == CLIDV_INT_TYPE) {
 536		words = dv->next->intValue;
 537	}
 538	while (words) {
 539		uint32_t line = 4;
 540		if (line > words) {
 541			line = words;
 542		}
 543		debugger->backend->printf(debugger->backend, "0x%08X:", address);
 544		for (; line > 0; --line, address += 4, --words) {
 545			uint32_t value;
 546			if (dv->segmentValue >= 0) {
 547				value = debugger->d.core->rawRead32(debugger->d.core, address, dv->segmentValue);
 548			} else {
 549				value = debugger->d.core->busRead32(debugger->d.core, address);
 550			}
 551			debugger->backend->printf(debugger->backend, " %08X", value);
 552		}
 553		debugger->backend->printf(debugger->backend, "\n");
 554	}
 555}
 556
 557#ifdef ENABLE_SCRIPTING
 558static void _source(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 559	if (!dv) {
 560		debugger->backend->printf(debugger->backend, "Needs a filename\n");
 561		return;
 562	}
 563	if (debugger->d.bridge && mScriptBridgeLoadScript(debugger->d.bridge, dv->charValue)) {
 564		mScriptBridgeRun(debugger->d.bridge);
 565	} else {
 566		debugger->backend->printf(debugger->backend, "Failed to load script\n");
 567	}
 568}
 569#endif
 570
 571static struct ParseTree* _parseTree(const char** string) {
 572	struct LexVector lv;
 573	bool error = false;
 574	LexVectorInit(&lv, 0);
 575	size_t i;
 576	for (i = 0; string[i]; ++i) {
 577		size_t length = strlen(string[i]);
 578		size_t adjusted = lexExpression(&lv, string[i], length, NULL);
 579		if (!adjusted || adjusted > length) {
 580			error = true;
 581		}
 582	}
 583	struct ParseTree* tree = NULL;
 584	if (!error) {
 585		tree = malloc(sizeof(*tree));
 586		parseLexedExpression(tree, &lv);
 587	}
 588	lexFree(&lv);
 589	LexVectorClear(&lv);
 590	LexVectorDeinit(&lv);
 591	if (error) {
 592		if (tree) {
 593			parseFree(tree);
 594			free(tree);
 595		}
 596		return NULL;
 597	} else {
 598		return tree;
 599	}
 600}
 601
 602static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 603	if (!dv || dv->type != CLIDV_INT_TYPE) {
 604		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 605		return;
 606	}
 607	struct mBreakpoint breakpoint = {
 608		.address = dv->intValue,
 609		.segment = dv->segmentValue,
 610		.type = BREAKPOINT_HARDWARE
 611	};
 612	if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
 613		struct ParseTree* tree = _parseTree((const char*[]) { dv->next->charValue, NULL });
 614		if (tree) {
 615			breakpoint.condition = tree;
 616		} else {
 617			debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
 618			return;
 619		}
 620	}
 621	ssize_t id = debugger->d.platform->setBreakpoint(debugger->d.platform, &breakpoint);
 622	if (id > 0) {
 623		debugger->backend->printf(debugger->backend, INFO_BREAKPOINT_ADDED, id);
 624	}
 625}
 626
 627static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum mWatchpointType type) {
 628	if (!dv || dv->type != CLIDV_INT_TYPE) {
 629		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 630		return;
 631	}
 632	if (!debugger->d.platform->setWatchpoint) {
 633		debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n");
 634		return;
 635	}
 636	struct mWatchpoint watchpoint = {
 637		.address = dv->intValue,
 638		.segment = dv->segmentValue,
 639		.type = type
 640	};
 641	if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
 642		struct ParseTree* tree = _parseTree((const char*[]) { dv->next->charValue, NULL });
 643		if (tree) {
 644			watchpoint.condition = tree;
 645		} else {
 646			debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
 647			return;
 648		}
 649	}
 650	ssize_t id = debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint);
 651	if (id > 0) {
 652		debugger->backend->printf(debugger->backend, INFO_WATCHPOINT_ADDED, id);
 653	}
 654}
 655
 656static void _setReadWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 657	_setWatchpoint(debugger, dv, WATCHPOINT_RW);
 658}
 659
 660static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 661	_setWatchpoint(debugger, dv, WATCHPOINT_READ);
 662}
 663
 664static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 665	_setWatchpoint(debugger, dv, WATCHPOINT_WRITE);
 666}
 667
 668static void _setWriteChangedWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 669	_setWatchpoint(debugger, dv, WATCHPOINT_WRITE_CHANGE);
 670}
 671
 672static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 673	if (!dv || dv->type != CLIDV_INT_TYPE) {
 674		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 675		return;
 676	}
 677	uint64_t id = dv->intValue;
 678	debugger->d.platform->clearBreakpoint(debugger->d.platform, id);
 679}
 680
 681static void _listBreakpoints(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 682	UNUSED(dv);
 683	struct mBreakpointList breakpoints;
 684	mBreakpointListInit(&breakpoints, 0);
 685	debugger->d.platform->listBreakpoints(debugger->d.platform, &breakpoints);
 686	size_t i;
 687	for (i = 0; i < mBreakpointListSize(&breakpoints); ++i) {
 688		struct mBreakpoint* breakpoint = mBreakpointListGetPointer(&breakpoints, i);
 689		if (breakpoint->segment >= 0) {
 690			debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", breakpoint->id, breakpoint->segment, breakpoint->address);
 691		} else {
 692			debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", breakpoint->id, breakpoint->address);
 693		}
 694	}
 695	mBreakpointListDeinit(&breakpoints);
 696}
 697
 698static void _listWatchpoints(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 699	UNUSED(dv);
 700	struct mWatchpointList watchpoints;
 701	mWatchpointListInit(&watchpoints, 0);
 702	debugger->d.platform->listWatchpoints(debugger->d.platform, &watchpoints);
 703	size_t i;
 704	for (i = 0; i < mWatchpointListSize(&watchpoints); ++i) {
 705		struct mWatchpoint* watchpoint = mWatchpointListGetPointer(&watchpoints, i);
 706		if (watchpoint->segment >= 0) {
 707			debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", watchpoint->id, watchpoint->segment, watchpoint->address);
 708		} else {
 709			debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", watchpoint->id, watchpoint->address);
 710		}
 711	}
 712	mWatchpointListDeinit(&watchpoints);
 713}
 714
 715static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 716	if (!dv || dv->type != CLIDV_INT_TYPE) {
 717		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
 718		return;
 719	}
 720
 721	debugger->traceRemaining = dv->intValue;
 722	if (debugger->traceVf) {
 723		debugger->traceVf->close(debugger->traceVf);
 724		debugger->traceVf = NULL;
 725	}
 726	if (debugger->traceRemaining == 0) {
 727		return;
 728	}
 729	if (dv->next && dv->next->charValue) {
 730		debugger->traceVf = VFileOpen(dv->next->charValue, O_CREAT | O_WRONLY | O_APPEND);
 731	}
 732	if (_doTrace(debugger)) {
 733		debugger->d.state = DEBUGGER_CALLBACK;
 734	} else {
 735		debugger->system->printStatus(debugger->system);
 736	}
 737}
 738
 739static bool _doTrace(struct CLIDebugger* debugger) {
 740	char trace[1024];
 741	trace[sizeof(trace) - 1] = '\0';
 742	size_t traceSize = sizeof(trace) - 2;
 743	debugger->d.platform->trace(debugger->d.platform, trace, &traceSize);
 744	if (traceSize + 1 <= sizeof(trace)) {
 745		trace[traceSize] = '\n';
 746		trace[traceSize + 1] = '\0';
 747	}
 748	if (debugger->traceVf) {
 749		debugger->traceVf->write(debugger->traceVf, trace, traceSize + 1);
 750	} else {
 751		debugger->backend->printf(debugger->backend, "%s", trace);
 752	}
 753	if (debugger->traceRemaining > 0) {
 754		--debugger->traceRemaining;
 755	}
 756	if (!debugger->traceRemaining) {
 757		if (debugger->traceVf) {
 758			debugger->traceVf->close(debugger->traceVf);
 759			debugger->traceVf = NULL;
 760		}
 761		return false;
 762	}
 763	return true;
 764}
 765
 766static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 767	UNUSED(dv);
 768	debugger->system->printStatus(debugger->system);
 769}
 770
 771struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* string, size_t length) {
 772	if (!string || length < 1) {
 773		return 0;
 774	}
 775
 776	struct CLIDebugVector dvTemp = { .type = CLIDV_INT_TYPE, .segmentValue = -1 };
 777
 778	struct LexVector lv;
 779	LexVectorInit(&lv, 0);
 780	size_t adjusted = lexExpression(&lv, string, length, " ");
 781	if (adjusted > length) {
 782		dvTemp.type = CLIDV_ERROR_TYPE;
 783	}
 784
 785	struct ParseTree tree;
 786	parseLexedExpression(&tree, &lv);
 787	if (tree.token.type == TOKEN_ERROR_TYPE) {
 788		dvTemp.type = CLIDV_ERROR_TYPE;
 789	} else {
 790		if (!mDebuggerEvaluateParseTree(&debugger->d, &tree, &dvTemp.intValue, &dvTemp.segmentValue)) {
 791			dvTemp.type = CLIDV_ERROR_TYPE;
 792		}
 793	}
 794
 795	parseFree(&tree);
 796
 797	lexFree(&lv);
 798	LexVectorDeinit(&lv);
 799
 800	struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
 801	if (dvTemp.type == CLIDV_ERROR_TYPE) {
 802		dv->type = CLIDV_ERROR_TYPE;
 803		dv->next = 0;
 804	} else {
 805		*dv = dvTemp;
 806	}
 807	return dv;
 808}
 809
 810struct CLIDebugVector* CLIDVStringParse(struct CLIDebugger* debugger, const char* string, size_t length) {
 811	UNUSED(debugger);
 812	if (!string || length < 1) {
 813		return 0;
 814	}
 815
 816	struct CLIDebugVector dvTemp = { .type = CLIDV_CHAR_TYPE };
 817
 818	dvTemp.charValue = strndup(string, length);
 819
 820	struct CLIDebugVector* dv = malloc(sizeof(struct CLIDebugVector));
 821	*dv = dvTemp;
 822	return dv;
 823}
 824
 825static void _DVFree(struct CLIDebugVector* dv) {
 826	struct CLIDebugVector* next;
 827	while (dv) {
 828		next = dv->next;
 829		if (dv->type == CLIDV_CHAR_TYPE) {
 830			free(dv->charValue);
 831		}
 832		free(dv);
 833		dv = next;
 834	}
 835}
 836
 837static struct CLIDebugVector* _parseArg(struct CLIDebugger* debugger, const char* args, size_t argsLen, char type) {
 838	struct CLIDebugVector* dv = NULL;
 839	switch (type) {
 840	case 'I':
 841	case 'i':
 842		return CLIDVParse(debugger, args, argsLen);
 843	case 'S':
 844	case 's':
 845		return CLIDVStringParse(debugger, args, argsLen);
 846	case '*':
 847		dv = _parseArg(debugger, args, argsLen, 'I');
 848		if (!dv) {
 849			dv = _parseArg(debugger, args, argsLen, 'S');
 850		}
 851		break;
 852	}
 853	return dv;
 854}
 855
 856static int _tryCommands(struct CLIDebugger* debugger, struct CLIDebuggerCommandSummary* commands, struct CLIDebuggerCommandAlias* aliases, const char* command, size_t commandLen, const char* args, size_t argsLen) {
 857	struct CLIDebugVector* dv = NULL;
 858	struct CLIDebugVector* dvLast = NULL;
 859	int i;
 860	const char* name;
 861	if (aliases) {
 862		for (i = 0; (name = aliases[i].name); ++i) {
 863			if (strlen(name) != commandLen) {
 864				continue;
 865			}
 866			if (strncasecmp(name, command, commandLen) == 0) {
 867				command = aliases[i].original;
 868				commandLen = strlen(aliases[i].original);
 869			}
 870		}
 871	}
 872	for (i = 0; (name = commands[i].name); ++i) {
 873		if (strlen(name) != commandLen) {
 874			continue;
 875		}
 876		if (strncasecmp(name, command, commandLen) == 0) {
 877			if (commands[i].format && args) {
 878				char lastArg = '\0';
 879				int arg;
 880				for (arg = 0; commands[i].format[arg] && argsLen; ++arg) {
 881					while (isspace(args[0]) && argsLen) {
 882						++args;
 883						--argsLen;
 884					}
 885					if (!args[0] || !argsLen) {
 886						debugger->backend->printf(debugger->backend, "Wrong number of arguments\n");
 887						_DVFree(dv);
 888						return 0;
 889					}
 890
 891					size_t adjusted;
 892					const char* next = strchr(args, ' ');
 893					if (next) {
 894						adjusted = next - args;
 895					} else {
 896						adjusted = argsLen;
 897					}
 898
 899					struct CLIDebugVector* dvNext = NULL;
 900					bool nextArgMandatory = false;
 901
 902					if (commands[i].format[arg] == '+') {
 903						dvNext = _parseArg(debugger, args, adjusted, lastArg);
 904						--arg;
 905					} else {
 906						nextArgMandatory = isupper(commands[i].format[arg]) || (commands[i].format[arg] == '*');
 907						dvNext = _parseArg(debugger, args, adjusted, commands[i].format[arg]);
 908						lastArg = commands[i].format[arg];
 909					}
 910
 911					args += adjusted;
 912					argsLen -= adjusted;
 913
 914					if (!dvNext) {
 915						if (!nextArgMandatory) {
 916							args = NULL;
 917						}
 918						break;
 919					}
 920					if (dvNext->type == CLIDV_ERROR_TYPE) {
 921						debugger->backend->printf(debugger->backend, "Parse error\n");
 922						_DVFree(dv);
 923						_DVFree(dvNext);
 924						return 0;
 925					}
 926
 927					if (dvLast) {
 928						dvLast->next = dvNext;
 929						dvLast = dvNext;
 930					} else {
 931						dv = dvNext;
 932						dvLast = dv;
 933					}
 934				}
 935			}
 936
 937			if (args) {
 938				while (isspace(args[0]) && argsLen) {
 939					++args;
 940					--argsLen;
 941				}
 942			}
 943			if (args && argsLen) {
 944				debugger->backend->printf(debugger->backend, "Wrong number of arguments\n");
 945				_DVFree(dv);
 946				return 0;
 947			}
 948			commands[i].command(debugger, dv);
 949			_DVFree(dv);
 950			return 1;
 951		}
 952	}
 953	return -1;
 954}
 955
 956bool CLIDebuggerRunCommand(struct CLIDebugger* debugger, const char* line, size_t count) {
 957	const char* firstSpace = strchr(line, ' ');
 958	size_t cmdLength;
 959	if (firstSpace) {
 960		cmdLength = firstSpace - line;
 961	} else {
 962		cmdLength = count;
 963	}
 964
 965	const char* args = 0;
 966	if (firstSpace) {
 967		args = firstSpace + 1;
 968	}
 969	int result = _tryCommands(debugger, _debuggerCommands, _debuggerCommandAliases, line, cmdLength, args, count - cmdLength - 1);
 970	if (result < 0 && debugger->system) {
 971		result = _tryCommands(debugger, debugger->system->commands, debugger->system->commandAliases, line, cmdLength, args, count - cmdLength - 1);
 972		if (result < 0) {
 973			result = _tryCommands(debugger, debugger->system->platformCommands, debugger->system->platformCommandAliases, line, cmdLength, args, count - cmdLength - 1);
 974		}
 975	}
 976	if (result < 0) {
 977		debugger->backend->printf(debugger->backend, "Command not found\n");
 978	}
 979	return false;
 980}
 981
 982static void _commandLine(struct mDebugger* debugger) {
 983	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
 984	const char* line;
 985		size_t len;
 986	_printStatus(cliDebugger, 0);
 987	while (debugger->state == DEBUGGER_PAUSED) {
 988		line = cliDebugger->backend->readline(cliDebugger->backend, &len);
 989		if (!line || len == 0) {
 990			debugger->state = DEBUGGER_SHUTDOWN;
 991			return;
 992		}
 993		if (line[0] == '\n') {
 994			line = cliDebugger->backend->historyLast(cliDebugger->backend, &len);
 995			if (line && len) {
 996				CLIDebuggerRunCommand(cliDebugger, line, len);
 997			}
 998		} else {
 999			CLIDebuggerRunCommand(cliDebugger, line, len);
1000			cliDebugger->backend->historyAppend(cliDebugger->backend, line);
1001		}
1002	}
1003}
1004
1005static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
1006	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1007	if (cliDebugger->traceRemaining > 0) {
1008		cliDebugger->traceRemaining = 0;
1009	}
1010	switch (reason) {
1011	case DEBUGGER_ENTER_MANUAL:
1012	case DEBUGGER_ENTER_ATTACHED:
1013		break;
1014	case DEBUGGER_ENTER_BREAKPOINT:
1015		if (info) {
1016			if (info->pointId > 0) {
1017				cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint %" PRIz "i at 0x%08X\n", info->pointId, info->address);
1018			} else {
1019				cliDebugger->backend->printf(cliDebugger->backend, "Hit unknown breakpoint at 0x%08X\n", info->address);
1020			}
1021		} else {
1022			cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint\n");
1023		}
1024		break;
1025	case DEBUGGER_ENTER_WATCHPOINT:
1026		if (info) {
1027			if (info->type.wp.accessType & WATCHPOINT_WRITE) {
1028				cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint %" PRIz "i at 0x%08X: (new value = 0x%08X, old value = 0x%08X)\n", info->pointId, info->address, info->type.wp.newValue, info->type.wp.oldValue);
1029			} else {
1030				cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint %" PRIz "i at 0x%08X: (value = 0x%08X)\n", info->pointId, info->address, info->type.wp.oldValue);
1031			}
1032		} else {
1033			cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint\n");
1034		}
1035		break;
1036	case DEBUGGER_ENTER_ILLEGAL_OP:
1037		if (info) {
1038			cliDebugger->backend->printf(cliDebugger->backend, "Hit illegal opcode at 0x%08X: 0x%08X\n", info->address, info->type.bp.opcode);
1039		} else {
1040			cliDebugger->backend->printf(cliDebugger->backend, "Hit illegal opcode\n");
1041		}
1042		break;
1043	case DEBUGGER_ENTER_STACK:
1044		if (info) {
1045			if (info->type.st.traceType == STACK_TRACE_BREAK_ON_CALL) {
1046				struct mStackTrace* stack = &cliDebugger->d.stackTrace;
1047				struct mStackFrame* frame = mStackTraceGetFrame(stack, 0);
1048				if (frame->interrupt) {
1049					cliDebugger->backend->printf(cliDebugger->backend, "Hit interrupt at at 0x%08X\n", info->address);
1050				} else {
1051					cliDebugger->backend->printf(cliDebugger->backend, "Hit function call at at 0x%08X\n", info->address);
1052				}
1053			} else {
1054				cliDebugger->backend->printf(cliDebugger->backend, "Hit function return at at 0x%08X\n", info->address);
1055			}
1056		} else {
1057			cliDebugger->backend->printf(cliDebugger->backend, "Hit function call or return\n");
1058		}
1059		_backtrace(cliDebugger, NULL);
1060		break;
1061	}
1062}
1063
1064static void _cliDebuggerInit(struct mDebugger* debugger) {
1065	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1066	cliDebugger->traceRemaining = 0;
1067	cliDebugger->traceVf = NULL;
1068	cliDebugger->backend->init(cliDebugger->backend);
1069}
1070
1071static void _cliDebuggerDeinit(struct mDebugger* debugger) {
1072	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1073	if (cliDebugger->traceVf) {
1074		cliDebugger->traceVf->close(cliDebugger->traceVf);
1075		cliDebugger->traceVf = NULL;
1076	}
1077
1078	if (cliDebugger->system) {
1079		if (cliDebugger->system->deinit) {
1080			cliDebugger->system->deinit(cliDebugger->system);
1081		}
1082		free(cliDebugger->system);
1083		cliDebugger->system = NULL;
1084	}
1085	if (cliDebugger->backend && cliDebugger->backend->deinit) {
1086		cliDebugger->backend->deinit(cliDebugger->backend);
1087		cliDebugger->backend = NULL;
1088	}
1089}
1090
1091static void _cliDebuggerCustom(struct mDebugger* debugger) {
1092	struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
1093	bool retain = true;
1094	enum mDebuggerState next = DEBUGGER_RUNNING;
1095	if (cliDebugger->traceRemaining) {
1096		retain = _doTrace(cliDebugger) && retain;
1097		next = DEBUGGER_PAUSED;
1098	}
1099	if (cliDebugger->system) {
1100		retain = cliDebugger->system->custom(cliDebugger->system) && retain;
1101	}
1102	if (!retain && debugger->state == DEBUGGER_CALLBACK) {
1103		debugger->state = next;
1104	}
1105}
1106
1107void CLIDebuggerCreate(struct CLIDebugger* debugger) {
1108	debugger->d.init = _cliDebuggerInit;
1109	debugger->d.deinit = _cliDebuggerDeinit;
1110	debugger->d.custom = _cliDebuggerCustom;
1111	debugger->d.paused = _commandLine;
1112	debugger->d.entered = _reportEntry;
1113	debugger->d.type = DEBUGGER_CLI;
1114
1115	debugger->system = NULL;
1116	debugger->backend = NULL;
1117}
1118
1119void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSystem* system) {
1120	if (debugger->system) {
1121		if (debugger->system->deinit) {
1122			debugger->system->deinit(debugger->system);
1123		}
1124		free(debugger->system);
1125	}
1126
1127	debugger->system = system;
1128	system->p = debugger;
1129}
1130
1131void CLIDebuggerAttachBackend(struct CLIDebugger* debugger, struct CLIDebuggerBackend* backend) {
1132	if (debugger->backend == backend) {
1133		return;
1134	}
1135	if (debugger->backend && debugger->backend->deinit) {
1136		debugger->backend->deinit(debugger->backend);
1137	}
1138
1139	debugger->backend = backend;
1140	backend->p = debugger;
1141}
1142
1143bool CLIDebuggerTabComplete(struct CLIDebugger* debugger, const char* token, bool initial, size_t tokenLen) {
1144	size_t cmd = 0;
1145	size_t len;
1146	const char* name = 0;
1147	for (len = 1; len <= tokenLen; ++len) {
1148		for (; (name = _debuggerCommands[cmd].name); ++cmd) {
1149			int cmp = strncasecmp(name, token, len);
1150			if (cmp > 0) {
1151				return false;
1152			}
1153			if (cmp == 0) {
1154				break;
1155			}
1156		}
1157	}
1158	if (!name) {
1159		return false;
1160	}
1161	if (_debuggerCommands[cmd + 1].name && strlen(_debuggerCommands[cmd + 1].name) >= len && name[len - 1] == _debuggerCommands[cmd + 1].name[len - 1]) {
1162		--len;
1163		const char* next = 0;
1164		int i;
1165		for (i = cmd + 1; _debuggerCommands[i].name; ++i) {
1166			if (strncasecmp(name, _debuggerCommands[i].name, len)) {
1167				break;
1168			}
1169			next = _debuggerCommands[i].name;
1170		}
1171		if (!next) {
1172			return false;
1173		}
1174
1175		for (; name[len]; ++len) {
1176			if (name[len] != next[len]) {
1177				break;
1178			}
1179			char out[2] = { name[len], '\0' };
1180			debugger->backend->lineAppend(debugger->backend, out);
1181		}
1182		return true;
1183	}
1184	name += len - 1;
1185	debugger->backend->lineAppend(debugger->backend, name);
1186	debugger->backend->lineAppend(debugger->backend, " ");
1187	return true;
1188}
1189
1190static void _backtrace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
1191	if (!CLIDebuggerCheckTraceMode(debugger, true)) {
1192		return;
1193	}
1194	struct mStackTrace* stack = &debugger->d.stackTrace;
1195	ssize_t frames = mStackTraceGetDepth(stack);
1196	if (dv && dv->type == CLIDV_INT_TYPE && dv->intValue < frames) {
1197		frames = dv->intValue;
1198	}
1199	ssize_t i;
1200	struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
1201	for (i = 0; i < frames; ++i) {
1202		char trace[1024];
1203		size_t traceSize = sizeof(trace) - 2;
1204		mStackTraceFormatFrame(stack, symbolTable, i, trace, &traceSize);
1205		debugger->backend->printf(debugger->backend, "%s", trace);
1206	}
1207}
1208
1209static void _finish(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
1210	UNUSED(dv);
1211	if (!CLIDebuggerCheckTraceMode(debugger, true)) {
1212		return;
1213	}
1214	struct mStackTrace* stack = &debugger->d.stackTrace;
1215	struct mStackFrame* frame = mStackTraceGetFrame(stack, 0);
1216	if (!frame) {
1217		debugger->backend->printf(debugger->backend, "No current stack frame.\n");
1218		return;
1219	}
1220	frame->breakWhenFinished = true;
1221	_continue(debugger, dv);
1222}
1223
1224static void _setStackTraceMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
1225	if (!CLIDebuggerCheckTraceMode(debugger, false)) {
1226		return;
1227	}
1228	if (!dv) {
1229		debugger->backend->printf(debugger->backend, "off           disable stack tracing (default)\n");
1230		debugger->backend->printf(debugger->backend, "trace-only    enable stack tracing\n");
1231		debugger->backend->printf(debugger->backend, "break-call    break on function calls\n");
1232		debugger->backend->printf(debugger->backend, "break-return  break on function returns\n");
1233		debugger->backend->printf(debugger->backend, "break-all     break on function calls and returns\n");
1234		return;
1235	}
1236	if (dv->type != CLIDV_CHAR_TYPE) {
1237		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
1238		return;
1239	}
1240	struct mDebuggerPlatform* platform = debugger->d.platform;
1241	if (strcmp(dv->charValue, "off") == 0) {
1242		platform->setStackTraceMode(platform, STACK_TRACE_DISABLED);
1243	} else if (strcmp(dv->charValue, "trace-only") == 0) {
1244		platform->setStackTraceMode(platform, STACK_TRACE_ENABLED);
1245	} else if (strcmp(dv->charValue, "break-call") == 0) {
1246		platform->setStackTraceMode(platform, STACK_TRACE_BREAK_ON_CALL);
1247	} else if (strcmp(dv->charValue, "break-return") == 0) {
1248		platform->setStackTraceMode(platform, STACK_TRACE_BREAK_ON_RETURN);
1249	} else if (strcmp(dv->charValue, "break-all") == 0) {
1250		platform->setStackTraceMode(platform, STACK_TRACE_BREAK_ON_BOTH);
1251	} else {
1252		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
1253	}
1254}
1255
1256static void _setSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
1257	struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
1258	if (!symbolTable) {
1259		debugger->backend->printf(debugger->backend, "No symbol table available.\n");
1260		return;
1261	}
1262	if (!dv || !dv->next) {
1263		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
1264		return;
1265	}
1266	if (dv->type != CLIDV_CHAR_TYPE || dv->next->type != CLIDV_INT_TYPE) {
1267		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
1268		return;
1269	}
1270	mDebuggerSymbolAdd(symbolTable, dv->charValue, dv->next->intValue, dv->next->segmentValue);
1271}
1272
1273static void _findSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
1274	struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable;
1275	if (!symbolTable) {
1276		debugger->backend->printf(debugger->backend, "No symbol table available.\n");
1277		return;
1278	}
1279	if (!dv) {
1280		debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
1281		return;
1282	}
1283	if (dv->type != CLIDV_INT_TYPE) {
1284		debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
1285		return;
1286	}
1287	const char* name = mDebuggerSymbolReverseLookup(symbolTable, dv->intValue, dv->segmentValue);
1288	if (name) {
1289		if (dv->segmentValue >= 0) {
1290			debugger->backend->printf(debugger->backend, " 0x%02X:%08X = %s\n", dv->segmentValue, dv->intValue, name);
1291		} else {
1292			debugger->backend->printf(debugger->backend, " 0x%08X = %s\n", dv->intValue, name);
1293		}
1294	} else {
1295		debugger->backend->printf(debugger->backend, "Not found.\n");
1296	}
1297}