[Lldb-commits] [lldb] [lldb-dap] Migrate disassemble request to structured handler (PR #140482)
Ely Ronnen via lldb-commits
lldb-commits at lists.llvm.org
Mon May 19 01:30:56 PDT 2025
https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/140482
>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 304c28f47a05e0753125bd85b343fd17e0994afd Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Mon, 19 May 2025 10:16:29 +0200
Subject: [PATCH 2/2] adding DisassembledInstruction unit tests
---
.../Handler/DisassembleRequestHandler.cpp | 2 +-
.../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 60 +++++++++++++++-
lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 10 ++-
lldb/unittests/DAP/ProtocolTypesTest.cpp | 72 +++++++++++++++++++
4 files changed, 137 insertions(+), 7 deletions(-)
diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
index 938078947259b..60165a357e735 100644
--- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -82,7 +82,7 @@ DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
}
DisassembledInstruction disassembled_inst;
- disassembled_inst.address = "0x" + llvm::utohexstr(inst_addr);
+ disassembled_inst.address = inst_addr;
disassembled_inst.instructionBytes =
bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : "";
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
index 94fe236d952a7..52c11ad828993 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
@@ -7,6 +7,9 @@
//===----------------------------------------------------------------------===//
#include "Protocol/ProtocolTypes.h"
+#include "JSONUtils.h"
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/JSON.h"
@@ -782,18 +785,69 @@ bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB,
O.mapOptional("mode", IB.mode);
}
+bool fromJSON(const llvm::json::Value &Params,
+ DisassembledInstruction::PresentationHint &PH,
+ llvm::json::Path P) {
+ auto rawHint = Params.getAsString();
+ if (!rawHint) {
+ P.report("expected a string");
+ return false;
+ }
+ std::optional<DisassembledInstruction::PresentationHint> hint =
+ StringSwitch<std::optional<DisassembledInstruction::PresentationHint>>(
+ *rawHint)
+ .Case("normal", DisassembledInstruction::
+ eDisassembledInstructionPresentationHintNormal)
+ .Case("invalid", DisassembledInstruction::
+ eDisassembledInstructionPresentationHintInvalid)
+ .Default(std::nullopt);
+ if (!hint) {
+ P.report("unexpected value");
+ return false;
+ }
+ PH = *hint;
+ return true;
+}
+
llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &PH) {
switch (PH) {
- case DisassembledInstruction::eSourcePresentationHintNormal:
+ case DisassembledInstruction::eDisassembledInstructionPresentationHintNormal:
return "normal";
- case DisassembledInstruction::eSourcePresentationHintInvalid:
+ case DisassembledInstruction::eDisassembledInstructionPresentationHintInvalid:
return "invalid";
}
llvm_unreachable("unhandled presentation hint.");
}
+bool fromJSON(const llvm::json::Value &Params, DisassembledInstruction &DI,
+ llvm::json::Path P) {
+ std::optional<llvm::StringRef> raw_address =
+ Params.getAsObject()->getString("address");
+ if (!raw_address) {
+ P.report("missing `address` field");
+ return false;
+ }
+
+ std::optional<lldb::addr_t> address = DecodeMemoryReference(*raw_address);
+ if (!address) {
+ P.report("invalid `address`");
+ return false;
+ }
+
+ DI.address = *address;
+ llvm::json::ObjectMapper O(Params, P);
+ return O && O.map("instruction", DI.instruction) &&
+ O.mapOptional("instructionBytes", DI.instructionBytes) &&
+ O.mapOptional("symbol", DI.symbol) &&
+ O.mapOptional("location", DI.location) &&
+ O.mapOptional("line", DI.line) && O.mapOptional("column", DI.column) &&
+ O.mapOptional("endLine", DI.endLine) &&
+ O.mapOptional("endColumn", DI.endColumn) &&
+ O.mapOptional("presentationHint", DI.presentationHint);
+}
+
llvm::json::Value toJSON(const DisassembledInstruction &DI) {
- llvm::json::Object result{{"address", DI.address},
+ llvm::json::Object result{{"address", "0x" + llvm::utohexstr(DI.address)},
{"instruction", DI.instruction}};
if (DI.instructionBytes)
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index 5c6858904a3cf..5bac62adcdd38 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -631,13 +631,13 @@ bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &,
/// request.
struct DisassembledInstruction {
enum PresentationHint : unsigned {
- eSourcePresentationHintNormal,
- eSourcePresentationHintInvalid,
+ eDisassembledInstructionPresentationHintNormal,
+ eDisassembledInstructionPresentationHintInvalid,
};
/// The address of the instruction. Treated as a hex value if prefixed with
/// `0x`, or as a decimal value otherwise.
- std::string address;
+ lldb::addr_t address;
/// Raw bytes representing the instruction and its operands, in an
/// implementation-defined format.
@@ -678,7 +678,11 @@ struct DisassembledInstruction {
/// Values: 'normal', 'invalid'
std::optional<PresentationHint> presentationHint;
};
+bool fromJSON(const llvm::json::Value &,
+ DisassembledInstruction::PresentationHint &, llvm::json::Path);
llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &);
+bool fromJSON(const llvm::json::Value &, DisassembledInstruction &,
+ llvm::json::Path);
llvm::json::Value toJSON(const DisassembledInstruction &);
} // namespace lldb_dap::protocol
diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp
index 5d5125dc78fba..41703f4a071fb 100644
--- a/lldb/unittests/DAP/ProtocolTypesTest.cpp
+++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp
@@ -530,3 +530,75 @@ TEST(ProtocolTypesTest, ChecksumAlgorithm) {
llvm::json::Path::Root root;
EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root));
}
+
+TEST(ProtocolTypesTest, DisassembledInstructionPresentationHint) {
+ // Test all PresentationHint values.
+ std::vector<
+ std::pair<DisassembledInstruction::PresentationHint, llvm::StringRef>>
+ test_cases = {{DisassembledInstruction::
+ eDisassembledInstructionPresentationHintNormal,
+ "normal"},
+ {DisassembledInstruction::
+ eDisassembledInstructionPresentationHintInvalid,
+ "invalid"}};
+
+ for (const auto &test_case : test_cases) {
+ // Serialize the PresentationHint to JSON.
+ llvm::json::Value serialized = toJSON(test_case.first);
+ ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String);
+ EXPECT_EQ(serialized.getAsString(), test_case.second);
+
+ // Deserialize the JSON back to PresentationHint.
+ DisassembledInstruction::PresentationHint deserialized;
+ llvm::json::Path::Root root;
+ ASSERT_TRUE(fromJSON(serialized, deserialized, root))
+ << llvm::toString(root.getError());
+ EXPECT_EQ(deserialized, test_case.first);
+ }
+
+ // Test invalid value.
+ llvm::json::Value invalid_value = "invalid_hint";
+ DisassembledInstruction::PresentationHint deserialized_invalid;
+ llvm::json::Path::Root root;
+ EXPECT_FALSE(fromJSON(invalid_value, deserialized_invalid, root));
+}
+
+TEST(ProtocolTypesTest, DisassembledInstruction) {
+ DisassembledInstruction instruction;
+ instruction.address = 0x12345678;
+ instruction.instructionBytes = "0F 1F 00";
+ instruction.instruction = "mov eax, ebx";
+ instruction.symbol = "main";
+ instruction.location = Source{"test.cpp", "/path/to/test.cpp", 123,
+ Source::eSourcePresentationHintNormal};
+ instruction.line = 10;
+ instruction.column = 5;
+ instruction.endLine = 15;
+ instruction.endColumn = 10;
+ instruction.presentationHint =
+ DisassembledInstruction::eDisassembledInstructionPresentationHintNormal;
+
+ llvm::Expected<DisassembledInstruction> deserialized_instruction =
+ roundtrip(instruction);
+ ASSERT_THAT_EXPECTED(deserialized_instruction, llvm::Succeeded());
+
+ EXPECT_EQ(instruction.address, deserialized_instruction->address);
+ EXPECT_EQ(instruction.instructionBytes,
+ deserialized_instruction->instructionBytes);
+ EXPECT_EQ(instruction.instruction, deserialized_instruction->instruction);
+ EXPECT_EQ(instruction.symbol, deserialized_instruction->symbol);
+ EXPECT_EQ(instruction.location->name,
+ deserialized_instruction->location->name);
+ EXPECT_EQ(instruction.location->path,
+ deserialized_instruction->location->path);
+ EXPECT_EQ(instruction.location->sourceReference,
+ deserialized_instruction->location->sourceReference);
+ EXPECT_EQ(instruction.location->presentationHint,
+ deserialized_instruction->location->presentationHint);
+ EXPECT_EQ(instruction.line, deserialized_instruction->line);
+ EXPECT_EQ(instruction.column, deserialized_instruction->column);
+ EXPECT_EQ(instruction.endLine, deserialized_instruction->endLine);
+ EXPECT_EQ(instruction.endColumn, deserialized_instruction->endColumn);
+ EXPECT_EQ(instruction.presentationHint,
+ deserialized_instruction->presentationHint);
+}
More information about the lldb-commits
mailing list