1//===-- ExceptionInfoRequestHandler.cpp -----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "DAP.h"
10#include "EventHelper.h"
11#include "JSONUtils.h"
12#include "RequestHandler.h"
13#include "lldb/API/SBStream.h"
14
15namespace lldb_dap {
16
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// },
114void ExceptionInfoRequestHandler::operator()(
115 const llvm::json::Object &request) const {
116 llvm::json::Object response;
117 FillResponse(request, response);
118 const auto *arguments = request.getObject(K: "arguments");
119 llvm::json::Object body;
120 lldb::SBThread thread = dap.GetLLDBThread(arguments: *arguments);
121 if (thread.IsValid()) {
122 auto stopReason = thread.GetStopReason();
123 if (stopReason == lldb::eStopReasonSignal)
124 body.try_emplace(K: "exceptionId", Args: "signal");
125 else if (stopReason == lldb::eStopReasonBreakpoint) {
126 ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread);
127 if (exc_bp) {
128 EmplaceSafeString(obj&: body, key: "exceptionId", str: exc_bp->GetFilter());
129 EmplaceSafeString(obj&: body, key: "description", str: exc_bp->GetLabel());
130 } else {
131 body.try_emplace(K: "exceptionId", Args: "exception");
132 }
133 } else {
134 body.try_emplace(K: "exceptionId", Args: "exception");
135 }
136 if (!ObjectContainsKey(obj: body, key: "description")) {
137 char description[1024];
138 if (thread.GetStopDescription(dst_or_null: description, dst_len: sizeof(description))) {
139 EmplaceSafeString(obj&: body, key: "description", str: description);
140 }
141 }
142 body.try_emplace(K: "breakMode", Args: "always");
143 auto exception = thread.GetCurrentException();
144 if (exception.IsValid()) {
145 llvm::json::Object details;
146 lldb::SBStream stream;
147 if (exception.GetDescription(description&: stream)) {
148 EmplaceSafeString(obj&: details, key: "message", str: stream.GetData());
149 }
150
151 auto exceptionBacktrace = thread.GetCurrentExceptionBacktrace();
152 if (exceptionBacktrace.IsValid()) {
153 lldb::SBStream stream;
154 exceptionBacktrace.GetDescription(description&: stream);
155 for (uint32_t i = 0; i < exceptionBacktrace.GetNumFrames(); i++) {
156 lldb::SBFrame frame = exceptionBacktrace.GetFrameAtIndex(idx: i);
157 frame.GetDescription(description&: stream);
158 }
159 EmplaceSafeString(obj&: details, key: "stackTrace", str: stream.GetData());
160 }
161
162 body.try_emplace(K: "details", Args: std::move(details));
163 }
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 }
171 response.try_emplace(K: "body", Args: std::move(body));
172 dap.SendJSON(json: llvm::json::Value(std::move(response)));
173}
174} // namespace lldb_dap
175

source code of lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp