add 'step' and 'resume' commands

This commit is contained in:
MihailRis 2025-10-07 21:53:46 +03:00
parent 5972bc769b
commit 9372a5226e
6 changed files with 91 additions and 42 deletions

View File

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

View File

@ -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,
? DebuggingEventType::SET_BREAKPOINT
: DebuggingEventType::REMOVE_BREAKPOINT,
BreakpointEventDto {
map["source"].asString(),
static_cast<int>(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<ClientConnection>(engine.getNetwork(), client);
}
std::vector<BreakpointEvent> DebuggingServer::pullBreakpointEvents() {
std::vector<DebuggingEvent> DebuggingServer::pullEvents() {
return std::move(breakpointEvents);
}

View File

@ -3,6 +3,7 @@
#include <memory>
#include <string>
#include <vector>
#include <variant>
#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<BreakpointEventDto, SignalEventDto> 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<BreakpointEvent> pullBreakpointEvents();
std::vector<DebuggingEvent> pullEvents();
private:
Engine& engine;
network::Server& server;
std::unique_ptr<ClientConnection> connection;
std::vector<BreakpointEvent> breakpointEvents;
std::vector<DebuggingEvent> breakpointEvents;
bool performCommand(const std::string& type, const dv::value& map);
bool performCommand(
const std::string& type, const dv::value& map
);
};
}

View File

@ -284,11 +284,13 @@ void Engine::postUpdate() {
scripting::process_post_runnables();
if (debuggingServer) {
if (!debuggingServer->update()) {
debuggingServer->update();
}
}
void Engine::detachDebugger() {
debuggingServer.reset();
}
}
}
void Engine::updateFrontend() {
double delta = time.getDelta();
@ -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()) {

View File

@ -190,4 +190,6 @@ public:
devtools::DebuggingServer* getDebuggingServer() {
return debuggingServer.get();
}
void detachDebugger();
};

View File

@ -280,8 +280,11 @@ 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();
auto server = engine->getDebuggingServer();
if (!server) {
return 0;
}
auto events = server->pullEvents();
if (events.empty()) {
return 0;
}
@ -293,18 +296,18 @@ static int l_debug_pull_events(lua::State* L) {
lua::pushinteger(L, static_cast<int>(event.type));
lua::rawseti(L, 1);
lua::pushstring(L, event.source);
if (auto dto = std::get_if<devtools::BreakpointEventDto>(&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;
}
return 0;
}
void initialize_libs_extends(lua::State* L) {
if (lua::getglobal(L, "debug")) {