From 9e65d1402e03f941b7b18d085b132d55a28aecb3 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Fri, 7 Jan 2022 12:50:19 -0800 Subject: Remove the LocalUnwinder object. This object is no longer needed, and is actually slower than using the Unwinder object. Bug: 120606663 Test: All unit tests pass. Change-Id: I1b0e53b1f12fc5ac92c6b0e167ded5e906c7962d --- libunwindstack/Android.bp | 2 - libunwindstack/LocalUnwinder.cpp | 130 ------------- .../benchmarks/local_unwind_benchmarks.cpp | 18 -- libunwindstack/include/unwindstack/LocalUnwinder.h | 86 --------- libunwindstack/tests/LocalUnwinderTest.cpp | 201 --------------------- libunwindstack/tests/TestLocal.cpp | 25 +-- 6 files changed, 2 insertions(+), 460 deletions(-) delete mode 100644 libunwindstack/LocalUnwinder.cpp delete mode 100644 libunwindstack/include/unwindstack/LocalUnwinder.h delete mode 100644 libunwindstack/tests/LocalUnwinderTest.cpp diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index 3e2ec16..e842c11 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -69,7 +69,6 @@ libunwindstack_common_src_files = [ "Memory.cpp", "MemoryMte.cpp", "MemoryXz.cpp", - "LocalUnwinder.cpp", "Regs.cpp", "RegsArm.cpp", "RegsArm64.cpp", @@ -291,7 +290,6 @@ cc_defaults { "tests/GlobalTest.cpp", "tests/IsolatedSettings.cpp", "tests/JitDebugTest.cpp", - "tests/LocalUnwinderTest.cpp", "tests/LocalUpdatableMapsTest.cpp", "tests/LogFake.cpp", "tests/MapInfoCreateMemoryTest.cpp", diff --git a/libunwindstack/LocalUnwinder.cpp b/libunwindstack/LocalUnwinder.cpp deleted file mode 100644 index 6bdcabb..0000000 --- a/libunwindstack/LocalUnwinder.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace unwindstack { - -bool LocalUnwinder::Init() { - // Create the maps. - maps_.reset(new unwindstack::LocalUpdatableMaps()); - if (!maps_->Parse()) { - maps_.reset(); - return false; - } - - process_memory_ = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid()); - - return true; -} - -bool LocalUnwinder::ShouldSkipLibrary(const std::string& map_name) { - for (const std::string& skip_library : skip_libraries_) { - if (skip_library == map_name) { - return true; - } - } - return false; -} - -bool LocalUnwinder::Unwind(std::vector* frame_info, size_t max_frames) { - std::unique_ptr regs(unwindstack::Regs::CreateFromLocal()); - unwindstack::RegsGetLocal(regs.get()); - ArchEnum arch = regs->Arch(); - - // Clear any cached data from previous unwinds. - process_memory_->Clear(); - - size_t num_frames = 0; - bool adjust_pc = false; - while (true) { - uint64_t cur_pc = regs->pc(); - uint64_t cur_sp = regs->sp(); - - std::shared_ptr map_info = maps_->Find(cur_pc); - if (map_info == nullptr) { - break; - } - - Elf* elf = map_info->GetElf(process_memory_, arch); - uint64_t rel_pc = elf->GetRelPc(cur_pc, map_info.get()); - uint64_t step_pc = rel_pc; - uint64_t pc_adjustment; - if (adjust_pc) { - pc_adjustment = GetPcAdjustment(rel_pc, elf, arch); - } else { - pc_adjustment = 0; - } - step_pc -= pc_adjustment; - - bool finished = false; - bool is_signal_frame = false; - if (elf->StepIfSignalHandler(rel_pc, regs.get(), process_memory_.get())) { - step_pc = rel_pc; - } else if (!elf->Step(step_pc, regs.get(), process_memory_.get(), &finished, - &is_signal_frame)) { - finished = true; - } - - // Skip any locations that are within this library. - if (num_frames != 0 || !ShouldSkipLibrary(map_info->name())) { - // Add frame information. - SharedString func_name; - uint64_t func_offset; - if (elf->GetFunctionName(rel_pc, &func_name, &func_offset)) { - frame_info->emplace_back(map_info, cur_pc - pc_adjustment, rel_pc - pc_adjustment, - func_name, func_offset); - } else { - frame_info->emplace_back(map_info, cur_pc - pc_adjustment, rel_pc - pc_adjustment, "", 0); - } - num_frames++; - } - - if (finished || frame_info->size() == max_frames || - (cur_pc == regs->pc() && cur_sp == regs->sp())) { - break; - } - adjust_pc = true; - } - return num_frames != 0; -} - -} // namespace unwindstack diff --git a/libunwindstack/benchmarks/local_unwind_benchmarks.cpp b/libunwindstack/benchmarks/local_unwind_benchmarks.cpp index 83894a2..dd12ab5 100644 --- a/libunwindstack/benchmarks/local_unwind_benchmarks.cpp +++ b/libunwindstack/benchmarks/local_unwind_benchmarks.cpp @@ -22,7 +22,6 @@ #include -#include #include #include #include @@ -76,13 +75,6 @@ static size_t Unwind(void* data_ptr) { return unwinder.NumFrames(); } -static size_t LocalUnwind(void* unwind_ptr) { - unwindstack::LocalUnwinder* unwinder = reinterpret_cast(unwind_ptr); - std::vector frame_info; - unwinder->Unwind(&frame_info, kMaxFrames); - return frame_info.size(); -} - static void BM_local_unwind_uncached_process_memory(benchmark::State& state) { auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid()); unwindstack::LocalMaps maps; @@ -143,16 +135,6 @@ static void BM_local_unwind_local_updatable_maps_thread_cached(benchmark::State& } BENCHMARK(BM_local_unwind_local_updatable_maps_thread_cached); -static void BM_local_unwind_local_unwinder(benchmark::State& state) { - unwindstack::LocalUnwinder unwinder; - if (!unwinder.Init()) { - state.SkipWithError("Failed to init local unwinder."); - } - - Run(state, LocalUnwind, &unwinder); -} -BENCHMARK(BM_local_unwind_local_unwinder); - static void BM_local_unwind_uncached_process_memory_no_func_names(benchmark::State& state) { auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid()); unwindstack::LocalMaps maps; diff --git a/libunwindstack/include/unwindstack/LocalUnwinder.h b/libunwindstack/include/unwindstack/LocalUnwinder.h deleted file mode 100644 index b3dbb4f..0000000 --- a/libunwindstack/include/unwindstack/LocalUnwinder.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#ifndef _LIBUNWINDSTACK_LOCAL_UNWINDER_H -#define _LIBUNWINDSTACK_LOCAL_UNWINDER_H - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -namespace unwindstack { - -// Forward declarations. -class Elf; -class MapInfo; - -struct LocalFrameData { - LocalFrameData(std::shared_ptr& map_info, uint64_t pc, uint64_t rel_pc, - const std::string& function_name, uint64_t function_offset) - : map_info(map_info), - pc(pc), - rel_pc(rel_pc), - function_name(function_name), - function_offset(function_offset) {} - - std::shared_ptr map_info; - uint64_t pc; - uint64_t rel_pc; - std::string function_name; - uint64_t function_offset; -}; - -// This is a specialized class that should only be used for doing local unwinds. -// The Unwind call can be made as multiple times on the same object, and it can -// be called by multiple threads at the same time. -// It is designed to be used in debugging circumstances to get a stack trace -// as fast as possible. -class LocalUnwinder { - public: - LocalUnwinder() = default; - LocalUnwinder(const std::vector& skip_libraries) : skip_libraries_(skip_libraries) {} - ~LocalUnwinder() = default; - - bool Init(); - - bool Unwind(std::vector* frame_info, size_t max_frames); - - bool ShouldSkipLibrary(const std::string& map_name); - - std::shared_ptr GetMapInfo(uint64_t pc); - - ErrorCode LastErrorCode() { return last_error_.code; } - uint64_t LastErrorAddress() { return last_error_.address; } - - private: - pthread_rwlock_t maps_rwlock_; - std::unique_ptr maps_ = nullptr; - std::shared_ptr process_memory_; - std::vector skip_libraries_; - ErrorData last_error_; -}; - -} // namespace unwindstack - -#endif // _LIBUNWINDSTACK_LOCAL_UNWINDER_H diff --git a/libunwindstack/tests/LocalUnwinderTest.cpp b/libunwindstack/tests/LocalUnwinderTest.cpp deleted file mode 100644 index 523d3d0..0000000 --- a/libunwindstack/tests/LocalUnwinderTest.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2018 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 -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#include - -#include "TestUtils.h" - -namespace unwindstack { - -static std::vector* g_frame_info; -static LocalUnwinder* g_unwinder; - -extern "C" void SignalLocalInnerFunction() { - g_unwinder->Unwind(g_frame_info, 256); -} - -extern "C" void SignalLocalMiddleFunction() { - SignalLocalInnerFunction(); -} - -extern "C" void SignalLocalOuterFunction() { - SignalLocalMiddleFunction(); -} - -static void SignalLocalCallerHandler(int, siginfo_t*, void*) { - SignalLocalOuterFunction(); -} - -static std::string ErrorMsg(const std::vector& function_names, - const std::vector& frame_info) { - std::string unwind; - size_t i = 0; - for (const auto& frame : frame_info) { - unwind += android::base::StringPrintf("#%02zu pc 0x%" PRIx64 " rel_pc 0x%" PRIx64, i++, - frame.pc, frame.rel_pc); - if (frame.map_info != nullptr) { - if (!frame.map_info->name().empty()) { - unwind += " "; - unwind += frame.map_info->name(); - } else { - unwind += android::base::StringPrintf(" 0x%" PRIx64 "-0x%" PRIx64, frame.map_info->start(), - frame.map_info->end()); - } - if (frame.map_info->offset() != 0) { - unwind += android::base::StringPrintf(" offset 0x%" PRIx64, frame.map_info->offset()); - } - } - if (!frame.function_name.empty()) { - unwind += " " + frame.function_name; - if (frame.function_offset != 0) { - unwind += android::base::StringPrintf("+%" PRId64, frame.function_offset); - } - } - unwind += '\n'; - } - - return std::string( - "Unwind completed without finding all frames\n" - " Looking for function: ") + - function_names.front() + "\n" + "Unwind data:\n" + unwind; -} - -// This test assumes that this code is compiled with optimizations turned -// off. If this doesn't happen, then all of the calls will be optimized -// away. -extern "C" void LocalInnerFunction(LocalUnwinder* unwinder, bool unwind_through_signal) { - std::vector frame_info; - g_frame_info = &frame_info; - g_unwinder = unwinder; - std::vector expected_function_names; - - if (unwind_through_signal) { - struct sigaction act, oldact; - memset(&act, 0, sizeof(act)); - act.sa_sigaction = SignalLocalCallerHandler; - act.sa_flags = SA_RESTART | SA_ONSTACK; - ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact)); - - raise(SIGUSR1); - - ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr)); - - expected_function_names = {"LocalOuterFunction", "LocalMiddleFunction", - "LocalInnerFunction", "SignalLocalOuterFunction", - "SignalLocalMiddleFunction", "SignalLocalInnerFunction"}; - } else { - ASSERT_TRUE(unwinder->Unwind(&frame_info, 256)); - - expected_function_names = {"LocalOuterFunction", "LocalMiddleFunction", "LocalInnerFunction"}; - } - - for (auto& frame : frame_info) { - if (frame.function_name == expected_function_names.back()) { - expected_function_names.pop_back(); - if (expected_function_names.empty()) { - break; - } - } - } - - ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, frame_info); -} - -extern "C" void LocalMiddleFunction(LocalUnwinder* unwinder, bool unwind_through_signal) { - LocalInnerFunction(unwinder, unwind_through_signal); -} - -extern "C" void LocalOuterFunction(LocalUnwinder* unwinder, bool unwind_through_signal) { - LocalMiddleFunction(unwinder, unwind_through_signal); -} - -class LocalUnwinderTest : public ::testing::Test { - protected: - void SetUp() override { - unwinder_.reset(new LocalUnwinder); - ASSERT_TRUE(unwinder_->Init()); - } - - std::unique_ptr unwinder_; -}; - -TEST_F(LocalUnwinderTest, local) { - LocalOuterFunction(unwinder_.get(), false); -} - -TEST_F(LocalUnwinderTest, local_signal) { - LocalOuterFunction(unwinder_.get(), true); -} - -TEST_F(LocalUnwinderTest, local_multiple) { - ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false)); - - ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), true)); - - ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false)); - - ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), true)); -} - -// This test verifies that doing an unwind before and after a dlopen -// works. It's verifying that the maps read during the first unwind -// do not cause a problem when doing the unwind using the code in -// the dlopen'd code. -TEST_F(LocalUnwinderTest, unwind_after_dlopen) { - // Prime the maps data. - ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false)); - - void* handle = GetTestLibHandle(); - ASSERT_TRUE(handle != nullptr); - - void (*unwind_function)(void*, void*) = - reinterpret_cast(dlsym(handle, "TestlibLevel1")); - ASSERT_TRUE(unwind_function != nullptr); - - std::vector frame_info; - unwind_function(unwinder_.get(), &frame_info); - - ASSERT_EQ(0, dlclose(handle)); - - std::vector expected_function_names{"TestlibLevel1", "TestlibLevel2", - "TestlibLevel3", "TestlibLevel4"}; - - for (auto& frame : frame_info) { - if (frame.function_name == expected_function_names.back()) { - expected_function_names.pop_back(); - if (expected_function_names.empty()) { - break; - } - } - } - - ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, frame_info); -} - -} // namespace unwindstack diff --git a/libunwindstack/tests/TestLocal.cpp b/libunwindstack/tests/TestLocal.cpp index 6653acb..f8684d7 100644 --- a/libunwindstack/tests/TestLocal.cpp +++ b/libunwindstack/tests/TestLocal.cpp @@ -14,29 +14,8 @@ * limitations under the License. */ -#include - -#include - -extern "C" void TestlibLevel4(void* unwinder_data, void* frame_data) { - unwindstack::LocalUnwinder* unwinder = - reinterpret_cast(unwinder_data); - std::vector* frame_info = - reinterpret_cast*>(frame_data); - unwinder->Unwind(frame_info, 256); -} - -extern "C" void TestlibLevel3(void* unwinder_data, void* frame_data) { - TestlibLevel4(unwinder_data, frame_data); -} - -extern "C" void TestlibLevel2(void* unwinder_data, void* frame_data) { - TestlibLevel3(unwinder_data, frame_data); -} - -extern "C" void TestlibLevel1(void* unwinder_data, void* frame_data) { - TestlibLevel2(unwinder_data, frame_data); -} +#include +#include // The loop in this function is only guaranteed to not be optimized away by the compiler // if optimizations are turned off. This is partially because the compiler doesn't have -- cgit v1.2.3