blob: 891c2af4f2f2895d95c8d93a83794b3a7b500067 [file] [log] [blame]
//===-- ReadMemoryRequestHandler.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 "llvm/ADT/StringExtras.h"
#include "llvm/Support/Base64.h"
namespace lldb_dap {
// "ReadMemoryRequest": {
// "allOf": [ { "$ref": "#/definitions/Request" }, {
// "type": "object",
// "description": "Reads bytes from memory at the provided location. Clients
// should only call this request if the corresponding
// capability `supportsReadMemoryRequest` is true.",
// "properties": {
// "command": {
// "type": "string",
// "enum": [ "readMemory" ]
// },
// "arguments": {
// "$ref": "#/definitions/ReadMemoryArguments"
// }
// },
// "required": [ "command", "arguments" ]
// }]
// },
// "ReadMemoryArguments": {
// "type": "object",
// "description": "Arguments for `readMemory` request.",
// "properties": {
// "memoryReference": {
// "type": "string",
// "description": "Memory reference to the base location from which data
// should be read."
// },
// "offset": {
// "type": "integer",
// "description": "Offset (in bytes) to be applied to the reference
// location before reading data. Can be negative."
// },
// "count": {
// "type": "integer",
// "description": "Number of bytes to read at the specified location and
// offset."
// }
// },
// "required": [ "memoryReference", "count" ]
// },
// "ReadMemoryResponse": {
// "allOf": [ { "$ref": "#/definitions/Response" }, {
// "type": "object",
// "description": "Response to `readMemory` request.",
// "properties": {
// "body": {
// "type": "object",
// "properties": {
// "address": {
// "type": "string",
// "description": "The address of the first byte of data returned.
// Treated as a hex value if prefixed with `0x`, or
// as a decimal value otherwise."
// },
// "unreadableBytes": {
// "type": "integer",
// "description": "The number of unreadable bytes encountered after
// the last successfully read byte.\nThis can be
// used to determine the number of bytes that should
// be skipped before a subsequent
// `readMemory` request succeeds."
// },
// "data": {
// "type": "string",
// "description": "The bytes read from memory, encoded using base64.
// If the decoded length of `data` is less than the
// requested `count` in the original `readMemory`
// request, and `unreadableBytes` is zero or
// omitted, then the client should assume it's
// reached the end of readable memory."
// }
// },
// "required": [ "address" ]
// }
// }
// }]
// },
void ReadMemoryRequestHandler::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_int = *addr_opt;
addr_int += GetInteger<uint64_t>(arguments, "offset").value_or(0);
const uint64_t count_requested =
GetInteger<uint64_t>(arguments, "count").value_or(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, dap.target};
size_t count_result =
dap.target.ReadMemory(addr, buf.data(), count_read, error);
if (count_result == 0) {
response["success"] = false;
EmplaceSafeString(response, "message", error.GetCString());
dap.SendJSON(llvm::json::Value(std::move(response)));
return;
}
buf.resize(std::min<size_t>(count_result, count_requested));
llvm::json::Object body;
std::string formatted_addr = "0x" + llvm::utohexstr(addr_int);
body.try_emplace("address", formatted_addr);
body.try_emplace("data", llvm::encodeBase64(buf));
response.try_emplace("body", std::move(body));
dap.SendJSON(llvm::json::Value(std::move(response)));
}
} // namespace lldb_dap