Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions lldb/include/lldb/Target/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -1721,11 +1721,24 @@ class Process : public std::enable_shared_from_this<Process>,
size_t byte_size, uint64_t fail_value,
Status &error);

/// Use Process::ReadMemoryRanges to efficiently read multiple unsigned
/// integers from memory at once.
/// TODO: this should be upstream once there is a use for it there.
llvm::SmallVector<std::optional<uint64_t>>
ReadUnsignedIntegersFromMemory(llvm::ArrayRef<lldb::addr_t> addresses,
unsigned byte_size);

int64_t ReadSignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size,
int64_t fail_value, Status &error);

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

/// Use Process::ReadMemoryRanges to efficiently read multiple pointers from
/// memory at once.
/// TODO: this should be upstream once there is a use for it there.
llvm::SmallVector<std::optional<lldb::addr_t>>
ReadPointersFromMemory(llvm::ArrayRef<lldb::addr_t> ptr_locs);

bool WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
Status &error);

Expand Down
45 changes: 45 additions & 0 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2429,6 +2429,45 @@ uint64_t Process::ReadUnsignedIntegerFromMemory(lldb::addr_t vm_addr,
return fail_value;
}

llvm::SmallVector<std::optional<uint64_t>>
Process::ReadUnsignedIntegersFromMemory(llvm::ArrayRef<addr_t> addresses,
unsigned integer_byte_size) {
if (addresses.empty())
return {};
// Like ReadUnsignedIntegerFromMemory, this only supports a handful
// of widths.
if (!llvm::is_contained({1u, 2u, 4u, 8u}, integer_byte_size))
return llvm::SmallVector<std::optional<uint64_t>>(addresses.size(),
std::nullopt);

llvm::SmallVector<Range<addr_t, size_t>> ranges{
llvm::map_range(addresses, [=](addr_t ptr) {
return Range<addr_t, size_t>(ptr, integer_byte_size);
})};

std::vector<uint8_t> buffer(integer_byte_size * addresses.size(), 0);
llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> memory =
ReadMemoryRanges(ranges, buffer);

llvm::SmallVector<std::optional<uint64_t>> result;
result.reserve(addresses.size());
const uint32_t addr_size = GetAddressByteSize();
const ByteOrder byte_order = GetByteOrder();

for (llvm::MutableArrayRef<uint8_t> range : memory) {
if (range.size() != integer_byte_size) {
result.push_back(std::nullopt);
continue;
}

DataExtractor data(range.data(), integer_byte_size, byte_order, addr_size);
offset_t offset = 0;
result.push_back(data.GetMaxU64(&offset, integer_byte_size));
assert(offset == integer_byte_size);
}
return result;
}

int64_t Process::ReadSignedIntegerFromMemory(lldb::addr_t vm_addr,
size_t integer_byte_size,
int64_t fail_value,
Expand All @@ -2448,6 +2487,12 @@ addr_t Process::ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error) {
return LLDB_INVALID_ADDRESS;
}

llvm::SmallVector<std::optional<addr_t>>
Process::ReadPointersFromMemory(llvm::ArrayRef<addr_t> ptr_locs) {
const size_t ptr_size = GetAddressByteSize();
return ReadUnsignedIntegersFromMemory(ptr_locs, ptr_size);
}

bool Process::WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
Status &error) {
Scalar scalar;
Expand Down
94 changes: 94 additions & 0 deletions lldb/unittests/Target/MemoryTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,97 @@ TEST_F(MemoryDeathTest, TestReadMemoryRangesWithShortBuffer) {
ASSERT_TRUE(result.empty());
#endif
}
TEST_F(MemoryTest, TestReadPointersFromMemory) {
ArchSpec arch("x86_64-apple-macosx-");
Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
DebuggerSP debugger_sp = Debugger::CreateInstance();
ASSERT_TRUE(debugger_sp);
TargetSP target_sp = CreateTarget(debugger_sp, arch);
ASSERT_TRUE(target_sp);
ListenerSP listener_sp(Listener::MakeListener("dummy"));
ProcessSP process =
std::make_shared<DummyReaderProcess>(target_sp, listener_sp);
ASSERT_TRUE(process);

// Read pointers at arbitrary addresses.
llvm::SmallVector<addr_t> ptr_locs = {0x0, 0x100, 0x2000, 0x123400};
// Because of how DummyReaderProcess works, each byte of a memory read result
// is its address modulo 256:
constexpr addr_t expected_result = 0x0706050403020100;

llvm::SmallVector<std::optional<addr_t>> read_results =
process->ReadPointersFromMemory(ptr_locs);

for (std::optional<addr_t> maybe_ptr : read_results) {
ASSERT_TRUE(maybe_ptr.has_value());
EXPECT_EQ(*maybe_ptr, expected_result);
}
}

TEST_F(MemoryTest, TestReadUnsignedIntegersFromMemory) {
ArchSpec arch("x86_64-apple-macosx-");

Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
DebuggerSP debugger_sp = Debugger::CreateInstance();
ASSERT_TRUE(debugger_sp);
TargetSP target_sp = CreateTarget(debugger_sp, arch);
ASSERT_TRUE(target_sp);
ListenerSP listener_sp(Listener::MakeListener("dummy"));
ProcessSP process =
std::make_shared<DummyReaderProcess>(target_sp, listener_sp);
ASSERT_TRUE(process);

{ // Test reads of size 1
llvm::SmallVector<addr_t> locs = {0x0, 0x101, 0x2002, 0x123403};
llvm::SmallVector<std::optional<addr_t>> read_results =
process->ReadUnsignedIntegersFromMemory(locs, /*byte_size=*/1);

for (auto [maybe_int, loc] : llvm::zip(read_results, locs)) {
ASSERT_TRUE(maybe_int.has_value());
EXPECT_EQ(*maybe_int, static_cast<uint8_t>(loc));
}
}

{ // Test reads of size 2
llvm::SmallVector<addr_t> locs = {0x0, 0x101, 0x2002, 0x123403};
llvm::SmallVector<std::optional<addr_t>> read_results =
process->ReadUnsignedIntegersFromMemory(locs, /*byte_size=*/2);

for (auto [maybe_int, loc] : llvm::zip(read_results, locs)) {
ASSERT_TRUE(maybe_int.has_value());
uint64_t lsb = static_cast<uint8_t>(loc);
uint64_t expected_result = ((lsb + 1) << 8) | lsb;
EXPECT_EQ(*maybe_int, expected_result);
}
}

{ // Test reads of size 4
llvm::SmallVector<addr_t> locs = {0x0, 0x101, 0x2002, 0x123403};
llvm::SmallVector<std::optional<addr_t>> read_results =
process->ReadUnsignedIntegersFromMemory(locs, /*byte_size=*/4);

for (auto [maybe_int, loc] : llvm::zip(read_results, locs)) {
ASSERT_TRUE(maybe_int.has_value());
uint64_t lsb = static_cast<uint8_t>(loc);
uint64_t expected_result =
((lsb + 3) << 24) | ((lsb + 2) << 16) | ((lsb + 1) << 8) | lsb;
EXPECT_EQ(*maybe_int, expected_result);
}
}

{ // Test reads of size 8
llvm::SmallVector<addr_t> locs = {0x0, 0x101, 0x2002, 0x123403};
llvm::SmallVector<std::optional<addr_t>> read_results =
process->ReadUnsignedIntegersFromMemory(locs, /*byte_size=*/8);

for (auto [maybe_int, loc] : llvm::zip(read_results, locs)) {
ASSERT_TRUE(maybe_int.has_value());
uint64_t lsb = static_cast<uint8_t>(loc);
uint64_t expected_result = ((lsb + 7) << 56) | ((lsb + 6) << 48) |
((lsb + 5) << 40) | ((lsb + 4) << 32) |
((lsb + 3) << 24) | ((lsb + 2) << 16) |
((lsb + 1) << 8) | lsb;
EXPECT_EQ(*maybe_int, expected_result);
}
}
}