all repos — mgba @ 82e3b814b496052891b41393c62b540403db66ed

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