From 30f90caf1ca3b412221cccca05e7cf3b8910982c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Lasersk=C3=B6ld?= Date: Fri, 3 Nov 2023 11:32:02 +0100 Subject: [PATCH] Visualize current paused position with debugger --- src/plugin/gdbdebugger.cpp | 73 +++++++++++++++++++++++++++----------- src/plugin/gdbdebugger.h | 5 ++- src/plugin/idebugger.h | 6 ++-- src/plugin/rundebug.cpp | 43 +++++++++++++++++++--- 4 files changed, 98 insertions(+), 29 deletions(-) diff --git a/src/plugin/gdbdebugger.cpp b/src/plugin/gdbdebugger.cpp index c671e1e..0b36ace 100644 --- a/src/plugin/gdbdebugger.cpp +++ b/src/plugin/gdbdebugger.cpp @@ -92,6 +92,8 @@ void GdbDebugger::run() { return; } + updateBreakpointInfo(); + _connection.send("run &"); } @@ -120,11 +122,6 @@ void GdbDebugger::stepOut() { _connection.send("finish &"); } -void GdbDebugger::toggleBreakpoint(SourceLocation loc) { - // TODO: Handle unsetting - setBreakpoint(loc); -} - void GdbDebugger::stateCallback(std::function f) { _callback = f; } @@ -134,11 +131,19 @@ void GdbDebugger::breakpointListCallback( _breakpointListCallback = f; } -void GdbDebugger::setBreakpoint(SourceLocation loc) { - _connection.send("b " + loc.path.string() + ":" + - std::to_string(loc.position.y() + 1)); - waitForDone(); - _breakpointInfos.clear(); +void GdbDebugger::toggleBreakpoint(SourceLocation loc) { + if (deleteBreakpoint(loc)) { + return; + } + setBreakpoint(loc); +} + +void GdbDebugger::updateBreakpointInfo() { + // We cannot simply clear the list since we need to send a message to those + // who need to remove breakpoints + for (auto &it : _breakpointInfos) { + it.second.clear(); + } _connection.send("info b"); // Request information about all set breakpoints // New breakpoint infos will be added in the input thread waitForDone(); @@ -148,7 +153,41 @@ void GdbDebugger::setBreakpoint(SourceLocation loc) { } } -void GdbDebugger::deleteBreakpoint(SourceLocation loc) {} +void GdbDebugger::setBreakpoint(SourceLocation loc) { + _connection.send("b " + loc.path.string() + ":" + + std::to_string(loc.position.y() + 1)); + waitForDone(); + updateBreakpointInfo(); +} + +bool GdbDebugger::deleteBreakpoint(SourceLocation loc) { + auto didFind = false; + for (auto &file : _breakpointInfos) { + auto ec = std::error_code{}; + if (!std::filesystem::equivalent(file.first, loc.path, ec)) { + continue; + } + for (size_t i = 0; i < file.second.size();) { + auto &info = file.second.at(i); + if (loc.position.y() == info.lineNumber) { + _connection.send("delete breakpoint " + + std::to_string(info.breakpointNumber)); + waitForDone(); + file.second.erase(file.second.begin() + i); + didFind = true; + } + else { + ++i; + } + } + break; // Only do one file + } + + if (didFind) { + updateBreakpointInfo(); + } + return didFind; +} GdbDebugger::WaitResult GdbDebugger::waitForDone() { _isWaiting = true; @@ -165,7 +204,6 @@ void GdbDebugger::changeState(DebuggerState state) { } void GdbDebugger::inputThread(std::istream &in) { - std::smatch matches; for (std::string line; std::getline(in, line);) { @@ -201,14 +239,14 @@ void GdbDebugger::inputThread(std::istream &in) { if (line.starts_with("~")) { static const auto re = std::regex{ - R"(~"(\d+)\s+breakpoint\s+.* in ([^\s]+) at ([^\s]+):(\d+))"}; + R"(~"(\d+)\s+breakpoint\s+.* in (.+) at (.+):(\d+))"}; auto match = std::smatch{}; if (std::regex_search(line, match, re)) { auto file = match[3].str(); _breakpointInfos[file].push_back({ - .breakpointNumber = match[1].str(), + .breakpointNumber = std::stoi(match[1].str()), .functionSignature = match[2].str(), .filePath = match[3].str(), .lineNumber = std::stoul(match[4].str()) - 1, @@ -225,15 +263,8 @@ void GdbDebugger::inputThread(std::istream &in) { static const auto stopExpression = std::regex( R"_(stopped,reason="([^"]+)",.*?addr="([^"]+)",.*?func="([^"]+)",.*?file="([^"]+)",.*?fullname="([^"]+)",.*?line="([^"]+)")_"); if (std::regex_search(line, matches, stopExpression)) { - // std::cout << "Reason: " << matches[1].str() << - // std::endl; std::cout << "Address: " << - // matches[2].str() << std::endl; std::cout << "Function: - // " << matches[3].str() << std::endl; std::cout << - // "File: " << matches[4].str() << std::endl; auto fullName = matches[5].str(); - // std::cout << "Fullname: " << fullName << std::endl; auto line = matches[6].str(); - // std::cout << "Line: " << line << std::endl; auto state = DebuggerState{}; state.location.position = {0, std::stoul(line) - 1}; diff --git a/src/plugin/gdbdebugger.h b/src/plugin/gdbdebugger.h index 5200e6a..d5a7301 100644 --- a/src/plugin/gdbdebugger.h +++ b/src/plugin/gdbdebugger.h @@ -49,7 +49,7 @@ class GdbDebugger : public IDebugger { void toggleBreakpoint(SourceLocation) override; void setBreakpoint(SourceLocation) override; - void deleteBreakpoint(SourceLocation) override; + bool deleteBreakpoint(SourceLocation) override; private: enum WaitResult { @@ -67,6 +67,9 @@ class GdbDebugger : public IDebugger { std::function _gdbStatusCallback; std::function _breakpointListCallback; + /// Query list of breakpoints from gdb + void updateBreakpointInfo(); + void inputThread(std::istream &in); lsp::Connection _connection; diff --git a/src/plugin/idebugger.h b/src/plugin/idebugger.h index 2634c7b..71e5436 100644 --- a/src/plugin/idebugger.h +++ b/src/plugin/idebugger.h @@ -35,7 +35,7 @@ struct DebuggerState { }; struct BreakpointInfo { - std::string breakpointNumber; + int breakpointNumber; std::string functionSignature; std::string filePath; size_t lineNumber; // medit line number, starting with 0 @@ -84,7 +84,9 @@ class IDebugger { virtual void toggleBreakpoint(SourceLocation) = 0; virtual void setBreakpoint(SourceLocation) = 0; - virtual void deleteBreakpoint(SourceLocation) = 0; + + /// Try to remove a breakpoint. Return true if successfull + virtual bool deleteBreakpoint(SourceLocation) = 0; // Watchpoints // Conditions diff --git a/src/plugin/rundebug.cpp b/src/plugin/rundebug.cpp index 573d579c..ff1e1e1 100644 --- a/src/plugin/rundebug.cpp +++ b/src/plugin/rundebug.cpp @@ -8,9 +8,17 @@ #include "text/fstring.h" #include "views/editor.h" #include "views/mainwindow.h" +#include #include #include +namespace { + +// Used to remove cursor when program exits +std::filesystem::path lastRunningPosition = {}; + +} // namespace + void debug(std::shared_ptr env) { auto debugger = env->core().debugger(); @@ -42,6 +50,8 @@ void debug(std::shared_ptr env) { }); }; + static constexpr auto runningDebuggerName = "running-debugger-name"; + auto stateCallback = [wenv = env->weak_from_this()](DebuggerState state) { auto env = wenv.lock(); if (state.state == DebuggerState::Running) { @@ -49,11 +59,34 @@ void debug(std::shared_ptr env) { env->statusMessage(FString{"running application"}); } - /// Todo create some indicator + if (!lastRunningPosition.empty()) { + env->context().guiQueue().addTask([env] { + env->core().files().publishDiagnostics( + lastRunningPosition, runningDebuggerName, {}); + }); + } + + if (state.state == DebuggerState::Stopped) { + return; + env->statusMessage(FString{"running application"}); + } + env->context().guiQueue().addTask([state, env] { env->mainWindow().open(state.location.path, state.location.position.x(), state.location.position.y()); + + auto d = std::vector{}; + d.push_back(Diagnostics::Diagnostic{ + .type = DiagnosticType::RunningPosition, + .source = runningDebuggerName, + .message = "Paused position", + .range = {.begin = state.location.position, + .end = state.location.position}, + }); + env->core().files().publishDiagnostics( + state.location.path, runningDebuggerName, std::move(d)); + lastRunningPosition = state.location.path; }); }; @@ -63,21 +96,21 @@ void debug(std::shared_ptr env) { /// Todo create some indicator env->context().guiQueue().addTask([infos = std::move(infos), env] { for (auto &it : infos) { + constexpr auto diagnosticName = "debugger"; auto d = std::vector{}; for (auto &info : it.second) { d.push_back({ .type = DiagnosticType::Breakpoint, - .source = "debugger", - .message = "breakpoint line " + - std::to_string(info.lineNumber + 1), + .source = diagnosticName, + .message = "breakpoint ", .range = {.begin = {0, info.lineNumber}, .end = {1, info.lineNumber}}, }); } env->core().files().publishDiagnostics( - it.first, "gdb", std::move(d)); + it.first, diagnosticName, std::move(d)); } }); };