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 <elyron...@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 <elyron...@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 { _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits