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 <elyron...@gmail.com> Date: Sun, 18 May 2025 23:51:58 +0200 Subject: [PATCH 1/3] [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 <elyron...@gmail.com> Date: Mon, 19 May 2025 10:16:29 +0200 Subject: [PATCH 2/3] 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); +} >From 1e18aaf9b6be843ccb6a8041de98643e0aee625c Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Mon, 19 May 2025 10:32:02 +0200 Subject: [PATCH 3/3] remove auto --- lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp index 60165a357e735..2e04d7d2da0bd 100644 --- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp @@ -13,7 +13,9 @@ #include "Protocol/ProtocolTypes.h" #include "RequestHandler.h" #include "lldb/API/SBInstruction.h" +#include "lldb/lldb-types.h" #include "llvm/ADT/StringExtras.h" +#include <optional> using namespace lldb_dap::protocol; @@ -26,7 +28,7 @@ llvm::Expected<DisassembleResponseBody> DisassembleRequestHandler::Run(const DisassembleArguments &args) const { std::vector<DisassembledInstruction> instructions; - auto addr_opt = DecodeMemoryReference(args.memoryReference); + std::optional<lldb::addr_t> addr_opt = DecodeMemoryReference(args.memoryReference); if (!addr_opt.has_value()) return llvm::make_error<DAPError>("Malformed memory reference: " + args.memoryReference); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits