Skip to content

Commit 55c8f39

Browse files
fixup! Address review comments
1 parent cb9357d commit 55c8f39

File tree

3 files changed

+94
-83
lines changed

3 files changed

+94
-83
lines changed
Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Tests the exit code/description coming from the debugserver.
2+
Tests debugserver support for MultiMemRead.
33
"""
44

55
import lldb
@@ -17,12 +17,16 @@ def send_process_packet(self, packet_str):
1717
# packet: <packet_str>
1818
# response: <response>
1919
reply = self.res.GetOutput().split("\n")
20-
reply[0] = reply[0].strip()
21-
reply[1] = reply[1].strip()
20+
packet = reply[0].strip()
21+
response = reply[1].strip()
2222

23-
self.assertTrue(reply[0].startswith("packet: "), reply[0])
24-
self.assertTrue(reply[1].startswith("response: "))
25-
return reply[1][len("response: ") :]
23+
self.assertTrue(packet.startswith("packet: "))
24+
self.assertTrue(response.startswith("response: "))
25+
return response[len("response: ") :]
26+
27+
def check_invalid_packet(self, packet_str):
28+
reply = self.send_process_packet("packet_str")
29+
self.assertEqual(reply, "E03")
2630

2731
def test_packets(self):
2832
self.build()
@@ -36,30 +40,41 @@ def test_packets(self):
3640

3741
mem_address_var = thread.frames[0].FindVariable("memory")
3842
self.assertTrue(mem_address_var)
39-
mem_address = int(mem_address_var.GetValue(), 16)
43+
mem_address = mem_address_var.GetValueAsUnsigned() + 42
4044

41-
reply = self.send_process_packet("MultiMemRead:")
42-
self.assertEqual(reply, "E03")
43-
reply = self.send_process_packet("MultiMemRead:ranges:")
44-
self.assertEqual(reply, "E03")
45-
reply = self.send_process_packet("MultiMemRead:ranges:10")
46-
self.assertEqual(reply, "E03")
47-
reply = self.send_process_packet("MultiMemRead:ranges:10,")
48-
self.assertEqual(reply, "E03")
49-
reply = self.send_process_packet("MultiMemRead:ranges:10,2")
50-
self.assertEqual(reply, "E03")
51-
reply = self.send_process_packet("MultiMemRead:ranges:10,2,")
52-
self.assertEqual(reply, "E03")
45+
# no ":"
46+
self.check_invalid_packet("MultiMemRead")
47+
# missing ranges
48+
self.check_invalid_packet("MultiMemRead:")
49+
# needs at least one range
50+
self.check_invalid_packet("MultiMemRead:ranges:")
51+
# needs at least one range
52+
self.check_invalid_packet("MultiMemRead:ranges:,")
53+
# a range is a pair of numbers
54+
self.check_invalid_packet("MultiMemRead:ranges:10")
55+
# a range is a pair of numbers
56+
self.check_invalid_packet("MultiMemRead:ranges:10,")
57+
# range list must end with ;
58+
self.check_invalid_packet("MultiMemRead:ranges:10,2")
59+
self.check_invalid_packet("MultiMemRead:ranges:10,2,")
60+
self.check_invalid_packet("MultiMemRead:ranges:10,2,3")
61+
# ranges are pairs of numbers.
62+
self.check_invalid_packet("MultiMemRead:ranges:10,2,3;")
63+
# unrecognized field
64+
self.check_invalid_packet("MultiMemRead:ranges:10,2;blah:;")
65+
# unrecognized field
66+
self.check_invalid_packet("MultiMemRead:blah:;ranges:10,2;")
67+
68+
# This is a valid way of testing for MultiMemRead support
69+
reply = self.send_process_packet("MultiMemRead:ranges:0,0;")
70+
self.assertEqual(reply, "0;")
71+
# Debugserver is permissive with trailing commas.
5372
reply = self.send_process_packet("MultiMemRead:ranges:10,2,;")
54-
self.assertEqual(reply, "0;") # Debugserver is permissive with trailing commas.
73+
self.assertEqual(reply, "0;")
5574
reply = self.send_process_packet("MultiMemRead:ranges:10,2;")
5675
self.assertEqual(reply, "0;")
5776
reply = self.send_process_packet(f"MultiMemRead:ranges:{mem_address:x},0;")
5877
self.assertEqual(reply, "0;")
59-
reply = self.send_process_packet(
60-
f"MultiMemRead:ranges:{mem_address:x},0;options:;"
61-
)
62-
self.assertEqual(reply, "0;")
6378
reply = self.send_process_packet(f"MultiMemRead:ranges:{mem_address:x},2;")
6479
self.assertEqual(reply, "2;ab")
6580
reply = self.send_process_packet(
@@ -70,3 +85,14 @@ def test_packets(self):
7085
f"MultiMemRead:ranges:{mem_address:x},2,{mem_address+2:x},4,{mem_address+6:x},8;"
7186
)
7287
self.assertEqual(reply, "2,4,8;abcdefghijklmn")
88+
89+
# Test zero length in the middle.
90+
reply = self.send_process_packet(
91+
f"MultiMemRead:ranges:{mem_address:x},2,{mem_address+2:x},0,{mem_address+6:x},8;"
92+
)
93+
self.assertEqual(reply, "2,0,8;abghijklmn")
94+
# Test zero length in the end.
95+
reply = self.send_process_packet(
96+
f"MultiMemRead:ranges:{mem_address:x},2,{mem_address+2:x},4,{mem_address+6:x},0;"
97+
)
98+
self.assertEqual(reply, "2,4,0;abcdef")

lldb/test/API/macosx/debugserver-multimemread/main.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
int main(int argc, char **argv) {
55
char *memory = malloc(1024);
66
memset(memory, '-', 1024);
7-
for (int i = 0; i < 50; i++)
8-
memory[i] = 'a' + i;
7+
// Write "interesting" characters at an offset from the memory filled with
8+
// `-`. This way, if we read outside the range in either direction, we should
9+
// find `-`s`.
10+
int offset = 42;
11+
for (int i = offset; i < offset + 14; i++)
12+
memory[i] = 'a' + (i - offset);
913
return 0; // break here
1014
}

lldb/tools/debugserver/source/RNBRemote.cpp

Lines changed: 38 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,20 @@ static uint64_t decode_uint64(const char *p, int base, char **end = nullptr,
170170
return addr;
171171
}
172172

173+
/// Attempts to parse a prefix of `number_str` as a uint64_t. If
174+
/// successful, the number is returned and the prefix is dropped from
175+
/// `number_str`.
176+
static std::optional<uint64_t> extract_u64(std::string_view &number_str) {
177+
char *str_end = nullptr;
178+
errno = 0;
179+
uint64_t number = strtoull(number_str.data(), &str_end, 16);
180+
if (errno != 0)
181+
return std::nullopt;
182+
assert(str_end);
183+
number_str.remove_prefix(str_end - number_str.data());
184+
return number;
185+
}
186+
173187
static void append_hex_value(std::ostream &ostrm, const void *buf,
174188
size_t buf_size, bool swap) {
175189
int i;
@@ -204,6 +218,25 @@ static void append_hexified_string(std::ostream &ostrm,
204218
}
205219
}
206220

221+
/// Returns true if `str` starts with `prefix`.
222+
static bool starts_with(std::string_view str, std::string_view prefix) {
223+
return str.substr(0, prefix.size()) == prefix;
224+
}
225+
226+
/// Splits `list_str` into multiple string_views separated by `,`.
227+
static std::vector<std::string_view>
228+
parse_comma_separated_list(std::string_view list_str) {
229+
std::vector<std::string_view> list;
230+
while (!list_str.empty()) {
231+
auto pos = list_str.find(',');
232+
list.push_back(list_str.substr(0, pos));
233+
if (pos == list_str.npos)
234+
break;
235+
list_str.remove_prefix(pos + 1);
236+
}
237+
return list;
238+
}
239+
207240
// from System.framework/Versions/B/PrivateHeaders/sys/codesign.h
208241
extern "C" {
209242
#define CS_OPS_STATUS 0 /* return status */
@@ -3155,42 +3188,6 @@ rnb_err_t RNBRemote::HandlePacket_m(const char *p) {
31553188
return SendPacket(ostrm.str());
31563189
}
31573190

3158-
/// Returns true if `str` starts with `prefix`.
3159-
static bool starts_with(std::string_view str, std::string_view prefix) {
3160-
return str.size() >= prefix.size() &&
3161-
str.compare(0, prefix.size(), prefix) == 0;
3162-
}
3163-
3164-
/// Attempts to parse a prefix of `number_str` as a number of type `T`. If
3165-
/// successful, the number is returned and the prefix is dropped from
3166-
/// `number_str`.
3167-
template <typename T>
3168-
static std::optional<T> extract_number(std::string_view &number_str) {
3169-
static_assert(std::is_integral<T>());
3170-
char *str_end = nullptr;
3171-
errno = 0;
3172-
nub_addr_t number = strtoull(number_str.data(), &str_end, 16);
3173-
if (errno != 0)
3174-
return std::nullopt;
3175-
assert(str_end);
3176-
number_str.remove_prefix(str_end - number_str.data());
3177-
return number;
3178-
}
3179-
3180-
/// Splits `list_str` into multiple string_views separated by `,`.
3181-
static std::vector<std::string_view>
3182-
parse_comma_separated_list(std::string_view list_str) {
3183-
std::vector<std::string_view> list;
3184-
while (!list_str.empty()) {
3185-
auto pos = list_str.find(',');
3186-
list.push_back(list_str.substr(0, pos));
3187-
if (pos == list_str.npos)
3188-
break;
3189-
list_str.remove_prefix(pos + 1);
3190-
}
3191-
return list;
3192-
}
3193-
31943191
rnb_err_t RNBRemote::HandlePacket_MultiMemRead(const char *p) {
31953192
const std::string_view packet_name("MultiMemRead:");
31963193
std::string_view packet(p);
@@ -3227,10 +3224,8 @@ rnb_err_t RNBRemote::HandlePacket_MultiMemRead(const char *p) {
32273224
"MultiMemRead has an odd number of numbers for the ranges");
32283225

32293226
for (unsigned idx = 0; idx < numbers_list.size(); idx += 2) {
3230-
std::optional<nub_addr_t> maybe_addr =
3231-
extract_number<nub_addr_t>(numbers_list[idx]);
3232-
std::optional<size_t> maybe_length =
3233-
extract_number<size_t>(numbers_list[idx + 1]);
3227+
std::optional<uint64_t> maybe_addr = extract_u64(numbers_list[idx]);
3228+
std::optional<uint64_t> maybe_length = extract_u64(numbers_list[idx + 1]);
32343229
if (!maybe_addr || !maybe_length)
32353230
return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),
32363231
"Invalid MultiMemRead range");
@@ -3248,28 +3243,14 @@ rnb_err_t RNBRemote::HandlePacket_MultiMemRead(const char *p) {
32483243
return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,
32493244
"MultiMemRead has an empty range list");
32503245

3251-
// If 'options:' is present, ensure it's empty.
3252-
const std::string_view options_prefix("options:");
3253-
if (starts_with(packet, options_prefix)) {
3254-
packet.remove_prefix(options_prefix.size());
3255-
if (packet.empty())
3256-
return HandlePacket_ILLFORMED(
3257-
__FILE__, __LINE__, packet.data(),
3258-
"Too short 'options' in MultiMemRead packet");
3259-
if (packet[0] != ';')
3260-
return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),
3261-
"Unimplemented 'options' in MultiMemRead");
3262-
packet.remove_prefix(1);
3263-
}
3264-
32653246
if (!packet.empty())
3266-
return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,
3267-
"Invalid MultiMemRead address_range");
3247+
return HandlePacket_ILLFORMED(
3248+
__FILE__, __LINE__, p, "MultiMemRead packet has unrecognized fields");
32683249

32693250
std::vector<std::vector<uint8_t>> buffers;
32703251
buffers.reserve(ranges.size());
32713252
for (auto [base_addr, length] : ranges) {
3272-
buffers.emplace_back(length, '\0');
3253+
buffers.emplace_back(length, 0);
32733254
nub_size_t bytes_read = DNBProcessMemoryRead(m_ctx.ProcessID(), base_addr,
32743255
length, buffers.back().data());
32753256
buffers.back().resize(bytes_read);

0 commit comments

Comments
 (0)