//===-- 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(arguments, "offset").value_or(0); const uint64_t count_requested = GetInteger(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(count_requested, 1); std::vector 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(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