Loading libunwindstack/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -212,6 +212,7 @@ cc_test { "tests/RegsStepIfSignalHandlerTest.cpp", "tests/RegsTest.cpp", "tests/SymbolsTest.cpp", "tests/TestUtils.cpp", "tests/UnwindOfflineTest.cpp", "tests/UnwindTest.cpp", "tests/UnwinderTest.cpp", Loading libunwindstack/tests/TestUtils.cpp 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <malloc.h> #include <stdint.h> #include <gtest/gtest.h> namespace unwindstack { void TestCheckForLeaks(void (*unwind_func)(void*), void* data) { static constexpr size_t kNumLeakLoops = 200; static constexpr size_t kMaxAllowedLeakBytes = 32 * 1024; size_t first_allocated_bytes = 0; size_t last_allocated_bytes = 0; for (size_t i = 0; i < kNumLeakLoops; i++) { unwind_func(data); size_t allocated_bytes = mallinfo().uordblks; if (first_allocated_bytes == 0) { first_allocated_bytes = allocated_bytes; } else if (last_allocated_bytes > first_allocated_bytes) { // Check that the memory did not increase too much over the first loop. ASSERT_LE(last_allocated_bytes - first_allocated_bytes, kMaxAllowedLeakBytes); } last_allocated_bytes = allocated_bytes; } } } // namespace unwindstack libunwindstack/tests/TestUtils.h +2 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,8 @@ inline bool TestQuiescePid(pid_t pid) { return ready; } void TestCheckForLeaks(void (*unwind_func)(void*), void* data); } // namespace unwindstack #endif // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H libunwindstack/tests/UnwindOfflineTest.cpp +38 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ #include <unwindstack/Unwinder.h> #include "ElfTestUtils.h" #include "TestUtils.h" namespace unwindstack { Loading Loading @@ -901,6 +902,43 @@ TEST_F(UnwindOfflineTest, jit_debug_arm) { EXPECT_EQ(0xff85f0c0U, unwinder.frames()[75].sp); } struct LeakType { LeakType(Maps* maps, Regs* regs, std::shared_ptr<Memory>& process_memory) : maps(maps), regs(regs), process_memory(process_memory) {} Maps* maps; Regs* regs; std::shared_ptr<Memory>& process_memory; }; static void OfflineUnwind(void* data) { LeakType* leak_data = reinterpret_cast<LeakType*>(data); std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone()); JitDebug jit_debug(leak_data->process_memory); Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory); unwinder.SetJitDebug(&jit_debug, regs_copy->Arch()); unwinder.Unwind(); ASSERT_EQ(76U, unwinder.NumFrames()); } TEST_F(UnwindOfflineTest, unwind_offline_check_for_leaks) { ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM)); MemoryOfflineParts* memory = new MemoryOfflineParts; AddMemory(dir_ + "descriptor.data", memory); AddMemory(dir_ + "descriptor1.data", memory); AddMemory(dir_ + "stack.data", memory); for (size_t i = 0; i < 7; i++) { AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory); AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory); } process_memory_.reset(memory); LeakType data(maps_.get(), regs_.get(), process_memory_); TestCheckForLeaks(OfflineUnwind, &data); } // The eh_frame_hdr data is present but set to zero fdes. This should // fallback to iterating over the cies/fdes and ignore the eh_frame_hdr. // No .gnu_debugdata section in the elf file, so no symbols. Loading libunwindstack/tests/UnwindTest.cpp +66 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,21 @@ TEST_F(UnwindTest, local_use_from_pid) { OuterFunction(TEST_TYPE_LOCAL_UNWINDER_FROM_PID); } static void LocalUnwind(void* data) { TestTypeEnum* test_type = reinterpret_cast<TestTypeEnum*>(data); OuterFunction(*test_type); } TEST_F(UnwindTest, local_check_for_leak) { TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER; TestCheckForLeaks(LocalUnwind, &test_type); } TEST_F(UnwindTest, local_use_from_pid_check_for_leak) { TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER_FROM_PID; TestCheckForLeaks(LocalUnwind, &test_type); } void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) { *completed = false; // Need to sleep before attempting first ptrace. Without this, on the Loading Loading @@ -279,6 +294,57 @@ TEST_F(UnwindTest, unwind_from_pid_remote) { << "ptrace detach failed with unexpected error: " << strerror(errno); } static void RemoteCheckForLeaks(void (*unwind_func)(void*)) { pid_t pid; if ((pid = fork()) == 0) { OuterFunction(TEST_TYPE_REMOTE); exit(0); } ASSERT_NE(-1, pid); TestScopedPidReaper reap(pid); bool completed; WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed); ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready."; TestCheckForLeaks(unwind_func, &pid); ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0)) << "ptrace detach failed with unexpected error: " << strerror(errno); } static void RemoteUnwind(void* data) { pid_t* pid = reinterpret_cast<pid_t*>(data); RemoteMaps maps(*pid); ASSERT_TRUE(maps.Parse()); std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid)); ASSERT_TRUE(regs.get() != nullptr); VerifyUnwind(*pid, &maps, regs.get(), kFunctionOrder); } TEST_F(UnwindTest, remote_check_for_leaks) { RemoteCheckForLeaks(RemoteUnwind); } static void RemoteUnwindFromPid(void* data) { pid_t* pid = reinterpret_cast<pid_t*>(data); std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid)); ASSERT_TRUE(regs.get() != nullptr); UnwinderFromPid unwinder(512, *pid); ASSERT_TRUE(unwinder.Init(regs->Arch())); unwinder.SetRegs(regs.get()); VerifyUnwind(&unwinder, kFunctionOrder); } TEST_F(UnwindTest, remote_unwind_for_pid_check_for_leaks) { RemoteCheckForLeaks(RemoteUnwindFromPid); } TEST_F(UnwindTest, from_context) { std::atomic_int tid(0); std::thread thread([&]() { Loading Loading
libunwindstack/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -212,6 +212,7 @@ cc_test { "tests/RegsStepIfSignalHandlerTest.cpp", "tests/RegsTest.cpp", "tests/SymbolsTest.cpp", "tests/TestUtils.cpp", "tests/UnwindOfflineTest.cpp", "tests/UnwindTest.cpp", "tests/UnwinderTest.cpp", Loading
libunwindstack/tests/TestUtils.cpp 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <malloc.h> #include <stdint.h> #include <gtest/gtest.h> namespace unwindstack { void TestCheckForLeaks(void (*unwind_func)(void*), void* data) { static constexpr size_t kNumLeakLoops = 200; static constexpr size_t kMaxAllowedLeakBytes = 32 * 1024; size_t first_allocated_bytes = 0; size_t last_allocated_bytes = 0; for (size_t i = 0; i < kNumLeakLoops; i++) { unwind_func(data); size_t allocated_bytes = mallinfo().uordblks; if (first_allocated_bytes == 0) { first_allocated_bytes = allocated_bytes; } else if (last_allocated_bytes > first_allocated_bytes) { // Check that the memory did not increase too much over the first loop. ASSERT_LE(last_allocated_bytes - first_allocated_bytes, kMaxAllowedLeakBytes); } last_allocated_bytes = allocated_bytes; } } } // namespace unwindstack
libunwindstack/tests/TestUtils.h +2 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,8 @@ inline bool TestQuiescePid(pid_t pid) { return ready; } void TestCheckForLeaks(void (*unwind_func)(void*), void* data); } // namespace unwindstack #endif // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
libunwindstack/tests/UnwindOfflineTest.cpp +38 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ #include <unwindstack/Unwinder.h> #include "ElfTestUtils.h" #include "TestUtils.h" namespace unwindstack { Loading Loading @@ -901,6 +902,43 @@ TEST_F(UnwindOfflineTest, jit_debug_arm) { EXPECT_EQ(0xff85f0c0U, unwinder.frames()[75].sp); } struct LeakType { LeakType(Maps* maps, Regs* regs, std::shared_ptr<Memory>& process_memory) : maps(maps), regs(regs), process_memory(process_memory) {} Maps* maps; Regs* regs; std::shared_ptr<Memory>& process_memory; }; static void OfflineUnwind(void* data) { LeakType* leak_data = reinterpret_cast<LeakType*>(data); std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone()); JitDebug jit_debug(leak_data->process_memory); Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory); unwinder.SetJitDebug(&jit_debug, regs_copy->Arch()); unwinder.Unwind(); ASSERT_EQ(76U, unwinder.NumFrames()); } TEST_F(UnwindOfflineTest, unwind_offline_check_for_leaks) { ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM)); MemoryOfflineParts* memory = new MemoryOfflineParts; AddMemory(dir_ + "descriptor.data", memory); AddMemory(dir_ + "descriptor1.data", memory); AddMemory(dir_ + "stack.data", memory); for (size_t i = 0; i < 7; i++) { AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory); AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory); } process_memory_.reset(memory); LeakType data(maps_.get(), regs_.get(), process_memory_); TestCheckForLeaks(OfflineUnwind, &data); } // The eh_frame_hdr data is present but set to zero fdes. This should // fallback to iterating over the cies/fdes and ignore the eh_frame_hdr. // No .gnu_debugdata section in the elf file, so no symbols. Loading
libunwindstack/tests/UnwindTest.cpp +66 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,21 @@ TEST_F(UnwindTest, local_use_from_pid) { OuterFunction(TEST_TYPE_LOCAL_UNWINDER_FROM_PID); } static void LocalUnwind(void* data) { TestTypeEnum* test_type = reinterpret_cast<TestTypeEnum*>(data); OuterFunction(*test_type); } TEST_F(UnwindTest, local_check_for_leak) { TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER; TestCheckForLeaks(LocalUnwind, &test_type); } TEST_F(UnwindTest, local_use_from_pid_check_for_leak) { TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER_FROM_PID; TestCheckForLeaks(LocalUnwind, &test_type); } void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) { *completed = false; // Need to sleep before attempting first ptrace. Without this, on the Loading Loading @@ -279,6 +294,57 @@ TEST_F(UnwindTest, unwind_from_pid_remote) { << "ptrace detach failed with unexpected error: " << strerror(errno); } static void RemoteCheckForLeaks(void (*unwind_func)(void*)) { pid_t pid; if ((pid = fork()) == 0) { OuterFunction(TEST_TYPE_REMOTE); exit(0); } ASSERT_NE(-1, pid); TestScopedPidReaper reap(pid); bool completed; WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed); ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready."; TestCheckForLeaks(unwind_func, &pid); ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0)) << "ptrace detach failed with unexpected error: " << strerror(errno); } static void RemoteUnwind(void* data) { pid_t* pid = reinterpret_cast<pid_t*>(data); RemoteMaps maps(*pid); ASSERT_TRUE(maps.Parse()); std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid)); ASSERT_TRUE(regs.get() != nullptr); VerifyUnwind(*pid, &maps, regs.get(), kFunctionOrder); } TEST_F(UnwindTest, remote_check_for_leaks) { RemoteCheckForLeaks(RemoteUnwind); } static void RemoteUnwindFromPid(void* data) { pid_t* pid = reinterpret_cast<pid_t*>(data); std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid)); ASSERT_TRUE(regs.get() != nullptr); UnwinderFromPid unwinder(512, *pid); ASSERT_TRUE(unwinder.Init(regs->Arch())); unwinder.SetRegs(regs.get()); VerifyUnwind(&unwinder, kFunctionOrder); } TEST_F(UnwindTest, remote_unwind_for_pid_check_for_leaks) { RemoteCheckForLeaks(RemoteUnwindFromPid); } TEST_F(UnwindTest, from_context) { std::atomic_int tid(0); std::thread thread([&]() { Loading