Skip to content

[lldb-dap] Refactor remaining request handlers (NFC)Remaining request handlers #128551

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lldb/tools/lldb-dap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,34 @@ add_lldb_tool(lldb-dap
Handler/ConfigurationDoneRequestHandler.cpp
Handler/ContinueRequestHandler.cpp
Handler/DataBreakpointInfoRequestHandler.cpp
Handler/DisassembleRequestHandler.cpp
Handler/DisconnectRequestHandler.cpp
Handler/EvaluateRequestHandler.cpp
Handler/ExceptionInfoRequestHandler.cpp
Handler/InitializeRequestHandler.cpp
Handler/LaunchRequestHandler.cpp
Handler/LocationsRequestHandler.cpp
Handler/ModulesRequestHandler.cpp
Handler/NextRequestHandler.cpp
Handler/PauseRequestHandler.cpp
Handler/ReadMemoryRequestHandler.cpp
Handler/RequestHandler.cpp
Handler/RestartRequestHandler.cpp
Handler/ScopesRequestHandler.cpp
Handler/SetBreakpointsRequestHandler.cpp
Handler/SetDataBreakpointsRequestHandler.cpp
Handler/SetExceptionBreakpointsRequestHandler.cpp
Handler/SetFunctionBreakpointsRequestHandler.cpp
Handler/SetInstructionBreakpointsRequestHandler.cpp
Handler/SetVariableRequestHandler.cpp
Handler/SourceRequestHandler.cpp
Handler/StackTraceRequestHandler.cpp
Handler/StepInRequestHandler.cpp
Handler/StepInTargetsRequestHandler.cpp
Handler/StepOutRequestHandler.cpp
Handler/TestGetTargetBreakpointsRequestHandler.cpp
Handler/ThreadsRequestHandler.cpp
Handler/VariablesRequestHandler.cpp

LINK_LIBS
liblldb
Expand Down
222 changes: 222 additions & 0 deletions lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
//===-- DisassembleRequestHandler.cpp -------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "DAP.h"
#include "EventHelper.h"
#include "JSONUtils.h"
#include "RequestHandler.h"
#include "lldb/API/SBInstruction.h"
#include "llvm/ADT/StringExtras.h"

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) {
llvm::json::Object response;
FillResponse(request, response);
auto *arguments = request.getObject("arguments");

llvm::StringRef memoryReference = GetString(arguments, "memoryReference");
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;

addr_ptr += GetSigned(arguments, "instructionOffset", 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;
}

const auto inst_count = GetUnsigned(arguments, "instructionCount", 0);
lldb::SBInstructionList insts = dap.target.ReadInstructions(addr, inst_count);

if (!insts.IsValid()) {
response["success"] = false;
response["message"] = "Failed to find instructions for memory address.";
dap.SendJSON(llvm::json::Value(std::move(response)));
return;
}

const bool resolveSymbols = GetBoolean(arguments, "resolveSymbols", false);
llvm::json::Array instructions;
const auto num_insts = insts.GetSize();
for (size_t i = 0; i < num_insts; ++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);
}
}

llvm::json::Object disassembled_inst{
{"address", "0x" + llvm::utohexstr(inst_addr)},
{"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.try_emplace("symbol", symbol.GetDisplayName());
}
}

si << llvm::formatv("{0,7} {1,12}", m, o);
if (c && c[0]) {
si << " ; " << c;
}

disassembled_inst.try_emplace("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.try_emplace("location", source);

const auto line = line_entry.GetLine();
if (line && line != LLDB_INVALID_LINE_NUMBER) {
disassembled_inst.try_emplace("line", line);
}
const auto column = line_entry.GetColumn();
if (column && column != LLDB_INVALID_COLUMN_NUMBER) {
disassembled_inst.try_emplace("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 &&
end_line != line) {
disassembled_inst.try_emplace("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);
}
}
}
}

instructions.emplace_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)));
}

} // namespace lldb_dap
Loading
Loading