Skip to content

[lldb-dap] Simplify readMemory #109485

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 4 commits into from
Sep 25, 2024
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
8 changes: 5 additions & 3 deletions lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,20 +93,22 @@ def test_readMemory(self):

# We can read the complete string
mem = self.dap_server.request_readMemory(memref, 0, 5)["body"]
self.assertEqual(mem["unreadableBytes"], 0)
self.assertEqual(b64decode(mem["data"]), b"dead\0")

# We can read large chunks, potentially returning partial results
mem = self.dap_server.request_readMemory(memref, 0, 4096)["body"]
self.assertEqual(b64decode(mem["data"])[0:5], b"dead\0")

# Use an offset
mem = self.dap_server.request_readMemory(memref, 2, 3)["body"]
self.assertEqual(b64decode(mem["data"]), b"ad\0")

# Reads of size 0 are successful
# VS-Code sends those in order to check if a `memoryReference` can actually be dereferenced.
# VS Code sends those in order to check if a `memoryReference` can actually be dereferenced.
mem = self.dap_server.request_readMemory(memref, 0, 0)
self.assertEqual(mem["success"], True)
self.assertEqual(mem["body"]["data"], "")

# Reads at offset 0x0 fail
mem = self.dap_server.request_readMemory("0x0", 0, 6)
self.assertEqual(mem["success"], False)
self.assertEqual(mem["message"], "Memory region is not readable")
69 changes: 18 additions & 51 deletions lldb/tools/lldb-dap/lldb-dap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4422,14 +4422,6 @@ void request_readMemory(const llvm::json::Object &request) {
FillResponse(request, response);
auto *arguments = request.getObject("arguments");

lldb::SBProcess process = g_dap.target.GetProcess();
if (!process.IsValid()) {
response["success"] = false;
response["message"] = "No process running";
g_dap.SendJSON(llvm::json::Value(std::move(response)));
return;
}

llvm::StringRef memoryReference = GetString(arguments, "memoryReference");
auto addr_opt = DecodeMemoryReference(memoryReference);
if (!addr_opt.has_value()) {
Expand All @@ -4439,57 +4431,32 @@ void request_readMemory(const llvm::json::Object &request) {
g_dap.SendJSON(llvm::json::Value(std::move(response)));
return;
}
lldb::addr_t addr = *addr_opt;

addr += GetSigned(arguments, "offset", 0);
const uint64_t requested_count = GetUnsigned(arguments, "count", 0);
lldb::SBMemoryRegionInfo region_info;
lldb::SBError memreg_error = process.GetMemoryRegionInfo(addr, region_info);
if (memreg_error.Fail()) {
response["success"] = false;
EmplaceSafeString(response, "message",
"Unable to find memory region: " +
std::string(memreg_error.GetCString()));
g_dap.SendJSON(llvm::json::Value(std::move(response)));
return;
}
if (!region_info.IsReadable()) {
lldb::addr_t addr_int = *addr_opt;
addr_int += GetSigned(arguments, "offset", 0);
const uint64_t count_requested = GetUnsigned(arguments, "count", 0);

// We also need support reading 0 bytes
// VS Code sends those requests to check if a `memoryReference`
// can be dereferenced.
const uint64_t count_read = std::max<uint64_t>(count_requested, 1);
std::vector<uint8_t> buf;
buf.resize(count_read);
lldb::SBError error;
lldb::SBAddress addr{addr_int, g_dap.target};
size_t count_result =
g_dap.target.ReadMemory(addr, buf.data(), count_read, error);
if (count_result == 0) {
response["success"] = false;
response.try_emplace("message", "Memory region is not readable");
EmplaceSafeString(response, "message", error.GetCString());
g_dap.SendJSON(llvm::json::Value(std::move(response)));
return;
}
const uint64_t available_count =
std::min(requested_count, region_info.GetRegionEnd() - addr);
const uint64_t unavailable_count = requested_count - available_count;

std::vector<uint8_t> buf;
buf.resize(available_count);
if (available_count > 0) {
lldb::SBError memread_error;
uint64_t bytes_read =
process.ReadMemory(addr, buf.data(), available_count, memread_error);
if (memread_error.Fail()) {
response["success"] = false;
EmplaceSafeString(response, "message",
"Unable to read memory: " +
std::string(memread_error.GetCString()));
g_dap.SendJSON(llvm::json::Value(std::move(response)));
return;
}
if (bytes_read != available_count) {
response["success"] = false;
EmplaceSafeString(response, "message", "Unexpected, short read");
g_dap.SendJSON(llvm::json::Value(std::move(response)));
return;
}
}
buf.resize(std::min(count_result, count_requested));

llvm::json::Object body;
std::string formatted_addr = "0x" + llvm::utohexstr(addr);
std::string formatted_addr = "0x" + llvm::utohexstr(addr_int);
body.try_emplace("address", formatted_addr);
body.try_emplace("data", llvm::encodeBase64(buf));
body.try_emplace("unreadableBytes", unavailable_count);
response.try_emplace("body", std::move(body));
g_dap.SendJSON(llvm::json::Value(std::move(response)));
}
Expand Down
Loading