diff --git a/res/scripts/stdmin.lua b/res/scripts/stdmin.lua index eb3ddbde..46976f77 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -2,8 +2,16 @@ -- may be reused one global ffi buffer per lua_State local breakpoints = {} +local dbg_steps_mode = false +local hook_lock = false debug.sethook(function (e, line) + if dbg_steps_mode and not hook_lock then + hook_lock = true + debug.breakpoint() + debug.pull_events() + end + hook_lock = false local bps = breakpoints[line] if not bps then return @@ -18,6 +26,9 @@ end, "l") local DBG_EVENT_SET_BREAKPOINT = 1 local DBG_EVENT_RM_BREAKPOINT = 2 +local DBG_EVENT_STEP = 3 +local DBG_EVENT_STEP_INTO_FUNCTION = 4 +local DBG_EVENT_RESUME = 5 local __pull_events = debug.__pull_events debug.__pull_events = nil @@ -31,6 +42,10 @@ function debug.pull_events() debug.set_breakpoint(event[2], event[3]) elseif event[1] == DBG_EVENT_RM_BREAKPOINT then debug.remove_breakpoint(event[2], event[3]) + elseif event[1] == DBG_EVENT_STEP then + dbg_steps_mode = true + elseif event[1] == DBG_EVENT_RESUME then + dbg_steps_mode = false end end end diff --git a/src/devtools/DebuggingServer.cpp b/src/devtools/DebuggingServer.cpp index 09c8c18f..9ef677e3 100644 --- a/src/devtools/DebuggingServer.cpp +++ b/src/devtools/DebuggingServer.cpp @@ -130,25 +130,25 @@ DebuggingServer::~DebuggingServer() { bool DebuggingServer::update() { if (connection == nullptr) { - return true; + return false; } std::string message = connection->read(); if (message.empty()) { - return true; + return false; } logger.debug() << "received: " << message; try { auto obj = json::parse(message); if (!obj.has("type")) { logger.error() << "missing message type"; - return true; + return false; } const auto& type = obj["type"].asString(); return performCommand(type, obj); } catch (const std::runtime_error& err) { logger.error() << "could not to parse message: " << err.what(); } - return true; + return false; } bool DebuggingServer::performCommand( @@ -158,24 +158,38 @@ bool DebuggingServer::performCommand( engine.quit(); connection->sendResponse("success"); } else if (type == "detach") { - logger.info() << "detach received"; connection->sendResponse("success"); connection.reset(); + engine.detachDebugger(); return false; } else if (type == "set-breakpoint" || type == "remove-breakpoint") { if (!map.has("source") || !map.has("line")) - return true; - breakpointEvents.push_back(BreakpointEvent { + return false; + breakpointEvents.push_back(DebuggingEvent { type[0] == 's' - ? BreakpointEventType::SET_BREAKPOINT - : BreakpointEventType::REMOVE_BREAKPOINT, - map["source"].asString(), - static_cast(map["line"].asInteger()), + ? DebuggingEventType::SET_BREAKPOINT + : DebuggingEventType::REMOVE_BREAKPOINT, + BreakpointEventDto { + map["source"].asString(), + static_cast(map["line"].asInteger()), + } }); + } else if (type == "step" || type == "step-into-function") { + breakpointEvents.push_back(DebuggingEvent { + type == "step" + ? DebuggingEventType::STEP + : DebuggingEventType::STEP_INTO_FUNCTION, + SignalEventDto {} + }); + return true; + } else if (type == "resume") { + breakpointEvents.push_back(DebuggingEvent { + DebuggingEventType::RESUME, SignalEventDto {}}); + return true; } else { logger.error() << "unsupported command '" << type << "'"; } - return true; + return false; } void DebuggingServer::onHitBreakpoint(dv::value&& stackTrace) { @@ -195,6 +209,6 @@ void DebuggingServer::setClient(u64id_t client) { std::make_unique(engine.getNetwork(), client); } -std::vector DebuggingServer::pullBreakpointEvents() { +std::vector DebuggingServer::pullEvents() { return std::move(breakpointEvents); } diff --git a/src/devtools/DebuggingServer.hpp b/src/devtools/DebuggingServer.hpp index 308cee87..d7be32cf 100644 --- a/src/devtools/DebuggingServer.hpp +++ b/src/devtools/DebuggingServer.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "typedefs.hpp" @@ -36,16 +37,27 @@ namespace devtools { u64id_t connection; }; - enum class BreakpointEventType { + enum class DebuggingEventType { SET_BREAKPOINT = 1, REMOVE_BREAKPOINT, + STEP, + STEP_INTO_FUNCTION, + RESUME, }; - struct BreakpointEvent { - BreakpointEventType type; + + struct BreakpointEventDto { std::string source; int line; }; + struct SignalEventDto { + }; + + struct DebuggingEvent { + DebuggingEventType type; + std::variant data; + }; + class DebuggingServer { public: DebuggingServer(Engine& engine, const std::string& serverString); @@ -55,13 +67,15 @@ namespace devtools { void onHitBreakpoint(dv::value&& stackTrace); void setClient(u64id_t client); - std::vector pullBreakpointEvents(); + std::vector pullEvents(); private: Engine& engine; network::Server& server; std::unique_ptr connection; - std::vector breakpointEvents; + std::vector breakpointEvents; - bool performCommand(const std::string& type, const dv::value& map); + bool performCommand( + const std::string& type, const dv::value& map + ); }; } diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 2a7820a6..a977f354 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -284,12 +284,14 @@ void Engine::postUpdate() { scripting::process_post_runnables(); if (debuggingServer) { - if (!debuggingServer->update()) { - debuggingServer.reset(); - } + debuggingServer->update(); } } +void Engine::detachDebugger() { + debuggingServer.reset(); +} + void Engine::updateFrontend() { double delta = time.getDelta(); updateHotkeys(); @@ -317,10 +319,9 @@ void Engine::startPauseLoop() { input->toggleCursor(); } } - while (!isQuitSignal()) { + while (!isQuitSignal() && debuggingServer) { network->update(); - if (!debuggingServer->update()) { - debuggingServer.reset(); + if (debuggingServer->update()) { break; } if (isHeadless()) { diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index a9fb62ea..67acc498 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -190,4 +190,6 @@ public: devtools::DebuggingServer* getDebuggingServer() { return debuggingServer.get(); } + + void detachDebugger(); }; diff --git a/src/logic/scripting/lua/lua_extensions.cpp b/src/logic/scripting/lua/lua_extensions.cpp index e845f925..fc312820 100644 --- a/src/logic/scripting/lua/lua_extensions.cpp +++ b/src/logic/scripting/lua/lua_extensions.cpp @@ -280,30 +280,33 @@ static int l_debug_breakpoint(lua::State* L) { } static int l_debug_pull_events(lua::State* L) { - if (auto server = engine->getDebuggingServer()) { - auto events = server->pullBreakpointEvents(); - if (events.empty()) { - return 0; - } - lua::createtable(L, events.size(), 0); - for (int i = 0; i < events.size(); i++) { - const auto& event = events[i]; - lua::createtable(L, 3, 0); + auto server = engine->getDebuggingServer(); + if (!server) { + return 0; + } + auto events = server->pullEvents(); + if (events.empty()) { + return 0; + } + lua::createtable(L, events.size(), 0); + for (int i = 0; i < events.size(); i++) { + const auto& event = events[i]; + lua::createtable(L, 3, 0); - lua::pushinteger(L, static_cast(event.type)); - lua::rawseti(L, 1); + lua::pushinteger(L, static_cast(event.type)); + lua::rawseti(L, 1); - lua::pushstring(L, event.source); + if (auto dto = std::get_if(&event.data)) { + lua::pushstring(L, dto->source); lua::rawseti(L, 2); - lua::pushinteger(L, event.line); + lua::pushinteger(L, dto->line); lua::rawseti(L, 3); - - lua::rawseti(L, i + 1); } - return 1; + + lua::rawseti(L, i + 1); } - return 0; + return 1; } void initialize_libs_extends(lua::State* L) {