123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmDebuggerBreakpointManager.h"
- #include <algorithm>
- #include <cstddef>
- #include <cstdint>
- #include <utility>
- #include <cm3p/cppdap/optional.h>
- #include <cm3p/cppdap/session.h>
- #include <cm3p/cppdap/types.h>
- #include "cmDebuggerSourceBreakpoint.h"
- #include "cmListFileCache.h"
- #include "cmSystemTools.h"
- namespace cmDebugger {
- cmDebuggerBreakpointManager::cmDebuggerBreakpointManager(
- dap::Session* dapSession)
- : DapSession(dapSession)
- {
- // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_SetBreakpoints
- DapSession->registerHandler([&](const dap::SetBreakpointsRequest& request) {
- return HandleSetBreakpointsRequest(request);
- });
- }
- int64_t cmDebuggerBreakpointManager::FindFunctionStartLine(
- std::string const& sourcePath, int64_t line)
- {
- auto location =
- find_if(ListFileFunctionLines[sourcePath].begin(),
- ListFileFunctionLines[sourcePath].end(),
- [=](cmDebuggerFunctionLocation const& loc) {
- return loc.StartLine <= line && loc.EndLine >= line;
- });
- if (location != ListFileFunctionLines[sourcePath].end()) {
- return location->StartLine;
- }
- return 0;
- }
- int64_t cmDebuggerBreakpointManager::CalibrateBreakpointLine(
- std::string const& sourcePath, int64_t line)
- {
- auto location = find_if(ListFileFunctionLines[sourcePath].begin(),
- ListFileFunctionLines[sourcePath].end(),
- [=](cmDebuggerFunctionLocation const& loc) {
- return loc.StartLine >= line;
- });
- if (location != ListFileFunctionLines[sourcePath].end()) {
- return location->StartLine;
- }
- if (!ListFileFunctionLines[sourcePath].empty() &&
- ListFileFunctionLines[sourcePath].back().EndLine <= line) {
- // return last function start line for any breakpoints after.
- return ListFileFunctionLines[sourcePath].back().StartLine;
- }
- return 0;
- }
- dap::SetBreakpointsResponse
- cmDebuggerBreakpointManager::HandleSetBreakpointsRequest(
- dap::SetBreakpointsRequest const& request)
- {
- std::unique_lock<std::mutex> lock(Mutex);
- dap::SetBreakpointsResponse response;
- auto sourcePath =
- cmSystemTools::GetActualCaseForPath(request.source.path.value());
- const dap::array<dap::SourceBreakpoint> defaultValue{};
- const auto& breakpoints = request.breakpoints.value(defaultValue);
- if (Breakpoints.find(sourcePath) != Breakpoints.end()) {
- Breakpoints[sourcePath].clear();
- }
- response.breakpoints.resize(breakpoints.size());
- if (ListFileFunctionLines.find(sourcePath) != ListFileFunctionLines.end()) {
- // The file has loaded, we can validate breakpoints.
- for (size_t i = 0; i < breakpoints.size(); i++) {
- int64_t correctedLine =
- CalibrateBreakpointLine(sourcePath, breakpoints[i].line);
- if (correctedLine > 0) {
- Breakpoints[sourcePath].emplace_back(NextBreakpointId++,
- correctedLine);
- response.breakpoints[i].id = Breakpoints[sourcePath].back().GetId();
- response.breakpoints[i].line =
- Breakpoints[sourcePath].back().GetLine();
- response.breakpoints[i].verified = true;
- } else {
- response.breakpoints[i].verified = false;
- response.breakpoints[i].line = breakpoints[i].line;
- }
- dap::Source dapSrc;
- dapSrc.path = sourcePath;
- response.breakpoints[i].source = dapSrc;
- }
- } else {
- // The file has not loaded, validate breakpoints later.
- ListFilePendingValidations.emplace(sourcePath);
- for (size_t i = 0; i < breakpoints.size(); i++) {
- Breakpoints[sourcePath].emplace_back(NextBreakpointId++,
- breakpoints[i].line);
- response.breakpoints[i].id = Breakpoints[sourcePath].back().GetId();
- response.breakpoints[i].line = Breakpoints[sourcePath].back().GetLine();
- response.breakpoints[i].verified = false;
- dap::Source dapSrc;
- dapSrc.path = sourcePath;
- response.breakpoints[i].source = dapSrc;
- }
- }
- return response;
- }
- void cmDebuggerBreakpointManager::SourceFileLoaded(
- std::string const& sourcePath,
- std::vector<cmListFileFunction> const& functions)
- {
- std::unique_lock<std::mutex> lock(Mutex);
- if (ListFileFunctionLines.find(sourcePath) != ListFileFunctionLines.end()) {
- // this is not expected.
- return;
- }
- for (cmListFileFunction const& func : functions) {
- ListFileFunctionLines[sourcePath].emplace_back(
- cmDebuggerFunctionLocation{ func.Line(), func.LineEnd() });
- }
- if (ListFilePendingValidations.find(sourcePath) ==
- ListFilePendingValidations.end()) {
- return;
- }
- ListFilePendingValidations.erase(sourcePath);
- for (size_t i = 0; i < Breakpoints[sourcePath].size(); i++) {
- dap::BreakpointEvent breakpointEvent;
- breakpointEvent.breakpoint.id = Breakpoints[sourcePath][i].GetId();
- breakpointEvent.breakpoint.line = Breakpoints[sourcePath][i].GetLine();
- auto source = dap::Source();
- source.path = sourcePath;
- breakpointEvent.breakpoint.source = source;
- int64_t correctedLine = CalibrateBreakpointLine(
- sourcePath, Breakpoints[sourcePath][i].GetLine());
- if (correctedLine != Breakpoints[sourcePath][i].GetLine()) {
- Breakpoints[sourcePath][i].ChangeLine(correctedLine);
- }
- breakpointEvent.reason = "changed";
- breakpointEvent.breakpoint.verified = (correctedLine > 0);
- if (breakpointEvent.breakpoint.verified) {
- breakpointEvent.breakpoint.line = correctedLine;
- } else {
- Breakpoints[sourcePath][i].Invalid();
- }
- DapSession->send(breakpointEvent);
- }
- }
- std::vector<int64_t> cmDebuggerBreakpointManager::GetBreakpoints(
- std::string const& sourcePath, int64_t line)
- {
- std::unique_lock<std::mutex> lock(Mutex);
- const auto& all = Breakpoints[sourcePath];
- std::vector<int64_t> breakpoints;
- if (all.empty()) {
- return breakpoints;
- }
- auto it = all.begin();
- while ((it = std::find_if(
- it, all.end(), [&](const cmDebuggerSourceBreakpoint& breakpoint) {
- return (breakpoint.GetIsValid() && breakpoint.GetLine() == line);
- })) != all.end()) {
- breakpoints.emplace_back(it->GetId());
- ++it;
- }
- return breakpoints;
- }
- size_t cmDebuggerBreakpointManager::GetBreakpointCount() const
- {
- size_t count = 0;
- for (auto const& pair : Breakpoints) {
- count += pair.second.size();
- }
- return count;
- }
- void cmDebuggerBreakpointManager::ClearAll()
- {
- std::unique_lock<std::mutex> lock(Mutex);
- Breakpoints.clear();
- }
- } // namespace cmDebugger
|