diff options
author | Christopher Ferris <cferris@google.com> | 2017-12-07 17:41:18 -0800 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2017-12-07 19:00:00 -0800 |
commit | e328673a305a5c9f4acf73a7a2826eb61390632c (patch) | |
tree | a4de300723718b8bfac81cff5a0ab7caa4b76b4a /libunwindstack/tests/MemoryRemoteTest.cpp | |
parent | 255c43cd050f5202e96483430684c19b7ce916ff (diff) |
Add method to detect remote read function to use.
The process_vm_read function is much faster than ptrace, but sometimes
that will not work on a remote process. Modify the libunwindstack
MemoryRemote object to figure out which one it can use.
Wrote new unit test to verify this checking behavior.
Modify libbacktrace so that the read from libunwind is used instead of
using the default ptrace calls.
Add some benchmarks to libbacktrace to compare the two different methods.
Test: Ran unit tests libbacktrace/libunwindstack/debuggerd.
Test: Ran debuggerd -b <SYSTEM_SERVER_PID>
Test: Ran debuggerd -b <MEDIACODEC PID>
Test: Ran debuggerd -b <RANDOM_PID>
Test: Used crasher to create tombstones and verified stack data is
Test: dumped properly.
Change-Id: If75ca238289532dd8e1de430d569cabb2523380a
Diffstat (limited to 'libunwindstack/tests/MemoryRemoteTest.cpp')
-rw-r--r-- | libunwindstack/tests/MemoryRemoteTest.cpp | 55 |
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 |