/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 |