Debugger: add support for simple command scripts
Adam Higerd chighland@gmail.com
Fri, 31 Jul 2020 17:24:06 -0500
6 files changed,
155 insertions(+),
4 deletions(-)
M
CHANGES
→
CHANGES
@@ -4,6 +4,7 @@ - e-Reader card scanning
- Add WebP and APNG recording - Support for unlicensed Pokemon Jade/Diamond Game Boy mapper - Stack tracing tools in ARM debugger (by ahigerd) + - Command scripts for CLI debugger (by ahigerd) Emulation fixes: - ARM: Fix ALU reading PC after shifting - ARM: Fix STR storing PC after address calculation
M
include/mgba/internal/debugger/cli-debugger.h
→
include/mgba/internal/debugger/cli-debugger.h
@@ -95,6 +95,11 @@ void CLIDebuggerAttachBackend(struct CLIDebugger*, struct CLIDebuggerBackend*);
bool CLIDebuggerTabComplete(struct CLIDebugger*, const char* token, bool initial, size_t len); +bool CLIDebuggerRunCommand(struct CLIDebugger* debugger, const char* line, size_t count); +#if ENABLE_SCRIPTING +void CLIDebuggerScriptEngineInstall(struct mScriptBridge* sb); +#endif + CXX_GUARD_END #endif
M
src/debugger/CMakeLists.txt
→
src/debugger/CMakeLists.txt
@@ -6,6 +6,10 @@ parser.c
symbols.c stack-trace.c) +if(ENABLE_SCRIPTING) + list(APPEND SOURCE_FILES cli-debugger-scripting.c) +endif() + set(TEST_FILES test/lexer.c test/parser.c)
A
src/debugger/cli-debugger-scripting.c
@@ -0,0 +1,137 @@
+/* Copyright (c) 2013-2020 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <mgba/core/scripting.h> +#include <mgba-util/string.h> +#include <mgba-util/vfs.h> + +#include <mgba/debugger/debugger.h> +#include <mgba/internal/debugger/cli-debugger.h> + +static const char* CLIScriptEngineName(struct mScriptEngine*); +static bool CLIScriptEngineInit(struct mScriptEngine*, struct mScriptBridge*); +static void CLIScriptEngineDeinit(struct mScriptEngine*); +static bool CLIScriptEngineIsScript(struct mScriptEngine*, const char* name, struct VFile* vf); +static bool CLIScriptEngineLoadScript(struct mScriptEngine*, const char* name, struct VFile* vf); +static void CLIScriptEngineRun(struct mScriptEngine*); +static bool CLIScriptEngineLookupSymbol(struct mScriptEngine*, const char* name, int32_t* out); +static void CLIScriptDebuggerEntered(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); + +struct CLIScriptStatement { + char* command; + size_t commandLen; +}; + +DECLARE_VECTOR(CLIScript, struct CLIScriptStatement); +DEFINE_VECTOR(CLIScript, struct CLIScriptStatement); + +struct CLIScriptEngine { + struct mScriptEngine d; + struct mScriptBridge* sb; + struct CLIScript script; +}; + +static void CLIScriptEngineClear(struct CLIScriptEngine* engine) { + size_t i = CLIScriptSize(&engine->script); + while (i-- > 0) { + struct CLIScriptStatement* statement = CLIScriptGetPointer(&engine->script, i); + free(statement->command); + } + CLIScriptClear(&engine->script); +} + +struct CLIScriptEngine* CLICreateScriptEngine(void) { + struct CLIScriptEngine* engine = malloc(sizeof(*engine)); + engine->d.name = CLIScriptEngineName; + engine->d.init = CLIScriptEngineInit; + engine->d.deinit = CLIScriptEngineDeinit; + engine->d.isScript = CLIScriptEngineIsScript; + engine->d.loadScript = CLIScriptEngineLoadScript; + engine->d.run = CLIScriptEngineRun; + engine->d.lookupSymbol = CLIScriptEngineLookupSymbol; + engine->d.debuggerEntered = CLIScriptDebuggerEntered; + engine->sb = NULL; + return engine; +} + +void CLIDebuggerScriptEngineInstall(struct mScriptBridge* sb) { + struct CLIScriptEngine* se = CLICreateScriptEngine(); + mScriptBridgeInstallEngine(sb, &se->d); +} + +const char* CLIScriptEngineName(struct mScriptEngine* se) { + UNUSED(se); + return "cli-debugger"; +} + +bool CLIScriptEngineInit(struct mScriptEngine* se, struct mScriptBridge* sb) { + struct CLIScriptEngine* engine = (struct CLIScriptEngine*) se; + engine->sb = sb; + CLIScriptInit(&engine->script, 0); + return true; +} + +void CLIScriptEngineDeinit(struct mScriptEngine* se) { + struct CLIScriptEngine* engine = (struct CLIScriptEngine*) se; + CLIScriptEngineClear(engine); + CLIScriptDeinit(&engine->script); + free(se); +} + +bool CLIScriptEngineIsScript(struct mScriptEngine* se, const char* name, struct VFile* vf) { + UNUSED(se); + UNUSED(vf); + return endswith(name, ".mrc"); +} + +bool CLIScriptEngineLoadScript(struct mScriptEngine* se, const char* name, struct VFile* vf) { + UNUSED(name); + struct CLIScriptEngine* engine = (struct CLIScriptEngine*) se; + char buffer[256]; + ssize_t size; + CLIScriptEngineClear(engine); + struct CLIScriptStatement* statement; + while ((size = vf->readline(vf, buffer, sizeof(buffer))) > 0) { + if (buffer[size - 1] == '\n') { + --size; + } + statement = CLIScriptAppend(&engine->script); + statement->command = strndup(buffer, size); + statement->commandLen = size; + } + return true; +} + +void CLIScriptEngineRun(struct mScriptEngine* se) { + struct CLIScriptEngine* engine = (struct CLIScriptEngine*) se; + struct CLIDebugger* debugger = (struct CLIDebugger*) mScriptBridgeGetDebugger(engine->sb); + struct CLIScriptStatement* statement; + size_t statementCount = CLIScriptSize(&engine->script); + size_t i; + for (i = 0; i < statementCount; i++) { + statement = CLIScriptGetPointer(&engine->script, i); + CLIDebuggerRunCommand(debugger, statement->command, statement->commandLen); + } +} + +bool CLIScriptEngineLookupSymbol(struct mScriptEngine* se, const char* name, int32_t* out) { + UNUSED(se); + UNUSED(name); + UNUSED(out); + return false; +} + +void CLIScriptDebuggerEntered(struct mScriptEngine* se, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { + UNUSED(reason); + UNUSED(info); + struct CLIScriptEngine* engine = (struct CLIScriptEngine*) se; + + struct mDebugger* debugger = mScriptBridgeGetDebugger(engine->sb); + if (!debugger) { + return; + } + + // TODO: CLIDebuggerEntered(reason, info); +}
M
src/debugger/cli-debugger.c
→
src/debugger/cli-debugger.c
@@ -137,6 +137,7 @@ { "p/t", "print/t" },
{ "p/x", "print/x" }, { "q", "quit" }, { "w", "watch" }, + { ".", "source" }, { 0, 0 } };@@ -944,7 +945,7 @@ }
return -1; } -static bool _parse(struct CLIDebugger* debugger, const char* line, size_t count) { +bool CLIDebuggerRunCommand(struct CLIDebugger* debugger, const char* line, size_t count) { const char* firstSpace = strchr(line, ' '); size_t cmdLength; if (firstSpace) {@@ -984,10 +985,10 @@ }
if (line[0] == '\n') { line = cliDebugger->backend->historyLast(cliDebugger->backend, &len); if (line && len) { - _parse(cliDebugger, line, len); + CLIDebuggerRunCommand(cliDebugger, line, len); } } else { - _parse(cliDebugger, line, len); + CLIDebuggerRunCommand(cliDebugger, line, len); cliDebugger->backend->historyAppend(cliDebugger->backend, line); } }
M
src/platform/sdl/main.c
→
src/platform/sdl/main.c
@@ -210,6 +210,9 @@ struct mScriptBridge* bridge = mScriptBridgeCreate();
#ifdef ENABLE_PYTHON mPythonSetup(bridge); #endif +#ifdef USE_DEBUGGERS + CLIDebuggerScriptEngineInstall(bridge); +#endif #endif #ifdef USE_DEBUGGERS@@ -223,7 +226,7 @@ }
#endif mDebuggerAttach(debugger, renderer->core); mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL); - #ifdef ENABLE_SCRIPTING +#ifdef ENABLE_SCRIPTING mScriptBridgeSetDebugger(bridge, debugger); #endif }