Skip to content

Commit 1014235

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

File tree

6 files changed

+193
-140
lines changed

6 files changed

+193
-140
lines changed

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

Lines changed: 46 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -9,113 +9,34 @@
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
24+
/// `supportsDisassembleRequest` is true.
25+
llvm::Expected<DisassembleResponseBody>
26+
DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
27+
std::vector<DisassembledInstruction> instructions;
10728

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-
}
29+
auto addr_opt = DecodeMemoryReference(args.memoryReference);
30+
if (!addr_opt.has_value())
31+
return llvm::make_error<DAPError>("Malformed memory reference: " +
32+
args.memoryReference);
11633

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

12041
std::string flavor_string;
12142
const auto target_triple = llvm::StringRef(dap.target.GetTriple());
@@ -132,19 +53,14 @@ void DisassembleRequestHandler::operator()(
13253
}
13354
}
13455

135-
lldb::SBInstructionList insts =
136-
dap.target.ReadInstructions(addr, inst_count, flavor_string.c_str());
56+
lldb::SBInstructionList insts = dap.target.ReadInstructions(
57+
addr, args.instructionCount, flavor_string.c_str());
13758

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

145-
const bool resolveSymbols =
146-
GetBoolean(arguments, "resolveSymbols").value_or(false);
147-
llvm::json::Array instructions;
63+
const bool resolveSymbols = args.resolveSymbols.value_or(false);
14864
const auto num_insts = insts.GetSize();
14965
for (size_t i = 0; i < num_insts; ++i) {
15066
lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
@@ -165,11 +81,10 @@ void DisassembleRequestHandler::operator()(
16581
}
16682
}
16783

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-
};
84+
DisassembledInstruction disassembled_inst;
85+
disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr);
86+
disassembled_inst.instructionBytes =
87+
bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : "";
17388

17489
std::string instruction;
17590
llvm::raw_string_ostream si(instruction);
@@ -185,59 +100,53 @@ void DisassembleRequestHandler::operator()(
185100
: symbol.GetName())
186101
<< ": ";
187102

188-
if (resolveSymbols) {
189-
disassembled_inst.try_emplace("symbol", symbol.GetDisplayName());
190-
}
103+
if (resolveSymbols)
104+
disassembled_inst.symbol = symbol.GetDisplayName();
191105
}
192106

193107
si << llvm::formatv("{0,7} {1,12}", m, o);
194108
if (c && c[0]) {
195109
si << " ; " << c;
196110
}
197111

198-
disassembled_inst.try_emplace("instruction", instruction);
112+
disassembled_inst.instruction = instruction;
199113

200114
auto line_entry = addr.GetLineEntry();
201115
// If the line number is 0 then the entry represents a compiler generated
202116
// location.
203117
if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
204118
line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
205119
auto source = CreateSource(line_entry);
206-
disassembled_inst.try_emplace("location", source);
120+
disassembled_inst.location = std::move(source);
207121

208122
const auto line = line_entry.GetLine();
209-
if (line && line != LLDB_INVALID_LINE_NUMBER) {
210-
disassembled_inst.try_emplace("line", line);
211-
}
123+
if (line != 0 && line != LLDB_INVALID_LINE_NUMBER)
124+
disassembled_inst.line = line;
125+
212126
const auto column = line_entry.GetColumn();
213-
if (column && column != LLDB_INVALID_COLUMN_NUMBER) {
214-
disassembled_inst.try_emplace("column", column);
215-
}
127+
if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER)
128+
disassembled_inst.column = column;
216129

217130
auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
218131
if (end_line_entry.IsValid() &&
219132
end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
220133
const auto end_line = end_line_entry.GetLine();
221-
if (end_line && end_line != LLDB_INVALID_LINE_NUMBER &&
134+
if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER &&
222135
end_line != line) {
223-
disassembled_inst.try_emplace("endLine", end_line);
136+
disassembled_inst.endLine = end_line;
224137

225138
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-
}
139+
if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER &&
140+
end_column != column)
141+
disassembled_inst.endColumn = end_column - 1;
230142
}
231143
}
232144
}
233145

234-
instructions.emplace_back(std::move(disassembled_inst));
146+
instructions.push_back(std::move(disassembled_inst));
235147
}
236148

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)));
149+
return DisassembleResponseBody{std::move(instructions)};
241150
}
242151

243152
} // 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: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,41 @@ 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+
757+
/// Response to `disassemble` request.
758+
struct DisassembleResponseBody {
759+
/// The list of disassembled instructions.
760+
std::vector<DisassembledInstruction> instructions;
761+
};
762+
llvm::json::Value toJSON(const DisassembleResponseBody &);
763+
729764
} // namespace lldb_dap::protocol
730765

731766
#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)