Skip to content

Commit b187a83

Browse files
committed
[lldb-dap] Migrate disassemble request to structured handler
1 parent 3360a23 commit b187a83

File tree

6 files changed

+179
-140
lines changed

6 files changed

+179
-140
lines changed

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

Lines changed: 39 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -9,113 +9,30 @@
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"
1416
#include "llvm/ADT/StringExtras.h"
1517

18+
using namespace lldb_dap::protocol;
19+
1620
namespace lldb_dap {
1721

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;
22+
/// Disassembles code stored at the provided location.
23+
/// Clients should only call this request if the corresponding capability `supportsDisassembleRequest` is true.
24+
llvm::Expected<DisassembleResponseBody> DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
25+
std::vector<DisassembledInstruction> instructions;
10726

108-
addr_ptr += GetInteger<int64_t>(arguments, "instructionOffset").value_or(0);
27+
auto addr_opt = DecodeMemoryReference(args.memoryReference);
28+
if (!addr_opt.has_value())
29+
return llvm::make_error<DAPError>("Malformed memory reference: " + args.memoryReference);
30+
31+
lldb::addr_t addr_ptr = *addr_opt;
32+
addr_ptr += args.instructionOffset.value_or(0);
10933
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-
}
116-
117-
const auto inst_count =
118-
GetInteger<int64_t>(arguments, "instructionCount").value_or(0);
34+
if (!addr.IsValid())
35+
return llvm::make_error<DAPError>("Memory reference not found in the current binary.");
11936

12037
std::string flavor_string;
12138
const auto target_triple = llvm::StringRef(dap.target.GetTriple());
@@ -133,18 +50,12 @@ void DisassembleRequestHandler::operator()(
13350
}
13451

13552
lldb::SBInstructionList insts =
136-
dap.target.ReadInstructions(addr, inst_count, flavor_string.c_str());
53+
dap.target.ReadInstructions(addr, args.instructionCount, flavor_string.c_str());
13754

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-
}
55+
if (!insts.IsValid())
56+
return llvm::make_error<DAPError>("Failed to find instructions for memory address.");
14457

145-
const bool resolveSymbols =
146-
GetBoolean(arguments, "resolveSymbols").value_or(false);
147-
llvm::json::Array instructions;
58+
const bool resolveSymbols = args.resolveSymbols.value_or(false);
14859
const auto num_insts = insts.GetSize();
14960
for (size_t i = 0; i < num_insts; ++i) {
15061
lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
@@ -165,11 +76,9 @@ void DisassembleRequestHandler::operator()(
16576
}
16677
}
16778

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-
};
79+
DisassembledInstruction disassembled_inst;
80+
disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr);
81+
disassembled_inst.instructionBytes = bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : "";
17382

17483
std::string instruction;
17584
llvm::raw_string_ostream si(instruction);
@@ -185,59 +94,52 @@ void DisassembleRequestHandler::operator()(
18594
: symbol.GetName())
18695
<< ": ";
18796

188-
if (resolveSymbols) {
189-
disassembled_inst.try_emplace("symbol", symbol.GetDisplayName());
190-
}
97+
if (resolveSymbols)
98+
disassembled_inst.symbol = symbol.GetDisplayName();
19199
}
192100

193101
si << llvm::formatv("{0,7} {1,12}", m, o);
194102
if (c && c[0]) {
195103
si << " ; " << c;
196104
}
197105

198-
disassembled_inst.try_emplace("instruction", instruction);
106+
disassembled_inst.instruction = instruction;
199107

200108
auto line_entry = addr.GetLineEntry();
201109
// If the line number is 0 then the entry represents a compiler generated
202110
// location.
203111
if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
204112
line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
205113
auto source = CreateSource(line_entry);
206-
disassembled_inst.try_emplace("location", source);
114+
disassembled_inst.location = std::move(source);
207115

208116
const auto line = line_entry.GetLine();
209-
if (line && line != LLDB_INVALID_LINE_NUMBER) {
210-
disassembled_inst.try_emplace("line", line);
211-
}
117+
if (line != 0 && line != LLDB_INVALID_LINE_NUMBER)
118+
disassembled_inst.line = line;
119+
212120
const auto column = line_entry.GetColumn();
213-
if (column && column != LLDB_INVALID_COLUMN_NUMBER) {
214-
disassembled_inst.try_emplace("column", column);
215-
}
121+
if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER)
122+
disassembled_inst.column = column;
216123

217124
auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
218125
if (end_line_entry.IsValid() &&
219126
end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
220127
const auto end_line = end_line_entry.GetLine();
221-
if (end_line && end_line != LLDB_INVALID_LINE_NUMBER &&
222-
end_line != line) {
223-
disassembled_inst.try_emplace("endLine", end_line);
128+
if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER && end_line != line) {
129+
disassembled_inst.endLine = end_line;
224130

225131
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-
}
132+
if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER &&
133+
end_column != column)
134+
disassembled_inst.endColumn = end_column - 1;
230135
}
231136
}
232137
}
233138

234-
instructions.emplace_back(std::move(disassembled_inst));
139+
instructions.push_back(std::move(disassembled_inst));
235140
}
236141

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)));
142+
return DisassembleResponseBody{std::move(instructions)};
241143
}
242144

243145
} // namespace lldb_dap

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,14 +534,15 @@ 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 : public RequestHandler<protocol::DisassembleArguments, llvm::Expected<protocol::DisassembleResponseBody>> {
538538
public:
539-
using LegacyRequestHandler::LegacyRequestHandler;
539+
using RequestHandler::RequestHandler;
540540
static llvm::StringLiteral GetCommand() { return "disassemble"; }
541541
FeatureSet GetSupportedFeatures() const override {
542542
return {protocol::eAdapterFeatureDisassembleRequest};
543543
}
544-
void operator()(const llvm::json::Object &request) const override;
544+
llvm::Expected<protocol::DisassembleResponseBody>
545+
Run(const protocol::DisassembleArguments &args) const override;
545546
};
546547

547548
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: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,37 @@ 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 disassemble.
732+
std::string memoryReference;
733+
734+
/// Offset (in bytes) to be applied to the reference location before disassembling. Can be negative.
735+
std::optional<int64_t> offset;
736+
737+
/// Offset (in instructions) to be applied after the byte offset (if any) before disassembling. Can be negative.
738+
std::optional<int64_t> instructionOffset;
739+
740+
/// Number of instructions to disassemble starting at the specified location
741+
/// and offset.
742+
/// An adapter must return exactly this number of instructions - any
743+
/// unavailable instructions should be replaced with an implementation-defined
744+
/// 'invalid instruction' value.
745+
uint32_t instructionCount;
746+
747+
/// If true, the adapter should attempt to resolve memory addresses and other values to symbolic names.
748+
std::optional<bool> resolveSymbols;
749+
};
750+
bool fromJSON(const llvm::json::Value &, DisassembleArguments &,
751+
llvm::json::Path);
752+
753+
/// Response to `disassemble` request.
754+
struct DisassembleResponseBody {
755+
/// The list of disassembled instructions.
756+
std::vector<DisassembledInstruction> instructions;
757+
};
758+
llvm::json::Value toJSON(const DisassembleResponseBody &);
759+
729760
} // namespace lldb_dap::protocol
730761

731762
#endif

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,4 +782,38 @@ bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB,
782782
O.mapOptional("mode", IB.mode);
783783
}
784784

785+
llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &PH) {
786+
switch (PH) {
787+
case DisassembledInstruction::eSourcePresentationHintNormal:
788+
return "normal";
789+
case DisassembledInstruction::eSourcePresentationHintInvalid:
790+
return "invalid";
791+
}
792+
llvm_unreachable("unhandled presentation hint.");
793+
}
794+
795+
llvm::json::Value toJSON(const DisassembledInstruction &DI) {
796+
llvm::json::Object result{{"address", DI.address},
797+
{"instruction", DI.instruction}};
798+
799+
if (DI.instructionBytes)
800+
result.insert({"instructionBytes", *DI.instructionBytes});
801+
if (DI.symbol)
802+
result.insert({"symbol", *DI.symbol});
803+
if (DI.location)
804+
result.insert({"location", *DI.location});
805+
if (DI.line)
806+
result.insert({"line", *DI.line});
807+
if (DI.column)
808+
result.insert({"column", *DI.column});
809+
if (DI.endLine)
810+
result.insert({"endLine", *DI.endLine});
811+
if (DI.endColumn)
812+
result.insert({"endColumn", *DI.endColumn});
813+
if (DI.presentationHint)
814+
result.insert({"presentationHint", *DI.presentationHint});
815+
816+
return result;
817+
}
818+
785819
} // namespace lldb_dap::protocol

0 commit comments

Comments
 (0)