[Lldb-commits] [lldb] [lldb-dap] fix disassembly request instruction offset handling (PR #140486)
Ely Ronnen via lldb-commits
lldb-commits at lists.llvm.org
Sun May 18 16:55:22 PDT 2025
https://github.com/eronnen created https://github.com/llvm/llvm-project/pull/140486
None
>From 1014235896b79eb4ea05a6822714a66adaa691ac Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Sun, 18 May 2025 23:51:58 +0200
Subject: [PATCH 1/2] [lldb-dap] Migrate disassemble request to structured
handler
---
.../Handler/DisassembleRequestHandler.cpp | 183 +++++-------------
lldb/tools/lldb-dap/Handler/RequestHandler.h | 9 +-
.../lldb-dap/Protocol/ProtocolRequests.cpp | 18 ++
.../lldb-dap/Protocol/ProtocolRequests.h | 35 ++++
.../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 34 ++++
lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 54 ++++++
6 files changed, 193 insertions(+), 140 deletions(-)
diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
index d738f54ff1a9f..938078947259b 100644
--- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -9,113 +9,34 @@
#include "DAP.h"
#include "EventHelper.h"
#include "JSONUtils.h"
+#include "Protocol/ProtocolRequests.h"
+#include "Protocol/ProtocolTypes.h"
#include "RequestHandler.h"
#include "lldb/API/SBInstruction.h"
#include "llvm/ADT/StringExtras.h"
+using namespace lldb_dap::protocol;
+
namespace lldb_dap {
-// "DisassembleRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "Disassembles code stored at the provided
-// location.\nClients should only call this request if the corresponding
-// capability `supportsDisassembleRequest` is true.", "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "disassemble" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/DisassembleArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "DisassembleArguments": {
-// "type": "object",
-// "description": "Arguments for `disassemble` request.",
-// "properties": {
-// "memoryReference": {
-// "type": "string",
-// "description": "Memory reference to the base location containing the
-// instructions to disassemble."
-// },
-// "offset": {
-// "type": "integer",
-// "description": "Offset (in bytes) to be applied to the reference
-// location before disassembling. Can be negative."
-// },
-// "instructionOffset": {
-// "type": "integer",
-// "description": "Offset (in instructions) to be applied after the byte
-// offset (if any) before disassembling. Can be negative."
-// },
-// "instructionCount": {
-// "type": "integer",
-// "description": "Number of instructions to disassemble starting at the
-// specified location and offset.\nAn adapter must return exactly this
-// number of instructions - any unavailable instructions should be
-// replaced with an implementation-defined 'invalid instruction' value."
-// },
-// "resolveSymbols": {
-// "type": "boolean",
-// "description": "If true, the adapter should attempt to resolve memory
-// addresses and other values to symbolic names."
-// }
-// },
-// "required": [ "memoryReference", "instructionCount" ]
-// },
-// "DisassembleResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to `disassemble` request.",
-// "properties": {
-// "body": {
-// "type": "object",
-// "properties": {
-// "instructions": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/DisassembledInstruction"
-// },
-// "description": "The list of disassembled instructions."
-// }
-// },
-// "required": [ "instructions" ]
-// }
-// }
-// }]
-// }
-void DisassembleRequestHandler::operator()(
- const llvm::json::Object &request) const {
- llvm::json::Object response;
- FillResponse(request, response);
- auto *arguments = request.getObject("arguments");
-
- llvm::StringRef memoryReference =
- GetString(arguments, "memoryReference").value_or("");
- auto addr_opt = DecodeMemoryReference(memoryReference);
- if (!addr_opt.has_value()) {
- response["success"] = false;
- response["message"] =
- "Malformed memory reference: " + memoryReference.str();
- dap.SendJSON(llvm::json::Value(std::move(response)));
- return;
- }
- lldb::addr_t addr_ptr = *addr_opt;
+/// Disassembles code stored at the provided location.
+/// Clients should only call this request if the corresponding capability
+/// `supportsDisassembleRequest` is true.
+llvm::Expected<DisassembleResponseBody>
+DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
+ std::vector<DisassembledInstruction> instructions;
- addr_ptr += GetInteger<int64_t>(arguments, "instructionOffset").value_or(0);
- lldb::SBAddress addr(addr_ptr, dap.target);
- if (!addr.IsValid()) {
- response["success"] = false;
- response["message"] = "Memory reference not found in the current binary.";
- dap.SendJSON(llvm::json::Value(std::move(response)));
- return;
- }
+ auto addr_opt = DecodeMemoryReference(args.memoryReference);
+ if (!addr_opt.has_value())
+ return llvm::make_error<DAPError>("Malformed memory reference: " +
+ args.memoryReference);
- const auto inst_count =
- GetInteger<int64_t>(arguments, "instructionCount").value_or(0);
+ lldb::addr_t addr_ptr = *addr_opt;
+ addr_ptr += args.instructionOffset.value_or(0);
+ lldb::SBAddress addr(addr_ptr, dap.target);
+ if (!addr.IsValid())
+ return llvm::make_error<DAPError>(
+ "Memory reference not found in the current binary.");
std::string flavor_string;
const auto target_triple = llvm::StringRef(dap.target.GetTriple());
@@ -132,19 +53,14 @@ void DisassembleRequestHandler::operator()(
}
}
- lldb::SBInstructionList insts =
- dap.target.ReadInstructions(addr, inst_count, flavor_string.c_str());
+ lldb::SBInstructionList insts = dap.target.ReadInstructions(
+ addr, args.instructionCount, flavor_string.c_str());
- if (!insts.IsValid()) {
- response["success"] = false;
- response["message"] = "Failed to find instructions for memory address.";
- dap.SendJSON(llvm::json::Value(std::move(response)));
- return;
- }
+ if (!insts.IsValid())
+ return llvm::make_error<DAPError>(
+ "Failed to find instructions for memory address.");
- const bool resolveSymbols =
- GetBoolean(arguments, "resolveSymbols").value_or(false);
- llvm::json::Array instructions;
+ const bool resolveSymbols = args.resolveSymbols.value_or(false);
const auto num_insts = insts.GetSize();
for (size_t i = 0; i < num_insts; ++i) {
lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
@@ -165,11 +81,10 @@ void DisassembleRequestHandler::operator()(
}
}
- llvm::json::Object disassembled_inst{
- {"address", "0x" + llvm::utohexstr(inst_addr)},
- {"instructionBytes",
- bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""},
- };
+ DisassembledInstruction disassembled_inst;
+ disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr);
+ disassembled_inst.instructionBytes =
+ bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : "";
std::string instruction;
llvm::raw_string_ostream si(instruction);
@@ -185,9 +100,8 @@ void DisassembleRequestHandler::operator()(
: symbol.GetName())
<< ": ";
- if (resolveSymbols) {
- disassembled_inst.try_emplace("symbol", symbol.GetDisplayName());
- }
+ if (resolveSymbols)
+ disassembled_inst.symbol = symbol.GetDisplayName();
}
si << llvm::formatv("{0,7} {1,12}", m, o);
@@ -195,7 +109,7 @@ void DisassembleRequestHandler::operator()(
si << " ; " << c;
}
- disassembled_inst.try_emplace("instruction", instruction);
+ disassembled_inst.instruction = instruction;
auto line_entry = addr.GetLineEntry();
// If the line number is 0 then the entry represents a compiler generated
@@ -203,41 +117,36 @@ void DisassembleRequestHandler::operator()(
if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
auto source = CreateSource(line_entry);
- disassembled_inst.try_emplace("location", source);
+ disassembled_inst.location = std::move(source);
const auto line = line_entry.GetLine();
- if (line && line != LLDB_INVALID_LINE_NUMBER) {
- disassembled_inst.try_emplace("line", line);
- }
+ if (line != 0 && line != LLDB_INVALID_LINE_NUMBER)
+ disassembled_inst.line = line;
+
const auto column = line_entry.GetColumn();
- if (column && column != LLDB_INVALID_COLUMN_NUMBER) {
- disassembled_inst.try_emplace("column", column);
- }
+ if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER)
+ disassembled_inst.column = column;
auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
if (end_line_entry.IsValid() &&
end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
const auto end_line = end_line_entry.GetLine();
- if (end_line && end_line != LLDB_INVALID_LINE_NUMBER &&
+ if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER &&
end_line != line) {
- disassembled_inst.try_emplace("endLine", end_line);
+ disassembled_inst.endLine = end_line;
const auto end_column = end_line_entry.GetColumn();
- if (end_column && end_column != LLDB_INVALID_COLUMN_NUMBER &&
- end_column != column) {
- disassembled_inst.try_emplace("endColumn", end_column - 1);
- }
+ if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER &&
+ end_column != column)
+ disassembled_inst.endColumn = end_column - 1;
}
}
}
- instructions.emplace_back(std::move(disassembled_inst));
+ instructions.push_back(std::move(disassembled_inst));
}
- llvm::json::Object body;
- body.try_emplace("instructions", std::move(instructions));
- response.try_emplace("body", std::move(body));
- dap.SendJSON(llvm::json::Value(std::move(response)));
+ return DisassembleResponseBody{std::move(instructions)};
}
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index e6bccfe12f402..998b98137a1ea 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -534,14 +534,17 @@ class LocationsRequestHandler : public LegacyRequestHandler {
void operator()(const llvm::json::Object &request) const override;
};
-class DisassembleRequestHandler : public LegacyRequestHandler {
+class DisassembleRequestHandler final
+ : public RequestHandler<protocol::DisassembleArguments,
+ llvm::Expected<protocol::DisassembleResponseBody>> {
public:
- using LegacyRequestHandler::LegacyRequestHandler;
+ using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "disassemble"; }
FeatureSet GetSupportedFeatures() const override {
return {protocol::eAdapterFeatureDisassembleRequest};
}
- void operator()(const llvm::json::Object &request) const override;
+ llvm::Expected<protocol::DisassembleResponseBody>
+ Run(const protocol::DisassembleArguments &args) const override;
};
class ReadMemoryRequestHandler : public LegacyRequestHandler {
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index 7efab87d39986..4160077d419e1 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -460,4 +460,22 @@ llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &SDBR) {
return result;
}
+bool fromJSON(const llvm::json::Value &Params, DisassembleArguments &DA,
+ llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("memoryReference", DA.memoryReference) &&
+ O.mapOptional("offset", DA.offset) &&
+ O.mapOptional("instructionOffset", DA.instructionOffset) &&
+ O.map("instructionCount", DA.instructionCount) &&
+ O.mapOptional("resolveSymbols", DA.resolveSymbols);
+}
+
+llvm::json::Value toJSON(const DisassembleResponseBody &DRB) {
+ llvm::json::Array instructions;
+ for (const auto &instruction : DRB.instructions) {
+ instructions.push_back(toJSON(instruction));
+ }
+ return llvm::json::Object{{"instructions", std::move(instructions)}};
+}
+
} // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index b421c631344de..c41f3a7296563 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -726,6 +726,41 @@ struct SetDataBreakpointsResponseBody {
};
llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &);
+/// Arguments to `disassemble` request.
+struct DisassembleArguments {
+ /// Memory reference to the base location containing the instructions to
+ /// disassemble.
+ std::string memoryReference;
+
+ /// Offset (in bytes) to be applied to the reference location before
+ /// disassembling. Can be negative.
+ std::optional<int64_t> offset;
+
+ /// Offset (in instructions) to be applied after the byte offset (if any)
+ /// before disassembling. Can be negative.
+ std::optional<int64_t> instructionOffset;
+
+ /// Number of instructions to disassemble starting at the specified location
+ /// and offset.
+ /// An adapter must return exactly this number of instructions - any
+ /// unavailable instructions should be replaced with an implementation-defined
+ /// 'invalid instruction' value.
+ uint32_t instructionCount;
+
+ /// If true, the adapter should attempt to resolve memory addresses and other
+ /// values to symbolic names.
+ std::optional<bool> resolveSymbols;
+};
+bool fromJSON(const llvm::json::Value &, DisassembleArguments &,
+ llvm::json::Path);
+
+/// Response to `disassemble` request.
+struct DisassembleResponseBody {
+ /// The list of disassembled instructions.
+ std::vector<DisassembledInstruction> instructions;
+};
+llvm::json::Value toJSON(const DisassembleResponseBody &);
+
} // namespace lldb_dap::protocol
#endif
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
index ce7519e3b16b8..94fe236d952a7 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
@@ -782,4 +782,38 @@ bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB,
O.mapOptional("mode", IB.mode);
}
+llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &PH) {
+ switch (PH) {
+ case DisassembledInstruction::eSourcePresentationHintNormal:
+ return "normal";
+ case DisassembledInstruction::eSourcePresentationHintInvalid:
+ return "invalid";
+ }
+ llvm_unreachable("unhandled presentation hint.");
+}
+
+llvm::json::Value toJSON(const DisassembledInstruction &DI) {
+ llvm::json::Object result{{"address", DI.address},
+ {"instruction", DI.instruction}};
+
+ if (DI.instructionBytes)
+ result.insert({"instructionBytes", *DI.instructionBytes});
+ if (DI.symbol)
+ result.insert({"symbol", *DI.symbol});
+ if (DI.location)
+ result.insert({"location", *DI.location});
+ if (DI.line)
+ result.insert({"line", *DI.line});
+ if (DI.column)
+ result.insert({"column", *DI.column});
+ if (DI.endLine)
+ result.insert({"endLine", *DI.endLine});
+ if (DI.endColumn)
+ result.insert({"endColumn", *DI.endColumn});
+ if (DI.presentationHint)
+ result.insert({"presentationHint", *DI.presentationHint});
+
+ return result;
+}
+
} // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index 3df77ee7374a7..5c6858904a3cf 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -627,6 +627,60 @@ struct InstructionBreakpoint {
bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &,
llvm::json::Path);
+/// Properties of a single disassembled instruction, returned by `disassemble`
+/// request.
+struct DisassembledInstruction {
+ enum PresentationHint : unsigned {
+ eSourcePresentationHintNormal,
+ eSourcePresentationHintInvalid,
+ };
+
+ /// The address of the instruction. Treated as a hex value if prefixed with
+ /// `0x`, or as a decimal value otherwise.
+ std::string address;
+
+ /// Raw bytes representing the instruction and its operands, in an
+ /// implementation-defined format.
+ std::optional<std::string> instructionBytes;
+
+ /// Text representing the instruction and its operands, in an
+ /// implementation-defined format.
+ std::string instruction;
+
+ /// Name of the symbol that corresponds with the location of this instruction,
+ /// if any.
+ std::optional<std::string> symbol;
+
+ /// Source location that corresponds to this instruction, if any.
+ /// Should always be set (if available) on the first instruction returned,
+ /// but can be omitted afterwards if this instruction maps to the same source
+ /// file as the previous instruction.
+ std::optional<protocol::Source> location;
+
+ /// The line within the source location that corresponds to this instruction,
+ /// if any.
+ std::optional<uint32_t> line;
+
+ /// The column within the line that corresponds to this instruction, if any.
+ std::optional<uint32_t> column;
+
+ /// The end line of the range that corresponds to this instruction, if any.
+ std::optional<uint32_t> endLine;
+
+ /// The end column of the range that corresponds to this instruction, if any.
+ std::optional<uint32_t> endColumn;
+
+ /// A hint for how to present the instruction in the UI.
+ ///
+ /// A value of `invalid` may be used to indicate this instruction is 'filler'
+ /// and cannot be reached by the program. For example, unreadable memory
+ /// addresses may be presented is 'invalid.'
+ /// Values: 'normal', 'invalid'
+ std::optional<PresentationHint> presentationHint;
+};
+llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &);
+llvm::json::Value toJSON(const DisassembledInstruction &);
+
} // namespace lldb_dap::protocol
#endif
>From cf7600dbfdb081f5bce80d860bb84bdc6c35cd1b Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Mon, 19 May 2025 01:54:19 +0200
Subject: [PATCH 2/2] [lldb-dap] Fix disassemble request instruction offset
handling
---
.../Handler/DisassembleRequestHandler.cpp | 232 ++++++++++++------
lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 +
2 files changed, 155 insertions(+), 81 deletions(-)
diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
index 938078947259b..88fdba3d9ca44 100644
--- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -24,15 +24,14 @@ namespace lldb_dap {
/// `supportsDisassembleRequest` is true.
llvm::Expected<DisassembleResponseBody>
DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
- std::vector<DisassembledInstruction> instructions;
-
auto addr_opt = DecodeMemoryReference(args.memoryReference);
if (!addr_opt.has_value())
return llvm::make_error<DAPError>("Malformed memory reference: " +
args.memoryReference);
lldb::addr_t addr_ptr = *addr_opt;
- addr_ptr += args.instructionOffset.value_or(0);
+ addr_ptr += args.offset.value_or(0);
+
lldb::SBAddress addr(addr_ptr, dap.target);
if (!addr.IsValid())
return llvm::make_error<DAPError>(
@@ -53,100 +52,171 @@ DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
}
}
- lldb::SBInstructionList insts = dap.target.ReadInstructions(
- addr, args.instructionCount, flavor_string.c_str());
+ int64_t instructionOffset = args.instructionOffset.value_or(0);
+ if (instructionOffset > 0) {
+ lldb::SBInstructionList forward_insts = dap.target.ReadInstructions(
+ addr, instructionOffset + 1, flavor_string.c_str());
+ if (forward_insts.GetSize() != static_cast<size_t>(instructionOffset + 1)) {
+ return llvm::make_error<DAPError>(
+ "Failed to disassemble instructions after " +
+ std::to_string(instructionOffset) +
+ " instructions from the given address.");
+ }
+ addr = forward_insts.GetInstructionAtIndex(instructionOffset).GetAddress();
+ }
+
+ const bool resolveSymbols = args.resolveSymbols.value_or(false);
+ std::vector<DisassembledInstruction> instructions;
+ if (instructionOffset < 0) {
+ // need to disassemble backwards, let's try from the start of the symbol if
+ // available.
+ size_t number_of_insts_before = std::abs(instructionOffset);
+ auto symbol = addr.GetSymbol();
+ if (symbol.IsValid()) {
+ // add valid instructions before the current instruction using the symbol.
+ lldb::SBInstructionList symbol_insts = dap.target.ReadInstructions(
+ symbol.GetStartAddress(), addr, flavor_string.c_str());
+ if (symbol_insts.IsValid()) {
+ size_t backwards_insts_start =
+ symbol_insts.GetSize() >= number_of_insts_before
+ ? symbol_insts.GetSize() - number_of_insts_before
+ : 0;
+ for (size_t i = backwards_insts_start;
+ i < symbol_insts.GetSize() &&
+ instructions.size() < args.instructionCount;
+ ++i) {
+ lldb::SBInstruction inst = symbol_insts.GetInstructionAtIndex(i);
+ instructions.push_back(
+ SBInstructionToDisassembledInstruction(inst, resolveSymbols));
+ --number_of_insts_before;
+ }
+ }
+ }
+
+ // pad the instructions with invalid instructions if needed.
+ for (size_t i = 0; i < number_of_insts_before &&
+ instructions.size() < args.instructionCount;
+ ++i) {
+ DisassembledInstruction invalid_inst;
+ invalid_inst.presentationHint =
+ DisassembledInstruction::eSourcePresentationHintInvalid;
+ instructions.insert(instructions.begin(), std::move(invalid_inst));
+ }
+ }
+
+ const auto instructions_left = args.instructionCount - instructions.size();
+ lldb::SBInstructionList insts = dap.target.ReadInstructions(
+ addr, instructions_left, flavor_string.c_str());
if (!insts.IsValid())
return llvm::make_error<DAPError>(
"Failed to find instructions for memory address.");
- const bool resolveSymbols = args.resolveSymbols.value_or(false);
+ // add the disassembly from the given address forward
const auto num_insts = insts.GetSize();
- for (size_t i = 0; i < num_insts; ++i) {
+ for (size_t i = 0;
+ i < num_insts && instructions.size() < args.instructionCount; ++i) {
lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
- auto addr = inst.GetAddress();
- const auto inst_addr = addr.GetLoadAddress(dap.target);
- const char *m = inst.GetMnemonic(dap.target);
- const char *o = inst.GetOperands(dap.target);
- const char *c = inst.GetComment(dap.target);
- auto d = inst.GetData(dap.target);
-
- std::string bytes;
- llvm::raw_string_ostream sb(bytes);
- for (unsigned i = 0; i < inst.GetByteSize(); i++) {
- lldb::SBError error;
- uint8_t b = d.GetUnsignedInt8(error, i);
- if (error.Success()) {
- sb << llvm::format("%2.2x ", b);
- }
- }
+ instructions.push_back(
+ SBInstructionToDisassembledInstruction(inst, resolveSymbols));
+ }
- DisassembledInstruction disassembled_inst;
- disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr);
- disassembled_inst.instructionBytes =
- bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : "";
-
- std::string instruction;
- llvm::raw_string_ostream si(instruction);
-
- lldb::SBSymbol symbol = addr.GetSymbol();
- // Only add the symbol on the first line of the function.
- if (symbol.IsValid() && symbol.GetStartAddress() == addr) {
- // If we have a valid symbol, append it as a label prefix for the first
- // instruction. This is so you can see the start of a function/callsite
- // in the assembly, at the moment VS Code (1.80) does not visualize the
- // symbol associated with the assembly instruction.
- si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName()
- : symbol.GetName())
- << ": ";
-
- if (resolveSymbols)
- disassembled_inst.symbol = symbol.GetDisplayName();
+ // Pad the instructions with invalid instructions if needed.
+ if (instructions.size() < args.instructionCount) {
+ for (size_t i = instructions.size(); i < args.instructionCount; ++i) {
+ DisassembledInstruction invalid_inst;
+ invalid_inst.presentationHint =
+ DisassembledInstruction::eSourcePresentationHintInvalid;
+ instructions.push_back(std::move(invalid_inst));
}
+ }
+
+ return DisassembleResponseBody{std::move(instructions)};
+}
- si << llvm::formatv("{0,7} {1,12}", m, o);
- if (c && c[0]) {
- si << " ; " << c;
+DisassembledInstruction
+DisassembleRequestHandler::SBInstructionToDisassembledInstruction(
+ lldb::SBInstruction &inst, bool resolveSymbols) const {
+ auto addr = inst.GetAddress();
+ const auto inst_addr = addr.GetLoadAddress(dap.target);
+ const char *m = inst.GetMnemonic(dap.target);
+ const char *o = inst.GetOperands(dap.target);
+ const char *c = inst.GetComment(dap.target);
+ auto d = inst.GetData(dap.target);
+
+ std::string bytes;
+ llvm::raw_string_ostream sb(bytes);
+ for (unsigned i = 0; i < inst.GetByteSize(); i++) {
+ lldb::SBError error;
+ uint8_t b = d.GetUnsignedInt8(error, i);
+ if (error.Success()) {
+ sb << llvm::format("%2.2x ", b);
}
+ }
- disassembled_inst.instruction = instruction;
-
- auto line_entry = addr.GetLineEntry();
- // If the line number is 0 then the entry represents a compiler generated
- // location.
- if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
- line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
- auto source = CreateSource(line_entry);
- disassembled_inst.location = std::move(source);
-
- const auto line = line_entry.GetLine();
- if (line != 0 && line != LLDB_INVALID_LINE_NUMBER)
- disassembled_inst.line = line;
-
- const auto column = line_entry.GetColumn();
- if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER)
- disassembled_inst.column = column;
-
- auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
- if (end_line_entry.IsValid() &&
- end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
- const auto end_line = end_line_entry.GetLine();
- if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER &&
- end_line != line) {
- disassembled_inst.endLine = end_line;
-
- const auto end_column = end_line_entry.GetColumn();
- if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER &&
- end_column != column)
- disassembled_inst.endColumn = end_column - 1;
- }
+ DisassembledInstruction disassembled_inst;
+ disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr);
+ disassembled_inst.instructionBytes =
+ bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : "";
+
+ std::string instruction;
+ llvm::raw_string_ostream si(instruction);
+
+ lldb::SBSymbol symbol = addr.GetSymbol();
+ // Only add the symbol on the first line of the function.
+ if (symbol.IsValid() && symbol.GetStartAddress() == addr) {
+ // If we have a valid symbol, append it as a label prefix for the first
+ // instruction. This is so you can see the start of a function/callsite
+ // in the assembly, at the moment VS Code (1.80) does not visualize the
+ // symbol associated with the assembly instruction.
+ si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName()
+ : symbol.GetName())
+ << ": ";
+
+ if (resolveSymbols)
+ disassembled_inst.symbol = symbol.GetDisplayName();
+ }
+
+ si << llvm::formatv("{0,7} {1,12}", m, o);
+ if (c && c[0]) {
+ si << " ; " << c;
+ }
+
+ disassembled_inst.instruction = instruction;
+
+ auto line_entry = addr.GetLineEntry();
+ // If the line number is 0 then the entry represents a compiler generated
+ // location.
+ if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
+ line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
+ auto source = CreateSource(line_entry);
+ disassembled_inst.location = std::move(source);
+
+ const auto line = line_entry.GetLine();
+ if (line != 0 && line != LLDB_INVALID_LINE_NUMBER)
+ disassembled_inst.line = line;
+
+ const auto column = line_entry.GetColumn();
+ if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER)
+ disassembled_inst.column = column;
+
+ auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
+ if (end_line_entry.IsValid() &&
+ end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
+ const auto end_line = end_line_entry.GetLine();
+ if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER &&
+ end_line != line) {
+ disassembled_inst.endLine = end_line;
+
+ const auto end_column = end_line_entry.GetColumn();
+ if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER &&
+ end_column != column)
+ disassembled_inst.endColumn = end_column - 1;
}
}
-
- instructions.push_back(std::move(disassembled_inst));
}
- return DisassembleResponseBody{std::move(instructions)};
+ return disassembled_inst;
}
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 998b98137a1ea..ccc2c829d9474 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -545,6 +545,10 @@ class DisassembleRequestHandler final
}
llvm::Expected<protocol::DisassembleResponseBody>
Run(const protocol::DisassembleArguments &args) const override;
+
+ protocol::DisassembledInstruction
+ SBInstructionToDisassembledInstruction(lldb::SBInstruction &inst,
+ bool resolveSymbols) const;
};
class ReadMemoryRequestHandler : public LegacyRequestHandler {
More information about the lldb-commits
mailing list