mirror of https://github.com/mgba-emu/mgba.git
Core: Add scripting debugger callbacks
This commit is contained in:
parent
d1ef27cff9
commit
a033f8783b
|
@ -10,9 +10,12 @@
|
||||||
|
|
||||||
CXX_GUARD_START
|
CXX_GUARD_START
|
||||||
|
|
||||||
|
#ifdef USE_DEBUGGERS
|
||||||
|
#include <mgba/debugger/debugger.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
struct mScriptBridge;
|
struct mScriptBridge;
|
||||||
struct VFile;
|
struct VFile;
|
||||||
struct mDebugger;
|
|
||||||
struct mScriptEngine {
|
struct mScriptEngine {
|
||||||
const char* (*name)(struct mScriptEngine*);
|
const char* (*name)(struct mScriptEngine*);
|
||||||
|
|
||||||
|
@ -21,6 +24,10 @@ struct mScriptEngine {
|
||||||
bool (*isScript)(struct mScriptEngine*, const char* name, struct VFile* vf);
|
bool (*isScript)(struct mScriptEngine*, const char* name, struct VFile* vf);
|
||||||
bool (*loadScript)(struct mScriptEngine*, const char* name, struct VFile* vf);
|
bool (*loadScript)(struct mScriptEngine*, const char* name, struct VFile* vf);
|
||||||
void (*run)(struct mScriptEngine*);
|
void (*run)(struct mScriptEngine*);
|
||||||
|
|
||||||
|
#ifdef USE_DEBUGGERS
|
||||||
|
void (*debuggerEntered)(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mScriptBridge* mScriptBridgeCreate(void);
|
struct mScriptBridge* mScriptBridgeCreate(void);
|
||||||
|
@ -28,8 +35,11 @@ void mScriptBridgeDestroy(struct mScriptBridge*);
|
||||||
|
|
||||||
void mScriptBridgeInstallEngine(struct mScriptBridge*, struct mScriptEngine*);
|
void mScriptBridgeInstallEngine(struct mScriptBridge*, struct mScriptEngine*);
|
||||||
|
|
||||||
|
#ifdef USE_DEBUGGERS
|
||||||
void mScriptBridgeSetDebugger(struct mScriptBridge*, struct mDebugger*);
|
void mScriptBridgeSetDebugger(struct mScriptBridge*, struct mDebugger*);
|
||||||
struct mDebugger* mScriptBridgeGetDebugger(struct mScriptBridge*);
|
struct mDebugger* mScriptBridgeGetDebugger(struct mScriptBridge*);
|
||||||
|
void mScriptBridgeDebuggerEntered(struct mScriptBridge*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
||||||
|
#endif
|
||||||
|
|
||||||
void mScriptBridgeRun(struct mScriptBridge*);
|
void mScriptBridgeRun(struct mScriptBridge*);
|
||||||
bool mScriptBridgeLoadScript(struct mScriptBridge*, const char* name);
|
bool mScriptBridgeLoadScript(struct mScriptBridge*, const char* name);
|
||||||
|
|
|
@ -30,7 +30,6 @@ enum mDebuggerState {
|
||||||
DEBUGGER_PAUSED,
|
DEBUGGER_PAUSED,
|
||||||
DEBUGGER_RUNNING,
|
DEBUGGER_RUNNING,
|
||||||
DEBUGGER_CUSTOM,
|
DEBUGGER_CUSTOM,
|
||||||
DEBUGGER_SCRIPT,
|
|
||||||
DEBUGGER_SHUTDOWN
|
DEBUGGER_SHUTDOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -428,7 +428,7 @@ static void _source(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (debugger->d.bridge && mScriptBridgeLoadScript(debugger->d.bridge, dv->charValue)) {
|
if (debugger->d.bridge && mScriptBridgeLoadScript(debugger->d.bridge, dv->charValue)) {
|
||||||
debugger->d.state = DEBUGGER_SCRIPT;
|
mScriptBridgeRun(debugger->d.bridge);
|
||||||
} else {
|
} else {
|
||||||
debugger->backend->printf(debugger->backend, "Failed to load script\n");
|
debugger->backend->printf(debugger->backend, "Failed to load script\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,14 +97,6 @@ void mDebuggerRun(struct mDebugger* debugger) {
|
||||||
debugger->state = DEBUGGER_RUNNING;
|
debugger->state = DEBUGGER_RUNNING;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DEBUGGER_SCRIPT:
|
|
||||||
#ifdef ENABLE_SCRIPTING
|
|
||||||
mScriptBridgeRun(debugger->bridge);
|
|
||||||
#endif
|
|
||||||
if (debugger->state == DEBUGGER_SCRIPT) {
|
|
||||||
debugger->state = DEBUGGER_PAUSED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DEBUGGER_SHUTDOWN:
|
case DEBUGGER_SHUTDOWN:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -122,6 +114,11 @@ void mDebuggerEnter(struct mDebugger* debugger, enum mDebuggerEntryReason reason
|
||||||
if (debugger->platform->entered) {
|
if (debugger->platform->entered) {
|
||||||
debugger->platform->entered(debugger->platform, reason, info);
|
debugger->platform->entered(debugger->platform, reason, info);
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_SCRIPTING
|
||||||
|
if (debugger->bridge) {
|
||||||
|
mScriptBridgeDebuggerEntered(debugger->bridge, reason, info);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mDebuggerInit(void* cpu, struct mCPUComponent* component) {
|
static void mDebuggerInit(void* cpu, struct mCPUComponent* component) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ file(GLOB PYTHON_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
|
||||||
add_library(${BINARY_NAME}-pylib STATIC ${CMAKE_CURRENT_BINARY_DIR}/lib.c ${PYTHON_SRC})
|
add_library(${BINARY_NAME}-pylib STATIC ${CMAKE_CURRENT_BINARY_DIR}/lib.c ${PYTHON_SRC})
|
||||||
add_dependencies(${BINARY_NAME}-pylib ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py)
|
add_dependencies(${BINARY_NAME}-pylib ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py)
|
||||||
set_target_properties(${BINARY_NAME}-pylib PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR};${INCLUDE_DIRECTORIES}")
|
set_target_properties(${BINARY_NAME}-pylib PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR};${INCLUDE_DIRECTORIES}")
|
||||||
|
set_target_properties(${BINARY_NAME}-pylib PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}")
|
||||||
set(PYTHON_LIBRARY ${BINARY_NAME}-pylib PARENT_SCOPE)
|
set(PYTHON_LIBRARY ${BINARY_NAME}-pylib PARENT_SCOPE)
|
||||||
|
|
||||||
add_custom_target(${BINARY_NAME}-py ALL DEPENDS ${BINARY_NAME}-pylib ${CMAKE_CURRENT_BINARY_DIR}/build/lib/${BINARY_NAME}/__init__.py)
|
add_custom_target(${BINARY_NAME}-py ALL DEPENDS ${BINARY_NAME}-pylib ${CMAKE_CURRENT_BINARY_DIR}/build/lib/${BINARY_NAME}/__init__.py)
|
||||||
|
|
|
@ -78,6 +78,8 @@ ffi.embedding_init_code("""
|
||||||
def mPythonSetDebugger(_debugger):
|
def mPythonSetDebugger(_debugger):
|
||||||
from mgba.debugger import NativeDebugger
|
from mgba.debugger import NativeDebugger
|
||||||
global debugger
|
global debugger
|
||||||
|
if debugger and debugger._native == _debugger:
|
||||||
|
return
|
||||||
debugger = _debugger and NativeDebugger(_debugger)
|
debugger = _debugger and NativeDebugger(_debugger)
|
||||||
|
|
||||||
@ffi.def_extern()
|
@ffi.def_extern()
|
||||||
|
@ -99,6 +101,16 @@ ffi.embedding_init_code("""
|
||||||
for code in pendingCode:
|
for code in pendingCode:
|
||||||
exec(code)
|
exec(code)
|
||||||
pendingCode = []
|
pendingCode = []
|
||||||
|
|
||||||
|
@ffi.def_extern()
|
||||||
|
def mPythonDebuggerEntered(reason, info):
|
||||||
|
global debugger
|
||||||
|
if not debugger:
|
||||||
|
return
|
||||||
|
if info == ffi.NULL:
|
||||||
|
info = None
|
||||||
|
for cb in debugger._cbs:
|
||||||
|
cb(reason, info)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -6,10 +6,13 @@
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
|
||||||
#include <mgba/core/scripting.h>
|
#include <mgba/core/scripting.h>
|
||||||
#include <mgba/debugger/debugger.h>
|
|
||||||
#include <mgba-util/string.h>
|
#include <mgba-util/string.h>
|
||||||
#include <mgba-util/vfs.h>
|
#include <mgba-util/vfs.h>
|
||||||
|
|
||||||
|
#ifdef USE_DEBUGGERS
|
||||||
|
#include <mgba/debugger/debugger.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
|
|
||||||
static const char* mPythonScriptEngineName(struct mScriptEngine*);
|
static const char* mPythonScriptEngineName(struct mScriptEngine*);
|
||||||
|
@ -19,6 +22,10 @@ static bool mPythonScriptEngineIsScript(struct mScriptEngine*, const char* name,
|
||||||
static bool mPythonScriptEngineLoadScript(struct mScriptEngine*, const char* name, struct VFile* vf);
|
static bool mPythonScriptEngineLoadScript(struct mScriptEngine*, const char* name, struct VFile* vf);
|
||||||
static void mPythonScriptEngineRun(struct mScriptEngine*);
|
static void mPythonScriptEngineRun(struct mScriptEngine*);
|
||||||
|
|
||||||
|
#ifdef USE_DEBUGGERS
|
||||||
|
static void mPythonScriptDebuggerEntered(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
||||||
|
#endif
|
||||||
|
|
||||||
struct mPythonScriptEngine {
|
struct mPythonScriptEngine {
|
||||||
struct mScriptEngine d;
|
struct mScriptEngine d;
|
||||||
struct mScriptBridge* sb;
|
struct mScriptBridge* sb;
|
||||||
|
@ -32,6 +39,9 @@ struct mPythonScriptEngine* mPythonCreateScriptEngine(void) {
|
||||||
engine->d.isScript = mPythonScriptEngineIsScript;
|
engine->d.isScript = mPythonScriptEngineIsScript;
|
||||||
engine->d.loadScript = mPythonScriptEngineLoadScript;
|
engine->d.loadScript = mPythonScriptEngineLoadScript;
|
||||||
engine->d.run = mPythonScriptEngineRun;
|
engine->d.run = mPythonScriptEngineRun;
|
||||||
|
#ifdef USE_DEBUGGERS
|
||||||
|
engine->d.debuggerEntered = mPythonScriptDebuggerEntered;
|
||||||
|
#endif
|
||||||
engine->sb = NULL;
|
engine->sb = NULL;
|
||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
@ -78,3 +88,16 @@ void mPythonScriptEngineRun(struct mScriptEngine* se) {
|
||||||
|
|
||||||
mPythonRunPending();
|
mPythonRunPending();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_DEBUGGERS
|
||||||
|
void mPythonScriptDebuggerEntered(struct mScriptEngine* se, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
|
||||||
|
struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se;
|
||||||
|
|
||||||
|
struct mDebugger* debugger = mScriptBridgeGetDebugger(engine->sb);
|
||||||
|
if (!debugger) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPythonDebuggerEntered(reason, info);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
struct mDebugger;
|
#include "flags.h"
|
||||||
|
|
||||||
struct VFile;
|
struct VFile;
|
||||||
|
|
||||||
extern void mPythonSetDebugger(struct mDebugger*);
|
|
||||||
extern bool mPythonLoadScript(const char*, struct VFile*);
|
extern bool mPythonLoadScript(const char*, struct VFile*);
|
||||||
extern void mPythonRunPending();
|
extern void mPythonRunPending();
|
||||||
|
|
||||||
|
#ifdef USE_DEBUGGERS
|
||||||
|
extern void mPythonSetDebugger(struct mDebugger*);
|
||||||
|
extern void mPythonDebuggerEntered(enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
||||||
|
#endif
|
||||||
|
|
|
@ -26,8 +26,18 @@ class NativeDebugger(IRunner):
|
||||||
WATCHPOINT_READ = lib.WATCHPOINT_READ
|
WATCHPOINT_READ = lib.WATCHPOINT_READ
|
||||||
WATCHPOINT_RW = lib.WATCHPOINT_RW
|
WATCHPOINT_RW = lib.WATCHPOINT_RW
|
||||||
|
|
||||||
|
BREAKPOINT_HARDWARE = lib.BREAKPOINT_HARDWARE
|
||||||
|
BREAKPOINT_SOFTWARE = lib.BREAKPOINT_SOFTWARE
|
||||||
|
|
||||||
|
ENTER_MANUAL = lib.DEBUGGER_ENTER_MANUAL
|
||||||
|
ENTER_ATTACHED = lib.DEBUGGER_ENTER_ATTACHED
|
||||||
|
ENTER_BREAKPOINT = lib.DEBUGGER_ENTER_BREAKPOINT
|
||||||
|
ENTER_WATCHPOINT = lib.DEBUGGER_ENTER_WATCHPOINT
|
||||||
|
ENTER_ILLEGAL_OP = lib.DEBUGGER_ENTER_ILLEGAL_OP
|
||||||
|
|
||||||
def __init__(self, native):
|
def __init__(self, native):
|
||||||
self._native = native
|
self._native = native
|
||||||
|
self._cbs = []
|
||||||
self._core = Core._detect(native.core)
|
self._core = Core._detect(native.core)
|
||||||
self._core._wasReset = True
|
self._core._wasReset = True
|
||||||
|
|
||||||
|
@ -65,3 +75,6 @@ class NativeDebugger(IRunner):
|
||||||
if not self._native.platform.clearWatchpoint:
|
if not self._native.platform.clearWatchpoint:
|
||||||
raise RuntimeError("Platform does not support watchpoints")
|
raise RuntimeError("Platform does not support watchpoints")
|
||||||
self._native.platform.clearWatchpoint(self._native.platform, address)
|
self._native.platform.clearWatchpoint(self._native.platform, address)
|
||||||
|
|
||||||
|
def addCallback(self, cb):
|
||||||
|
self._cbs.append(cb)
|
||||||
|
|
Loading…
Reference in New Issue