1//===-- ReadMemoryRequestHandler.cpp --------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "DAP.h"
10#include "EventHelper.h"
11#include "JSONUtils.h"
12#include "RequestHandler.h"
13#include "llvm/ADT/StringExtras.h"
14#include "llvm/Support/Base64.h"
15
16namespace lldb_dap {
17
18// "ReadMemoryRequest": {
19// "allOf": [ { "$ref": "#/definitions/Request" }, {
20// "type": "object",
21// "description": "Reads bytes from memory at the provided location. Clients
22// should only call this request if the corresponding
23// capability `supportsReadMemoryRequest` is true.",
24// "properties": {
25// "command": {
26// "type": "string",
27// "enum": [ "readMemory" ]
28// },
29// "arguments": {
30// "$ref": "#/definitions/ReadMemoryArguments"
31// }
32// },
33// "required": [ "command", "arguments" ]
34// }]
35// },
36// "ReadMemoryArguments": {
37// "type": "object",
38// "description": "Arguments for `readMemory` request.",
39// "properties": {
40// "memoryReference": {
41// "type": "string",
42// "description": "Memory reference to the base location from which data
43// should be read."
44// },
45// "offset": {
46// "type": "integer",
47// "description": "Offset (in bytes) to be applied to the reference
48// location before reading data. Can be negative."
49// },
50// "count": {
51// "type": "integer",
52// "description": "Number of bytes to read at the specified location and
53// offset."
54// }
55// },
56// "required": [ "memoryReference", "count" ]
57// },
58// "ReadMemoryResponse": {
59// "allOf": [ { "$ref": "#/definitions/Response" }, {
60// "type": "object",
61// "description": "Response to `readMemory` request.",
62// "properties": {
63// "body": {
64// "type": "object",
65// "properties": {
66// "address": {
67// "type": "string",
68// "description": "The address of the first byte of data returned.
69// Treated as a hex value if prefixed with `0x`, or
70// as a decimal value otherwise."
71// },
72// "unreadableBytes": {
73// "type": "integer",
74// "description": "The number of unreadable bytes encountered after
75// the last successfully read byte.\nThis can be
76// used to determine the number of bytes that should
77// be skipped before a subsequent
78// `readMemory` request succeeds."
79// },
80// "data": {
81// "type": "string",
82// "description": "The bytes read from memory, encoded using base64.
83// If the decoded length of `data` is less than the
84// requested `count` in the original `readMemory`
85// request, and `unreadableBytes` is zero or
86// omitted, then the client should assume it's
87// reached the end of readable memory."
88// }
89// },
90// "required": [ "address" ]
91// }
92// }
93// }]
94// },
95void ReadMemoryRequestHandler::operator()(
96 const llvm::json::Object &request) const {
97 llvm::json::Object response;
98 FillResponse(request, response);
99 auto *arguments = request.getObject(K: "arguments");
100
101 llvm::StringRef memoryReference =
102 GetString(obj: arguments, key: "memoryReference").value_or(u: "");
103 auto addr_opt = DecodeMemoryReference(memoryReference);
104 if (!addr_opt.has_value()) {
105 response["success"] = false;
106 response["message"] =
107 "Malformed memory reference: " + memoryReference.str();
108 dap.SendJSON(json: llvm::json::Value(std::move(response)));
109 return;
110 }
111 lldb::addr_t addr_int = *addr_opt;
112 addr_int += GetInteger<uint64_t>(obj: arguments, key: "offset").value_or(u: 0);
113 const uint64_t count_requested =
114 GetInteger<uint64_t>(obj: arguments, key: "count").value_or(u: 0);
115
116 // We also need support reading 0 bytes
117 // VS Code sends those requests to check if a `memoryReference`
118 // can be dereferenced.
119 const uint64_t count_read = std::max<uint64_t>(a: count_requested, b: 1);
120 std::vector<uint8_t> buf;
121 buf.resize(new_size: count_read);
122 lldb::SBError error;
123 lldb::SBAddress addr{addr_int, dap.target};
124 size_t count_result =
125 dap.target.ReadMemory(addr, buf: buf.data(), size: count_read, error);
126 if (count_result == 0) {
127 response["success"] = false;
128 EmplaceSafeString(obj&: response, key: "message", str: error.GetCString());
129 dap.SendJSON(json: llvm::json::Value(std::move(response)));
130 return;
131 }
132 buf.resize(new_size: std::min<size_t>(a: count_result, b: count_requested));
133
134 llvm::json::Object body;
135 std::string formatted_addr = "0x" + llvm::utohexstr(X: addr_int);
136 body.try_emplace(K: "address", Args&: formatted_addr);
137 body.try_emplace(K: "data", Args: llvm::encodeBase64(Bytes: buf));
138 response.try_emplace(K: "body", Args: std::move(body));
139 dap.SendJSON(json: llvm::json::Value(std::move(response)));
140}
141
142} // namespace lldb_dap
143

source code of lldb/tools/lldb-dap/Handler/ReadMemoryRequestHandler.cpp