From d5cc939a6be49b8de63e5008840f08d2057f6c22 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Mon, 4 Oct 2021 11:03:21 +0200 Subject: [PATCH] Adds support for step over, step into and step out. --- src/AngelscriptDebugger.cpp | 74 ++++++++++++++++++++++++++++- src/AngelscriptDebugger.hpp | 10 ++++ src/DebugAdapterProtocol/Events.hpp | 4 +- 3 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/AngelscriptDebugger.cpp b/src/AngelscriptDebugger.cpp index 026f35a..d634489 100644 --- a/src/AngelscriptDebugger.cpp +++ b/src/AngelscriptDebugger.cpp @@ -37,8 +37,37 @@ void AngelscriptDebugger::on_line_callback(asIScriptContext* ctx, AngelscriptDeb const char* scriptSection = nullptr; int column = 0; int line = ctx->GetLineNumber(0, &column, &scriptSection); - if (line == 0) + if (line == 0) { return; + } + + if (d->_next && d->_nextContext == ctx && d->_nextDepth >= ctx->GetCallstackSize()) { + d->_next = false; + ctx->Suspend(); + d->_pausedContexts.push_back(ctx); + auto* o = new DebugAdapterProtocol::StoppedEvent(new DebugAdapterProtocol::StoppedEventBody("step", "", "")); + + d->Send(o); + return; + } + if (d->_stepInto && d->_nextContext == ctx) { + d->_stepInto = false; + ctx->Suspend(); + d->_pausedContexts.push_back(ctx); + auto* o = new DebugAdapterProtocol::StoppedEvent(new DebugAdapterProtocol::StoppedEventBody("step", "", "")); + + d->Send(o); + return; + } + if (d->_stepOut && d->_nextContext == ctx && d->_nextDepth > ctx->GetCallstackSize()) { + d->_stepOut = false; + ctx->Suspend(); + d->_pausedContexts.push_back(ctx); + auto* o = new DebugAdapterProtocol::StoppedEvent(new DebugAdapterProtocol::StoppedEventBody("step", "", "")); + + d->Send(o); + return; + } auto resolvedScriptPath = d->GetResolvedScriptPath(scriptSection); auto sectionBreakpoints = d->_breakpoints.find(resolvedScriptPath); @@ -257,7 +286,7 @@ void AngelscriptDebugger::OnRequest(asio::ip::tcp::socket* client, DebugAdapterP const char* scriptSection = nullptr; int column = 0; int line; - if (i == 0 && ctx->GetExceptionString() != nullptr) { + if (i == 0 && ctx->GetExceptionFunction() != nullptr) { line = ctx->GetExceptionLineNumber(&column, &scriptSection); } else { line = ctx->GetLineNumber(i, &column, &scriptSection); @@ -330,7 +359,48 @@ void AngelscriptDebugger::OnRequest(asio::ip::tcp::socket* client, DebugAdapterP auto body = new DebugAdapterProtocol::VariablesResponseBody(variables); response->body = body; Send(client, response); + } else if (msg->GetCommand() == "next") { + Next(_pausedContexts.at(0)); + } else if (msg->GetCommand() == "stepIn") { + StepInto(_pausedContexts.at(0)); + } else if (msg->GetCommand() == "stepOut") { + StepOut(_pausedContexts.at(0)); } else { + std::cout << "Unhandled message: " << msg->GetCommand() << std::endl; Send(client, new DebugAdapterProtocol::DefinedResponse(msg->seq)); } } +void AngelscriptDebugger::Next(asIScriptContext* ctx) { + _nextContext = ctx; + _next = true; + _nextDepth = ctx->GetCallstackSize(); + _storedVariableReferences.clear(); + while (!_pausedContexts.empty()) { + auto* c = _pausedContexts[_pausedContexts.size() - 1]; + _pausedContexts.pop_back(); + std::thread([](asIScriptContext* c) { c->Execute(); }, c).detach(); + } +} + +void AngelscriptDebugger::StepInto(asIScriptContext* ctx) { + _nextContext = ctx; + _stepInto = true; + _nextDepth = ctx->GetCallstackSize(); + _storedVariableReferences.clear(); + while (!_pausedContexts.empty()) { + auto* c = _pausedContexts[_pausedContexts.size() - 1]; + _pausedContexts.pop_back(); + std::thread([](asIScriptContext* c) { c->Execute(); }, c).detach(); + } +} +void AngelscriptDebugger::StepOut(asIScriptContext* ctx) { + _nextContext = ctx; + _stepOut = true; + _nextDepth = ctx->GetCallstackSize(); + _storedVariableReferences.clear(); + while (!_pausedContexts.empty()) { + auto* c = _pausedContexts[_pausedContexts.size() - 1]; + _pausedContexts.pop_back(); + std::thread([](asIScriptContext* c) { c->Execute(); }, c).detach(); + } +} diff --git a/src/AngelscriptDebugger.hpp b/src/AngelscriptDebugger.hpp index 3dda07c..0d66f4d 100644 --- a/src/AngelscriptDebugger.hpp +++ b/src/AngelscriptDebugger.hpp @@ -56,6 +56,10 @@ private: void OnRequest(asio::ip::tcp::socket* client, DebugAdapterProtocol::Request* msg); std::string GetResolvedScriptPath(const char* scriptSection); + void Next(asIScriptContext* ctx); + void StepInto(asIScriptContext* ctx); + void StepOut(asIScriptContext* ctx); + asio::io_context _ioContext; asio::ip::tcp::acceptor* _server; std::unordered_set _connections; @@ -64,6 +68,12 @@ private: std::vector _pausedContexts; std::optional _scriptPath; + asIScriptContext* _nextContext; + bool _next; + size_t _nextDepth; + bool _stepInto; + bool _stepOut; + struct StackScope { size_t StackLevel; uint8_t Type; diff --git a/src/DebugAdapterProtocol/Events.hpp b/src/DebugAdapterProtocol/Events.hpp index 239387c..e727988 100644 --- a/src/DebugAdapterProtocol/Events.hpp +++ b/src/DebugAdapterProtocol/Events.hpp @@ -182,7 +182,7 @@ namespace DebugAdapterProtocol { EventDefinition(Stopped, "stopped", { std::string reason; std::optional description; - std::optional number; + std::optional threadId = 0; std::optional preserveFocusHint = false; std::optional text; std::optional allThreadsStopped = true; @@ -197,7 +197,7 @@ namespace DebugAdapterProtocol { auto o = EventBody::ToJson(); o["reason"] = reason; JsonSerializeOptional(o, description); - JsonSerializeOptional(o, number); + JsonSerializeOptional(o, threadId); JsonSerializeOptional(o, preserveFocusHint); JsonSerializeOptional(o, text); JsonSerializeOptional(o, allThreadsStopped);