Skip to content

Commit

Permalink
refactor PapryusDebugger to persist across sessions
Browse files Browse the repository at this point in the history
This way we don't have to repopulate the PEX cache between sessions
  • Loading branch information
nikitalita committed Feb 12, 2023
1 parent 7c16d64 commit 487bd1c
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 65 deletions.
10 changes: 6 additions & 4 deletions src/DarkId.Papyrus.DebugServer/BreakpointManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ namespace DarkId::Papyrus::DebugServer

if (binary)
{
for (auto functionInfo : binary->getDebugInfo().getFunctionInfos())
for (auto & functionInfo : binary->getDebugInfo().getFunctionInfos())
{
if (foundLine)
{
Expand Down Expand Up @@ -71,10 +71,12 @@ namespace DarkId::Papyrus::DebugServer
m_breakpoints[sourceReference] = breakpointLines;
return response;
}

void BreakpointManager::ClearBreakpoints() {
m_breakpoints.clear();
}
bool BreakpointManager::GetExecutionIsAtValidBreakpoint(RE::BSScript::Internal::CodeTasklet* tasklet)
{
auto func = tasklet->topFrame->owningFunction;
auto & func = tasklet->topFrame->owningFunction;

if (func->GetIsNative())
{
Expand All @@ -85,7 +87,7 @@ namespace DarkId::Papyrus::DebugServer

if (m_breakpoints.find(sourceReference) != m_breakpoints.end())
{
auto breakpointLines = m_breakpoints[sourceReference];
auto & breakpointLines = m_breakpoints[sourceReference];
if (!breakpointLines.empty())
{
uint32_t currentLine;
Expand Down
1 change: 1 addition & 0 deletions src/DarkId.Papyrus.DebugServer/BreakpointManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace DarkId::Papyrus::DebugServer
}

dap::ResponseOrError<dap::SetBreakpointsResponse> SetBreakpoints(dap::Source& source, const std::vector<dap::SourceBreakpoint>& srcBreakpoints);
void ClearBreakpoints();
bool GetExecutionIsAtValidBreakpoint(RE::BSScript::Internal::CodeTasklet* tasklet);
};
}
70 changes: 41 additions & 29 deletions src/DarkId.Papyrus.DebugServer/DebugExecutionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,25 @@ namespace DarkId::Papyrus::DebugServer
return;
}

const auto func = tasklet->topFrame->owningFunction;
auto shouldSendPause = false;
dap::StoppedEvent event;

const auto & func = tasklet->topFrame->owningFunction;
bool shouldContinue = false;
bool shouldSendEvent = false;
std::string pauseReason = "";
DebuggerState new_state = m_state;

if (m_state == DebuggerState::kPaused)
{
shouldSendPause = true;
pauseReason = "paused";
}

if (m_state != DebuggerState::kPaused && m_breakpointManager->GetExecutionIsAtValidBreakpoint(tasklet))
else if (m_state != DebuggerState::kPaused && m_breakpointManager->GetExecutionIsAtValidBreakpoint(tasklet))
{
m_state = DebuggerState::kPaused;
event.reason = "breakpoint";
event.threadId = tasklet->stack->stackID;
m_session->send(event);
pauseReason = "breakpoint";
}

if (m_state == DebuggerState::kStepping && !RuntimeState::GetStack(m_currentStepStackId))
else if (m_state == DebuggerState::kStepping && !RuntimeState::GetStack(m_currentStepStackId))
{
m_session->send(dap::ContinuedEvent());
m_currentStepStackId = 0;
m_currentStepStackFrame = nullptr;

m_state = DebuggerState::kRunning;
shouldContinue = true;
}

if (m_state == DebuggerState::kStepping && tasklet->stack->stackID == m_currentStepStackId)
else if (m_state == DebuggerState::kStepping && tasklet->stack->stackID == m_currentStepStackId)
{
if (m_currentStepStackFrame)
{
Expand All @@ -60,36 +52,48 @@ namespace DarkId::Papyrus::DebugServer
switch (m_currentStepType)
{
case StepType::STEP_IN:
shouldSendPause = true;
event.reason = "step";
pauseReason = "step";
break;
case StepType::STEP_OUT:
// If the stack exists, but the original frame is gone, we know we're in a previous frame now.
if (stepFrameIndex == -1)
{
shouldSendPause = true;
event.reason = "step";
pauseReason = "step";
}
break;
case StepType::STEP_OVER:
if (stepFrameIndex <= 0)
{
shouldSendPause = true;
event.reason = "step";
pauseReason = "step";
}
break;
}
}
}
}

if (shouldSendPause)
if (!pauseReason.empty())
{
m_state = DebuggerState::kPaused;
m_currentStepStackId = 0;
m_currentStepStackFrame = nullptr;
event.threadId = tasklet->stack->stackID;
m_session->send(event);
if (m_session) {
m_session->send(dap::StoppedEvent{
.reason = pauseReason,
.threadId = tasklet->stack->stackID
});
}
}
else if (shouldContinue) {
m_state = DebuggerState::kRunning;
m_currentStepStackId = 0;
m_currentStepStackFrame = nullptr;
if (m_session) {
m_session->send(dap::ContinuedEvent{
.allThreadsContinued = true,
.threadId = tasklet->stack->stackID
});
}
}

while (m_state == DebuggerState::kPaused && !m_closed)
Expand All @@ -100,10 +104,18 @@ namespace DarkId::Papyrus::DebugServer

}

void DebugExecutionManager::Open(std::shared_ptr<dap::Session> ses)
{
m_closed = false;
m_session = ses;
std::lock_guard<std::mutex> lock(m_instructionMutex);
}

void DebugExecutionManager::Close()
{
m_closed = true;
std::lock_guard<std::mutex> lock(m_instructionMutex);
m_session = nullptr;
}

bool DebugExecutionManager::Continue()
Expand Down
9 changes: 5 additions & 4 deletions src/DarkId.Papyrus.DebugServer/DebugExecutionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace DarkId::Papyrus::DebugServer
};

std::mutex m_instructionMutex;
bool m_closed = false;
bool m_closed;

std::shared_ptr<dap::Session> m_session;
RuntimeState* m_runtimeState;
Expand All @@ -40,15 +40,16 @@ namespace DarkId::Papyrus::DebugServer
StepType m_currentStepType = StepType::STEP_IN;
RE::BSScript::StackFrame* m_currentStepStackFrame;
public:
explicit DebugExecutionManager(std::shared_ptr<dap::Session> session, RuntimeState* runtimeState,
explicit DebugExecutionManager(RuntimeState* runtimeState,
BreakpointManager* breakpointManager)
: m_session(session), m_runtimeState(runtimeState), m_breakpointManager(breakpointManager),
m_currentStepStackFrame(nullptr)
: m_runtimeState(runtimeState), m_breakpointManager(breakpointManager),
m_currentStepStackFrame(nullptr), m_closed(true)
{
}

void Close();
void HandleInstruction(CodeTasklet* tasklet, CodeTasklet::OpCode opCode);
void Open(std::shared_ptr<dap::Session> ses);
bool Continue();
bool Pause();
bool Step(uint32_t stackId, StepType stepType);
Expand Down
7 changes: 5 additions & 2 deletions src/DarkId.Papyrus.DebugServer/DebugServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
namespace DarkId::Papyrus::DebugServer
{
DebugServer::DebugServer() {
terminate = false;
restart_thread = std::thread(std::bind(&DebugServer::runRestartThread, this));
debugger = std::unique_ptr<PapyrusDebugger>(new PapyrusDebugger());
}

void DebugServer::runRestartThread() {
while (true){
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [&] { return terminate; });
terminate = false;
debugger = nullptr;
debugger->EndSession();
}
}

Expand All @@ -29,12 +31,13 @@ namespace DarkId::Papyrus::DebugServer
std::shared_ptr<dap::Session> sess;
sess = dap::Session::create();
sess->bind(connection);
debugger = std::unique_ptr<PapyrusDebugger>( new PapyrusDebugger(sess) );
// After we send the disconnect response, stop the session
sess->registerSentHandler(
[&](const dap::ResponseOrError<dap::DisconnectResponse>&) {
terminate = true;
cv.notify_all();
});
debugger->StartSession(sess);
};

auto onError = [&](const char* msg) {
Expand Down
90 changes: 67 additions & 23 deletions src/DarkId.Papyrus.DebugServer/PapyrusDebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ namespace RE{

namespace DarkId::Papyrus::DebugServer
{
PapyrusDebugger::PapyrusDebugger(const std::shared_ptr<dap::Session>& session):
m_session(session)
PapyrusDebugger::PapyrusDebugger()
{
m_pexCache = std::make_shared<PexCache>();

Expand All @@ -38,8 +37,14 @@ namespace DarkId::Papyrus::DebugServer
m_idProvider = std::make_shared<IdProvider>();
m_runtimeState = std::make_shared<RuntimeState>(m_idProvider);

m_executionManager = std::make_shared<DebugExecutionManager>(m_session, m_runtimeState.get(), m_breakpointManager.get());
m_executionManager = std::make_shared<DebugExecutionManager>(m_runtimeState.get(), m_breakpointManager.get());

}

void PapyrusDebugger::StartSession(std::shared_ptr<dap::Session> session) {
m_closed = false;
m_session = session;
m_executionManager->Open(session);
m_createStackEventHandle =
RuntimeEvents::SubscribeToCreateStack(std::bind(&PapyrusDebugger::StackCreated, this, std::placeholders::_1));

Expand All @@ -54,6 +59,20 @@ namespace DarkId::Papyrus::DebugServer
m_logEventHandle =
RuntimeEvents::SubscribeToLog(std::bind(&PapyrusDebugger::EventLogged, this, std::placeholders::_1));
RegisterSessionHandlers();
}
void PapyrusDebugger::EndSession() {
m_executionManager->Close();
m_session = nullptr;
m_closed = true;

m_breakpointManager->ClearBreakpoints();
RuntimeEvents::UnsubscribeFromLog(m_logEventHandle);
// RuntimeEvents::UnsubscribeFromInitScript(m_initScriptEventHandle);
RuntimeEvents::UnsubscribeFromInstructionExecution(m_instructionExecutionEventHandle);
RuntimeEvents::UnsubscribeFromCreateStack(m_createStackEventHandle);
RuntimeEvents::UnsubscribeFromCleanupStack(m_cleanupStackEventHandle);

m_executionManager->Close();

}

Expand All @@ -70,7 +89,7 @@ namespace DarkId::Papyrus::DebugServer
//sess->onError()
m_session->registerSentHandler(
[&](const dap::ResponseOrError<dap::InitializeResponse>&) {
m_session->send(dap::InitializedEvent());
SendEvent(dap::InitializedEvent());
});

// Client is done configuring.
Expand Down Expand Up @@ -132,6 +151,13 @@ namespace DarkId::Papyrus::DebugServer
return GetLoadedSources(request);
});
}

template <typename T, typename>
void PapyrusDebugger::SendEvent(const T& event) const{
if (m_session)
m_session->send(event);
}

std::string LogSeverityEnumStr(RE::BSScript::ErrorLogger::Severity severity) {
if (severity == RE::BSScript::ErrorLogger::Severity::kInfo) {
return std::string("INFO");
Expand All @@ -145,9 +171,25 @@ namespace DarkId::Papyrus::DebugServer
return std::string("UNKNOWN_ENUM_LEVEL");
}

// EVENTS
void PapyrusDebugger::LogGameOutput(RE::BSScript::ErrorLogger::Severity severity, const std::string &msg) const {
constexpr const char* format = "GAME EVENT -- {}";
if (severity == RE::BSScript::ErrorLogger::Severity::kInfo) {
logger::info(format, msg);
}
else if (severity == RE::BSScript::ErrorLogger::Severity::kWarning) {
logger::warn(format, msg);
}
else if (severity == RE::BSScript::ErrorLogger::Severity::kError) {
logger::error(format, msg);
}
else if (severity == RE::BSScript::ErrorLogger::Severity::kFatal) {
logger::critical(format, msg);
}
}

void PapyrusDebugger::EventLogged(const RE::BSScript::LogEvent* logEvent) const
{
const std::string severity = LogSeverityEnumStr(logEvent->severity);
dap::OutputEvent output;
output.category = "console";
#if SKYRIM
Expand All @@ -157,10 +199,10 @@ namespace DarkId::Papyrus::DebugServer
logEvent->errorMsg.GetErrorMsg(message);
output.output = std::format("{} - {}\r\n", logEvent->ownerModule.c_str(), message.c_str());
#endif
m_session->send(output);
LogGameOutput(logEvent->severity, output.output);
SendEvent(output);
}


void PapyrusDebugger::StackCreated(RE::BSTSmartPointer<RE::BSScript::Stack>& stack)
{
const auto stackId = stack->stackID;
Expand All @@ -177,10 +219,11 @@ namespace DarkId::Papyrus::DebugServer
{
return;
}
dap::ThreadEvent threadEvent;
threadEvent.reason = "started";
threadEvent.threadId = stackId;
m_session->send(threadEvent);

SendEvent(dap::ThreadEvent{
.reason = "started",
.threadId = stackId
});

if (stack->top && stack->top->owningFunction)
{
Expand All @@ -196,15 +239,12 @@ namespace DarkId::Papyrus::DebugServer
{
XSE::GetTaskInterface()->AddTask([this, stackId]()
{
if (m_closed)
{
return;
}
dap::ThreadEvent threadEvent;
threadEvent.reason = "exited";
threadEvent.threadId = stackId;
if (m_closed) return;

m_session->send(threadEvent);
SendEvent(dap::ThreadEvent{
.reason = "exited",
.threadId = stackId
});
});
}

Expand All @@ -222,10 +262,10 @@ namespace DarkId::Papyrus::DebugServer
{
return;
}
dap::LoadedSourceEvent event;
event.reason = "new";
event.source = source;
m_session->send(event);
SendEvent(dap::LoadedSourceEvent{
.reason = "new",
.source = source
});
}
}

Expand All @@ -242,6 +282,10 @@ namespace DarkId::Papyrus::DebugServer

m_executionManager->Close();
}
dap::ResponseOrError<dap::InitializeResponse> PapyrusDebugger::Initialize(const dap::InitializeRequest& request)
{
return dap::ResponseOrError<dap::InitializeResponse>();
}
dap::ResponseOrError<dap::AttachResponse> PapyrusDebugger::Attach(const dap::PDSAttachRequest& request)
{
m_projectPath = request.projectPath.value("");
Expand Down
Loading

0 comments on commit 487bd1c

Please sign in to comment.