Skip to content

Commit 5f3f175

Browse files
authored
[lldb-dap] Use protocol types for exceptioninfo (#165858)
Relands the commit b8062f8
1 parent 564c3de commit 5f3f175

File tree

11 files changed

+294
-154
lines changed

11 files changed

+294
-154
lines changed

lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp

Lines changed: 58 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -7,168 +7,75 @@
77
//===----------------------------------------------------------------------===//
88

99
#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"
1213
#include "RequestHandler.h"
1314
#include "lldb/API/SBStream.h"
1415

16+
using namespace lldb_dap::protocol;
17+
1518
namespace lldb_dap {
1619

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();
13345
} else {
134-
body.try_emplace("exceptionId", "exception");
46+
response.exceptionId = "exception";
13547
}
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()};
14157
}
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+
}
15059

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);
16171

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()};
16377
}
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);
17078
}
171-
response.try_emplace("body", std::move(body));
172-
dap.SendJSON(llvm::json::Value(std::move(response)));
79+
return response;
17380
}
17481
} // namespace lldb_dap

lldb/tools/lldb-dap/Handler/RequestHandler.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,14 +302,18 @@ class EvaluateRequestHandler : public LegacyRequestHandler {
302302
}
303303
};
304304

305-
class ExceptionInfoRequestHandler : public LegacyRequestHandler {
305+
class ExceptionInfoRequestHandler final
306+
: public RequestHandler<
307+
protocol::ExceptionInfoArguments,
308+
llvm::Expected<protocol::ExceptionInfoResponseBody>> {
306309
public:
307-
using LegacyRequestHandler::LegacyRequestHandler;
310+
using RequestHandler::RequestHandler;
308311
static llvm::StringLiteral GetCommand() { return "exceptionInfo"; }
309312
FeatureSet GetSupportedFeatures() const override {
310313
return {protocol::eAdapterFeatureExceptionInfoRequest};
311314
}
312-
void operator()(const llvm::json::Object &request) const override;
315+
llvm::Expected<protocol::ExceptionInfoResponseBody>
316+
Run(const protocol::ExceptionInfoArguments &args) const override;
313317
};
314318

315319
class InitializeRequestHandler

lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,4 +625,22 @@ llvm::json::Value toJSON(const ModuleSymbolsResponseBody &DGMSR) {
625625
return result;
626626
}
627627

628+
bool fromJSON(const json::Value &Params, ExceptionInfoArguments &Args,
629+
json::Path Path) {
630+
json::ObjectMapper O(Params, Path);
631+
return O && O.map("threadId", Args.threadId);
632+
}
633+
634+
json::Value toJSON(const ExceptionInfoResponseBody &ERB) {
635+
json::Object result{{"exceptionId", ERB.exceptionId},
636+
{"breakMode", ERB.breakMode}};
637+
638+
if (!ERB.description.empty())
639+
result.insert({"description", ERB.description.c_str()});
640+
if (ERB.details.has_value())
641+
result.insert({"details", *ERB.details});
642+
643+
return result;
644+
}
645+
628646
} // namespace lldb_dap::protocol

lldb/tools/lldb-dap/Protocol/ProtocolRequests.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,28 @@ struct ModuleSymbolsResponseBody {
10391039
};
10401040
llvm::json::Value toJSON(const ModuleSymbolsResponseBody &);
10411041

1042+
struct ExceptionInfoArguments {
1043+
/// Thread for which exception information should be retrieved.
1044+
lldb::tid_t threadId = LLDB_INVALID_THREAD_ID;
1045+
};
1046+
bool fromJSON(const llvm::json::Value &, ExceptionInfoArguments &,
1047+
llvm::json::Path);
1048+
1049+
struct ExceptionInfoResponseBody {
1050+
/// ID of the exception that was thrown.
1051+
std::string exceptionId;
1052+
1053+
/// Descriptive text for the exception.
1054+
std::string description;
1055+
1056+
/// Mode that caused the exception notification to be raised.
1057+
ExceptionBreakMode breakMode = eExceptionBreakModeNever;
1058+
1059+
/// Detailed information about the exception.
1060+
std::optional<ExceptionDetails> details;
1061+
};
1062+
llvm::json::Value toJSON(const ExceptionInfoResponseBody &);
1063+
10421064
} // namespace lldb_dap::protocol
10431065

10441066
#endif

lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,4 +1136,37 @@ bool fromJSON(const json::Value &Param, Variable &V, json::Path Path) {
11361136
Path, /*required=*/false);
11371137
}
11381138

1139+
json::Value toJSON(const ExceptionBreakMode Mode) {
1140+
switch (Mode) {
1141+
case eExceptionBreakModeNever:
1142+
return "never";
1143+
case eExceptionBreakModeAlways:
1144+
return "always";
1145+
case eExceptionBreakModeUnhandled:
1146+
return "unhandled";
1147+
case eExceptionBreakModeUserUnhandled:
1148+
return "userUnhandled";
1149+
}
1150+
llvm_unreachable("unhandled exception breakMode.");
1151+
}
1152+
1153+
json::Value toJSON(const ExceptionDetails &ED) {
1154+
json::Object result;
1155+
1156+
if (!ED.message.empty())
1157+
result.insert({"message", ED.message});
1158+
if (!ED.typeName.empty())
1159+
result.insert({"typeName", ED.typeName});
1160+
if (!ED.fullTypeName.empty())
1161+
result.insert({"fullTypeName", ED.fullTypeName});
1162+
if (!ED.evaluateName.empty())
1163+
result.insert({"evaluateName", ED.evaluateName});
1164+
if (!ED.stackTrace.empty())
1165+
result.insert({"stackTrace", ED.stackTrace});
1166+
if (!ED.innerException.empty())
1167+
result.insert({"innerException", ED.innerException});
1168+
1169+
return result;
1170+
}
1171+
11391172
} // namespace lldb_dap::protocol

lldb/tools/lldb-dap/Protocol/ProtocolTypes.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,36 @@ struct Variable {
10071007
llvm::json::Value toJSON(const Variable &);
10081008
bool fromJSON(const llvm::json::Value &, Variable &, llvm::json::Path);
10091009

1010+
enum ExceptionBreakMode : unsigned {
1011+
eExceptionBreakModeNever,
1012+
eExceptionBreakModeAlways,
1013+
eExceptionBreakModeUnhandled,
1014+
eExceptionBreakModeUserUnhandled,
1015+
};
1016+
llvm::json::Value toJSON(ExceptionBreakMode);
1017+
1018+
struct ExceptionDetails {
1019+
/// Message contained in the exception.
1020+
std::string message;
1021+
1022+
/// Short type name of the exception object.
1023+
std::string typeName;
1024+
1025+
/// Fully-qualified type name of the exception object.
1026+
std::string fullTypeName;
1027+
1028+
/// An expression that can be evaluated in the current scope to obtain the
1029+
/// exception object.
1030+
std::string evaluateName;
1031+
1032+
/// Stack trace at the time the exception was thrown.
1033+
std::string stackTrace;
1034+
1035+
/// Details of the exception contained by this exception, if any.
1036+
std::vector<ExceptionDetails> innerException;
1037+
};
1038+
llvm::json::Value toJSON(const ExceptionDetails &);
1039+
10101040
} // namespace lldb_dap::protocol
10111041

10121042
#endif

lldb/unittests/DAP/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_lldb_unittest(DAPTests
77
Handler/ContinueTest.cpp
88
JSONUtilsTest.cpp
99
LLDBUtilsTest.cpp
10+
ProtocolRequestsTest.cpp
1011
ProtocolTypesTest.cpp
1112
ProtocolUtilsTest.cpp
1213
TestBase.cpp

0 commit comments

Comments
 (0)