Skip to content

Commit cf7600d

Browse files
committed
[lldb-dap] Fix disassemble request instruction offset handling
1 parent 1014235 commit cf7600d

File tree

2 files changed

+155
-81
lines changed

2 files changed

+155
-81
lines changed

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

Lines changed: 151 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,14 @@ namespace lldb_dap {
2424
/// `supportsDisassembleRequest` is true.
2525
llvm::Expected<DisassembleResponseBody>
2626
DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
27-
std::vector<DisassembledInstruction> instructions;
28-
2927
auto addr_opt = DecodeMemoryReference(args.memoryReference);
3028
if (!addr_opt.has_value())
3129
return llvm::make_error<DAPError>("Malformed memory reference: " +
3230
args.memoryReference);
3331

3432
lldb::addr_t addr_ptr = *addr_opt;
35-
addr_ptr += args.instructionOffset.value_or(0);
33+
addr_ptr += args.offset.value_or(0);
34+
3635
lldb::SBAddress addr(addr_ptr, dap.target);
3736
if (!addr.IsValid())
3837
return llvm::make_error<DAPError>(
@@ -53,100 +52,171 @@ DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
5352
}
5453
}
5554

56-
lldb::SBInstructionList insts = dap.target.ReadInstructions(
57-
addr, args.instructionCount, flavor_string.c_str());
55+
int64_t instructionOffset = args.instructionOffset.value_or(0);
56+
if (instructionOffset > 0) {
57+
lldb::SBInstructionList forward_insts = dap.target.ReadInstructions(
58+
addr, instructionOffset + 1, flavor_string.c_str());
59+
if (forward_insts.GetSize() != static_cast<size_t>(instructionOffset + 1)) {
60+
return llvm::make_error<DAPError>(
61+
"Failed to disassemble instructions after " +
62+
std::to_string(instructionOffset) +
63+
" instructions from the given address.");
64+
}
5865

66+
addr = forward_insts.GetInstructionAtIndex(instructionOffset).GetAddress();
67+
}
68+
69+
const bool resolveSymbols = args.resolveSymbols.value_or(false);
70+
std::vector<DisassembledInstruction> instructions;
71+
if (instructionOffset < 0) {
72+
// need to disassemble backwards, let's try from the start of the symbol if
73+
// available.
74+
size_t number_of_insts_before = std::abs(instructionOffset);
75+
auto symbol = addr.GetSymbol();
76+
if (symbol.IsValid()) {
77+
// add valid instructions before the current instruction using the symbol.
78+
lldb::SBInstructionList symbol_insts = dap.target.ReadInstructions(
79+
symbol.GetStartAddress(), addr, flavor_string.c_str());
80+
if (symbol_insts.IsValid()) {
81+
size_t backwards_insts_start =
82+
symbol_insts.GetSize() >= number_of_insts_before
83+
? symbol_insts.GetSize() - number_of_insts_before
84+
: 0;
85+
for (size_t i = backwards_insts_start;
86+
i < symbol_insts.GetSize() &&
87+
instructions.size() < args.instructionCount;
88+
++i) {
89+
lldb::SBInstruction inst = symbol_insts.GetInstructionAtIndex(i);
90+
instructions.push_back(
91+
SBInstructionToDisassembledInstruction(inst, resolveSymbols));
92+
--number_of_insts_before;
93+
}
94+
}
95+
}
96+
97+
// pad the instructions with invalid instructions if needed.
98+
for (size_t i = 0; i < number_of_insts_before &&
99+
instructions.size() < args.instructionCount;
100+
++i) {
101+
DisassembledInstruction invalid_inst;
102+
invalid_inst.presentationHint =
103+
DisassembledInstruction::eSourcePresentationHintInvalid;
104+
instructions.insert(instructions.begin(), std::move(invalid_inst));
105+
}
106+
}
107+
108+
const auto instructions_left = args.instructionCount - instructions.size();
109+
lldb::SBInstructionList insts = dap.target.ReadInstructions(
110+
addr, instructions_left, flavor_string.c_str());
59111
if (!insts.IsValid())
60112
return llvm::make_error<DAPError>(
61113
"Failed to find instructions for memory address.");
62114

63-
const bool resolveSymbols = args.resolveSymbols.value_or(false);
115+
// add the disassembly from the given address forward
64116
const auto num_insts = insts.GetSize();
65-
for (size_t i = 0; i < num_insts; ++i) {
117+
for (size_t i = 0;
118+
i < num_insts && instructions.size() < args.instructionCount; ++i) {
66119
lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
67-
auto addr = inst.GetAddress();
68-
const auto inst_addr = addr.GetLoadAddress(dap.target);
69-
const char *m = inst.GetMnemonic(dap.target);
70-
const char *o = inst.GetOperands(dap.target);
71-
const char *c = inst.GetComment(dap.target);
72-
auto d = inst.GetData(dap.target);
73-
74-
std::string bytes;
75-
llvm::raw_string_ostream sb(bytes);
76-
for (unsigned i = 0; i < inst.GetByteSize(); i++) {
77-
lldb::SBError error;
78-
uint8_t b = d.GetUnsignedInt8(error, i);
79-
if (error.Success()) {
80-
sb << llvm::format("%2.2x ", b);
81-
}
82-
}
120+
instructions.push_back(
121+
SBInstructionToDisassembledInstruction(inst, resolveSymbols));
122+
}
83123

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) : "";
88-
89-
std::string instruction;
90-
llvm::raw_string_ostream si(instruction);
91-
92-
lldb::SBSymbol symbol = addr.GetSymbol();
93-
// Only add the symbol on the first line of the function.
94-
if (symbol.IsValid() && symbol.GetStartAddress() == addr) {
95-
// If we have a valid symbol, append it as a label prefix for the first
96-
// instruction. This is so you can see the start of a function/callsite
97-
// in the assembly, at the moment VS Code (1.80) does not visualize the
98-
// symbol associated with the assembly instruction.
99-
si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName()
100-
: symbol.GetName())
101-
<< ": ";
102-
103-
if (resolveSymbols)
104-
disassembled_inst.symbol = symbol.GetDisplayName();
124+
// Pad the instructions with invalid instructions if needed.
125+
if (instructions.size() < args.instructionCount) {
126+
for (size_t i = instructions.size(); i < args.instructionCount; ++i) {
127+
DisassembledInstruction invalid_inst;
128+
invalid_inst.presentationHint =
129+
DisassembledInstruction::eSourcePresentationHintInvalid;
130+
instructions.push_back(std::move(invalid_inst));
105131
}
132+
}
133+
134+
return DisassembleResponseBody{std::move(instructions)};
135+
}
106136

107-
si << llvm::formatv("{0,7} {1,12}", m, o);
108-
if (c && c[0]) {
109-
si << " ; " << c;
137+
DisassembledInstruction
138+
DisassembleRequestHandler::SBInstructionToDisassembledInstruction(
139+
lldb::SBInstruction &inst, bool resolveSymbols) const {
140+
auto addr = inst.GetAddress();
141+
const auto inst_addr = addr.GetLoadAddress(dap.target);
142+
const char *m = inst.GetMnemonic(dap.target);
143+
const char *o = inst.GetOperands(dap.target);
144+
const char *c = inst.GetComment(dap.target);
145+
auto d = inst.GetData(dap.target);
146+
147+
std::string bytes;
148+
llvm::raw_string_ostream sb(bytes);
149+
for (unsigned i = 0; i < inst.GetByteSize(); i++) {
150+
lldb::SBError error;
151+
uint8_t b = d.GetUnsignedInt8(error, i);
152+
if (error.Success()) {
153+
sb << llvm::format("%2.2x ", b);
110154
}
155+
}
111156

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

149-
return DisassembleResponseBody{std::move(instructions)};
219+
return disassembled_inst;
150220
}
151221

152222
} // namespace lldb_dap

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,10 @@ class DisassembleRequestHandler final
545545
}
546546
llvm::Expected<protocol::DisassembleResponseBody>
547547
Run(const protocol::DisassembleArguments &args) const override;
548+
549+
protocol::DisassembledInstruction
550+
SBInstructionToDisassembledInstruction(lldb::SBInstruction &inst,
551+
bool resolveSymbols) const;
548552
};
549553

550554
class ReadMemoryRequestHandler : public LegacyRequestHandler {

0 commit comments

Comments
 (0)