summaryrefslogtreecommitdiff
path: root/libunwindstack/tests/MemoryRemoteTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libunwindstack/tests/MemoryRemoteTest.cpp')
-rw-r--r--libunwindstack/tests/MemoryRemoteTest.cpp55
1 files changed, 53 insertions, 2 deletions
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index 8aa860522..f5492a267 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -225,7 +225,7 @@ TEST_F(MemoryRemoteTest, read_mprotect_hole) {
MemoryRemote remote(pid);
std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
- size_t read_size = remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), page_size * 3);
+ size_t read_size = remote.Read(reinterpret_cast<uint64_t>(mapping), dst.data(), page_size * 3);
// Some read methods can read PROT_NONE maps, allow that.
ASSERT_LE(page_size, read_size);
for (size_t i = 0; i < read_size; ++i) {
@@ -260,7 +260,7 @@ TEST_F(MemoryRemoteTest, read_munmap_hole) {
MemoryRemote remote(pid);
std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
- size_t read_size = remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), page_size * 3);
+ size_t read_size = remote.Read(reinterpret_cast<uint64_t>(mapping), dst.data(), page_size * 3);
ASSERT_EQ(page_size, read_size);
for (size_t i = 0; i < read_size; ++i) {
ASSERT_EQ(0xFF, dst[i]);
@@ -270,4 +270,55 @@ TEST_F(MemoryRemoteTest, read_munmap_hole) {
}
}
+// Verify that the memory remote object chooses a memory read function
+// properly. Either process_vm_readv or ptrace.
+TEST_F(MemoryRemoteTest, read_choose_correctly) {
+ size_t page_size = getpagesize();
+ void* mapping =
+ mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ ASSERT_NE(MAP_FAILED, mapping);
+ memset(mapping, 0xFC, 2 * page_size);
+ ASSERT_EQ(0, mprotect(static_cast<char*>(mapping), page_size, PROT_NONE));
+
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ while (true)
+ ;
+ exit(1);
+ }
+ ASSERT_LT(0, pid);
+ TestScopedPidReaper reap(pid);
+
+ ASSERT_EQ(0, munmap(mapping, 2 * page_size));
+
+ ASSERT_TRUE(Attach(pid));
+
+ // We know that process_vm_readv of a mprotect'd PROT_NONE region will fail.
+ // Read from the PROT_NONE area first to force the choice of ptrace.
+ MemoryRemote remote_ptrace(pid);
+ uint32_t value;
+ size_t bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+ ASSERT_EQ(sizeof(value), bytes);
+ ASSERT_EQ(0xfcfcfcfcU, value);
+ bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+ ASSERT_EQ(sizeof(value), bytes);
+ ASSERT_EQ(0xfcfcfcfcU, value);
+ bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+ ASSERT_EQ(sizeof(value), bytes);
+ ASSERT_EQ(0xfcfcfcfcU, value);
+
+ // Now verify that choosing process_vm_readv results in failing reads of
+ // the PROT_NONE part of the map. Read from a valid map first which
+ // should prefer process_vm_readv, and keep that as the read function.
+ MemoryRemote remote_readv(pid);
+ bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+ ASSERT_EQ(sizeof(value), bytes);
+ ASSERT_EQ(0xfcfcfcfcU, value);
+ bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+ ASSERT_EQ(0U, bytes);
+ bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+ ASSERT_EQ(sizeof(value), bytes);
+ ASSERT_EQ(0xfcfcfcfcU, value);
+}
+
} // namespace unwindstack