aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2022-01-07 13:38:10 -0800
committerChristopher Ferris <cferris@google.com>2022-03-03 15:23:25 -0800
commit459eecb28b68f9b8f2a71ca9765b291f11007030 (patch)
tree96a636854aa41bdfca0adfe4ac98bd1923ece7a4
parent39837afad7ba9411445677497f8c60b01a0b4195 (diff)
downloadbionic-459eecb28b68f9b8f2a71ca9765b291f11007030.tar.gz
Update for LocalUnwinder object removal.
Modify libfdtrack to use the normal Unwinder object. In addition, update the libfdtrack so that it doesn't record frames in libfdtrack.so rather than skipping frames it thinks will be in the library. Modify the malloc debug code to use the normal Unwinder object. Bug: 120606663 Test: All unit tests pass. Change-Id: I3c9612dd10e62389e6219e68045ee87f7b2625f5
-rw-r--r--libc/malloc_debug/PointerData.cpp7
-rw-r--r--libc/malloc_debug/PointerData.h6
-rw-r--r--libc/malloc_debug/UnwindBacktrace.cpp50
-rw-r--r--libc/malloc_debug/UnwindBacktrace.h7
-rw-r--r--libc/malloc_debug/malloc_debug.cpp3
-rw-r--r--libc/malloc_debug/tests/backtrace_fake.cpp11
-rw-r--r--libc/malloc_debug/tests/backtrace_fake.h4
-rw-r--r--libc/malloc_debug/tests/malloc_debug_unit_tests.cpp18
-rw-r--r--libfdtrack/Android.bp1
-rw-r--r--libfdtrack/fdtrack.cpp52
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;