Skip to content

Commit 3cfe849

Browse files
committed
[lldb-dap] Fix disassemble request instruction offset handling
1 parent 0b4cfd1 commit 3cfe849

File tree

3 files changed

+173
-81
lines changed

3 files changed

+173
-81
lines changed

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ def request_disconnect(self, terminateDebuggee=None):
735735
return self.send_recv(command_dict)
736736

737737
def request_disassemble(
738-
self, memoryReference, offset=-50, instructionCount=200, resolveSymbols=True
738+
self, memoryReference, offset=0, instructionCount=200, resolveSymbols=True
739739
):
740740
args_dict = {
741741
"memoryReference": memoryReference,

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

Lines changed: 163 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,14 @@ namespace lldb_dap {
2626
/// `supportsDisassembleRequest` is true.
2727
llvm::Expected<DisassembleResponseBody>
2828
DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
29-
std::vector<DisassembledInstruction> instructions;
30-
3129
std::optional<lldb::addr_t> addr_opt =
3230
DecodeMemoryReference(args.memoryReference);
3331
if (!addr_opt.has_value())
3432
return llvm::make_error<DAPError>("Malformed memory reference: " +
3533
args.memoryReference);
3634

3735
lldb::addr_t addr_ptr = *addr_opt;
38-
addr_ptr += args.instructionOffset.value_or(0);
36+
addr_ptr += args.offset.value_or(0);
3937
lldb::SBAddress addr(addr_ptr, dap.target);
4038
if (!addr.IsValid())
4139
return llvm::make_error<DAPError>(
@@ -56,100 +54,185 @@ DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
5654
}
5755
}
5856

57+
int64_t instructionOffset = args.instructionOffset.value_or(0);
58+
if (instructionOffset > 0) {
59+
lldb::SBInstructionList forward_insts = dap.target.ReadInstructions(
60+
addr, instructionOffset + 1, flavor_string.c_str());
61+
if (forward_insts.GetSize() != static_cast<size_t>(instructionOffset + 1)) {
62+
return llvm::make_error<DAPError>(
63+
"Failed to disassemble instructions after " +
64+
std::to_string(instructionOffset) +
65+
" instructions from the given address.");
66+
}
67+
68+
addr = forward_insts.GetInstructionAtIndex(instructionOffset).GetAddress();
69+
}
70+
71+
const bool resolve_symbols = args.resolveSymbols.value_or(false);
72+
std::vector<DisassembledInstruction> instructions;
73+
if (instructionOffset < 0)
74+
instructions = disassembleBackwards(addr, std::abs(instructionOffset),
75+
flavor_string.c_str(), resolve_symbols);
76+
77+
const auto instructions_left = args.instructionCount - instructions.size();
5978
lldb::SBInstructionList insts = dap.target.ReadInstructions(
60-
addr, args.instructionCount, flavor_string.c_str());
79+
addr, instructions_left, flavor_string.c_str());
6180

6281
if (!insts.IsValid())
6382
return llvm::make_error<DAPError>(
6483
"Failed to find instructions for memory address.");
6584

66-
const bool resolve_symbols = args.resolveSymbols.value_or(false);
85+
// add the disassembly from the given address forward
6786
const auto num_insts = insts.GetSize();
68-
for (size_t i = 0; i < num_insts; ++i) {
87+
for (size_t i = 0;
88+
i < num_insts && instructions.size() < args.instructionCount; ++i) {
6989
lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
70-
auto addr = inst.GetAddress();
71-
const auto inst_addr = addr.GetLoadAddress(dap.target);
72-
const char *m = inst.GetMnemonic(dap.target);
73-
const char *o = inst.GetOperands(dap.target);
74-
const char *c = inst.GetComment(dap.target);
75-
auto d = inst.GetData(dap.target);
76-
77-
std::string bytes;
78-
llvm::raw_string_ostream sb(bytes);
79-
for (unsigned i = 0; i < inst.GetByteSize(); i++) {
80-
lldb::SBError error;
81-
uint8_t b = d.GetUnsignedInt8(error, i);
82-
if (error.Success()) {
83-
sb << llvm::format("%2.2x ", b);
90+
instructions.push_back(
91+
SBInstructionToDisassembledInstruction(inst, resolve_symbols));
92+
}
93+
94+
// Pad the instructions with invalid instructions if needed.
95+
if (instructions.size() < args.instructionCount)
96+
for (size_t i = instructions.size(); i < args.instructionCount; ++i)
97+
instructions.push_back(GetInvalidInstruction());
98+
99+
return DisassembleResponseBody{std::move(instructions)};
100+
}
101+
102+
std::vector<protocol::DisassembledInstruction>
103+
DisassembleRequestHandler::disassembleBackwards(
104+
lldb::SBAddress &addr, const uint32_t instruction_count,
105+
const char *flavor_string, bool resolve_symbols) const {
106+
std::vector<DisassembledInstruction> instructions;
107+
108+
// TODO: Simply disassemble from `addr` - `instruction_count` *
109+
// `instruction_size` in architectures with a fixed instruction size.
110+
111+
// need to disassemble backwards, let's try from the start of the symbol if
112+
// available.
113+
auto symbol = addr.GetSymbol();
114+
if (symbol.IsValid()) {
115+
// add valid instructions before the current instruction using the symbol.
116+
lldb::SBInstructionList symbol_insts = dap.target.ReadInstructions(
117+
symbol.GetStartAddress(), addr, flavor_string);
118+
if (symbol_insts.IsValid()) {
119+
size_t backwards_insts_start =
120+
symbol_insts.GetSize() >= instruction_count
121+
? symbol_insts.GetSize() - instruction_count
122+
: 0;
123+
for (size_t i = backwards_insts_start;
124+
i < symbol_insts.GetSize() &&
125+
instructions.size() < instruction_count;
126+
++i) {
127+
lldb::SBInstruction inst = symbol_insts.GetInstructionAtIndex(i);
128+
instructions.push_back(
129+
SBInstructionToDisassembledInstruction(inst, resolve_symbols));
84130
}
85131
}
132+
}
86133

87-
DisassembledInstruction disassembled_inst;
88-
disassembled_inst.address = inst_addr;
89-
disassembled_inst.instructionBytes =
90-
bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : "";
91-
92-
std::string instruction;
93-
llvm::raw_string_ostream si(instruction);
94-
95-
lldb::SBSymbol symbol = addr.GetSymbol();
96-
// Only add the symbol on the first line of the function.
97-
if (symbol.IsValid() && symbol.GetStartAddress() == addr) {
98-
// If we have a valid symbol, append it as a label prefix for the first
99-
// instruction. This is so you can see the start of a function/callsite
100-
// in the assembly, at the moment VS Code (1.80) does not visualize the
101-
// symbol associated with the assembly instruction.
102-
si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName()
103-
: symbol.GetName())
104-
<< ": ";
105-
106-
if (resolve_symbols)
107-
disassembled_inst.symbol = symbol.GetDisplayName();
108-
}
134+
// pad the instructions with invalid instructions if needed.
135+
while (instructions.size() < instruction_count) {
136+
instructions.insert(instructions.begin(), GetInvalidInstruction());
137+
}
109138

110-
si << llvm::formatv("{0,7} {1,12}", m, o);
111-
if (c && c[0]) {
112-
si << " ; " << c;
113-
}
139+
return instructions;
140+
}
141+
142+
DisassembledInstruction
143+
DisassembleRequestHandler::SBInstructionToDisassembledInstruction(
144+
lldb::SBInstruction &inst, bool resolve_symbols) const {
145+
if (!inst.IsValid())
146+
return GetInvalidInstruction();
147+
148+
auto addr = inst.GetAddress();
149+
const auto inst_addr = addr.GetLoadAddress(dap.target);
150+
const char *m = inst.GetMnemonic(dap.target);
151+
const char *o = inst.GetOperands(dap.target);
152+
const char *c = inst.GetComment(dap.target);
153+
auto d = inst.GetData(dap.target);
154+
155+
std::string bytes;
156+
llvm::raw_string_ostream sb(bytes);
157+
for (unsigned i = 0; i < inst.GetByteSize(); i++) {
158+
lldb::SBError error;
159+
uint8_t b = d.GetUnsignedInt8(error, i);
160+
if (error.Success())
161+
sb << llvm::format("%2.2x ", b);
162+
}
114163

115-
disassembled_inst.instruction = instruction;
116-
117-
auto line_entry = addr.GetLineEntry();
118-
// If the line number is 0 then the entry represents a compiler generated
119-
// location.
120-
if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
121-
line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
122-
auto source = CreateSource(line_entry);
123-
disassembled_inst.location = std::move(source);
124-
125-
const auto line = line_entry.GetLine();
126-
if (line != 0 && line != LLDB_INVALID_LINE_NUMBER)
127-
disassembled_inst.line = line;
128-
129-
const auto column = line_entry.GetColumn();
130-
if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER)
131-
disassembled_inst.column = column;
132-
133-
auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
134-
if (end_line_entry.IsValid() &&
135-
end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
136-
const auto end_line = end_line_entry.GetLine();
137-
if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER &&
138-
end_line != line) {
139-
disassembled_inst.endLine = end_line;
140-
141-
const auto end_column = end_line_entry.GetColumn();
142-
if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER &&
143-
end_column != column)
144-
disassembled_inst.endColumn = end_column - 1;
145-
}
164+
DisassembledInstruction disassembled_inst;
165+
disassembled_inst.address = inst_addr;
166+
disassembled_inst.instructionBytes =
167+
bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : "";
168+
169+
std::string instruction;
170+
llvm::raw_string_ostream si(instruction);
171+
172+
lldb::SBSymbol symbol = addr.GetSymbol();
173+
// Only add the symbol on the first line of the function.
174+
if (symbol.IsValid() && symbol.GetStartAddress() == addr) {
175+
// If we have a valid symbol, append it as a label prefix for the first
176+
// instruction. This is so you can see the start of a function/callsite
177+
// in the assembly, at the moment VS Code (1.80) does not visualize the
178+
// symbol associated with the assembly instruction.
179+
si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName()
180+
: symbol.GetName())
181+
<< ": ";
182+
183+
if (resolve_symbols)
184+
disassembled_inst.symbol = symbol.GetDisplayName();
185+
}
186+
187+
si << llvm::formatv("{0,7} {1,12}", m, o);
188+
if (c && c[0]) {
189+
si << " ; " << c;
190+
}
191+
192+
disassembled_inst.instruction = std::move(instruction);
193+
194+
auto line_entry = addr.GetLineEntry();
195+
// If the line number is 0 then the entry represents a compiler generated
196+
// location.
197+
198+
if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
199+
line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
200+
auto source = CreateSource(line_entry);
201+
disassembled_inst.location = std::move(source);
202+
203+
const auto line = line_entry.GetLine();
204+
if (line != 0 && line != LLDB_INVALID_LINE_NUMBER)
205+
disassembled_inst.line = line;
206+
207+
const auto column = line_entry.GetColumn();
208+
if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER)
209+
disassembled_inst.column = column;
210+
211+
auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
212+
if (end_line_entry.IsValid() &&
213+
end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
214+
const auto end_line = end_line_entry.GetLine();
215+
if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER &&
216+
end_line != line) {
217+
disassembled_inst.endLine = end_line;
218+
219+
const auto end_column = end_line_entry.GetColumn();
220+
if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER &&
221+
end_column != column)
222+
disassembled_inst.endColumn = end_column - 1;
146223
}
147224
}
148-
149-
instructions.push_back(std::move(disassembled_inst));
150225
}
151226

152-
return DisassembleResponseBody{std::move(instructions)};
227+
return disassembled_inst;
228+
}
229+
230+
DisassembledInstruction
231+
DisassembleRequestHandler::GetInvalidInstruction() const {
232+
DisassembledInstruction invalid_inst;
233+
invalid_inst.presentationHint =
234+
DisassembledInstruction::eDisassembledInstructionPresentationHintInvalid;
235+
return invalid_inst;
153236
}
154237

155238
} // namespace lldb_dap

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "Protocol/ProtocolBase.h"
1616
#include "Protocol/ProtocolRequests.h"
1717
#include "Protocol/ProtocolTypes.h"
18+
#include "lldb/API/SBAddress.h"
1819
#include "llvm/ADT/DenseSet.h"
1920
#include "llvm/ADT/StringRef.h"
2021
#include "llvm/Support/Error.h"
@@ -545,6 +546,14 @@ class DisassembleRequestHandler final
545546
}
546547
llvm::Expected<protocol::DisassembleResponseBody>
547548
Run(const protocol::DisassembleArguments &args) const override;
549+
550+
std::vector<protocol::DisassembledInstruction>
551+
disassembleBackwards(lldb::SBAddress &addr, const uint32_t instruction_count,
552+
const char *flavor_string, bool resolve_symbols) const;
553+
protocol::DisassembledInstruction
554+
SBInstructionToDisassembledInstruction(lldb::SBInstruction &inst,
555+
bool resolve_symbols) const;
556+
protocol::DisassembledInstruction GetInvalidInstruction() const;
548557
};
549558

550559
class ReadMemoryRequestHandler : public LegacyRequestHandler {

0 commit comments

Comments
 (0)