Skip to content

Commit 0f33f54

Browse files
committed
[lldb-dap] Refactor remaining request handlers (NFC)
1 parent e1f4611 commit 0f33f54

13 files changed

+1525
-1334
lines changed

lldb/tools/lldb-dap/CMakeLists.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,34 @@ add_lldb_tool(lldb-dap
4444
Handler/ConfigurationDoneRequestHandler.cpp
4545
Handler/ContinueRequestHandler.cpp
4646
Handler/DataBreakpointInfoRequestHandler.cpp
47+
Handler/DisassembleRequestHandler.cpp
4748
Handler/DisconnectRequestHandler.cpp
4849
Handler/EvaluateRequestHandler.cpp
4950
Handler/ExceptionInfoRequestHandler.cpp
5051
Handler/InitializeRequestHandler.cpp
5152
Handler/LaunchRequestHandler.cpp
53+
Handler/LocationsRequestHandler.cpp
5254
Handler/ModulesRequestHandler.cpp
5355
Handler/NextRequestHandler.cpp
56+
Handler/PauseRequestHandler.cpp
57+
Handler/ReadMemoryRequestHandler.cpp
5458
Handler/RequestHandler.cpp
5559
Handler/RestartRequestHandler.cpp
60+
Handler/ScopesRequestHandler.cpp
5661
Handler/SetBreakpointsRequestHandler.cpp
5762
Handler/SetDataBreakpointsRequestHandler.cpp
5863
Handler/SetExceptionBreakpointsRequestHandler.cpp
5964
Handler/SetFunctionBreakpointsRequestHandler.cpp
60-
Handler/SetInstructionBreakpointsRequestHandler.cpp Handler/StepOutRequestHandler.cpp
65+
Handler/SetInstructionBreakpointsRequestHandler.cpp
66+
Handler/SetVariableRequestHandler.cpp
67+
Handler/SourceRequestHandler.cpp
68+
Handler/StackTraceRequestHandler.cpp
6169
Handler/StepInRequestHandler.cpp
6270
Handler/StepInTargetsRequestHandler.cpp
71+
Handler/StepOutRequestHandler.cpp
6372
Handler/TestGetTargetBreakpointsRequestHandler.cpp
73+
Handler/ThreadsRequestHandler.cpp
74+
Handler/VariablesRequestHandler.cpp
6475

6576
LINK_LIBS
6677
liblldb
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
//===-- DisassembleRequestHandler.cpp -------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "DAP.h"
10+
#include "EventHelper.h"
11+
#include "JSONUtils.h"
12+
#include "RequestHandler.h"
13+
#include "lldb/API/SBInstruction.h"
14+
#include "llvm/ADT/StringExtras.h"
15+
16+
namespace lldb_dap {
17+
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()(const llvm::json::Object &request) {
91+
llvm::json::Object response;
92+
FillResponse(request, response);
93+
auto *arguments = request.getObject("arguments");
94+
95+
llvm::StringRef memoryReference = GetString(arguments, "memoryReference");
96+
auto addr_opt = DecodeMemoryReference(memoryReference);
97+
if (!addr_opt.has_value()) {
98+
response["success"] = false;
99+
response["message"] =
100+
"Malformed memory reference: " + memoryReference.str();
101+
dap.SendJSON(llvm::json::Value(std::move(response)));
102+
return;
103+
}
104+
lldb::addr_t addr_ptr = *addr_opt;
105+
106+
addr_ptr += GetSigned(arguments, "instructionOffset", 0);
107+
lldb::SBAddress addr(addr_ptr, dap.target);
108+
if (!addr.IsValid()) {
109+
response["success"] = false;
110+
response["message"] = "Memory reference not found in the current binary.";
111+
dap.SendJSON(llvm::json::Value(std::move(response)));
112+
return;
113+
}
114+
115+
const auto inst_count = GetUnsigned(arguments, "instructionCount", 0);
116+
lldb::SBInstructionList insts = dap.target.ReadInstructions(addr, inst_count);
117+
118+
if (!insts.IsValid()) {
119+
response["success"] = false;
120+
response["message"] = "Failed to find instructions for memory address.";
121+
dap.SendJSON(llvm::json::Value(std::move(response)));
122+
return;
123+
}
124+
125+
const bool resolveSymbols = GetBoolean(arguments, "resolveSymbols", false);
126+
llvm::json::Array instructions;
127+
const auto num_insts = insts.GetSize();
128+
for (size_t i = 0; i < num_insts; ++i) {
129+
lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
130+
auto addr = inst.GetAddress();
131+
const auto inst_addr = addr.GetLoadAddress(dap.target);
132+
const char *m = inst.GetMnemonic(dap.target);
133+
const char *o = inst.GetOperands(dap.target);
134+
const char *c = inst.GetComment(dap.target);
135+
auto d = inst.GetData(dap.target);
136+
137+
std::string bytes;
138+
llvm::raw_string_ostream sb(bytes);
139+
for (unsigned i = 0; i < inst.GetByteSize(); i++) {
140+
lldb::SBError error;
141+
uint8_t b = d.GetUnsignedInt8(error, i);
142+
if (error.Success()) {
143+
sb << llvm::format("%2.2x ", b);
144+
}
145+
}
146+
147+
llvm::json::Object disassembled_inst{
148+
{"address", "0x" + llvm::utohexstr(inst_addr)},
149+
{"instructionBytes",
150+
bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""},
151+
};
152+
153+
std::string instruction;
154+
llvm::raw_string_ostream si(instruction);
155+
156+
lldb::SBSymbol symbol = addr.GetSymbol();
157+
// Only add the symbol on the first line of the function.
158+
if (symbol.IsValid() && symbol.GetStartAddress() == addr) {
159+
// If we have a valid symbol, append it as a label prefix for the first
160+
// instruction. This is so you can see the start of a function/callsite
161+
// in the assembly, at the moment VS Code (1.80) does not visualize the
162+
// symbol associated with the assembly instruction.
163+
si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName()
164+
: symbol.GetName())
165+
<< ": ";
166+
167+
if (resolveSymbols) {
168+
disassembled_inst.try_emplace("symbol", symbol.GetDisplayName());
169+
}
170+
}
171+
172+
si << llvm::formatv("{0,7} {1,12}", m, o);
173+
if (c && c[0]) {
174+
si << " ; " << c;
175+
}
176+
177+
disassembled_inst.try_emplace("instruction", instruction);
178+
179+
auto line_entry = addr.GetLineEntry();
180+
// If the line number is 0 then the entry represents a compiler generated
181+
// location.
182+
if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
183+
line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
184+
auto source = CreateSource(line_entry);
185+
disassembled_inst.try_emplace("location", source);
186+
187+
const auto line = line_entry.GetLine();
188+
if (line && line != LLDB_INVALID_LINE_NUMBER) {
189+
disassembled_inst.try_emplace("line", line);
190+
}
191+
const auto column = line_entry.GetColumn();
192+
if (column && column != LLDB_INVALID_COLUMN_NUMBER) {
193+
disassembled_inst.try_emplace("column", column);
194+
}
195+
196+
auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
197+
if (end_line_entry.IsValid() &&
198+
end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
199+
const auto end_line = end_line_entry.GetLine();
200+
if (end_line && end_line != LLDB_INVALID_LINE_NUMBER &&
201+
end_line != line) {
202+
disassembled_inst.try_emplace("endLine", end_line);
203+
204+
const auto end_column = end_line_entry.GetColumn();
205+
if (end_column && end_column != LLDB_INVALID_COLUMN_NUMBER &&
206+
end_column != column) {
207+
disassembled_inst.try_emplace("endColumn", end_column - 1);
208+
}
209+
}
210+
}
211+
}
212+
213+
instructions.emplace_back(std::move(disassembled_inst));
214+
}
215+
216+
llvm::json::Object body;
217+
body.try_emplace("instructions", std::move(instructions));
218+
response.try_emplace("body", std::move(body));
219+
dap.SendJSON(llvm::json::Value(std::move(response)));
220+
}
221+
222+
} // namespace lldb_dap

0 commit comments

Comments
 (0)