Skip to content

Commit 30c9909

Browse files
authored
[lldb-dap] Migrate disassemble request to structured handler (#140482)
1 parent 72b2219 commit 30c9909

File tree

7 files changed

+329
-140
lines changed

7 files changed

+329
-140
lines changed

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

Lines changed: 49 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -9,113 +9,37 @@
99
#include "DAP.h"
1010
#include "EventHelper.h"
1111
#include "JSONUtils.h"
12+
#include "Protocol/ProtocolRequests.h"
13+
#include "Protocol/ProtocolTypes.h"
1214
#include "RequestHandler.h"
1315
#include "lldb/API/SBInstruction.h"
16+
#include "lldb/lldb-types.h"
1417
#include "llvm/ADT/StringExtras.h"
18+
#include <optional>
19+
20+
using namespace lldb_dap::protocol;
1521

1622
namespace lldb_dap {
1723

18-
// "DisassembleRequest": {
19-
// "allOf": [ { "$ref": "#/definitions/Request" }, {
20-
// "type": "object",
21-
// "description": "Disassembles code stored at the provided
22-
// location.\nClients should only call this request if the corresponding
23-
// capability `supportsDisassembleRequest` is true.", "properties": {
24-
// "command": {
25-
// "type": "string",
26-
// "enum": [ "disassemble" ]
27-
// },
28-
// "arguments": {
29-
// "$ref": "#/definitions/DisassembleArguments"
30-
// }
31-
// },
32-
// "required": [ "command", "arguments" ]
33-
// }]
34-
// },
35-
// "DisassembleArguments": {
36-
// "type": "object",
37-
// "description": "Arguments for `disassemble` request.",
38-
// "properties": {
39-
// "memoryReference": {
40-
// "type": "string",
41-
// "description": "Memory reference to the base location containing the
42-
// instructions to disassemble."
43-
// },
44-
// "offset": {
45-
// "type": "integer",
46-
// "description": "Offset (in bytes) to be applied to the reference
47-
// location before disassembling. Can be negative."
48-
// },
49-
// "instructionOffset": {
50-
// "type": "integer",
51-
// "description": "Offset (in instructions) to be applied after the byte
52-
// offset (if any) before disassembling. Can be negative."
53-
// },
54-
// "instructionCount": {
55-
// "type": "integer",
56-
// "description": "Number of instructions to disassemble starting at the
57-
// specified location and offset.\nAn adapter must return exactly this
58-
// number of instructions - any unavailable instructions should be
59-
// replaced with an implementation-defined 'invalid instruction' value."
60-
// },
61-
// "resolveSymbols": {
62-
// "type": "boolean",
63-
// "description": "If true, the adapter should attempt to resolve memory
64-
// addresses and other values to symbolic names."
65-
// }
66-
// },
67-
// "required": [ "memoryReference", "instructionCount" ]
68-
// },
69-
// "DisassembleResponse": {
70-
// "allOf": [ { "$ref": "#/definitions/Response" }, {
71-
// "type": "object",
72-
// "description": "Response to `disassemble` request.",
73-
// "properties": {
74-
// "body": {
75-
// "type": "object",
76-
// "properties": {
77-
// "instructions": {
78-
// "type": "array",
79-
// "items": {
80-
// "$ref": "#/definitions/DisassembledInstruction"
81-
// },
82-
// "description": "The list of disassembled instructions."
83-
// }
84-
// },
85-
// "required": [ "instructions" ]
86-
// }
87-
// }
88-
// }]
89-
// }
90-
void DisassembleRequestHandler::operator()(
91-
const llvm::json::Object &request) const {
92-
llvm::json::Object response;
93-
FillResponse(request, response);
94-
auto *arguments = request.getObject("arguments");
95-
96-
llvm::StringRef memoryReference =
97-
GetString(arguments, "memoryReference").value_or("");
98-
auto addr_opt = DecodeMemoryReference(memoryReference);
99-
if (!addr_opt.has_value()) {
100-
response["success"] = false;
101-
response["message"] =
102-
"Malformed memory reference: " + memoryReference.str();
103-
dap.SendJSON(llvm::json::Value(std::move(response)));
104-
return;
105-
}
106-
lldb::addr_t addr_ptr = *addr_opt;
24+
/// Disassembles code stored at the provided location.
25+
/// Clients should only call this request if the corresponding capability
26+
/// `supportsDisassembleRequest` is true.
27+
llvm::Expected<DisassembleResponseBody>
28+
DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
29+
std::vector<DisassembledInstruction> instructions;
10730

108-
addr_ptr += GetInteger<int64_t>(arguments, "instructionOffset").value_or(0);
109-
lldb::SBAddress addr(addr_ptr, dap.target);
110-
if (!addr.IsValid()) {
111-
response["success"] = false;
112-
response["message"] = "Memory reference not found in the current binary.";
113-
dap.SendJSON(llvm::json::Value(std::move(response)));
114-
return;
115-
}
31+
std::optional<lldb::addr_t> addr_opt =
32+
DecodeMemoryReference(args.memoryReference);
33+
if (!addr_opt.has_value())
34+
return llvm::make_error<DAPError>("Malformed memory reference: " +
35+
args.memoryReference);
11636

117-
const auto inst_count =
118-
GetInteger<int64_t>(arguments, "instructionCount").value_or(0);
37+
lldb::addr_t addr_ptr = *addr_opt;
38+
addr_ptr += args.instructionOffset.value_or(0);
39+
lldb::SBAddress addr(addr_ptr, dap.target);
40+
if (!addr.IsValid())
41+
return llvm::make_error<DAPError>(
42+
"Memory reference not found in the current binary.");
11943

12044
std::string flavor_string;
12145
const auto target_triple = llvm::StringRef(dap.target.GetTriple());
@@ -132,19 +56,14 @@ void DisassembleRequestHandler::operator()(
13256
}
13357
}
13458

135-
lldb::SBInstructionList insts =
136-
dap.target.ReadInstructions(addr, inst_count, flavor_string.c_str());
59+
lldb::SBInstructionList insts = dap.target.ReadInstructions(
60+
addr, args.instructionCount, flavor_string.c_str());
13761

138-
if (!insts.IsValid()) {
139-
response["success"] = false;
140-
response["message"] = "Failed to find instructions for memory address.";
141-
dap.SendJSON(llvm::json::Value(std::move(response)));
142-
return;
143-
}
62+
if (!insts.IsValid())
63+
return llvm::make_error<DAPError>(
64+
"Failed to find instructions for memory address.");
14465

145-
const bool resolveSymbols =
146-
GetBoolean(arguments, "resolveSymbols").value_or(false);
147-
llvm::json::Array instructions;
66+
const bool resolve_symbols = args.resolveSymbols.value_or(false);
14867
const auto num_insts = insts.GetSize();
14968
for (size_t i = 0; i < num_insts; ++i) {
15069
lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
@@ -165,11 +84,10 @@ void DisassembleRequestHandler::operator()(
16584
}
16685
}
16786

168-
llvm::json::Object disassembled_inst{
169-
{"address", "0x" + llvm::utohexstr(inst_addr)},
170-
{"instructionBytes",
171-
bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""},
172-
};
87+
DisassembledInstruction disassembled_inst;
88+
disassembled_inst.address = inst_addr;
89+
disassembled_inst.instructionBytes =
90+
bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : "";
17391

17492
std::string instruction;
17593
llvm::raw_string_ostream si(instruction);
@@ -185,59 +103,53 @@ void DisassembleRequestHandler::operator()(
185103
: symbol.GetName())
186104
<< ": ";
187105

188-
if (resolveSymbols) {
189-
disassembled_inst.try_emplace("symbol", symbol.GetDisplayName());
190-
}
106+
if (resolve_symbols)
107+
disassembled_inst.symbol = symbol.GetDisplayName();
191108
}
192109

193110
si << llvm::formatv("{0,7} {1,12}", m, o);
194111
if (c && c[0]) {
195112
si << " ; " << c;
196113
}
197114

198-
disassembled_inst.try_emplace("instruction", instruction);
115+
disassembled_inst.instruction = instruction;
199116

200117
auto line_entry = addr.GetLineEntry();
201118
// If the line number is 0 then the entry represents a compiler generated
202119
// location.
203120
if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
204121
line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
205122
auto source = CreateSource(line_entry);
206-
disassembled_inst.try_emplace("location", source);
123+
disassembled_inst.location = std::move(source);
207124

208125
const auto line = line_entry.GetLine();
209-
if (line && line != LLDB_INVALID_LINE_NUMBER) {
210-
disassembled_inst.try_emplace("line", line);
211-
}
126+
if (line != 0 && line != LLDB_INVALID_LINE_NUMBER)
127+
disassembled_inst.line = line;
128+
212129
const auto column = line_entry.GetColumn();
213-
if (column && column != LLDB_INVALID_COLUMN_NUMBER) {
214-
disassembled_inst.try_emplace("column", column);
215-
}
130+
if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER)
131+
disassembled_inst.column = column;
216132

217133
auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
218134
if (end_line_entry.IsValid() &&
219135
end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
220136
const auto end_line = end_line_entry.GetLine();
221-
if (end_line && end_line != LLDB_INVALID_LINE_NUMBER &&
137+
if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER &&
222138
end_line != line) {
223-
disassembled_inst.try_emplace("endLine", end_line);
139+
disassembled_inst.endLine = end_line;
224140

225141
const auto end_column = end_line_entry.GetColumn();
226-
if (end_column && end_column != LLDB_INVALID_COLUMN_NUMBER &&
227-
end_column != column) {
228-
disassembled_inst.try_emplace("endColumn", end_column - 1);
229-
}
142+
if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER &&
143+
end_column != column)
144+
disassembled_inst.endColumn = end_column - 1;
230145
}
231146
}
232147
}
233148

234-
instructions.emplace_back(std::move(disassembled_inst));
149+
instructions.push_back(std::move(disassembled_inst));
235150
}
236151

237-
llvm::json::Object body;
238-
body.try_emplace("instructions", std::move(instructions));
239-
response.try_emplace("body", std::move(body));
240-
dap.SendJSON(llvm::json::Value(std::move(response)));
152+
return DisassembleResponseBody{std::move(instructions)};
241153
}
242154

243155
} // namespace lldb_dap

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,14 +534,17 @@ class LocationsRequestHandler : public LegacyRequestHandler {
534534
void operator()(const llvm::json::Object &request) const override;
535535
};
536536

537-
class DisassembleRequestHandler : public LegacyRequestHandler {
537+
class DisassembleRequestHandler final
538+
: public RequestHandler<protocol::DisassembleArguments,
539+
llvm::Expected<protocol::DisassembleResponseBody>> {
538540
public:
539-
using LegacyRequestHandler::LegacyRequestHandler;
541+
using RequestHandler::RequestHandler;
540542
static llvm::StringLiteral GetCommand() { return "disassemble"; }
541543
FeatureSet GetSupportedFeatures() const override {
542544
return {protocol::eAdapterFeatureDisassembleRequest};
543545
}
544-
void operator()(const llvm::json::Object &request) const override;
546+
llvm::Expected<protocol::DisassembleResponseBody>
547+
Run(const protocol::DisassembleArguments &args) const override;
545548
};
546549

547550
class ReadMemoryRequestHandler : public LegacyRequestHandler {

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,4 +460,22 @@ llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &SDBR) {
460460
return result;
461461
}
462462

463+
bool fromJSON(const llvm::json::Value &Params, DisassembleArguments &DA,
464+
llvm::json::Path P) {
465+
json::ObjectMapper O(Params, P);
466+
return O && O.map("memoryReference", DA.memoryReference) &&
467+
O.mapOptional("offset", DA.offset) &&
468+
O.mapOptional("instructionOffset", DA.instructionOffset) &&
469+
O.map("instructionCount", DA.instructionCount) &&
470+
O.mapOptional("resolveSymbols", DA.resolveSymbols);
471+
}
472+
473+
llvm::json::Value toJSON(const DisassembleResponseBody &DRB) {
474+
llvm::json::Array instructions;
475+
for (const auto &instruction : DRB.instructions) {
476+
instructions.push_back(toJSON(instruction));
477+
}
478+
return llvm::json::Object{{"instructions", std::move(instructions)}};
479+
}
480+
463481
} // namespace lldb_dap::protocol

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,44 @@ struct SetDataBreakpointsResponseBody {
726726
};
727727
llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &);
728728

729+
/// Arguments to `disassemble` request.
730+
struct DisassembleArguments {
731+
/// Memory reference to the base location containing the instructions to
732+
/// disassemble.
733+
std::string memoryReference;
734+
735+
/// Offset (in bytes) to be applied to the reference location before
736+
/// disassembling. Can be negative.
737+
std::optional<int64_t> offset;
738+
739+
/// Offset (in instructions) to be applied after the byte offset (if any)
740+
/// before disassembling. Can be negative.
741+
std::optional<int64_t> instructionOffset;
742+
743+
/// Number of instructions to disassemble starting at the specified location
744+
/// and offset.
745+
/// An adapter must return exactly this number of instructions - any
746+
/// unavailable instructions should be replaced with an implementation-defined
747+
/// 'invalid instruction' value.
748+
uint32_t instructionCount;
749+
750+
/// If true, the adapter should attempt to resolve memory addresses and other
751+
/// values to symbolic names.
752+
std::optional<bool> resolveSymbols;
753+
};
754+
bool fromJSON(const llvm::json::Value &, DisassembleArguments &,
755+
llvm::json::Path);
756+
llvm::json::Value toJSON(const DisassembleArguments &);
757+
758+
/// Response to `disassemble` request.
759+
struct DisassembleResponseBody {
760+
/// The list of disassembled instructions.
761+
std::vector<DisassembledInstruction> instructions;
762+
};
763+
bool fromJSON(const llvm::json::Value &, DisassembleResponseBody &,
764+
llvm::json::Path);
765+
llvm::json::Value toJSON(const DisassembleResponseBody &);
766+
729767
} // namespace lldb_dap::protocol
730768

731769
#endif

0 commit comments

Comments
 (0)