Debugger: add support for simple command scripts

This commit is contained in:
Adam Higerd 2020-07-31 17:24:06 -05:00 committed by Vicki Pfau
parent 002e9c8802
commit a98c01bafc
6 changed files with 155 additions and 4 deletions

View File

@ -4,6 +4,7 @@ Features:
- 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

View File

@ -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

View File

@ -6,6 +6,10 @@ set(SOURCE_FILES
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)

View File

@ -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);
}

View File

@ -137,6 +137,7 @@ static struct CLIDebuggerCommandAlias _debuggerCommandAliases[] = {
{ "p/x", "print/x" },
{ "q", "quit" },
{ "w", "watch" },
{ ".", "source" },
{ 0, 0 }
};
@ -944,7 +945,7 @@ static int _tryCommands(struct CLIDebugger* debugger, struct CLIDebuggerCommandS
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 @@ static void _commandLine(struct mDebugger* debugger) {
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);
}
}

View File

@ -210,6 +210,9 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
#ifdef ENABLE_PYTHON
mPythonSetup(bridge);
#endif
#ifdef USE_DEBUGGERS
CLIDebuggerScriptEngineInstall(bridge);
#endif
#endif
#ifdef USE_DEBUGGERS
@ -223,7 +226,7 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
#endif
mDebuggerAttach(debugger, renderer->core);
mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL);
#ifdef ENABLE_SCRIPTING
#ifdef ENABLE_SCRIPTING
mScriptBridgeSetDebugger(bridge, debugger);
#endif
}