Skip to content

Commit 7ef61a7

Browse files
[lldb] Implement Process::{ReadPointers,ReadUnsignedIntegers}FromMemory
These are methods that use the MultiMemRead packet to speed up reading unsigned numbers / pointers from memory. As the comments say, they should go upstream once we find a use for them there (and the timing constraints are a bit more favourable).
1 parent 0f62bb2 commit 7ef61a7

File tree

3 files changed

+152
-0
lines changed

3 files changed

+152
-0
lines changed

lldb/include/lldb/Target/Process.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,11 +1726,24 @@ class Process : public std::enable_shared_from_this<Process>,
17261726
size_t byte_size, uint64_t fail_value,
17271727
Status &error);
17281728

1729+
/// Use Process::ReadMemoryRanges to efficiently read multiple unsigned
1730+
/// integers from memory at once.
1731+
/// TODO: this should be upstream once there is a use for it there.
1732+
llvm::SmallVector<std::optional<uint64_t>>
1733+
ReadUnsignedIntegersFromMemory(llvm::ArrayRef<lldb::addr_t> addresses,
1734+
unsigned byte_size);
1735+
17291736
int64_t ReadSignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size,
17301737
int64_t fail_value, Status &error);
17311738

17321739
lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error);
17331740

1741+
/// Use Process::ReadMemoryRanges to efficiently read multiple pointers from
1742+
/// memory at once.
1743+
/// TODO: this should be upstream once there is a use for it there.
1744+
llvm::SmallVector<std::optional<lldb::addr_t>>
1745+
ReadPointersFromMemory(llvm::ArrayRef<lldb::addr_t> ptr_locs);
1746+
17341747
bool WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
17351748
Status &error);
17361749

lldb/source/Target/Process.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2429,6 +2429,45 @@ uint64_t Process::ReadUnsignedIntegerFromMemory(lldb::addr_t vm_addr,
24292429
return fail_value;
24302430
}
24312431

2432+
llvm::SmallVector<std::optional<uint64_t>>
2433+
Process::ReadUnsignedIntegersFromMemory(llvm::ArrayRef<addr_t> addresses,
2434+
unsigned integer_byte_size) {
2435+
if (addresses.empty())
2436+
return {};
2437+
// Like ReadUnsignedIntegerFromMemory, this only supports a handful
2438+
// of widths.
2439+
if (!llvm::is_contained({1u, 2u, 4u, 8u}, integer_byte_size))
2440+
return llvm::SmallVector<std::optional<uint64_t>>(addresses.size(),
2441+
std::nullopt);
2442+
2443+
llvm::SmallVector<Range<addr_t, size_t>> ranges{
2444+
llvm::map_range(addresses, [=](addr_t ptr) {
2445+
return Range<addr_t, size_t>(ptr, integer_byte_size);
2446+
})};
2447+
2448+
std::vector<uint8_t> buffer(integer_byte_size * addresses.size(), 0);
2449+
llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> memory =
2450+
ReadMemoryRanges(ranges, buffer);
2451+
2452+
llvm::SmallVector<std::optional<uint64_t>> result;
2453+
result.reserve(addresses.size());
2454+
const uint32_t addr_size = GetAddressByteSize();
2455+
const ByteOrder byte_order = GetByteOrder();
2456+
2457+
for (llvm::MutableArrayRef<uint8_t> range : memory) {
2458+
if (range.size() != integer_byte_size) {
2459+
result.push_back(std::nullopt);
2460+
continue;
2461+
}
2462+
2463+
DataExtractor data(range.data(), integer_byte_size, byte_order, addr_size);
2464+
offset_t offset = 0;
2465+
result.push_back(data.GetMaxU64(&offset, integer_byte_size));
2466+
assert(offset == integer_byte_size);
2467+
}
2468+
return result;
2469+
}
2470+
24322471
int64_t Process::ReadSignedIntegerFromMemory(lldb::addr_t vm_addr,
24332472
size_t integer_byte_size,
24342473
int64_t fail_value,
@@ -2448,6 +2487,12 @@ addr_t Process::ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error) {
24482487
return LLDB_INVALID_ADDRESS;
24492488
}
24502489

2490+
llvm::SmallVector<std::optional<addr_t>>
2491+
Process::ReadPointersFromMemory(llvm::ArrayRef<addr_t> ptr_locs) {
2492+
const size_t ptr_size = GetAddressByteSize();
2493+
return ReadUnsignedIntegersFromMemory(ptr_locs, ptr_size);
2494+
}
2495+
24512496
bool Process::WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
24522497
Status &error) {
24532498
Scalar scalar;

lldb/unittests/Target/MemoryTest.cpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,97 @@ TEST_F(MemoryDeathTest, TestReadMemoryRangesWithShortBuffer) {
367367
ASSERT_TRUE(result.empty());
368368
#endif
369369
}
370+
TEST_F(MemoryTest, TestReadPointersFromMemory) {
371+
ArchSpec arch("x86_64-apple-macosx-");
372+
Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
373+
DebuggerSP debugger_sp = Debugger::CreateInstance();
374+
ASSERT_TRUE(debugger_sp);
375+
TargetSP target_sp = CreateTarget(debugger_sp, arch);
376+
ASSERT_TRUE(target_sp);
377+
ListenerSP listener_sp(Listener::MakeListener("dummy"));
378+
ProcessSP process =
379+
std::make_shared<DummyReaderProcess>(target_sp, listener_sp);
380+
ASSERT_TRUE(process);
381+
382+
// Read pointers at arbitrary addresses.
383+
llvm::SmallVector<addr_t> ptr_locs = {0x0, 0x100, 0x2000, 0x123400};
384+
// Because of how DummyReaderProcess works, each byte of a memory read result
385+
// is its address modulo 256:
386+
constexpr addr_t expected_result = 0x0706050403020100;
387+
388+
llvm::SmallVector<std::optional<addr_t>> read_results =
389+
process->ReadPointersFromMemory(ptr_locs);
390+
391+
for (std::optional<addr_t> maybe_ptr : read_results) {
392+
ASSERT_TRUE(maybe_ptr.has_value());
393+
EXPECT_EQ(*maybe_ptr, expected_result);
394+
}
395+
}
396+
397+
TEST_F(MemoryTest, TestReadUnsignedIntegersFromMemory) {
398+
ArchSpec arch("x86_64-apple-macosx-");
399+
400+
Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
401+
DebuggerSP debugger_sp = Debugger::CreateInstance();
402+
ASSERT_TRUE(debugger_sp);
403+
TargetSP target_sp = CreateTarget(debugger_sp, arch);
404+
ASSERT_TRUE(target_sp);
405+
ListenerSP listener_sp(Listener::MakeListener("dummy"));
406+
ProcessSP process =
407+
std::make_shared<DummyReaderProcess>(target_sp, listener_sp);
408+
ASSERT_TRUE(process);
409+
410+
{ // Test reads of size 1
411+
llvm::SmallVector<addr_t> locs = {0x0, 0x101, 0x2002, 0x123403};
412+
llvm::SmallVector<std::optional<addr_t>> read_results =
413+
process->ReadUnsignedIntegersFromMemory(locs, /*byte_size=*/1);
414+
415+
for (auto [maybe_int, loc] : llvm::zip(read_results, locs)) {
416+
ASSERT_TRUE(maybe_int.has_value());
417+
EXPECT_EQ(*maybe_int, static_cast<uint8_t>(loc));
418+
}
419+
}
420+
421+
{ // Test reads of size 2
422+
llvm::SmallVector<addr_t> locs = {0x0, 0x101, 0x2002, 0x123403};
423+
llvm::SmallVector<std::optional<addr_t>> read_results =
424+
process->ReadUnsignedIntegersFromMemory(locs, /*byte_size=*/2);
425+
426+
for (auto [maybe_int, loc] : llvm::zip(read_results, locs)) {
427+
ASSERT_TRUE(maybe_int.has_value());
428+
uint64_t lsb = static_cast<uint8_t>(loc);
429+
uint64_t expected_result = ((lsb + 1) << 8) | lsb;
430+
EXPECT_EQ(*maybe_int, expected_result);
431+
}
432+
}
433+
434+
{ // Test reads of size 4
435+
llvm::SmallVector<addr_t> locs = {0x0, 0x101, 0x2002, 0x123403};
436+
llvm::SmallVector<std::optional<addr_t>> read_results =
437+
process->ReadUnsignedIntegersFromMemory(locs, /*byte_size=*/4);
438+
439+
for (auto [maybe_int, loc] : llvm::zip(read_results, locs)) {
440+
ASSERT_TRUE(maybe_int.has_value());
441+
uint64_t lsb = static_cast<uint8_t>(loc);
442+
uint64_t expected_result =
443+
((lsb + 3) << 24) | ((lsb + 2) << 16) | ((lsb + 1) << 8) | lsb;
444+
EXPECT_EQ(*maybe_int, expected_result);
445+
}
446+
}
447+
448+
{ // Test reads of size 8
449+
llvm::SmallVector<addr_t> locs = {0x0, 0x101, 0x2002, 0x123403};
450+
llvm::SmallVector<std::optional<addr_t>> read_results =
451+
process->ReadUnsignedIntegersFromMemory(locs, /*byte_size=*/8);
452+
453+
for (auto [maybe_int, loc] : llvm::zip(read_results, locs)) {
454+
ASSERT_TRUE(maybe_int.has_value());
455+
uint64_t lsb = static_cast<uint8_t>(loc);
456+
uint64_t expected_result = ((lsb + 7) << 56) | ((lsb + 6) << 48) |
457+
((lsb + 5) << 40) | ((lsb + 4) << 32) |
458+
((lsb + 3) << 24) | ((lsb + 2) << 16) |
459+
((lsb + 1) << 8) | lsb;
460+
EXPECT_EQ(*maybe_int, expected_result);
461+
}
462+
}
463+
}

0 commit comments

Comments
 (0)