all repos — mgba @ 1a9ead1e25587c0ce424ca3063b6c0abdb6f5328

mGBA Game Boy Advance Emulator

src/debugger/cli-debugger.c (view raw)

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