|
10 | 10 |
|
11 | 11 | #include "JSONUtils.h"
|
12 | 12 |
|
| 13 | +#include <lldb/API/SBBreakpointLocation.h> |
| 14 | +#include <lldb/API/SBListener.h> |
13 | 15 | #include <lldb/API/SBStream.h>
|
14 | 16 |
|
15 | 17 | namespace lldb_dap {
|
16 | 18 |
|
| 19 | +static llvm::SmallVector<lldb::SBLineEntry> |
| 20 | +GetLineValidEntry(DAP &dap, const lldb::SBFileSpec &file_spec, uint32_t line) { |
| 21 | + // disable breakpoint listeners so they do not send events to the DAP client. |
| 22 | + lldb::SBListener listener = dap.debugger.GetListener(); |
| 23 | + lldb::SBBroadcaster broadcaster = dap.target.GetBroadcaster(); |
| 24 | + constexpr auto event_mask = lldb::SBTarget::eBroadcastBitBreakpointChanged; |
| 25 | + listener.StopListeningForEvents(broadcaster, event_mask); |
| 26 | + |
| 27 | + // create a breakpoint to resolve the line if it is on an empty line. |
| 28 | + lldb::SBBreakpoint goto_bp = |
| 29 | + dap.target.BreakpointCreateByLocation(file_spec, line); |
| 30 | + if (!goto_bp.IsValid()) |
| 31 | + return {}; |
| 32 | + |
| 33 | + llvm::SmallVector<lldb::SBLineEntry> entry_locations{}; |
| 34 | + const size_t resolved_count = goto_bp.GetNumResolvedLocations(); |
| 35 | + for (size_t idx = 0; idx < resolved_count; ++idx) { |
| 36 | + lldb::SBBreakpointLocation location = goto_bp.GetLocationAtIndex(idx); |
| 37 | + if (!location.IsValid()) |
| 38 | + continue; |
| 39 | + |
| 40 | + lldb::SBAddress addr = location.GetAddress(); |
| 41 | + if (!addr.IsValid()) |
| 42 | + continue; |
| 43 | + |
| 44 | + lldb::SBLineEntry line_entry = addr.GetLineEntry(); |
| 45 | + if (!line_entry.IsValid()) |
| 46 | + continue; |
| 47 | + |
| 48 | + entry_locations.push_back(line_entry); |
| 49 | + } |
| 50 | + |
| 51 | + // clean up; |
| 52 | + dap.target.BreakpointDelete(goto_bp.GetID()); |
| 53 | + listener.StartListeningForEvents(broadcaster, event_mask); |
| 54 | + |
| 55 | + return entry_locations; |
| 56 | +} |
| 57 | + |
17 | 58 | // "GotoTargetsRequest": {
|
18 | 59 | // "allOf": [ { "$ref": "#/definitions/Request" }, {
|
19 | 60 | // "type": "object",
|
@@ -83,37 +124,40 @@ void GoToTargetsRequestHandler::operator()(
|
83 | 124 | const llvm::json::Object &request) const {
|
84 | 125 | llvm::json::Object response;
|
85 | 126 | FillResponse(request, response);
|
86 |
| - const auto *arguments = request.getObject("arguments"); |
87 |
| - const auto *source = arguments->getObject("source"); |
88 |
| - const std::string path = GetString(source, "path").str(); |
89 |
| - |
90 |
| - const auto goto_line = GetInteger<uint64_t>(arguments, "line").value_or(0u); |
91 |
| - const auto goto_column = |
92 |
| - GetInteger<uint64_t>(arguments, "column").value_or(0u); |
93 | 127 |
|
94 |
| - lldb::SBLineEntry line_entry{}; |
| 128 | + const llvm::json::Object *arguments = request.getObject("arguments"); |
| 129 | + const llvm::json::Object *source = arguments->getObject("source"); |
| 130 | + const std::string path = GetString(source, "path").str(); |
95 | 131 | const lldb::SBFileSpec file_spec(path.c_str(), true);
|
96 |
| - line_entry.SetFileSpec(file_spec); |
97 |
| - line_entry.SetLine(goto_line); |
98 |
| - line_entry.SetColumn(goto_column); |
99 |
| - |
100 |
| - const auto target_id = dap.goto_id_map.InsertLineEntry(line_entry); |
101 |
| - llvm::json::Array response_targets; |
102 |
| - const auto target_line = line_entry.GetLine(); |
103 |
| - const auto target_column = line_entry.GetColumn(); |
104 |
| - auto target = llvm::json::Object(); |
105 |
| - target.try_emplace("id", target_id); |
106 |
| - |
107 |
| - lldb::SBStream stream; |
108 |
| - line_entry.GetDescription(stream); |
109 |
| - target.try_emplace("label", |
110 |
| - llvm::StringRef(stream.GetData(), stream.GetSize())); |
111 |
| - target.try_emplace("column", target_column); |
112 |
| - target.try_emplace("line", target_line); |
113 |
| - |
114 |
| - response_targets.push_back(std::move(target)); |
| 132 | + const uint64_t goto_line = |
| 133 | + GetInteger<uint64_t>(arguments, "line").value_or(1U); |
| 134 | + |
115 | 135 | llvm::json::Object body;
|
116 |
| - body.try_emplace("targets", std::move(response_targets)); |
| 136 | + |
| 137 | + llvm::SmallVector<lldb::SBLineEntry> goto_locations = |
| 138 | + GetLineValidEntry(dap, file_spec, goto_line); |
| 139 | + if (goto_locations.empty()) { |
| 140 | + response["success"] = false; |
| 141 | + response["message"] = "Invalid jump location"; |
| 142 | + } else { |
| 143 | + llvm::json::Array response_targets; |
| 144 | + for (lldb::SBLineEntry &line_entry : goto_locations) { |
| 145 | + const uint64_t target_id = dap.goto_id_map.InsertLineEntry(line_entry); |
| 146 | + const uint32_t target_line = line_entry.GetLine(); |
| 147 | + auto target = llvm::json::Object(); |
| 148 | + target.try_emplace("id", target_id); |
| 149 | + |
| 150 | + lldb::SBStream stream; |
| 151 | + line_entry.GetDescription(stream); |
| 152 | + target.try_emplace("label", |
| 153 | + llvm::StringRef(stream.GetData(), stream.GetSize())); |
| 154 | + target.try_emplace("line", target_line); |
| 155 | + response_targets.push_back(std::move(target)); |
| 156 | + } |
| 157 | + |
| 158 | + body.try_emplace("targets", std::move(response_targets)); |
| 159 | + } |
| 160 | + |
117 | 161 | response.try_emplace("body", std::move(body));
|
118 | 162 | dap.SendJSON(llvm::json::Value(std::move(response)));
|
119 | 163 | }
|
|
0 commit comments