[Lldb-commits] [lldb] [lldb][lldb-dap] Added readMemory and WriteMemory, var type correction (PR #108036)

Walter Erquinigo via lldb-commits lldb-commits at lists.llvm.org
Wed Sep 11 15:25:51 PDT 2024


================
@@ -4332,6 +4339,232 @@ void request_setInstructionBreakpoints(const llvm::json::Object &request) {
   g_dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
+// "ReadMemoryRequest": {
+//   "allOf": [ { "$ref": "#/definitions/Request" }, {
+//     "type": "object",
+//     "description": "Reads bytes from memory at the provided location.\n
+//     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.
+//             \nTreated 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 request_readMemory(const llvm::json::Object &request) {
+  llvm::json::Object response;
+  llvm::json::Array response_readMemory;
+  llvm::json::Object body;
+  lldb::SBError error;
+  FillResponse(request, response);
+
+  auto arguments = request.getObject("arguments");
+  llvm::StringRef memoryReference = GetString(arguments, "memoryReference");
+  const size_t count = GetUnsigned(arguments, "count", 0);
+  const auto offset = GetSigned(arguments, "offset", 0);
+
+  lldb::addr_t address;
+  memoryReference.getAsInteger(0, address);
+  lldb::addr_t address_offset = address + offset;
+  // address as string
+  std::string address_offset_str(std::to_string(address_offset));
+
+  // make storage for the memory to read
+  //  need to use a vector because VC++ 2019 errors out on char buffer[count]
+  std::vector<char> buffer(count);
+
+  // read the memory add to storage
+  lldb::SBProcess process = g_dap.target.GetProcess();
+  size_t countRead =
+      process.ReadMemory(address_offset, buffer.data(), count, error);
+  const llvm::StringRef inputBytes = {buffer.data(), countRead};
+  // return the read memory in base64
+  std::string data = llvm::encodeBase64(inputBytes);
+
+  // body: address, data? in spec formats
+  body.try_emplace("address", std::move(address_offset_str));
+  body.try_emplace("data", std::move(data));
+
+  response.try_emplace("body", std::move(body));
+  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+// "WriteMemoryRequest": {
+//       "allOf": [ { "$ref": "#/definitions/Request" }, {
+//         "type": "object",
+//         "description": "Writes bytes to memory at the provided location.\n
+//         Clients should only call this request if the corresponding
+//         capability `supportsWriteMemoryRequest` is true.",
+//         "properties": {
+//           "command": {
+//             "type": "string",
+//             "enum": [ "writeMemory" ]
+//           },
+//           "arguments": {
+//             "$ref": "#/definitions/WriteMemoryArguments"
+//           }
+//         },
+//         "required": [ "command", "arguments" ]
+//       }]
+//     },
+//     "WriteMemoryArguments": {
+//       "type": "object",
+//       "description": "Arguments for `writeMemory` request.",
+//       "properties": {
+//         "memoryReference": {
+//           "type": "string",
+//           "description": "Memory reference to the base location to which
+//           data should be written."
+//         },
+//         "offset": {
+//           "type": "integer",
+//           "description": "Offset (in bytes) to be applied to the reference
+//           location before writing data. Can be negative."
+//         },
+//         "allowPartial": {
+//           "type": "boolean",
+//           "description": "Property to control partial writes. If true, the
+//           debug adapter should attempt to write memory even if the entire
+//           memory region is not writable. In such a case the debug adapter
+//           should stop after hitting the first byte of memory that cannot be
+//           written and return the number of bytes written in the response
+//           via the `offset` and `bytesWritten` properties.\nIf false or
+//           missing, a debug adapter should attempt to verify the region is
+//           writable before writing, and fail the response if it is not."
+//         },
+//         "data": {
+//           "type": "string",
+//           "description": "Bytes to write, encoded using base64."
+//         }
+//       },
+//       "required": [ "memoryReference", "data" ]
+//     },
+//     "WriteMemoryResponse": {
+//       "allOf": [ { "$ref": "#/definitions/Response" }, {
+//         "type": "object",
+//         "description": "Response to `writeMemory` request.",
+//         "properties": {
+//           "body": {
+//             "type": "object",
+//             "properties": {
+//               "offset": {
+//                 "type": "integer",
+//                 "description": "Property that should be returned when
+//                 `allowPartial` is true to indicate the offset of the first
+//                 byte of data successfully written. Can be negative."
+//               },
+//               "bytesWritten": {
+//                 "type": "integer",
+//                 "description": "Property that should be returned when
+//                 `allowPartial` is true to indicate the number of bytes
+//                 starting from address that were successfully written."
+//               }
+//             }
+//           }
+//         }
+//       }]
+//     },
+
+void request_writeMemory(const llvm::json::Object &request) {
+  llvm::json::Object response;
+  llvm::json::Array response_writeMemory;
+  llvm::json::Object body;
+  FillResponse(request, response);
+
+  auto arguments = request.getObject("arguments");
+  llvm::StringRef memoryReference = GetString(arguments, "memoryReference");
+  const auto offset = GetSigned(arguments, "offset", 0);
+  llvm::StringRef data64 = GetString(arguments, "data");
+
+  lldb::addr_t address;
+  memoryReference.getAsInteger(0, address);
+  lldb::addr_t address_offset = address + offset;
+
+  std::vector<char> output;
+  lldb::SBError writeError;
+  int64_t countWrite = 0;
+
+  llvm::Error decodeError = llvm::decodeBase64(data64, output);
+
+  int64_t dataLen = output.size();
+
+  // write the memory
+  if (decodeError.success()) {
+    lldb::SBProcess process = g_dap.target.GetProcess();
+    countWrite =
+        process.WriteMemory(address_offset, static_cast<void *>(output.data()),
+                            dataLen, writeError);
----------------
walter-erquinigo wrote:

Related to this, can you handle `allowPartial` correctly? If LLDB can't support easily a `true` case, at least write some documentation about it

https://github.com/llvm/llvm-project/pull/108036


More information about the lldb-commits mailing list