all repos — mgba @ 60ec3e0e9926da9a10771f164f5040359f077872

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