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