diff options
| author | Felipe de Azevedo Piovezan <fpiovezan@apple.com> | 2025-10-22 07:40:29 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-10-22 07:40:29 -0700 |
| commit | 276bccda66f333171f5ba08d18d9301ee663cf7a (patch) | |
| tree | 14852c7880cb2e38699e35f69cb4f9e9cbb607f0 /lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | |
| parent | eb74d8e03cef0bb29bccf221f5ea565e47d7ab26 (diff) | |
| download | llvm-276bccda66f333171f5ba08d18d9301ee663cf7a.zip llvm-276bccda66f333171f5ba08d18d9301ee663cf7a.tar.gz llvm-276bccda66f333171f5ba08d18d9301ee663cf7a.tar.bz2 | |
[lldb] Implement ProcessGDBRemote support for ReadMemoryRanges (#164311)
This commit makes use of the newly created MultiMemRead packet to
provide an efficient implementation of MultiMemRead inside
ProcessGDBRemote.
Testing is tricky, but it is accomplished two ways:
1. Some Objective-C tests would fail if this were implemented incorrectly,
as there is already an in-tree use of the base class implementation of
MultiMemRead, which is now getting replaced by the derived class.
2. One Objective-C test is modified so that we ensure the packet is
being sent by looking at the packet logs. While not the most elegant
solution, it is a strategy adopted in other tests as well. This gets
around the fact that we cannot instantiate / unittest a mock
ProcessGDBRemote.
Depends on https://github.com/llvm/llvm-project/pull/163651
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
| -rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 91f3a6c..b4422a7 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -86,6 +86,7 @@ #include "lldb/Host/Host.h" #include "lldb/Utility/StringExtractorGDBRemote.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" @@ -2762,6 +2763,108 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size, return 0; } +llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> +ProcessGDBRemote::ReadMemoryRanges( + llvm::ArrayRef<Range<lldb::addr_t, size_t>> ranges, + llvm::MutableArrayRef<uint8_t> buffer) { + if (!m_gdb_comm.GetMultiMemReadSupported()) + return Process::ReadMemoryRanges(ranges, buffer); + + llvm::Expected<StringExtractorGDBRemote> response = + SendMultiMemReadPacket(ranges); + if (!response) { + LLDB_LOG_ERROR(GetLog(GDBRLog::Process), response.takeError(), + "MultiMemRead error response: {0}"); + return Process::ReadMemoryRanges(ranges, buffer); + } + + llvm::StringRef response_str = response->GetStringRef(); + const unsigned expected_num_ranges = ranges.size(); + llvm::Expected<llvm::SmallVector<llvm::MutableArrayRef<uint8_t>>> + parsed_response = + ParseMultiMemReadPacket(response_str, buffer, expected_num_ranges); + if (!parsed_response) { + LLDB_LOG_ERROR(GetLog(GDBRLog::Process), parsed_response.takeError(), + "MultiMemRead error parsing response: {0}"); + return Process::ReadMemoryRanges(ranges, buffer); + } + return std::move(*parsed_response); +} + +llvm::Expected<StringExtractorGDBRemote> +ProcessGDBRemote::SendMultiMemReadPacket( + llvm::ArrayRef<Range<lldb::addr_t, size_t>> ranges) { + std::string packet_str; + llvm::raw_string_ostream stream(packet_str); + stream << "MultiMemRead:ranges:"; + + auto range_to_stream = [&](auto range) { + // the "-" marker omits the '0x' prefix. + stream << llvm::formatv("{0:x-},{1:x-}", range.base, range.size); + }; + llvm::interleave(ranges, stream, range_to_stream, ","); + stream << ";"; + + StringExtractorGDBRemote response; + GDBRemoteCommunication::PacketResult packet_result = + m_gdb_comm.SendPacketAndWaitForResponse(packet_str.data(), response, + GetInterruptTimeout()); + if (packet_result != GDBRemoteCommunication::PacketResult::Success) + return llvm::createStringError( + llvm::formatv("MultiMemRead failed to send packet: '{0}'", packet_str)); + + if (response.IsErrorResponse()) + return llvm::createStringError( + llvm::formatv("MultiMemRead failed: '{0}'", response.GetStringRef())); + + if (!response.IsNormalResponse()) + return llvm::createStringError(llvm::formatv( + "MultiMemRead unexpected response: '{0}'", response.GetStringRef())); + + return response; +} + +llvm::Expected<llvm::SmallVector<llvm::MutableArrayRef<uint8_t>>> +ProcessGDBRemote::ParseMultiMemReadPacket(llvm::StringRef response_str, + llvm::MutableArrayRef<uint8_t> buffer, + unsigned expected_num_ranges) { + // The sizes and the data are separated by a `;`. + auto [sizes_str, memory_data] = response_str.split(';'); + if (sizes_str.size() == response_str.size()) + return llvm::createStringError(llvm::formatv( + "MultiMemRead response missing field separator ';' in: '{0}'", + response_str)); + + llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results; + + // Sizes are separated by a `,`. + for (llvm::StringRef size_str : llvm::split(sizes_str, ',')) { + uint64_t read_size; + if (size_str.getAsInteger(16, read_size)) + return llvm::createStringError(llvm::formatv( + "MultiMemRead response has invalid size string: {0}", size_str)); + + if (memory_data.size() < read_size) + return llvm::createStringError( + llvm::formatv("MultiMemRead response did not have enough data, " + "requested sizes: {0}", + sizes_str)); + + llvm::StringRef region_to_read = memory_data.take_front(read_size); + memory_data = memory_data.drop_front(read_size); + + assert(buffer.size() >= read_size); + llvm::MutableArrayRef<uint8_t> region_to_write = + buffer.take_front(read_size); + buffer = buffer.drop_front(read_size); + + memcpy(region_to_write.data(), region_to_read.data(), read_size); + read_results.push_back(region_to_write); + } + + return read_results; +} + bool ProcessGDBRemote::SupportsMemoryTagging() { return m_gdb_comm.GetMemoryTaggingSupported(); } |
