summaryrefslogtreecommitdiff
path: root/libc/malloc_debug/PointerData.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libc/malloc_debug/PointerData.cpp')
-rw-r--r--libc/malloc_debug/PointerData.cpp111
1 files changed, 81 insertions, 30 deletions
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
index 85139e607..b0e2fc849 100644
--- a/libc/malloc_debug/PointerData.cpp
+++ b/libc/malloc_debug/PointerData.cpp
@@ -43,6 +43,7 @@
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
+#include <demangle.h>
#include <private/bionic_macros.h>
#include "Config.h"
@@ -51,6 +52,7 @@
#include "backtrace.h"
#include "debug_log.h"
#include "malloc_debug.h"
+#include "UnwindBacktrace.h"
std::atomic_uint8_t PointerData::backtrace_enabled_;
std::atomic_bool PointerData::backtrace_dump_;
@@ -63,6 +65,7 @@ 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_);
constexpr size_t kBacktraceEmptyIndex = 1;
size_t PointerData::cur_hash_index_ GUARDED_BY(PointerData::frame_mutex_);
@@ -127,10 +130,18 @@ bool PointerData::Initialize(const Config& config) NO_THREAD_SAFETY_ANALYSIS {
}
size_t PointerData::AddBacktrace(size_t num_frames) {
- std::vector<uintptr_t> frames(num_frames);
- num_frames = backtrace_get(frames.data(), frames.size());
- if (num_frames == 0) {
- return kBacktraceEmptyIndex;
+ std::vector<uintptr_t> frames;
+ std::vector<unwindstack::LocalFrameData> frames_info;
+ if (g_debug->config().options() & BACKTRACE_FULL) {
+ if (!Unwind(&frames, &frames_info, num_frames)) {
+ return kBacktraceEmptyIndex;
+ }
+ } else {
+ frames.resize(num_frames);
+ num_frames = backtrace_get(frames.data(), frames.size());
+ if (num_frames == 0) {
+ return kBacktraceEmptyIndex;
+ }
}
FrameKeyType key{.num_frames = num_frames, .frames = frames.data()};
@@ -144,6 +155,9 @@ size_t PointerData::AddBacktrace(size_t num_frames) {
key_to_index_.emplace(key, hash_index);
frames_.emplace(hash_index, FrameInfoType{.references = 1, .frames = std::move(frames)});
+ if (g_debug->config().options() & BACKTRACE_FULL) {
+ backtraces_info_.emplace(hash_index, std::move(frames_info));
+ }
} else {
hash_index = entry->second;
FrameInfoType* frame_info = &frames_[hash_index];
@@ -168,6 +182,9 @@ void PointerData::RemoveBacktrace(size_t hash_index) {
FrameKeyType key{.num_frames = frame_info->frames.size(), .frames = frame_info->frames.data()};
key_to_index_.erase(key);
frames_.erase(hash_index);
+ if (g_debug->config().options() & BACKTRACE_FULL) {
+ backtraces_info_.erase(hash_index);
+ }
}
}
@@ -230,6 +247,25 @@ size_t PointerData::GetFrames(const void* ptr, uintptr_t* frames, size_t max_fra
return max_frames;
}
+void PointerData::LogBacktrace(size_t hash_index) {
+ std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+ if (g_debug->config().options() & BACKTRACE_FULL) {
+ auto backtrace_info_entry = backtraces_info_.find(hash_index);
+ if (backtrace_info_entry != backtraces_info_.end()) {
+ UnwindLog(backtrace_info_entry->second);
+ return;
+ }
+ } else {
+ auto frame_entry = frames_.find(hash_index);
+ if (frame_entry != frames_.end()) {
+ FrameInfoType* frame_info = &frame_entry->second;
+ backtrace_log(frame_info->frames.data(), frame_info->frames.size());
+ return;
+ }
+ }
+ error_log(" hash_index %zu does not have matching frame data.", hash_index);
+}
+
void PointerData::LogFreeError(const FreePointerInfoType& info, size_t usable_size) {
error_log(LOG_DIVIDER);
uint8_t* memory = reinterpret_cast<uint8_t*>(info.pointer);
@@ -242,13 +278,8 @@ void PointerData::LogFreeError(const FreePointerInfoType& info, size_t usable_si
}
if (info.hash_index > kBacktraceEmptyIndex) {
- std::lock_guard<std::mutex> frame_guard(frame_mutex_);
- auto frame_entry = frames_.find(info.hash_index);
- if (frame_entry != frames_.end()) {
- FrameInfoType* frame_info = &frame_entry->second;
- error_log("Backtrace at time of free:");
- backtrace_log(frame_info->frames.data(), frame_info->frames.size());
- }
+ error_log("Backtrace at time of free:");
+ LogBacktrace(info.hash_index);
}
error_log(LOG_DIVIDER);
@@ -328,15 +359,8 @@ void PointerData::LogFreeBacktrace(const void* ptr) {
return;
}
- std::lock_guard<std::mutex> frame_guard(frame_mutex_);
- auto frame_entry = frames_.find(hash_index);
- if (frame_entry == frames_.end()) {
- error_log("Freed pointer hash_index %zu does not have matching frame data.", hash_index);
- return;
- }
- FrameInfoType* frame_info = &frame_entry->second;
error_log("Backtrace of original free:");
- backtrace_log(frame_info->frames.data(), frame_info->frames.size());
+ LogBacktrace(hash_index);
}
void PointerData::VerifyAllFreed() {
@@ -350,18 +374,28 @@ 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;
size_t hash_index = entry.second.hash_index;
if (hash_index > kBacktraceEmptyIndex) {
- frame_info = &frames_[hash_index];
- if (frame_info->references == 0) {
+ auto frame_entry = frames_.find(hash_index);
+ if (frame_entry == frames_.end()) {
// Somehow wound up with a pointer with a valid hash_index, but
// no frame data. This should not be possible since adding a pointer
// occurs after the hash_index and frame data have been added.
// When removing a pointer, the pointer is deleted before the frame
// data.
- frames_.erase(hash_index);
error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
- frame_info = nullptr;
+ } else {
+ frame_info = &frame_entry->second;
+ }
+
+ if (g_debug->config().options() & BACKTRACE_FULL) {
+ auto backtrace_entry = backtraces_info_.find(hash_index);
+ if (backtrace_entry == backtraces_info_.end()) {
+ error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
+ } else {
+ backtrace_info = &backtrace_entry->second;
+ }
}
}
if (hash_index == 0 && only_with_backtrace) {
@@ -369,7 +403,7 @@ void PointerData::GetList(std::vector<ListInfoType>* list, bool only_with_backtr
}
list->emplace_back(ListInfoType{entry.first, 1, entry.second.RealSize(),
- entry.second.ZygoteChildAlloc(), frame_info});
+ entry.second.ZygoteChildAlloc(), frame_info, backtrace_info});
}
// Sort by the size of the allocation.
@@ -440,7 +474,10 @@ void PointerData::LogLeaks() {
for (const auto& list_info : list) {
error_log("+++ %s leaked block of size %zu at 0x%" PRIxPTR " (leak %zu of %zu)", getprogname(),
list_info.size, list_info.pointer, ++track_count, list.size());
- if (list_info.frame_info != nullptr) {
+ if (list_info.backtrace_info != nullptr) {
+ error_log("Backtrace at time of allocation:");
+ UnwindLog(*list_info.backtrace_info);
+ } else if (list_info.frame_info != nullptr) {
error_log("Backtrace at time of allocation:");
backtrace_log(list_info.frame_info->frames.data(), list_info.frame_info->frames.size());
}
@@ -520,14 +557,28 @@ void PointerData::DumpLiveToFile(FILE* fp) {
if (frame_info->frames[i] == 0) {
break;
}
-#if defined(__LP64__)
- fprintf(fp, " %016" PRIxPTR, frame_info->frames[i]);
-#else
- fprintf(fp, " %08" PRIxPTR, frame_info->frames[i]);
-#endif
+ fprintf(fp, " %" PRIxPTR, frame_info->frames[i]);
}
}
fprintf(fp, "\n");
+ if (info.backtrace_info != nullptr) {
+ fprintf(fp, " bt_info");
+ for (const auto& frame : *info.backtrace_info) {
+ fprintf(fp, " {");
+ if (frame.map_info != nullptr && !frame.map_info->name.empty()) {
+ fprintf(fp, "\"%s\"", frame.map_info->name.c_str());
+ } else {
+ fprintf(fp, "\"\"");
+ }
+ fprintf(fp, " %" PRIx64, frame.rel_pc);
+ if (frame.function_name.empty()) {
+ fprintf(fp, " \"\" 0}");
+ } else {
+ fprintf(fp, " \"%s\" %" PRIx64 "}", demangle(frame.function_name.c_str()).c_str(), frame.function_offset);
+ }
+ }
+ fprintf(fp, "\n");
+ }
}
}