add 'step' and 'resume' commands
This commit is contained in:
parent
5972bc769b
commit
9372a5226e
@ -2,8 +2,16 @@
|
|||||||
-- may be reused one global ffi buffer per lua_State
|
-- may be reused one global ffi buffer per lua_State
|
||||||
|
|
||||||
local breakpoints = {}
|
local breakpoints = {}
|
||||||
|
local dbg_steps_mode = false
|
||||||
|
local hook_lock = false
|
||||||
|
|
||||||
debug.sethook(function (e, line)
|
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]
|
local bps = breakpoints[line]
|
||||||
if not bps then
|
if not bps then
|
||||||
return
|
return
|
||||||
@ -18,6 +26,9 @@ end, "l")
|
|||||||
|
|
||||||
local DBG_EVENT_SET_BREAKPOINT = 1
|
local DBG_EVENT_SET_BREAKPOINT = 1
|
||||||
local DBG_EVENT_RM_BREAKPOINT = 2
|
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
|
local __pull_events = debug.__pull_events
|
||||||
debug.__pull_events = nil
|
debug.__pull_events = nil
|
||||||
|
|
||||||
@ -31,6 +42,10 @@ function debug.pull_events()
|
|||||||
debug.set_breakpoint(event[2], event[3])
|
debug.set_breakpoint(event[2], event[3])
|
||||||
elseif event[1] == DBG_EVENT_RM_BREAKPOINT then
|
elseif event[1] == DBG_EVENT_RM_BREAKPOINT then
|
||||||
debug.remove_breakpoint(event[2], event[3])
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -130,25 +130,25 @@ DebuggingServer::~DebuggingServer() {
|
|||||||
|
|
||||||
bool DebuggingServer::update() {
|
bool DebuggingServer::update() {
|
||||||
if (connection == nullptr) {
|
if (connection == nullptr) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
std::string message = connection->read();
|
std::string message = connection->read();
|
||||||
if (message.empty()) {
|
if (message.empty()) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
logger.debug() << "received: " << message;
|
logger.debug() << "received: " << message;
|
||||||
try {
|
try {
|
||||||
auto obj = json::parse(message);
|
auto obj = json::parse(message);
|
||||||
if (!obj.has("type")) {
|
if (!obj.has("type")) {
|
||||||
logger.error() << "missing message type";
|
logger.error() << "missing message type";
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
const auto& type = obj["type"].asString();
|
const auto& type = obj["type"].asString();
|
||||||
return performCommand(type, obj);
|
return performCommand(type, obj);
|
||||||
} catch (const std::runtime_error& err) {
|
} catch (const std::runtime_error& err) {
|
||||||
logger.error() << "could not to parse message: " << err.what();
|
logger.error() << "could not to parse message: " << err.what();
|
||||||
}
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebuggingServer::performCommand(
|
bool DebuggingServer::performCommand(
|
||||||
@ -158,24 +158,38 @@ bool DebuggingServer::performCommand(
|
|||||||
engine.quit();
|
engine.quit();
|
||||||
connection->sendResponse("success");
|
connection->sendResponse("success");
|
||||||
} else if (type == "detach") {
|
} else if (type == "detach") {
|
||||||
logger.info() << "detach received";
|
|
||||||
connection->sendResponse("success");
|
connection->sendResponse("success");
|
||||||
connection.reset();
|
connection.reset();
|
||||||
|
engine.detachDebugger();
|
||||||
return false;
|
return false;
|
||||||
} else if (type == "set-breakpoint" || type == "remove-breakpoint") {
|
} else if (type == "set-breakpoint" || type == "remove-breakpoint") {
|
||||||
if (!map.has("source") || !map.has("line"))
|
if (!map.has("source") || !map.has("line"))
|
||||||
return true;
|
return false;
|
||||||
breakpointEvents.push_back(BreakpointEvent {
|
breakpointEvents.push_back(DebuggingEvent {
|
||||||
type[0] == 's'
|
type[0] == 's'
|
||||||
? BreakpointEventType::SET_BREAKPOINT
|
? DebuggingEventType::SET_BREAKPOINT
|
||||||
: BreakpointEventType::REMOVE_BREAKPOINT,
|
: DebuggingEventType::REMOVE_BREAKPOINT,
|
||||||
map["source"].asString(),
|
BreakpointEventDto {
|
||||||
static_cast<int>(map["line"].asInteger()),
|
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 {
|
} else {
|
||||||
logger.error() << "unsupported command '" << type << "'";
|
logger.error() << "unsupported command '" << type << "'";
|
||||||
}
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggingServer::onHitBreakpoint(dv::value&& stackTrace) {
|
void DebuggingServer::onHitBreakpoint(dv::value&& stackTrace) {
|
||||||
@ -195,6 +209,6 @@ void DebuggingServer::setClient(u64id_t client) {
|
|||||||
std::make_unique<ClientConnection>(engine.getNetwork(), client);
|
std::make_unique<ClientConnection>(engine.getNetwork(), client);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BreakpointEvent> DebuggingServer::pullBreakpointEvents() {
|
std::vector<DebuggingEvent> DebuggingServer::pullEvents() {
|
||||||
return std::move(breakpointEvents);
|
return std::move(breakpointEvents);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
|
|
||||||
@ -36,16 +37,27 @@ namespace devtools {
|
|||||||
u64id_t connection;
|
u64id_t connection;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class BreakpointEventType {
|
enum class DebuggingEventType {
|
||||||
SET_BREAKPOINT = 1,
|
SET_BREAKPOINT = 1,
|
||||||
REMOVE_BREAKPOINT,
|
REMOVE_BREAKPOINT,
|
||||||
|
STEP,
|
||||||
|
STEP_INTO_FUNCTION,
|
||||||
|
RESUME,
|
||||||
};
|
};
|
||||||
struct BreakpointEvent {
|
|
||||||
BreakpointEventType type;
|
struct BreakpointEventDto {
|
||||||
std::string source;
|
std::string source;
|
||||||
int line;
|
int line;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SignalEventDto {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DebuggingEvent {
|
||||||
|
DebuggingEventType type;
|
||||||
|
std::variant<BreakpointEventDto, SignalEventDto> data;
|
||||||
|
};
|
||||||
|
|
||||||
class DebuggingServer {
|
class DebuggingServer {
|
||||||
public:
|
public:
|
||||||
DebuggingServer(Engine& engine, const std::string& serverString);
|
DebuggingServer(Engine& engine, const std::string& serverString);
|
||||||
@ -55,13 +67,15 @@ namespace devtools {
|
|||||||
void onHitBreakpoint(dv::value&& stackTrace);
|
void onHitBreakpoint(dv::value&& stackTrace);
|
||||||
|
|
||||||
void setClient(u64id_t client);
|
void setClient(u64id_t client);
|
||||||
std::vector<BreakpointEvent> pullBreakpointEvents();
|
std::vector<DebuggingEvent> pullEvents();
|
||||||
private:
|
private:
|
||||||
Engine& engine;
|
Engine& engine;
|
||||||
network::Server& server;
|
network::Server& server;
|
||||||
std::unique_ptr<ClientConnection> connection;
|
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
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -284,12 +284,14 @@ void Engine::postUpdate() {
|
|||||||
scripting::process_post_runnables();
|
scripting::process_post_runnables();
|
||||||
|
|
||||||
if (debuggingServer) {
|
if (debuggingServer) {
|
||||||
if (!debuggingServer->update()) {
|
debuggingServer->update();
|
||||||
debuggingServer.reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Engine::detachDebugger() {
|
||||||
|
debuggingServer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
void Engine::updateFrontend() {
|
void Engine::updateFrontend() {
|
||||||
double delta = time.getDelta();
|
double delta = time.getDelta();
|
||||||
updateHotkeys();
|
updateHotkeys();
|
||||||
@ -317,10 +319,9 @@ void Engine::startPauseLoop() {
|
|||||||
input->toggleCursor();
|
input->toggleCursor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (!isQuitSignal()) {
|
while (!isQuitSignal() && debuggingServer) {
|
||||||
network->update();
|
network->update();
|
||||||
if (!debuggingServer->update()) {
|
if (debuggingServer->update()) {
|
||||||
debuggingServer.reset();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (isHeadless()) {
|
if (isHeadless()) {
|
||||||
|
|||||||
@ -190,4 +190,6 @@ public:
|
|||||||
devtools::DebuggingServer* getDebuggingServer() {
|
devtools::DebuggingServer* getDebuggingServer() {
|
||||||
return debuggingServer.get();
|
return debuggingServer.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void detachDebugger();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -280,30 +280,33 @@ static int l_debug_breakpoint(lua::State* L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int l_debug_pull_events(lua::State* L) {
|
static int l_debug_pull_events(lua::State* L) {
|
||||||
if (auto server = engine->getDebuggingServer()) {
|
auto server = engine->getDebuggingServer();
|
||||||
auto events = server->pullBreakpointEvents();
|
if (!server) {
|
||||||
if (events.empty()) {
|
return 0;
|
||||||
return 0;
|
}
|
||||||
}
|
auto events = server->pullEvents();
|
||||||
lua::createtable(L, events.size(), 0);
|
if (events.empty()) {
|
||||||
for (int i = 0; i < events.size(); i++) {
|
return 0;
|
||||||
const auto& event = events[i];
|
}
|
||||||
lua::createtable(L, 3, 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<int>(event.type));
|
lua::pushinteger(L, static_cast<int>(event.type));
|
||||||
lua::rawseti(L, 1);
|
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::rawseti(L, 2);
|
||||||
|
|
||||||
lua::pushinteger(L, event.line);
|
lua::pushinteger(L, dto->line);
|
||||||
lua::rawseti(L, 3);
|
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) {
|
void initialize_libs_extends(lua::State* L) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user