[Lldb-commits] [lldb] [debugserver] Implement MultiMemRead packet (PR #162670)
Jason Molenda via lldb-commits
lldb-commits at lists.llvm.org
Thu Oct 9 16:32:38 PDT 2025
================
@@ -3160,6 +3165,140 @@ rnb_err_t RNBRemote::HandlePacket_m(const char *p) {
return SendPacket(ostrm.str());
}
+/// Returns true if `str` starts with `prefix`.
+static bool starts_with(std::string_view str, std::string_view prefix) {
+ return str.size() >= prefix.size() &&
+ str.compare(0, prefix.size(), prefix) == 0;
+}
+
+/// Attempts to parse a prefix of `number_str` as a number of type `T`. If
+/// successful, the number is returned and the prefix is dropped from
+/// `number_str`.
+template <typename T>
+static std::optional<T> extract_number(std::string_view &number_str) {
+ static_assert(std::is_integral<T>());
+ char *str_end = nullptr;
+ errno = 0;
+ nub_addr_t number = strtoull(number_str.data(), &str_end, 16);
+ if (errno != 0)
+ return std::nullopt;
+ assert(str_end);
+ number_str.remove_prefix(str_end - number_str.data());
+ return number;
+}
+
+/// Splits `list_str` into multiple string_views separated by `,`.
+static std::vector<std::string_view>
+parse_comma_separated_list(std::string_view list_str) {
+ std::vector<std::string_view> list;
+ while (!list_str.empty()) {
+ auto pos = list_str.find(',');
+ list.push_back(list_str.substr(0, pos));
+ if (pos == list_str.npos)
+ break;
+ list_str.remove_prefix(pos + 1);
+ }
+ return list;
+}
+
+rnb_err_t RNBRemote::HandlePacket_MultiMemRead(const char *p) {
+ const std::string_view packet_name("MultiMemRead:");
+ std::string_view packet(p);
+
+ if (!starts_with(packet, packet_name))
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,
+ "Invalid MultiMemRead packet prefix");
+
+ packet.remove_prefix(packet_name.size());
+
+ const std::string_view ranges_prefix("ranges:");
+ if (!starts_with(packet, ranges_prefix))
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),
+ "Missing 'ranges' in MultiMemRead packet");
+ packet.remove_prefix(ranges_prefix.size());
+
+ std::vector<std::pair<nub_addr_t, std::size_t>> ranges;
+ std::size_t total_length = 0;
+
+ // Ranges should have the form: <addr>,<size>[,<addr>,<size>]*;
+ auto end_of_ranges_pos = packet.find(';');
+ if (end_of_ranges_pos == packet.npos)
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),
+ "MultiMemRead missing end of ranges marker");
+
+ std::vector<std::string_view> numbers_list =
+ parse_comma_separated_list(packet.substr(0, end_of_ranges_pos));
+ packet.remove_prefix(end_of_ranges_pos + 1);
+
+ // Ranges are pairs, so the number of elements must be even.
+ if (numbers_list.size() % 2 == 1)
+ return HandlePacket_ILLFORMED(
+ __FILE__, __LINE__, p,
+ "MultiMemRead has an odd number of numbers for the ranges");
+
+ for (unsigned idx = 0; idx < numbers_list.size(); idx += 2) {
+ std::optional<nub_addr_t> maybe_addr =
+ extract_number<nub_addr_t>(numbers_list[idx]);
+ std::optional<size_t> maybe_length =
+ extract_number<size_t>(numbers_list[idx + 1]);
+ if (!maybe_addr || !maybe_length)
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),
+ "Invalid MultiMemRead range");
+ // A sanity check that the packet requested is not too large or a negative
+ // number.
+ if (*maybe_length > 4 * 1024 * 1024)
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),
+ "MultiMemRead length is too large");
+
+ ranges.emplace_back(*maybe_addr, *maybe_length);
+ total_length += *maybe_length;
+ }
+
+ if (ranges.empty())
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,
+ "MultiMemRead has an empty range list");
+
+ // If 'options:' is present, ensure it's empty.
+ const std::string_view options_prefix("options:");
+ if (starts_with(packet, options_prefix)) {
----------------
jasonmolenda wrote:
This hardcodes that `options` key must come after `ranges` key. I'd `find` these from the start of the original packet string.
https://github.com/llvm/llvm-project/pull/162670
More information about the lldb-commits
mailing list