summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2022-03-05 00:05:05 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-03-05 00:05:05 +0000
commita3676b41f2eafe9c3e2ffc9d8044962e1fa2dc85 (patch)
tree245a317b99cbca1426cdcbb49173021d065e75cf
parent3036c56a4c90ba448a88463ad1e081b541576fba (diff)
parentb43bf83bd7751132ce7951ea33f714d3f8c23215 (diff)
downloadunwinding-a3676b41f2eafe9c3e2ffc9d8044962e1fa2dc85.tar.gz
Remove the LocalUnwinder object. am: 9e65d1402e am: 43539a2626 am: b43bf83bd7
Original change: https://android-review.googlesource.com/c/platform/system/unwinding/+/2008230 Change-Id: I789d64e8571158668052fdfab3bba66e71ebafbe
-rw-r--r--libunwindstack/Android.bp2
-rw-r--r--libunwindstack/LocalUnwinder.cpp130
-rw-r--r--libunwindstack/benchmarks/local_unwind_benchmarks.cpp18
-rw-r--r--libunwindstack/include/unwindstack/LocalUnwinder.h86
-rw-r--r--libunwindstack/tests/LocalUnwinderTest.cpp201
-rw-r--r--libunwindstack/tests/TestLocal.cpp25
6 files changed, 2 insertions, 460 deletions
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 <pthread.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/LocalUnwinder.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/RegsGetLocal.h>
-
-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<LocalFrameData>* frame_info, size_t max_frames) {
- std::unique_ptr<unwindstack::Regs> 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<MapInfo> 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 <android-base/strings.h>
-#include <unwindstack/LocalUnwinder.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
@@ -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<unwindstack::LocalUnwinder*>(unwind_ptr);
- std::vector<unwindstack::LocalFrameData> 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 <pthread.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <unwindstack/Error.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Elf;
-class MapInfo;
-
-struct LocalFrameData {
- LocalFrameData(std::shared_ptr<MapInfo>& 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<MapInfo> 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<std::string>& skip_libraries) : skip_libraries_(skip_libraries) {}
- ~LocalUnwinder() = default;
-
- bool Init();
-
- bool Unwind(std::vector<LocalFrameData>* frame_info, size_t max_frames);
-
- bool ShouldSkipLibrary(const std::string& map_name);
-
- std::shared_ptr<MapInfo> 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<LocalUpdatableMaps> maps_ = nullptr;
- std::shared_ptr<Memory> process_memory_;
- std::vector<std::string> 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 <dlfcn.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <android-base/stringprintf.h>
-
-#include <unwindstack/LocalUnwinder.h>
-
-#include "TestUtils.h"
-
-namespace unwindstack {
-
-static std::vector<LocalFrameData>* 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<const char*>& function_names,
- const std::vector<LocalFrameData>& 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<LocalFrameData> frame_info;
- g_frame_info = &frame_info;
- g_unwinder = unwinder;
- std::vector<const char*> 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<LocalUnwinder> 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<void (*)(void*, void*)>(dlsym(handle, "TestlibLevel1"));
- ASSERT_TRUE(unwind_function != nullptr);
-
- std::vector<LocalFrameData> frame_info;
- unwind_function(unwinder_.get(), &frame_info);
-
- ASSERT_EQ(0, dlclose(handle));
-
- std::vector<const char*> 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 <unwindstack/LocalUnwinder.h>
-
-#include <vector>
-
-extern "C" void TestlibLevel4(void* unwinder_data, void* frame_data) {
- unwindstack::LocalUnwinder* unwinder =
- reinterpret_cast<unwindstack::LocalUnwinder*>(unwinder_data);
- std::vector<unwindstack::LocalFrameData>* frame_info =
- reinterpret_cast<std::vector<unwindstack::LocalFrameData>*>(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 <stdint.h>
+#include <stdlib.h>
// 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