AngelscriptDebuggerServer/src/AngelscriptDebugger.hpp

101 lines
3.4 KiB
C++

#ifndef ANGELSCRIPTDEBUGGER_ANGELSCRIPTDEBUGGER_HPP
#define ANGELSCRIPTDEBUGGER_ANGELSCRIPTDEBUGGER_HPP
#include <angelscript.h>
#include <iostream>
#include <unordered_set>
#include <variant>
#include <asio.hpp>
#include "Breakpoint.hpp"
#include "DebugAdapterProtocol/BaseProtocol.hpp"
class AngelscriptDebugger {
public:
~AngelscriptDebugger() {
_server->close();
delete _server;
}
void Run(uint16_t port);
void Stop() { _server->close(); }
void RegisterContext(asIScriptContext* ctx);
void Continue() {
std::cout << "Continuing from suspension" << std::endl;
_storedVariableReferences.clear();
while (!_pausedContexts.empty()) {
auto* ctx = _pausedContexts[_pausedContexts.size() - 1];
_pausedContexts.pop_back();
std::thread([](asIScriptContext* ctx) { ctx->Execute(); }, ctx).detach();
}
}
bool HasDebuggerAttached() const {
for (const auto& c : _connections) {
if (c->is_open()) {
return true;
}
}
return false;
}
size_t StoreVariable(void* address, int typeId, const std::optional<std::function<void(void* address)>>& release) {
_storedVariableReferences.emplace_back(std::make_unique<PointerVariable>(address, typeId, release));
return _storedVariableReferences.size();
}
private:
static void on_line_callback(asIScriptContext* ctx, AngelscriptDebugger* dbg);
static void on_exception_callback(asIScriptContext* ctx, AngelscriptDebugger* d);
void EnterBreakpoint(asIScriptContext* ctx, const std::string& section, size_t line);
[[noreturn]] void AcceptLoop();
void ClientLoop(asio::ip::tcp::socket&);
void Send(DebugAdapterProtocol::ProtocolMessage* msg);
void Send(asio::ip::tcp::socket* client, DebugAdapterProtocol::ProtocolMessage* msg);
void OnMessage(asio::ip::tcp::socket* client, DebugAdapterProtocol::ProtocolMessage* msg);
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<asio::ip::tcp::socket*> _connections;
std::unordered_map<std::string, std::unordered_set<size_t>> _breakpoints;
std::vector<asIScriptContext*> _pausedContexts;
std::optional<std::string> _scriptPath;
asIScriptContext* _nextContext;
bool _next;
size_t _nextDepth;
bool _stepInto;
bool _stepOut;
struct StackScope {
size_t StackLevel;
uint8_t Type;
StackScope(size_t stackLevel, uint8_t type) : StackLevel(stackLevel), Type(type) {}
};
struct PointerVariable {
void* Address;
int TypeID;
std::optional<std::function<void(void*)>> Release;
PointerVariable(void* address, int typeId, std::optional<std::function<void(void*)>> release)
: Address(address), TypeID(typeId), Release(release) {}
~PointerVariable() {
if (Release.has_value()) {
Release.value()(Address);
}
}
};
std::vector<std::variant<std::unique_ptr<StackScope>, std::unique_ptr<PointerVariable>>> _storedVariableReferences;
};
#endif // ANGELSCRIPTDEBUGGER_ANGELSCRIPTDEBUGGER_HPP