|
7 | 7 | //===----------------------------------------------------------------------===// |
8 | 8 |
|
9 | 9 | #include "DAP.h" |
10 | | -#include "EventHelper.h" |
11 | | -#include "JSONUtils.h" |
| 10 | +#include "DAPError.h" |
| 11 | +#include "Protocol/ProtocolRequests.h" |
| 12 | +#include "Protocol/ProtocolTypes.h" |
12 | 13 | #include "RequestHandler.h" |
13 | 14 | #include "lldb/API/SBStream.h" |
14 | 15 |
|
| 16 | +using namespace lldb_dap::protocol; |
| 17 | + |
15 | 18 | namespace lldb_dap { |
16 | 19 |
|
17 | | -// "ExceptionInfoRequest": { |
18 | | -// "allOf": [ { "$ref": "#/definitions/Request" }, { |
19 | | -// "type": "object", |
20 | | -// "description": "Retrieves the details of the exception that |
21 | | -// caused this event to be raised. Clients should only call this request if |
22 | | -// the corresponding capability `supportsExceptionInfoRequest` is true.", |
23 | | -// "properties": { |
24 | | -// "command": { |
25 | | -// "type": "string", |
26 | | -// "enum": [ "exceptionInfo" ] |
27 | | -// }, |
28 | | -// "arguments": { |
29 | | -// "$ref": "#/definitions/ExceptionInfoArguments" |
30 | | -// } |
31 | | -// }, |
32 | | -// "required": [ "command", "arguments" ] |
33 | | -// }] |
34 | | -// }, |
35 | | -// "ExceptionInfoArguments": { |
36 | | -// "type": "object", |
37 | | -// "description": "Arguments for `exceptionInfo` request.", |
38 | | -// "properties": { |
39 | | -// "threadId": { |
40 | | -// "type": "integer", |
41 | | -// "description": "Thread for which exception information should be |
42 | | -// retrieved." |
43 | | -// } |
44 | | -// }, |
45 | | -// "required": [ "threadId" ] |
46 | | -// }, |
47 | | -// "ExceptionInfoResponse": { |
48 | | -// "allOf": [ { "$ref": "#/definitions/Response" }, { |
49 | | -// "type": "object", |
50 | | -// "description": "Response to `exceptionInfo` request.", |
51 | | -// "properties": { |
52 | | -// "body": { |
53 | | -// "type": "object", |
54 | | -// "properties": { |
55 | | -// "exceptionId": { |
56 | | -// "type": "string", |
57 | | -// "description": "ID of the exception that was thrown." |
58 | | -// }, |
59 | | -// "description": { |
60 | | -// "type": "string", |
61 | | -// "description": "Descriptive text for the exception." |
62 | | -// }, |
63 | | -// "breakMode": { |
64 | | -// "$ref": "#/definitions/ExceptionBreakMode", |
65 | | -// "description": "Mode that caused the exception notification to |
66 | | -// be raised." |
67 | | -// }, |
68 | | -// "details": { |
69 | | -// "$ref": "#/definitions/ExceptionDetails", |
70 | | -// "description": "Detailed information about the exception." |
71 | | -// } |
72 | | -// }, |
73 | | -// "required": [ "exceptionId", "breakMode" ] |
74 | | -// } |
75 | | -// }, |
76 | | -// "required": [ "body" ] |
77 | | -// }] |
78 | | -// } |
79 | | -// "ExceptionDetails": { |
80 | | -// "type": "object", |
81 | | -// "description": "Detailed information about an exception that has |
82 | | -// occurred.", "properties": { |
83 | | -// "message": { |
84 | | -// "type": "string", |
85 | | -// "description": "Message contained in the exception." |
86 | | -// }, |
87 | | -// "typeName": { |
88 | | -// "type": "string", |
89 | | -// "description": "Short type name of the exception object." |
90 | | -// }, |
91 | | -// "fullTypeName": { |
92 | | -// "type": "string", |
93 | | -// "description": "Fully-qualified type name of the exception object." |
94 | | -// }, |
95 | | -// "evaluateName": { |
96 | | -// "type": "string", |
97 | | -// "description": "An expression that can be evaluated in the current |
98 | | -// scope to obtain the exception object." |
99 | | -// }, |
100 | | -// "stackTrace": { |
101 | | -// "type": "string", |
102 | | -// "description": "Stack trace at the time the exception was thrown." |
103 | | -// }, |
104 | | -// "innerException": { |
105 | | -// "type": "array", |
106 | | -// "items": { |
107 | | -// "$ref": "#/definitions/ExceptionDetails" |
108 | | -// }, |
109 | | -// "description": "Details of the exception contained by this exception, |
110 | | -// if any." |
111 | | -// } |
112 | | -// } |
113 | | -// }, |
114 | | -void ExceptionInfoRequestHandler::operator()( |
115 | | - const llvm::json::Object &request) const { |
116 | | - llvm::json::Object response; |
117 | | - FillResponse(request, response); |
118 | | - const auto *arguments = request.getObject("arguments"); |
119 | | - llvm::json::Object body; |
120 | | - lldb::SBThread thread = dap.GetLLDBThread(*arguments); |
121 | | - if (thread.IsValid()) { |
122 | | - auto stopReason = thread.GetStopReason(); |
123 | | - if (stopReason == lldb::eStopReasonSignal) |
124 | | - body.try_emplace("exceptionId", "signal"); |
125 | | - else if (stopReason == lldb::eStopReasonBreakpoint) { |
126 | | - ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread); |
127 | | - if (exc_bp) { |
128 | | - EmplaceSafeString(body, "exceptionId", exc_bp->GetFilter()); |
129 | | - EmplaceSafeString(body, "description", exc_bp->GetLabel()); |
130 | | - } else { |
131 | | - body.try_emplace("exceptionId", "exception"); |
132 | | - } |
| 20 | +/// Retrieves the details of the exception that caused this event to be raised. |
| 21 | +/// |
| 22 | +/// Clients should only call this request if the corresponding capability |
| 23 | +/// `supportsExceptionInfoRequest` is true. |
| 24 | +llvm::Expected<ExceptionInfoResponseBody> |
| 25 | +ExceptionInfoRequestHandler::Run(const ExceptionInfoArguments &args) const { |
| 26 | + |
| 27 | + lldb::SBThread thread = dap.GetLLDBThread(args.threadId); |
| 28 | + if (!thread.IsValid()) |
| 29 | + return llvm::make_error<DAPError>( |
| 30 | + llvm::formatv("Invalid thread id: {}", args.threadId).str()); |
| 31 | + |
| 32 | + ExceptionInfoResponseBody response; |
| 33 | + response.breakMode = eExceptionBreakModeAlways; |
| 34 | + const lldb::StopReason stop_reason = thread.GetStopReason(); |
| 35 | + switch (stop_reason) { |
| 36 | + case lldb::eStopReasonSignal: |
| 37 | + response.exceptionId = "signal"; |
| 38 | + break; |
| 39 | + case lldb::eStopReasonBreakpoint: { |
| 40 | + const ExceptionBreakpoint *exc_bp = |
| 41 | + dap.GetExceptionBPFromStopReason(thread); |
| 42 | + if (exc_bp) { |
| 43 | + response.exceptionId = exc_bp->GetFilter(); |
| 44 | + response.description = exc_bp->GetLabel(); |
133 | 45 | } else { |
134 | | - body.try_emplace("exceptionId", "exception"); |
| 46 | + response.exceptionId = "exception"; |
135 | 47 | } |
136 | | - if (!ObjectContainsKey(body, "description")) { |
137 | | - char description[1024]; |
138 | | - if (thread.GetStopDescription(description, sizeof(description))) { |
139 | | - EmplaceSafeString(body, "description", description); |
140 | | - } |
| 48 | + } break; |
| 49 | + default: |
| 50 | + response.exceptionId = "exception"; |
| 51 | + } |
| 52 | + |
| 53 | + lldb::SBStream stream; |
| 54 | + if (response.description.empty()) { |
| 55 | + if (thread.GetStopDescription(stream)) { |
| 56 | + response.description = {stream.GetData(), stream.GetSize()}; |
141 | 57 | } |
142 | | - body.try_emplace("breakMode", "always"); |
143 | | - auto exception = thread.GetCurrentException(); |
144 | | - if (exception.IsValid()) { |
145 | | - llvm::json::Object details; |
146 | | - lldb::SBStream stream; |
147 | | - if (exception.GetDescription(stream)) { |
148 | | - EmplaceSafeString(details, "message", stream.GetData()); |
149 | | - } |
| 58 | + } |
150 | 59 |
|
151 | | - auto exceptionBacktrace = thread.GetCurrentExceptionBacktrace(); |
152 | | - if (exceptionBacktrace.IsValid()) { |
153 | | - lldb::SBStream stream; |
154 | | - exceptionBacktrace.GetDescription(stream); |
155 | | - for (uint32_t i = 0; i < exceptionBacktrace.GetNumFrames(); i++) { |
156 | | - lldb::SBFrame frame = exceptionBacktrace.GetFrameAtIndex(i); |
157 | | - frame.GetDescription(stream); |
158 | | - } |
159 | | - EmplaceSafeString(details, "stackTrace", stream.GetData()); |
160 | | - } |
| 60 | + if (lldb::SBValue exception = thread.GetCurrentException()) { |
| 61 | + stream.Clear(); |
| 62 | + response.details = ExceptionDetails{}; |
| 63 | + if (exception.GetDescription(stream)) { |
| 64 | + response.details->message = {stream.GetData(), stream.GetSize()}; |
| 65 | + } |
| 66 | + |
| 67 | + if (lldb::SBThread exception_backtrace = |
| 68 | + thread.GetCurrentExceptionBacktrace()) { |
| 69 | + stream.Clear(); |
| 70 | + exception_backtrace.GetDescription(stream); |
161 | 71 |
|
162 | | - body.try_emplace("details", std::move(details)); |
| 72 | + for (uint32_t idx = 0; idx < exception_backtrace.GetNumFrames(); idx++) { |
| 73 | + lldb::SBFrame frame = exception_backtrace.GetFrameAtIndex(idx); |
| 74 | + frame.GetDescription(stream); |
| 75 | + } |
| 76 | + response.details->stackTrace = {stream.GetData(), stream.GetSize()}; |
163 | 77 | } |
164 | | - // auto excInfoCount = thread.GetStopReasonDataCount(); |
165 | | - // for (auto i=0; i<excInfoCount; ++i) { |
166 | | - // uint64_t exc_data = thread.GetStopReasonDataAtIndex(i); |
167 | | - // } |
168 | | - } else { |
169 | | - response["success"] = llvm::json::Value(false); |
170 | 78 | } |
171 | | - response.try_emplace("body", std::move(body)); |
172 | | - dap.SendJSON(llvm::json::Value(std::move(response))); |
| 79 | + return response; |
173 | 80 | } |
174 | 81 | } // namespace lldb_dap |
0 commit comments