Skip to content

Commit 54782ac

Browse files
committed
data breakpoint
1 parent 5e8830c commit 54782ac

File tree

9 files changed

+77
-152
lines changed

9 files changed

+77
-152
lines changed

lldb/tools/lldb-dap/DAP.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <chrono>
4646
#include <condition_variable>
4747
#include <cstdarg>
48+
#include <cstdint>
4849
#include <cstdio>
4950
#include <fstream>
5051
#include <future>
@@ -514,15 +515,18 @@ lldb::SBThread DAP::GetLLDBThread(const llvm::json::Object &arguments) {
514515
return target.GetProcess().GetThreadByID(tid);
515516
}
516517

517-
lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) {
518-
const uint64_t frame_id =
519-
GetInteger<uint64_t>(arguments, "frameId").value_or(UINT64_MAX);
518+
lldb::SBFrame DAP::GetLLDBFrame(std::optional<uint64_t> frame_id) {
519+
uint64_t id = frame_id.value_or(0);
520520
lldb::SBProcess process = target.GetProcess();
521521
// Upper 32 bits is the thread index ID
522-
lldb::SBThread thread =
523-
process.GetThreadByIndexID(GetLLDBThreadIndexID(frame_id));
522+
lldb::SBThread thread = process.GetThreadByIndexID(GetLLDBThreadIndexID(id));
524523
// Lower 32 bits is the frame index
525-
return thread.GetFrameAtIndex(GetLLDBFrameID(frame_id));
524+
return thread.GetFrameAtIndex(GetLLDBFrameID(id));
525+
}
526+
527+
lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) {
528+
const auto frame_id = GetInteger<uint64_t>(arguments, "frameId");
529+
return GetLLDBFrame(frame_id);
526530
}
527531

528532
llvm::json::Value DAP::CreateTopLevelScopes() {

lldb/tools/lldb-dap/DAP.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ struct DAP {
275275
lldb::SBThread GetLLDBThread(lldb::tid_t id);
276276
lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments);
277277

278+
lldb::SBFrame GetLLDBFrame(std::optional<uint64_t> frame_id);
278279
lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments);
279280

280281
llvm::json::Value CreateTopLevelScopes();

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

Lines changed: 39 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -8,144 +8,49 @@
88

99
#include "DAP.h"
1010
#include "EventHelper.h"
11-
#include "JSONUtils.h"
11+
#include "Protocol/ProtocolTypes.h"
1212
#include "RequestHandler.h"
1313
#include "lldb/API/SBMemoryRegionInfo.h"
1414
#include "llvm/ADT/StringExtras.h"
15+
#include <optional>
1516

1617
namespace lldb_dap {
1718

18-
// "DataBreakpointInfoRequest": {
19-
// "allOf": [ { "$ref": "#/definitions/Request" }, {
20-
// "type": "object",
21-
// "description": "Obtains information on a possible data breakpoint that
22-
// could be set on an expression or variable.\nClients should only call this
23-
// request if the corresponding capability `supportsDataBreakpoints` is
24-
// true.", "properties": {
25-
// "command": {
26-
// "type": "string",
27-
// "enum": [ "dataBreakpointInfo" ]
28-
// },
29-
// "arguments": {
30-
// "$ref": "#/definitions/DataBreakpointInfoArguments"
31-
// }
32-
// },
33-
// "required": [ "command", "arguments" ]
34-
// }]
35-
// },
36-
// "DataBreakpointInfoArguments": {
37-
// "type": "object",
38-
// "description": "Arguments for `dataBreakpointInfo` request.",
39-
// "properties": {
40-
// "variablesReference": {
41-
// "type": "integer",
42-
// "description": "Reference to the variable container if the data
43-
// breakpoint is requested for a child of the container. The
44-
// `variablesReference` must have been obtained in the current suspended
45-
// state. See 'Lifetime of Object References' in the Overview section for
46-
// details."
47-
// },
48-
// "name": {
49-
// "type": "string",
50-
// "description": "The name of the variable's child to obtain data
51-
// breakpoint information for.\nIf `variablesReference` isn't specified,
52-
// this can be an expression."
53-
// },
54-
// "frameId": {
55-
// "type": "integer",
56-
// "description": "When `name` is an expression, evaluate it in the scope
57-
// of this stack frame. If not specified, the expression is evaluated in
58-
// the global scope. When `variablesReference` is specified, this property
59-
// has no effect."
60-
// }
61-
// },
62-
// "required": [ "name" ]
63-
// },
64-
// "DataBreakpointInfoResponse": {
65-
// "allOf": [ { "$ref": "#/definitions/Response" }, {
66-
// "type": "object",
67-
// "description": "Response to `dataBreakpointInfo` request.",
68-
// "properties": {
69-
// "body": {
70-
// "type": "object",
71-
// "properties": {
72-
// "dataId": {
73-
// "type": [ "string", "null" ],
74-
// "description": "An identifier for the data on which a data
75-
// breakpoint can be registered with the `setDataBreakpoints`
76-
// request or null if no data breakpoint is available. If a
77-
// `variablesReference` or `frameId` is passed, the `dataId` is
78-
// valid in the current suspended state, otherwise it's valid
79-
// indefinitely. See 'Lifetime of Object References' in the Overview
80-
// section for details. Breakpoints set using the `dataId` in the
81-
// `setDataBreakpoints` request may outlive the lifetime of the
82-
// associated `dataId`."
83-
// },
84-
// "description": {
85-
// "type": "string",
86-
// "description": "UI string that describes on what data the
87-
// breakpoint is set on or why a data breakpoint is not available."
88-
// },
89-
// "accessTypes": {
90-
// "type": "array",
91-
// "items": {
92-
// "$ref": "#/definitions/DataBreakpointAccessType"
93-
// },
94-
// "description": "Attribute lists the available access types for a
95-
// potential data breakpoint. A UI client could surface this
96-
// information."
97-
// },
98-
// "canPersist": {
99-
// "type": "boolean",
100-
// "description": "Attribute indicates that a potential data
101-
// breakpoint could be persisted across sessions."
102-
// }
103-
// },
104-
// "required": [ "dataId", "description" ]
105-
// }
106-
// },
107-
// "required": [ "body" ]
108-
// }]
109-
// }
110-
void DataBreakpointInfoRequestHandler::operator()(
111-
const llvm::json::Object &request) const {
112-
llvm::json::Object response;
113-
FillResponse(request, response);
114-
llvm::json::Object body;
115-
lldb::SBError error;
116-
llvm::json::Array accessTypes{"read", "write", "readWrite"};
117-
const auto *arguments = request.getObject("arguments");
118-
const auto variablesReference =
119-
GetInteger<uint64_t>(arguments, "variablesReference").value_or(0);
120-
llvm::StringRef name = GetString(arguments, "name").value_or("");
121-
lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
122-
lldb::SBValue variable = dap.variables.FindVariable(variablesReference, name);
19+
/// Obtains information on a possible data breakpoint that could be set on an
20+
/// expression or variable. Clients should only call this request if the
21+
/// corresponding capability supportsDataBreakpoints is true.
22+
llvm::Expected<protocol::DataBreakpointInfoResponseBody>
23+
DataBreakpointInfoRequestHandler::Run(
24+
const protocol::DataBreakpointInfoArguments &args) const {
25+
protocol::DataBreakpointInfoResponseBody response;
26+
lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId);
27+
lldb::SBValue variable = dap.variables.FindVariable(
28+
args.variablesReference.value_or(0), args.name);
12329
std::string addr, size;
12430

12531
if (variable.IsValid()) {
12632
lldb::addr_t load_addr = variable.GetLoadAddress();
12733
size_t byte_size = variable.GetByteSize();
12834
if (load_addr == LLDB_INVALID_ADDRESS) {
129-
body.try_emplace("dataId", nullptr);
130-
body.try_emplace("description",
131-
"does not exist in memory, its location is " +
132-
std::string(variable.GetLocation()));
35+
response.dataId = std::nullopt;
36+
response.description = "does not exist in memory, its location is " +
37+
std::string(variable.GetLocation());
13338
} else if (byte_size == 0) {
134-
body.try_emplace("dataId", nullptr);
135-
body.try_emplace("description", "variable size is 0");
39+
response.dataId = std::nullopt;
40+
response.description = "variable size is 0";
13641
} else {
13742
addr = llvm::utohexstr(load_addr);
13843
size = llvm::utostr(byte_size);
13944
}
140-
} else if (variablesReference == 0 && frame.IsValid()) {
141-
lldb::SBValue value = frame.EvaluateExpression(name.data());
45+
} else if (args.variablesReference.value_or(0) == 0 && frame.IsValid()) {
46+
lldb::SBValue value = frame.EvaluateExpression(args.name.c_str());
14247
if (value.GetError().Fail()) {
14348
lldb::SBError error = value.GetError();
14449
const char *error_cstr = error.GetCString();
145-
body.try_emplace("dataId", nullptr);
146-
body.try_emplace("description", error_cstr && error_cstr[0]
147-
? std::string(error_cstr)
148-
: "evaluation failed");
50+
response.dataId = std::nullopt;
51+
response.description = error_cstr && error_cstr[0]
52+
? std::string(error_cstr)
53+
: "evaluation failed";
14954
} else {
15055
uint64_t load_addr = value.GetValueAsUnsigned();
15156
lldb::SBData data = value.GetPointeeData();
@@ -159,32 +64,31 @@ void DataBreakpointInfoRequestHandler::operator()(
15964
// request if SBProcess::GetMemoryRegionInfo returns error.
16065
if (err.Success()) {
16166
if (!(region.IsReadable() || region.IsWritable())) {
162-
body.try_emplace("dataId", nullptr);
163-
body.try_emplace("description",
164-
"memory region for address " + addr +
165-
" has no read or write permissions");
67+
response.dataId = std::nullopt;
68+
response.description = "memory region for address " + addr +
69+
" has no read or write permissions";
16670
}
16771
}
16872
} else {
169-
body.try_emplace("dataId", nullptr);
170-
body.try_emplace("description",
171-
"unable to get byte size for expression: " +
172-
name.str());
73+
response.dataId = std::nullopt;
74+
response.description =
75+
"unable to get byte size for expression: " + args.name;
17376
}
17477
}
17578
} else {
176-
body.try_emplace("dataId", nullptr);
177-
body.try_emplace("description", "variable not found: " + name.str());
79+
response.dataId = std::nullopt;
80+
response.description = "variable not found: " + args.name;
17881
}
17982

180-
if (!body.getObject("dataId")) {
181-
body.try_emplace("dataId", addr + "/" + size);
182-
body.try_emplace("accessTypes", std::move(accessTypes));
183-
body.try_emplace("description",
184-
size + " bytes at " + addr + " " + name.str());
83+
if (!response.dataId.has_value()) {
84+
response.dataId = addr + "/" + size;
85+
response.accessTypes = {protocol::eDataBreakpointAccessTypeRead,
86+
protocol::eDataBreakpointAccessTypeWrite,
87+
protocol::eDataBreakpointAccessTypeReadWrite};
88+
response.description = size + " bytes at " + addr + " " + args.name;
18589
}
186-
response.try_emplace("body", std::move(body));
187-
dap.SendJSON(llvm::json::Value(std::move(response)));
90+
91+
return response;
18892
}
18993

19094
} // namespace lldb_dap

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ static void EventThreadFunction(DAP &dap) {
212212
// avoids sending paths that should be source mapped. Note that
213213
// CreateBreakpoint doesn't apply source mapping and certain
214214
// implementation ignore the source part of this event anyway.
215-
llvm::json::Value source_bp = CreateBreakpoint(&bp);
215+
llvm::json::Value source_bp = bp.ToProtocolBreakpoint();
216216
source_bp.getAsObject()->erase("source");
217217

218218
llvm::json::Object body;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ void TestGetTargetBreakpointsRequestHandler::operator()(
2020
llvm::json::Array response_breakpoints;
2121
for (uint32_t i = 0; dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) {
2222
auto bp = Breakpoint(dap, dap.target.GetBreakpointAtIndex(i));
23-
AppendBreakpoint(&bp, response_breakpoints);
23+
response_breakpoints.push_back(bp.ToProtocolBreakpoint());
2424
}
2525
llvm::json::Object body;
2626
body.try_emplace("breakpoints", std::move(response_breakpoints));

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ struct DataBreakpointInfoArguments {
506506
/// When `name` is an expression, evaluate it in the scope of this stack
507507
/// frame. If not specified, the expression is evaluated in the global scope.
508508
/// When `asAddress` is true, the `frameId` is ignored.
509-
std::optional<int64_t> frameId;
509+
std::optional<uint64_t> frameId;
510510

511511
/// If specified, a debug adapter should return information for the range of
512512
/// memory extending `bytes` number of bytes from the address or variable
@@ -539,7 +539,7 @@ struct DataBreakpointInfoResponseBody {
539539
/// for details. Breakpoints set using the `dataId` in the
540540
/// `setDataBreakpoints` request may outlive the lifetime of the associated
541541
/// `dataId`.
542-
std::optional<std::string> dataId;
542+
std::optional<std::optional<std::string>> dataId;
543543

544544
/// UI string that describes on what data the breakpoint is set on or why a
545545
/// data breakpoint is not available.

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

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,28 @@ bool fromJSON(const json::Value &Params, Source &S, json::Path P) {
4343
O.map("sourceReference", S.sourceReference);
4444
}
4545

46+
static llvm::json::Value ToString(PresentationHint hint) {
47+
switch (hint) {
48+
case ePresentationHintNormal:
49+
return "normal";
50+
case ePresentationHintEmphasize:
51+
return "emphasize";
52+
case ePresentationHintDeemphasize:
53+
return "deemphasize";
54+
}
55+
llvm_unreachable("unhandled presentation hint.");
56+
}
57+
4658
llvm::json::Value toJSON(const Source &S) {
47-
json::Object result{
48-
{"name", S.name},
49-
{"path", S.path},
50-
{"sourceReference", S.sourceReference},
51-
{"presentationHint", S.presentationHint},
52-
};
59+
json::Object result;
60+
if (S.name)
61+
result.insert({"name", *S.name});
62+
if (S.path)
63+
result.insert({"path", *S.path});
64+
if (S.name)
65+
result.insert({"sourceReference", *S.sourceReference});
66+
if (S.presentationHint)
67+
result.insert({"sourceReference", ToString(*S.presentationHint)});
5368

5469
return result;
5570
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ enum PresentationHint : unsigned {
273273
ePresentationHintEmphasize,
274274
ePresentationHintDeemphasize,
275275
};
276+
llvm::json::Value toJSON(const PresentationHint &);
276277

277278
/// A `Source` is a descriptor for source code. It is returned from the debug
278279
/// adapter as part of a `StackFrame` and it is used by clients when specifying

lldb/tools/lldb-dap/Watchpoint.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class Watchpoint : public BreakpointBase {
2828
void SetCondition() override;
2929
void SetHitCondition() override;
3030

31-
protocol::Breakpoint ToProtocolBreakpoint();
31+
protocol::Breakpoint ToProtocolBreakpoint() override;
3232

3333
void SetWatchpoint();
3434

0 commit comments

Comments
 (0)