all repos — mgba @ 5d8403f5a3deb02c08f46ccb1e179a807f0e0a69

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