|
86 | 86 | #include "lldb/Host/Host.h" |
87 | 87 | #include "lldb/Utility/StringExtractorGDBRemote.h" |
88 | 88 |
|
| 89 | +#include "llvm/ADT/STLExtras.h" |
89 | 90 | #include "llvm/ADT/ScopeExit.h" |
90 | 91 | #include "llvm/ADT/StringMap.h" |
91 | 92 | #include "llvm/ADT/StringSwitch.h" |
@@ -2762,6 +2763,108 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size, |
2762 | 2763 | return 0; |
2763 | 2764 | } |
2764 | 2765 |
|
| 2766 | +llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> |
| 2767 | +ProcessGDBRemote::ReadMemoryRanges( |
| 2768 | + llvm::ArrayRef<Range<lldb::addr_t, size_t>> ranges, |
| 2769 | + llvm::MutableArrayRef<uint8_t> buffer) { |
| 2770 | + if (!m_gdb_comm.GetMultiMemReadSupported()) |
| 2771 | + return Process::ReadMemoryRanges(ranges, buffer); |
| 2772 | + |
| 2773 | + llvm::Expected<StringExtractorGDBRemote> response = |
| 2774 | + SendMultiMemReadPacket(ranges); |
| 2775 | + if (!response) { |
| 2776 | + LLDB_LOG_ERROR(GetLog(GDBRLog::Process), response.takeError(), |
| 2777 | + "MultiMemRead error response: {0}"); |
| 2778 | + return Process::ReadMemoryRanges(ranges, buffer); |
| 2779 | + } |
| 2780 | + |
| 2781 | + llvm::StringRef response_str = response->GetStringRef(); |
| 2782 | + const unsigned expected_num_ranges = ranges.size(); |
| 2783 | + llvm::Expected<llvm::SmallVector<llvm::MutableArrayRef<uint8_t>>> |
| 2784 | + parsed_response = |
| 2785 | + ParseMultiMemReadPacket(response_str, buffer, expected_num_ranges); |
| 2786 | + if (!parsed_response) { |
| 2787 | + LLDB_LOG_ERROR(GetLog(GDBRLog::Process), parsed_response.takeError(), |
| 2788 | + "MultiMemRead error parsing response: {0}"); |
| 2789 | + return Process::ReadMemoryRanges(ranges, buffer); |
| 2790 | + } |
| 2791 | + return std::move(*parsed_response); |
| 2792 | +} |
| 2793 | + |
| 2794 | +llvm::Expected<StringExtractorGDBRemote> |
| 2795 | +ProcessGDBRemote::SendMultiMemReadPacket( |
| 2796 | + llvm::ArrayRef<Range<lldb::addr_t, size_t>> ranges) { |
| 2797 | + std::string packet_str; |
| 2798 | + llvm::raw_string_ostream stream(packet_str); |
| 2799 | + stream << "MultiMemRead:ranges:"; |
| 2800 | + |
| 2801 | + auto range_to_stream = [&](auto range) { |
| 2802 | + // the "-" marker omits the '0x' prefix. |
| 2803 | + stream << llvm::formatv("{0:x-},{1:x-}", range.base, range.size); |
| 2804 | + }; |
| 2805 | + llvm::interleave(ranges, stream, range_to_stream, ","); |
| 2806 | + stream << ";"; |
| 2807 | + |
| 2808 | + StringExtractorGDBRemote response; |
| 2809 | + GDBRemoteCommunication::PacketResult packet_result = |
| 2810 | + m_gdb_comm.SendPacketAndWaitForResponse(packet_str.data(), response, |
| 2811 | + GetInterruptTimeout()); |
| 2812 | + if (packet_result != GDBRemoteCommunication::PacketResult::Success) |
| 2813 | + return llvm::createStringError( |
| 2814 | + llvm::formatv("MultiMemRead failed to send packet: '{0}'", packet_str)); |
| 2815 | + |
| 2816 | + if (response.IsErrorResponse()) |
| 2817 | + return llvm::createStringError( |
| 2818 | + llvm::formatv("MultiMemRead failed: '{0}'", response.GetStringRef())); |
| 2819 | + |
| 2820 | + if (!response.IsNormalResponse()) |
| 2821 | + return llvm::createStringError(llvm::formatv( |
| 2822 | + "MultiMemRead unexpected response: '{0}'", response.GetStringRef())); |
| 2823 | + |
| 2824 | + return response; |
| 2825 | +} |
| 2826 | + |
| 2827 | +llvm::Expected<llvm::SmallVector<llvm::MutableArrayRef<uint8_t>>> |
| 2828 | +ProcessGDBRemote::ParseMultiMemReadPacket(llvm::StringRef response_str, |
| 2829 | + llvm::MutableArrayRef<uint8_t> buffer, |
| 2830 | + unsigned expected_num_ranges) { |
| 2831 | + // The sizes and the data are separated by a `;`. |
| 2832 | + auto [sizes_str, memory_data] = response_str.split(';'); |
| 2833 | + if (sizes_str.size() == response_str.size()) |
| 2834 | + return llvm::createStringError(llvm::formatv( |
| 2835 | + "MultiMemRead response missing field separator ';' in: '{0}'", |
| 2836 | + response_str)); |
| 2837 | + |
| 2838 | + llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results; |
| 2839 | + |
| 2840 | + // Sizes are separated by a `,`. |
| 2841 | + for (llvm::StringRef size_str : llvm::split(sizes_str, ',')) { |
| 2842 | + uint64_t read_size; |
| 2843 | + if (size_str.getAsInteger(16, read_size)) |
| 2844 | + return llvm::createStringError(llvm::formatv( |
| 2845 | + "MultiMemRead response has invalid size string: {0}", size_str)); |
| 2846 | + |
| 2847 | + if (memory_data.size() < read_size) |
| 2848 | + return llvm::createStringError( |
| 2849 | + llvm::formatv("MultiMemRead response did not have enough data, " |
| 2850 | + "requested sizes: {0}", |
| 2851 | + sizes_str)); |
| 2852 | + |
| 2853 | + llvm::StringRef region_to_read = memory_data.take_front(read_size); |
| 2854 | + memory_data = memory_data.drop_front(read_size); |
| 2855 | + |
| 2856 | + assert(buffer.size() >= read_size); |
| 2857 | + llvm::MutableArrayRef<uint8_t> region_to_write = |
| 2858 | + buffer.take_front(read_size); |
| 2859 | + buffer = buffer.drop_front(read_size); |
| 2860 | + |
| 2861 | + memcpy(region_to_write.data(), region_to_read.data(), read_size); |
| 2862 | + read_results.push_back(region_to_write); |
| 2863 | + } |
| 2864 | + |
| 2865 | + return read_results; |
| 2866 | +} |
| 2867 | + |
2765 | 2868 | bool ProcessGDBRemote::SupportsMemoryTagging() { |
2766 | 2869 | return m_gdb_comm.GetMemoryTaggingSupported(); |
2767 | 2870 | } |
|
0 commit comments