Coverage Report

Created: 2026-04-29 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmDebuggerExceptionManager.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#include "cmDebuggerExceptionManager.h"
4
5
#include <utility>
6
#include <vector>
7
8
#include <cm3p/cppdap/optional.h>
9
#include <cm3p/cppdap/session.h>
10
#include <cm3p/cppdap/types.h>
11
12
#include "cmDebuggerProtocol.h"
13
#include "cmMessageType.h"
14
15
namespace cmDebugger {
16
17
cmDebuggerExceptionManager::cmDebuggerExceptionManager(
18
  dap::Session* dapSession)
19
0
  : DapSession(dapSession)
20
0
{
21
  // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_SetExceptionBreakpoints
22
0
  DapSession->registerHandler(
23
0
    [&](dap::SetExceptionBreakpointsRequest const& request) {
24
0
      return HandleSetExceptionBreakpointsRequest(request);
25
0
    });
26
27
  // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_ExceptionInfo
28
0
  DapSession->registerHandler([&](dap::ExceptionInfoRequest /*unused*/) {
29
0
    return HandleExceptionInfoRequest();
30
0
  });
31
32
0
  ExceptionMap[MessageType::FATAL_ERROR] =
33
0
    cmDebuggerExceptionFilter{ "FATAL_ERROR", "Fatal error" };
34
0
  ExceptionMap[MessageType::INTERNAL_ERROR] =
35
0
    cmDebuggerExceptionFilter{ "INTERNAL_ERROR", "Internal error" };
36
0
  ExceptionMap[MessageType::MESSAGE] =
37
0
    cmDebuggerExceptionFilter{ "MESSAGE", "Other messages" };
38
0
  ExceptionMap[MessageType::WARNING] =
39
0
    cmDebuggerExceptionFilter{ "WARNING", "Warning" };
40
0
  ExceptionMap[MessageType::LOG] =
41
0
    cmDebuggerExceptionFilter{ "LOG", "Debug log" };
42
0
  RaiseExceptions["FATAL_ERROR"] = true;
43
0
  RaiseExceptions["INTERNAL_ERROR"] = true;
44
0
}
45
46
dap::SetExceptionBreakpointsResponse
47
cmDebuggerExceptionManager::HandleSetExceptionBreakpointsRequest(
48
  dap::SetExceptionBreakpointsRequest const& request)
49
0
{
50
0
  std::unique_lock<std::mutex> lock(Mutex);
51
0
  dap::SetExceptionBreakpointsResponse response;
52
0
  RaiseExceptions.clear();
53
0
  for (auto const& filter : request.filters) {
54
0
    RaiseExceptions[filter] = true;
55
0
  }
56
57
0
  return response;
58
0
}
59
60
dap::ExceptionInfoResponse
61
cmDebuggerExceptionManager::HandleExceptionInfoRequest()
62
0
{
63
0
  std::unique_lock<std::mutex> lock(Mutex);
64
65
0
  dap::ExceptionInfoResponse response;
66
0
  if (TheException.has_value()) {
67
0
    response.exceptionId = TheException->Id;
68
0
    response.breakMode = "always";
69
0
    response.description = TheException->Description;
70
0
    TheException = cm::nullopt;
71
0
  }
72
0
  return response;
73
0
}
74
75
void cmDebuggerExceptionManager::HandleInitializeRequest(
76
  dap::CMakeInitializeResponse& response)
77
0
{
78
0
  std::unique_lock<std::mutex> lock(Mutex);
79
0
  response.supportsExceptionInfoRequest = true;
80
81
0
  dap::array<dap::ExceptionBreakpointsFilter> exceptionBreakpointFilters;
82
0
  for (auto& pair : ExceptionMap) {
83
0
    dap::ExceptionBreakpointsFilter filter;
84
0
    filter.filter = pair.second.Filter;
85
0
    filter.label = pair.second.Label;
86
0
    filter.def = RaiseExceptions[filter.filter];
87
0
    exceptionBreakpointFilters.emplace_back(filter);
88
0
  }
89
90
0
  response.exceptionBreakpointFilters = exceptionBreakpointFilters;
91
0
}
92
93
cm::optional<dap::StoppedEvent>
94
cmDebuggerExceptionManager::RaiseExceptionIfAny(MessageType t,
95
                                                std::string const& text)
96
0
{
97
0
  cm::optional<dap::StoppedEvent> maybeStoppedEvent;
98
0
  std::unique_lock<std::mutex> lock(Mutex);
99
0
  if (RaiseExceptions[ExceptionMap[t].Filter]) {
100
0
    dap::StoppedEvent stoppedEvent;
101
0
    stoppedEvent.allThreadsStopped = true;
102
0
    stoppedEvent.reason = "exception";
103
0
    stoppedEvent.description = "Pause on exception";
104
0
    stoppedEvent.text = text;
105
0
    TheException = cmDebuggerException{ ExceptionMap[t].Filter, text };
106
0
    maybeStoppedEvent = std::move(stoppedEvent);
107
0
  }
108
109
0
  return maybeStoppedEvent;
110
0
}
111
112
void cmDebuggerExceptionManager::ClearAll()
113
0
{
114
0
  std::unique_lock<std::mutex> lock(Mutex);
115
0
  RaiseExceptions.clear();
116
0
}
117
118
} // namespace cmDebugger