Use new AndroidLocalUnwinder.
The new object incorporates all Android specific knowledge into a single place and makes everything simpler. Fixed a bug where if backtrace_full was enabled, the AddBacktrace function would always set the size to the maximum number of frames instead of the actual number of frames. Added a new smoke system tests for backtrace_full. Modified the smoke test to do a malloc/free, so it's really a smoke test. Bug: 232575330 Test: Unit tests pass on device. Test: Verify the full backtrace actually produces valid backtraces. Test: Run bionic-unit-tests with backtrace_full enabled. Test: Run bionic-benchmarks --benchmark_filter=stdlib_malloc_free_decay1/512 Change-Id: I23128a73a8691007e1c7f69e0c99bb4dcd713db8
This commit is contained in:
parent
a2e4fbb366
commit
dfbc59ae51
5 changed files with 23 additions and 52 deletions
|
@ -181,7 +181,6 @@ cc_test {
|
|||
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbacktrace",
|
||||
"liblog",
|
||||
"libunwindstack",
|
||||
],
|
||||
|
|
|
@ -149,14 +149,14 @@ size_t PointerData::AddBacktrace(size_t num_frames) {
|
|||
if (num_frames == 0) {
|
||||
return kBacktraceEmptyIndex;
|
||||
}
|
||||
frames.resize(num_frames);
|
||||
}
|
||||
|
||||
FrameKeyType key{.num_frames = num_frames, .frames = frames.data()};
|
||||
FrameKeyType key{.num_frames = frames.size(), .frames = frames.data()};
|
||||
size_t hash_index;
|
||||
std::lock_guard<std::mutex> frame_guard(frame_mutex_);
|
||||
auto entry = key_to_index_.find(key);
|
||||
if (entry == key_to_index_.end()) {
|
||||
frames.resize(num_frames);
|
||||
hash_index = cur_hash_index_++;
|
||||
key.frames = frames.data();
|
||||
key_to_index_.emplace(key, hash_index);
|
||||
|
|
|
@ -36,11 +36,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Maps.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
#include <unwindstack/RegsGetLocal.h>
|
||||
#include <unwindstack/AndroidUnwinder.h>
|
||||
#include <unwindstack/Unwinder.h>
|
||||
|
||||
#include "UnwindBacktrace.h"
|
||||
|
@ -54,51 +50,22 @@
|
|||
|
||||
extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
|
||||
|
||||
static pthread_once_t g_setup_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
static unwindstack::LocalUpdatableMaps* g_maps;
|
||||
static std::shared_ptr<unwindstack::Memory> g_process_memory;
|
||||
#if defined(__LP64__)
|
||||
static std::vector<std::string> g_skip_libraries{"/system/lib64/libunwindstack.so",
|
||||
"/system/lib64/libc_malloc_debug.so"};
|
||||
#else
|
||||
static std::vector<std::string> g_skip_libraries{"/system/lib/libunwindstack.so",
|
||||
"/system/lib/libc_malloc_debug.so"};
|
||||
#endif
|
||||
|
||||
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::FrameData>* frame_info,
|
||||
size_t max_frames) {
|
||||
pthread_once(&g_setup_once, Setup);
|
||||
|
||||
if (g_maps == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
[[clang::no_destroy]] static unwindstack::AndroidLocalUnwinder unwinder(
|
||||
std::vector<std::string>{"libc_malloc_debug.so"});
|
||||
unwindstack::AndroidUnwinderData data(max_frames);
|
||||
if (!unwinder.Unwind(data)) {
|
||||
frames->clear();
|
||||
frame_info->clear();
|
||||
return false;
|
||||
}
|
||||
*frame_info = unwinder.ConsumeFrames();
|
||||
|
||||
frames->resize(frame_info->size());
|
||||
for (size_t i = 0; i < frame_info->size(); i++) {
|
||||
frames->at(i) = frame_info->at(i).pc;
|
||||
frames->resize(data.frames.size());
|
||||
for (const auto& frame : data.frames) {
|
||||
frames->at(frame.num) = frame.pc;
|
||||
}
|
||||
*frame_info = std::move(data.frames);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,10 +30,8 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Unwinder.h>
|
||||
|
||||
bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::FrameData>* info,
|
||||
|
|
|
@ -52,8 +52,7 @@
|
|||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <backtrace/Backtrace.h>
|
||||
#include <backtrace/BacktraceMap.h>
|
||||
#include <unwindstack/AndroidUnwinder.h>
|
||||
|
||||
#include <bionic/malloc.h>
|
||||
#include <tests/utils.h>
|
||||
|
@ -452,12 +451,19 @@ class MallocDebugSystemTest : public ::testing::Test {
|
|||
static constexpr size_t kMaxRetries = 3;
|
||||
};
|
||||
|
||||
TEST(MallocTests, DISABLED_smoke) {}
|
||||
TEST(MallocTests, DISABLED_smoke) {
|
||||
void* ptr = malloc(128);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugSystemTest, smoke) {
|
||||
Exec("MallocTests.DISABLED_smoke", "verbose backtrace");
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugSystemTest, backtrace_full_smoke) {
|
||||
Exec("MallocTests.DISABLED_smoke", "verbose backtrace backtrace_full");
|
||||
}
|
||||
|
||||
static void SetAllocationLimit() {
|
||||
// Set to a large value, this is only to enable the limit code and
|
||||
// verify that malloc debug is still called properly.
|
||||
|
@ -763,13 +769,14 @@ TEST(MallocTests, DISABLED_malloc_and_backtrace_deadlock) {
|
|||
}
|
||||
|
||||
static constexpr size_t kNumUnwinds = 1000;
|
||||
unwindstack::AndroidLocalUnwinder unwinder;
|
||||
for (size_t i = 0; i < kNumUnwinds; i++) {
|
||||
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), tid));
|
||||
// Only verify that there is at least one frame in the unwind.
|
||||
// This is not a test of the unwinder and clang for arm seems to
|
||||
// produces an increasing number of code that does not have unwind
|
||||
// information.
|
||||
ASSERT_TRUE(backtrace->Unwind(0)) << "Failed on unwind " << i;
|
||||
unwindstack::AndroidUnwinderData data;
|
||||
ASSERT_TRUE(unwinder.Unwind(data)) << "Failed on unwind " << i;
|
||||
}
|
||||
running = false;
|
||||
thread.join();
|
||||
|
|
Loading…
Reference in a new issue