all repos — mgba @ 8a6cf8dc9c00082e9917b4777f949de0d35ce710

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