Coverage Report

Created: 2026-02-09 06:05

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::AUTHOR_WARNING] =
33
0
    cmDebuggerExceptionFilter{ "AUTHOR_WARNING", "Warning (dev)" };
34
0
  ExceptionMap[MessageType::AUTHOR_ERROR] =
35
0
    cmDebuggerExceptionFilter{ "AUTHOR_ERROR", "Error (dev)" };
36
0
  ExceptionMap[MessageType::FATAL_ERROR] =
37
0
    cmDebuggerExceptionFilter{ "FATAL_ERROR", "Fatal error" };
38
0
  ExceptionMap[MessageType::INTERNAL_ERROR] =
39
0
    cmDebuggerExceptionFilter{ "INTERNAL_ERROR", "Internal error" };
40
0
  ExceptionMap[MessageType::MESSAGE] =
41
0
    cmDebuggerExceptionFilter{ "MESSAGE", "Other messages" };
42
0
  ExceptionMap[MessageType::WARNING] =
43
0
    cmDebuggerExceptionFilter{ "WARNING", "Warning" };
44
0
  ExceptionMap[MessageType::LOG] =
45
0
    cmDebuggerExceptionFilter{ "LOG", "Debug log" };
46
0
  ExceptionMap[MessageType::DEPRECATION_ERROR] =
47
0
    cmDebuggerExceptionFilter{ "DEPRECATION_ERROR", "Deprecation error" };
48
0
  ExceptionMap[MessageType::DEPRECATION_WARNING] =
49
0
    cmDebuggerExceptionFilter{ "DEPRECATION_WARNING", "Deprecation warning" };
50
0
  RaiseExceptions["AUTHOR_ERROR"] = true;
51
0
  RaiseExceptions["FATAL_ERROR"] = true;
52
0
  RaiseExceptions["INTERNAL_ERROR"] = true;
53
0
  RaiseExceptions["DEPRECATION_ERROR"] = true;
54
0
}
55
56
dap::SetExceptionBreakpointsResponse
57
cmDebuggerExceptionManager::HandleSetExceptionBreakpointsRequest(
58
  dap::SetExceptionBreakpointsRequest const& request)
59
0
{
60
0
  std::unique_lock<std::mutex> lock(Mutex);
61
0
  dap::SetExceptionBreakpointsResponse response;
62
0
  RaiseExceptions.clear();
63
0
  for (auto const& filter : request.filters) {
64
0
    RaiseExceptions[filter] = true;
65
0
  }
66
67
0
  return response;
68
0
}
69
70
dap::ExceptionInfoResponse
71
cmDebuggerExceptionManager::HandleExceptionInfoRequest()
72
0
{
73
0
  std::unique_lock<std::mutex> lock(Mutex);
74
75
0
  dap::ExceptionInfoResponse response;
76
0
  if (TheException.has_value()) {
77
0
    response.exceptionId = TheException->Id;
78
0
    response.breakMode = "always";
79
0
    response.description = TheException->Description;
80
0
    TheException = cm::nullopt;
81
0
  }
82
0
  return response;
83
0
}
84
85
void cmDebuggerExceptionManager::HandleInitializeRequest(
86
  dap::CMakeInitializeResponse& response)
87
0
{
88
0
  std::unique_lock<std::mutex> lock(Mutex);
89
0
  response.supportsExceptionInfoRequest = true;
90
91
0
  dap::array<dap::ExceptionBreakpointsFilter> exceptionBreakpointFilters;
92
0
  for (auto& pair : ExceptionMap) {
93
0
    dap::ExceptionBreakpointsFilter filter;
94
0
    filter.filter = pair.second.Filter;
95
0
    filter.label = pair.second.Label;
96
0
    filter.def = RaiseExceptions[filter.filter];
97
0
    exceptionBreakpointFilters.emplace_back(filter);
98
0
  }
99
100
0
  response.exceptionBreakpointFilters = exceptionBreakpointFilters;
101
0
}
102
103
cm::optional<dap::StoppedEvent>
104
cmDebuggerExceptionManager::RaiseExceptionIfAny(MessageType t,
105
                                                std::string const& text)
106
0
{
107
0
  cm::optional<dap::StoppedEvent> maybeStoppedEvent;
108
0
  std::unique_lock<std::mutex> lock(Mutex);
109
0
  if (RaiseExceptions[ExceptionMap[t].Filter]) {
110
0
    dap::StoppedEvent stoppedEvent;
111
0
    stoppedEvent.allThreadsStopped = true;
112
0
    stoppedEvent.reason = "exception";
113
0
    stoppedEvent.description = "Pause on exception";
114
0
    stoppedEvent.text = text;
115
0
    TheException = cmDebuggerException{ ExceptionMap[t].Filter, text };
116
0
    maybeStoppedEvent = std::move(stoppedEvent);
117
0
  }
118
119
0
  return maybeStoppedEvent;
120
0
}
121
122
void cmDebuggerExceptionManager::ClearAll()
123
0
{
124
0
  std::unique_lock<std::mutex> lock(Mutex);
125
0
  RaiseExceptions.clear();
126
0
}
127
128
} // namespace cmDebugger