mirror of https://github.com/mgba-emu/mgba.git
Debugger: add support for simple command scripts
This commit is contained in:
parent
002e9c8802
commit
a98c01bafc
1
CHANGES
1
CHANGES
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue