diff options
-rw-r--r-- | libc/malloc_debug/PointerData.cpp | 7 | ||||
-rw-r--r-- | libc/malloc_debug/PointerData.h | 6 | ||||
-rw-r--r-- | libc/malloc_debug/UnwindBacktrace.cpp | 50 | ||||
-rw-r--r-- | libc/malloc_debug/UnwindBacktrace.h | 7 | ||||
-rw-r--r-- | libc/malloc_debug/malloc_debug.cpp | 3 | ||||
-rw-r--r-- | libc/malloc_debug/tests/backtrace_fake.cpp | 11 | ||||
-rw-r--r-- | libc/malloc_debug/tests/backtrace_fake.h | 4 | ||||
-rw-r--r-- | libc/malloc_debug/tests/malloc_debug_unit_tests.cpp | 18 | ||||
-rw-r--r-- | libfdtrack/Android.bp | 1 | ||||
-rw-r--r-- | libfdtrack/fdtrack.cpp | 52 |
10 files changed, 100 insertions, 59 deletions
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp index 90c913638..b982c0ae8 100644 --- a/libc/malloc_debug/PointerData.cpp +++ b/libc/malloc_debug/PointerData.cpp @@ -66,7 +66,8 @@ std::mutex PointerData::frame_mutex_; std::unordered_map<FrameKeyType, size_t> PointerData::key_to_index_ GUARDED_BY( PointerData::frame_mutex_); std::unordered_map<size_t, FrameInfoType> PointerData::frames_ GUARDED_BY(PointerData::frame_mutex_); -std::unordered_map<size_t, std::vector<unwindstack::LocalFrameData>> PointerData::backtraces_info_ GUARDED_BY(PointerData::frame_mutex_); +std::unordered_map<size_t, std::vector<unwindstack::FrameData>> PointerData::backtraces_info_ + GUARDED_BY(PointerData::frame_mutex_); constexpr size_t kBacktraceEmptyIndex = 1; size_t PointerData::cur_hash_index_ GUARDED_BY(PointerData::frame_mutex_); @@ -136,7 +137,7 @@ bool PointerData::Initialize(const Config& config) NO_THREAD_SAFETY_ANALYSIS { size_t PointerData::AddBacktrace(size_t num_frames) { std::vector<uintptr_t> frames; - std::vector<unwindstack::LocalFrameData> frames_info; + std::vector<unwindstack::FrameData> frames_info; if (g_debug->config().options() & BACKTRACE_FULL) { if (!Unwind(&frames, &frames_info, num_frames)) { return kBacktraceEmptyIndex; @@ -386,7 +387,7 @@ void PointerData::GetList(std::vector<ListInfoType>* list, bool only_with_backtr REQUIRES(pointer_mutex_, frame_mutex_) { for (const auto& entry : pointers_) { FrameInfoType* frame_info = nullptr; - std::vector<unwindstack::LocalFrameData>* backtrace_info = nullptr; + std::vector<unwindstack::FrameData>* backtrace_info = nullptr; size_t hash_index = entry.second.hash_index; if (hash_index > kBacktraceEmptyIndex) { auto frame_entry = frames_.find(hash_index); diff --git a/libc/malloc_debug/PointerData.h b/libc/malloc_debug/PointerData.h index 37d87db1a..92d2653d6 100644 --- a/libc/malloc_debug/PointerData.h +++ b/libc/malloc_debug/PointerData.h @@ -39,7 +39,7 @@ #include <vector> #include <platform/bionic/macros.h> -#include <unwindstack/LocalUnwinder.h> +#include <unwindstack/Unwinder.h> #include "OptionData.h" #include "UnwindBacktrace.h" @@ -109,7 +109,7 @@ struct ListInfoType { size_t size; bool zygote_child_alloc; FrameInfoType* frame_info; - std::vector<unwindstack::LocalFrameData>* backtrace_info; + std::vector<unwindstack::FrameData>* backtrace_info; }; class PointerData : public OptionData { @@ -181,7 +181,7 @@ class PointerData : public OptionData { static std::mutex frame_mutex_; static std::unordered_map<FrameKeyType, size_t> key_to_index_; static std::unordered_map<size_t, FrameInfoType> frames_; - static std::unordered_map<size_t, std::vector<unwindstack::LocalFrameData>> backtraces_info_; + static std::unordered_map<size_t, std::vector<unwindstack::FrameData>> backtraces_info_; static size_t cur_hash_index_; static std::mutex free_pointer_mutex_; diff --git a/libc/malloc_debug/UnwindBacktrace.cpp b/libc/malloc_debug/UnwindBacktrace.cpp index a7036d935..f6c3e69e0 100644 --- a/libc/malloc_debug/UnwindBacktrace.cpp +++ b/libc/malloc_debug/UnwindBacktrace.cpp @@ -36,8 +36,12 @@ #include <vector> #include <android-base/stringprintf.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> +#include <unwindstack/Unwinder.h> #include "UnwindBacktrace.h" #include "debug_log.h" @@ -52,42 +56,56 @@ extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*); static pthread_once_t g_setup_once = PTHREAD_ONCE_INIT; -static unwindstack::LocalUnwinder* g_unwinder; - -static void Setup() { +static unwindstack::LocalUpdatableMaps* g_maps; +static std::shared_ptr<unwindstack::Memory> g_process_memory; #if defined(__LP64__) - std::vector<std::string> skip_libraries{"/system/lib64/libunwindstack.so", "/system/lib64/libc_malloc_debug.so"}; +static std::vector<std::string> g_skip_libraries{"/system/lib64/libunwindstack.so", + "/system/lib64/libc_malloc_debug.so"}; #else - std::vector<std::string> skip_libraries{"/system/lib/libunwindstack.so", "/system/lib/libc_malloc_debug.so"}; +static std::vector<std::string> g_skip_libraries{"/system/lib/libunwindstack.so", + "/system/lib/libc_malloc_debug.so"}; #endif - g_unwinder = new unwindstack::LocalUnwinder(skip_libraries); - g_unwinder->Init(); +static void Setup() { + g_maps = new unwindstack::LocalUpdatableMaps; + if (!g_maps->Parse()) { + delete g_maps; + g_maps = nullptr; + } + + g_process_memory = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid()); } -bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::LocalFrameData>* frame_info, size_t max_frames) { +bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::FrameData>* frame_info, + size_t max_frames) { pthread_once(&g_setup_once, Setup); - if (g_unwinder == nullptr) { + if (g_maps == nullptr) { return false; } - if (!g_unwinder->Unwind(frame_info, max_frames)) { + std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal()); + unwindstack::RegsGetLocal(regs.get()); + unwindstack::Unwinder unwinder(max_frames, g_maps, regs.get(), g_process_memory); + unwinder.Unwind(&g_skip_libraries); + if (unwinder.NumFrames() == 0) { frames->clear(); frame_info->clear(); return false; } + *frame_info = unwinder.ConsumeFrames(); - for (const auto& frame : *frame_info) { - frames->push_back(frame.pc); + frames->resize(frame_info->size()); + for (size_t i = 0; i < frame_info->size(); i++) { + frames->at(i) = frame_info->at(i).pc; } return true; } -void UnwindLog(const std::vector<unwindstack::LocalFrameData>& frame_info) { +void UnwindLog(const std::vector<unwindstack::FrameData>& frame_info) { for (size_t i = 0; i < frame_info.size(); i++) { - const unwindstack::LocalFrameData* info = &frame_info[i]; - std::shared_ptr<unwindstack::MapInfo> map_info = info->map_info; + const unwindstack::FrameData* info = &frame_info[i]; + auto map_info = info->map_info; std::string line = android::base::StringPrintf(" #%0zd pc %" PAD_PTR " ", i, info->rel_pc); if (map_info != nullptr && map_info->offset() != 0) { diff --git a/libc/malloc_debug/UnwindBacktrace.h b/libc/malloc_debug/UnwindBacktrace.h index 4c6c8d4a5..7f8990716 100644 --- a/libc/malloc_debug/UnwindBacktrace.h +++ b/libc/malloc_debug/UnwindBacktrace.h @@ -33,9 +33,10 @@ #include <string> #include <vector> -#include <unwindstack/LocalUnwinder.h> #include <unwindstack/MapInfo.h> +#include <unwindstack/Unwinder.h> -bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::LocalFrameData>* info, size_t max_frames); +bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::FrameData>* info, + size_t max_frames); -void UnwindLog(const std::vector<unwindstack::LocalFrameData>& frame_info); +void UnwindLog(const std::vector<unwindstack::FrameData>& frame_info); diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp index d23ab15c3..9f38946af 100644 --- a/libc/malloc_debug/malloc_debug.cpp +++ b/libc/malloc_debug/malloc_debug.cpp @@ -49,6 +49,7 @@ #include <platform/bionic/reserved_signals.h> #include <private/MallocXmlElem.h> #include <private/bionic_malloc_dispatch.h> +#include <unwindstack/Unwinder.h> #include "Config.h" #include "DebugData.h" @@ -193,7 +194,7 @@ static void InitAtfork() { void BacktraceAndLog() { if (g_debug->config().options() & BACKTRACE_FULL) { std::vector<uintptr_t> frames; - std::vector<unwindstack::LocalFrameData> frames_info; + std::vector<unwindstack::FrameData> frames_info; if (!Unwind(&frames, &frames_info, 256)) { error_log(" Backtrace failed to get any frames."); } else { diff --git a/libc/malloc_debug/tests/backtrace_fake.cpp b/libc/malloc_debug/tests/backtrace_fake.cpp index ad16c0211..f54bae86b 100644 --- a/libc/malloc_debug/tests/backtrace_fake.cpp +++ b/libc/malloc_debug/tests/backtrace_fake.cpp @@ -20,7 +20,7 @@ #include <vector> #include <utility> -#include <unwindstack/LocalUnwinder.h> +#include <unwindstack/Unwinder.h> #include "backtrace.h" #include "backtrace_fake.h" @@ -60,17 +60,17 @@ void backtrace_log(const uintptr_t* frames, size_t frame_count) { } } -static std::deque<std::vector<unwindstack::LocalFrameData>> g_fake_local_frame_data; +static std::deque<std::vector<unwindstack::FrameData>> g_fake_local_frame_data; void BacktraceUnwindFakeClearAll() { g_fake_local_frame_data.clear(); } -void BacktraceUnwindFake(const std::vector<unwindstack::LocalFrameData>& frames) { +void BacktraceUnwindFake(const std::vector<unwindstack::FrameData>& frames) { g_fake_local_frame_data.push_back(frames); } -bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::LocalFrameData>* info, size_t) { +bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::FrameData>* info, size_t) { if (g_fake_local_frame_data.empty()) { return false; } @@ -85,5 +85,4 @@ bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::LocalFrameD return true; } -void UnwindLog(const std::vector<unwindstack::LocalFrameData>& /*frame_info*/) { -} +void UnwindLog(const std::vector<unwindstack::FrameData>& /*frame_info*/) {} diff --git a/libc/malloc_debug/tests/backtrace_fake.h b/libc/malloc_debug/tests/backtrace_fake.h index a9ee97dc7..246fc614b 100644 --- a/libc/malloc_debug/tests/backtrace_fake.h +++ b/libc/malloc_debug/tests/backtrace_fake.h @@ -21,12 +21,12 @@ #include <vector> -#include <unwindstack/LocalUnwinder.h> +#include <unwindstack/Unwinder.h> void backtrace_fake_clear_all(); void backtrace_fake_add(const std::vector<uintptr_t>& ips); void BacktraceUnwindFakeClearAll(); -void BacktraceUnwindFake(const std::vector<unwindstack::LocalFrameData>& frames); +void BacktraceUnwindFake(const std::vector<unwindstack::FrameData>& frames); #endif // MALLOC_DEBUG_TESTS_BACKTRACE_FAKE_H diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp index 7b58f31c4..46de3e93e 100644 --- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp +++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp @@ -44,6 +44,8 @@ #include <platform/bionic/macros.h> #include <private/bionic_malloc_dispatch.h> +#include <unwindstack/Unwinder.h> + #include "Config.h" #include "malloc_debug.h" @@ -1530,16 +1532,18 @@ TEST_F(MallocDebugTest, backtrace_full_dump_on_exit) { if ((pid = fork()) == 0) { std::shared_ptr<unwindstack::MapInfo> empty_map; Init("backtrace=4 backtrace_full backtrace_dump_on_exit"); - BacktraceUnwindFake(std::vector<unwindstack::LocalFrameData>{ - {empty_map, 0x1100, 0x100, "fake1", 10}, {empty_map, 0x1200, 0x200, "fake2", 20}}); + BacktraceUnwindFake( + std::vector<unwindstack::FrameData>{{0, 0x100, 0x1100, 0, "fake1", 10, empty_map}, + {1, 0x200, 0x1200, 0, "fake2", 20, empty_map}}); std::shared_ptr<unwindstack::MapInfo> map_info = unwindstack::MapInfo::Create(0x10000, 0x20000, 0, PROT_READ | PROT_EXEC, "/data/fake.so"); - BacktraceUnwindFake(std::vector<unwindstack::LocalFrameData>{ - {map_info, 0x1a000, 0xa000, "level1", 0}, {map_info, 0x1b000, 0xb000, "level2", 10}}); BacktraceUnwindFake( - std::vector<unwindstack::LocalFrameData>{{empty_map, 0x1a000, 0xa000, "func1", 0}, - {empty_map, 0x1b000, 0xb000, "func2", 10}, - {empty_map, 0x1c000, 0xc000, "", 30}}); + std::vector<unwindstack::FrameData>{{0, 0xa000, 0x1a000, 0, "level1", 0, map_info}, + {1, 0xb000, 0x1b000, 0, "level2", 10, map_info}}); + BacktraceUnwindFake( + std::vector<unwindstack::FrameData>{{0, 0xa000, 0x1a000, 0, "func1", 0, empty_map}, + {1, 0xb000, 0x1b000, 0, "func2", 10, empty_map}, + {2, 0xc000, 0x1c000, 0, "", 30, empty_map}}); std::vector<void*> pointers; pointers.push_back(debug_malloc(300)); diff --git a/libfdtrack/Android.bp b/libfdtrack/Android.bp index fb28623ef..83ea7cb4b 100644 --- a/libfdtrack/Android.bp +++ b/libfdtrack/Android.bp @@ -38,4 +38,5 @@ cc_test { whole_static_libs: ["libBionicCtsGtestMain"], static_libs: ["liblog"], test_suites: ["device-tests"], + runtime_libs: ["libfdtrack"], } diff --git a/libfdtrack/fdtrack.cpp b/libfdtrack/fdtrack.cpp index 2e9cfbcd0..2d114f23e 100644 --- a/libfdtrack/fdtrack.cpp +++ b/libfdtrack/fdtrack.cpp @@ -31,6 +31,8 @@ #include <array> #include <mutex> +#include <string> +#include <string_view> #include <thread> #include <utility> #include <vector> @@ -43,11 +45,14 @@ #include <android-base/thread_annotations.h> #include <async_safe/log.h> #include <bionic/reserved_signals.h> -#include <unwindstack/LocalUnwinder.h> +#include <unwindstack/Maps.h> +#include <unwindstack/Regs.h> +#include <unwindstack/RegsGetLocal.h> +#include <unwindstack/Unwinder.h> struct FdEntry { std::mutex mutex; - std::vector<unwindstack::LocalFrameData> backtrace GUARDED_BY(mutex); + std::vector<unwindstack::FrameData> backtrace GUARDED_BY(mutex); }; extern "C" void fdtrack_dump(); @@ -62,15 +67,21 @@ static void fd_hook(android_fdtrack_event* event); // Backtraces for the first 4k file descriptors ought to be enough to diagnose an fd leak. static constexpr size_t kFdTableSize = 4096; -// 32 frames, plus two to skip from fdtrack itself. -static constexpr size_t kStackDepth = 34; -static constexpr size_t kStackFrameSkip = 2; +// Only unwind up to 32 frames outside of libfdtrack.so. +static constexpr size_t kStackDepth = 32; + +// Skip any initial frames from libfdtrack.so. +static std::vector<std::string> kSkipFdtrackLib [[clang::no_destroy]] = {"libfdtrack.so"}; static bool installed = false; static std::array<FdEntry, kFdTableSize> stack_traces [[clang::no_destroy]]; -static unwindstack::LocalUnwinder& Unwinder() { - static android::base::NoDestructor<unwindstack::LocalUnwinder> unwinder; - return *unwinder.get(); +static unwindstack::LocalUpdatableMaps& Maps() { + static android::base::NoDestructor<unwindstack::LocalUpdatableMaps> maps; + return *maps.get(); +} +static std::shared_ptr<unwindstack::Memory>& ProcessMemory() { + static android::base::NoDestructor<std::shared_ptr<unwindstack::Memory>> process_memory; + return *process_memory.get(); } __attribute__((constructor)) static void ctor() { @@ -89,7 +100,8 @@ __attribute__((constructor)) static void ctor() { sa.sa_flags = SA_SIGINFO | SA_ONSTACK; sigaction(BIONIC_SIGNAL_FDTRACK, &sa, nullptr); - if (Unwinder().Init()) { + if (Maps().Parse()) { + ProcessMemory() = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid()); android_fdtrack_hook_t expected = nullptr; installed = android_fdtrack_compare_exchange_hook(&expected, &fd_hook); } @@ -116,7 +128,12 @@ static void fd_hook(android_fdtrack_event* event) { if (FdEntry* entry = GetFdEntry(event->fd); entry) { std::lock_guard<std::mutex> lock(entry->mutex); entry->backtrace.clear(); - Unwinder().Unwind(&entry->backtrace, kStackDepth); + + std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal()); + unwindstack::RegsGetLocal(regs.get()); + unwindstack::Unwinder unwinder(kStackDepth, &Maps(), regs.get(), ProcessMemory()); + unwinder.Unwind(&kSkipFdtrackLib); + entry->backtrace = unwinder.ConsumeFrames(); } } else if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CLOSE) { if (FdEntry* entry = GetFdEntry(event->fd); entry) { @@ -153,14 +170,13 @@ void fdtrack_iterate(fdtrack_callback_t callback, void* arg) { continue; } - for (size_t i = kStackFrameSkip; i < entry->backtrace.size(); ++i) { - size_t j = i - kStackFrameSkip; - function_names[j] = entry->backtrace[i].function_name.c_str(); - function_offsets[j] = entry->backtrace[i].function_offset; + for (size_t i = 0; i < entry->backtrace.size(); ++i) { + function_names[i] = entry->backtrace[i].function_name.c_str(); + function_offsets[i] = entry->backtrace[i].function_offset; } - bool should_continue = callback(fd, function_names, function_offsets, - entry->backtrace.size() - kStackFrameSkip, arg); + bool should_continue = + callback(fd, function_names, function_offsets, entry->backtrace.size(), arg); entry->mutex.unlock(); @@ -200,8 +216,8 @@ static void fdtrack_dump_impl(bool fatal) { size_t count = 0; size_t stack_depth = 0; - const char* function_names[kStackDepth - kStackFrameSkip]; - uint64_t function_offsets[kStackDepth - kStackFrameSkip]; + const char* function_names[kStackDepth]; + uint64_t function_offsets[kStackDepth]; }; struct StackList { size_t count = 0; |