1//===-- WriteMemoryRequestHandler.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 "JSONUtils.h"
11#include "RequestHandler.h"
12#include "lldb/API/SBMemoryRegionInfo.h"
13#include "llvm/ADT/StringExtras.h"
14#include "llvm/Support/Base64.h"
15
16namespace lldb_dap {
17
18// Writes bytes to memory at the provided location.
19//
20// Clients should only call this request if the corresponding capability
21// supportsWriteMemoryRequest is true.
22llvm::Expected<protocol::WriteMemoryResponseBody>
23WriteMemoryRequestHandler::Run(
24 const protocol::WriteMemoryArguments &args) const {
25 const lldb::addr_t address = args.memoryReference + args.offset;
26
27 lldb::SBProcess process = dap.target.GetProcess();
28 if (!lldb::SBDebugger::StateIsStoppedState(state: process.GetState()))
29 return llvm::make_error<NotStoppedError>();
30
31 if (args.data.empty()) {
32 return llvm::make_error<DAPError>(
33 Args: "Data cannot be empty value. Provide valid data");
34 }
35
36 // The VSCode IDE or other DAP clients send memory data as a Base64 string.
37 // This function decodes it into raw binary before writing it to the target
38 // process memory.
39 std::vector<char> output;
40 auto decode_error = llvm::decodeBase64(Input: args.data, Output&: output);
41
42 if (decode_error) {
43 return llvm::make_error<DAPError>(
44 Args: llvm::toString(E: std::move(decode_error)).c_str());
45 }
46
47 lldb::SBError write_error;
48 uint64_t bytes_written = 0;
49
50 // Write the memory.
51 if (!output.empty()) {
52 lldb::SBProcess process = dap.target.GetProcess();
53 // If 'allowPartial' is false or missing, a debug adapter should attempt to
54 // verify the region is writable before writing, and fail the response if it
55 // is not.
56 if (!args.allowPartial) {
57 // Start checking from the initial write address.
58 lldb::addr_t start_address = address;
59 // Compute the end of the write range.
60 lldb::addr_t end_address = start_address + output.size() - 1;
61
62 while (start_address <= end_address) {
63 // Get memory region info for the given address.
64 // This provides the region's base, end, and permissions
65 // (read/write/executable).
66 lldb::SBMemoryRegionInfo region_info;
67 lldb::SBError error =
68 process.GetMemoryRegionInfo(load_addr: start_address, region_info);
69 // Fail if the region info retrieval fails, is not writable, or the
70 // range exceeds the region.
71 if (!error.Success() || !region_info.IsWritable()) {
72 return llvm::make_error<DAPError>(
73 Args: "Memory 0x" + llvm::utohexstr(X: args.memoryReference) +
74 " region is not writable");
75 }
76 // If the current region covers the full requested range, stop further
77 // iterations.
78 if (end_address <= region_info.GetRegionEnd()) {
79 break;
80 }
81 // Move to the start of the next memory region.
82 start_address = region_info.GetRegionEnd() + 1;
83 }
84 }
85
86 bytes_written =
87 process.WriteMemory(addr: address, buf: static_cast<void *>(output.data()),
88 size: output.size(), error&: write_error);
89 }
90
91 if (bytes_written == 0) {
92 return llvm::make_error<DAPError>(Args: write_error.GetCString());
93 }
94 protocol::WriteMemoryResponseBody response;
95 response.bytesWritten = bytes_written;
96 return response;
97}
98
99} // namespace lldb_dap
100

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