aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;