Merge "Allow calling GetFunctionName before unwinding."

This commit is contained in:
Christopher Ferris 2017-03-22 17:30:33 +00:00 committed by Gerrit Code Review
commit 435fc45103
9 changed files with 160 additions and 112 deletions

View file

@ -36,7 +36,7 @@
class BacktraceMap; class BacktraceMap;
class BacktraceCurrent : public Backtrace { class BacktraceCurrent : public Backtrace {
public: public:
BacktraceCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {} BacktraceCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
virtual ~BacktraceCurrent() {} virtual ~BacktraceCurrent() {}
@ -46,10 +46,10 @@ public:
bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override; bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
protected: protected:
bool DiscardFrame(const backtrace_frame_data_t& frame); bool DiscardFrame(const backtrace_frame_data_t& frame);
private: private:
bool UnwindThread(size_t num_ignore_frames); bool UnwindThread(size_t num_ignore_frames);
virtual bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) = 0; virtual bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) = 0;

View file

@ -25,7 +25,7 @@
class BacktraceMap; class BacktraceMap;
class BacktracePtrace : public Backtrace { class BacktracePtrace : public Backtrace {
public: public:
BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {} BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
virtual ~BacktracePtrace() {} virtual ~BacktracePtrace() {}

View file

@ -22,7 +22,7 @@
#include <ucontext.h> #include <ucontext.h>
class ThreadEntry { class ThreadEntry {
public: public:
static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true); static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true);
static void Remove(ThreadEntry* entry); static void Remove(ThreadEntry* entry);
@ -47,7 +47,7 @@ public:
inline ucontext_t* GetUcontext() { return &ucontext_; } inline ucontext_t* GetUcontext() { return &ucontext_; }
private: private:
ThreadEntry(pid_t pid, pid_t tid); ThreadEntry(pid_t pid, pid_t tid);
~ThreadEntry(); ~ThreadEntry();

View file

@ -23,12 +23,23 @@
#define UNW_LOCAL_ONLY #define UNW_LOCAL_ONLY
#include <libunwind.h> #include <libunwind.h>
#include <android-base/logging.h>
#include <backtrace/Backtrace.h> #include <backtrace/Backtrace.h>
#include "BacktraceLog.h" #include "BacktraceLog.h"
#include "UnwindCurrent.h" #include "UnwindCurrent.h"
std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
if (!initialized_) {
// If init local is not called, then trying to get a function name will
// fail, so try to initialize first.
std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
if (unw_init_local(cursor.get(), &context_) < 0) {
return "";
}
initialized_ = true;
}
*offset = 0; *offset = 0;
char buf[512]; char buf[512];
unw_word_t value; unw_word_t value;
@ -85,6 +96,7 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucon
error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
return false; return false;
} }
initialized_ = true;
size_t num_frames = 0; size_t num_frames = 0;
do { do {
@ -124,6 +136,11 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucon
num_frames++; num_frames++;
} else { } else {
num_ignore_frames--; num_ignore_frames--;
// Set the number of frames to zero to remove the frame added
// above. By definition, if we still have frames to ignore
// there should only be one frame in the vector.
CHECK(num_frames == 0);
frames_.resize(0);
} }
} }
ret = unw_step (cursor.get()); ret = unw_step (cursor.get());

View file

@ -32,18 +32,20 @@
#include <libunwind.h> #include <libunwind.h>
class UnwindCurrent : public BacktraceCurrent { class UnwindCurrent : public BacktraceCurrent {
public: public:
UnwindCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {} UnwindCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {}
virtual ~UnwindCurrent() {} virtual ~UnwindCurrent() {}
std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override; std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
private: private:
void GetUnwContextFromUcontext(const ucontext_t* ucontext); void GetUnwContextFromUcontext(const ucontext_t* ucontext);
bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override; bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
unw_context_t context_; unw_context_t context_;
bool initialized_ = false;
}; };
#endif // _LIBBACKTRACE_UNWIND_CURRENT_H #endif // _LIBBACKTRACE_UNWIND_CURRENT_H

View file

@ -28,28 +28,28 @@
// libunwind.h first then this header. // libunwind.h first then this header.
class UnwindMap : public BacktraceMap { class UnwindMap : public BacktraceMap {
public: public:
explicit UnwindMap(pid_t pid); explicit UnwindMap(pid_t pid);
unw_map_cursor_t* GetMapCursor() { return &map_cursor_; } unw_map_cursor_t* GetMapCursor() { return &map_cursor_; }
protected: protected:
unw_map_cursor_t map_cursor_; unw_map_cursor_t map_cursor_;
}; };
class UnwindMapRemote : public UnwindMap { class UnwindMapRemote : public UnwindMap {
public: public:
explicit UnwindMapRemote(pid_t pid); explicit UnwindMapRemote(pid_t pid);
virtual ~UnwindMapRemote(); virtual ~UnwindMapRemote();
bool Build() override; bool Build() override;
private: private:
bool GenerateMap(); bool GenerateMap();
}; };
class UnwindMapLocal : public UnwindMap { class UnwindMapLocal : public UnwindMap {
public: public:
UnwindMapLocal(); UnwindMapLocal();
virtual ~UnwindMapLocal(); virtual ~UnwindMapLocal();
@ -60,7 +60,7 @@ public:
void LockIterator() override { pthread_rwlock_rdlock(&map_lock_); } void LockIterator() override { pthread_rwlock_rdlock(&map_lock_); }
void UnlockIterator() override { pthread_rwlock_unlock(&map_lock_); } void UnlockIterator() override { pthread_rwlock_unlock(&map_lock_); }
private: private:
bool GenerateMap(); bool GenerateMap();
bool map_created_; bool map_created_;

View file

@ -37,6 +37,7 @@ UnwindPtrace::~UnwindPtrace() {
_UPT_destroy(upt_info_); _UPT_destroy(upt_info_);
upt_info_ = nullptr; upt_info_ = nullptr;
} }
if (addr_space_) { if (addr_space_) {
// Remove the map from the address space before destroying it. // Remove the map from the address space before destroying it.
// It will be freed in the UnwindMap destructor. // It will be freed in the UnwindMap destructor.
@ -47,18 +48,14 @@ UnwindPtrace::~UnwindPtrace() {
} }
} }
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { bool UnwindPtrace::Init() {
if (GetMap() == nullptr) { if (upt_info_) {
// Without a map object, we can't do anything. return true;
error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
return false;
} }
error_ = BACKTRACE_UNWIND_NO_ERROR; if (addr_space_) {
// If somehow the addr_space_ gets initialized but upt_info_ doesn't,
if (ucontext) { // then that indicates there is some kind of failure.
BACK_LOGW("Unwinding from a specified context not supported yet.");
error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
return false; return false;
} }
@ -79,6 +76,28 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
return false; return false;
} }
return true;
}
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
if (GetMap() == nullptr) {
// Without a map object, we can't do anything.
error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
return false;
}
error_ = BACKTRACE_UNWIND_NO_ERROR;
if (ucontext) {
BACK_LOGW("Unwinding from a specified context not supported yet.");
error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
return false;
}
if (!Init()) {
return false;
}
unw_cursor_t cursor; unw_cursor_t cursor;
int ret = unw_init_remote(&cursor, addr_space_, upt_info_); int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
if (ret < 0) { if (ret < 0) {
@ -115,10 +134,10 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
prev->stack_size = frame->sp - prev->sp; prev->stack_size = frame->sp - prev->sp;
} }
frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
FillInMap(frame->pc, &frame->map); FillInMap(frame->pc, &frame->map);
frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
num_frames++; num_frames++;
} else { } else {
num_ignore_frames--; num_ignore_frames--;
@ -130,6 +149,10 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
} }
std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
if (!Init()) {
return "";
}
*offset = 0; *offset = 0;
char buf[512]; char buf[512];
unw_word_t value; unw_word_t value;

View file

@ -30,7 +30,7 @@
#include "BacktracePtrace.h" #include "BacktracePtrace.h"
class UnwindPtrace : public BacktracePtrace { class UnwindPtrace : public BacktracePtrace {
public: public:
UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map); UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
virtual ~UnwindPtrace(); virtual ~UnwindPtrace();
@ -38,7 +38,9 @@ public:
std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override; std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
private: private:
bool Init();
unw_addr_space_t addr_space_; unw_addr_space_t addr_space_;
struct UPT_info* upt_info_; struct UPT_info* upt_info_;
}; };

View file

@ -43,6 +43,7 @@
#include <backtrace/BacktraceMap.h> #include <backtrace/BacktraceMap.h>
#include <android-base/stringprintf.h> #include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/atomic.h> #include <cutils/atomic.h>
#include <cutils/threads.h> #include <cutils/threads.h>
@ -85,13 +86,13 @@ int test_level_one(int, int, int, int, void (*)(void*), void*);
int test_recursive_call(int, void (*)(void*), void*); int test_recursive_call(int, void (*)(void*), void*);
} }
uint64_t NanoTime() { static uint64_t NanoTime() {
struct timespec t = { 0, 0 }; struct timespec t = { 0, 0 };
clock_gettime(CLOCK_MONOTONIC, &t); clock_gettime(CLOCK_MONOTONIC, &t);
return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec); return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
} }
std::string DumpFrames(Backtrace* backtrace) { static std::string DumpFrames(Backtrace* backtrace) {
if (backtrace->NumFrames() == 0) { if (backtrace->NumFrames() == 0) {
return " No frames to dump.\n"; return " No frames to dump.\n";
} }
@ -103,7 +104,7 @@ std::string DumpFrames(Backtrace* backtrace) {
return frame; return frame;
} }
void WaitForStop(pid_t pid) { static void WaitForStop(pid_t pid) {
uint64_t start = NanoTime(); uint64_t start = NanoTime();
siginfo_t si; siginfo_t si;
@ -116,7 +117,28 @@ void WaitForStop(pid_t pid) {
} }
} }
bool ReadyLevelBacktrace(Backtrace* backtrace) { static void CreateRemoteProcess(pid_t* pid) {
if ((*pid = fork()) == 0) {
while (true)
;
_exit(0);
}
ASSERT_NE(-1, *pid);
ASSERT_TRUE(ptrace(PTRACE_ATTACH, *pid, 0, 0) == 0);
// Wait for the process to get to a stopping point.
WaitForStop(*pid);
}
static void FinishRemoteProcess(pid_t pid) {
ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
kill(pid, SIGKILL);
ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
}
static bool ReadyLevelBacktrace(Backtrace* backtrace) {
// See if test_level_four is in the backtrace. // See if test_level_four is in the backtrace.
bool found = false; bool found = false;
for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) { for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) {
@ -129,7 +151,7 @@ bool ReadyLevelBacktrace(Backtrace* backtrace) {
return found; return found;
} }
void VerifyLevelDump(Backtrace* backtrace) { static void VerifyLevelDump(Backtrace* backtrace) {
ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0)) ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0))
<< DumpFrames(backtrace); << DumpFrames(backtrace);
ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)) ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
@ -157,7 +179,7 @@ void VerifyLevelDump(Backtrace* backtrace) {
<< DumpFrames(backtrace); << DumpFrames(backtrace);
} }
void VerifyLevelBacktrace(void*) { static void VerifyLevelBacktrace(void*) {
std::unique_ptr<Backtrace> backtrace( std::unique_ptr<Backtrace> backtrace(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace.get() != nullptr);
@ -167,11 +189,11 @@ void VerifyLevelBacktrace(void*) {
VerifyLevelDump(backtrace.get()); VerifyLevelDump(backtrace.get());
} }
bool ReadyMaxBacktrace(Backtrace* backtrace) { static bool ReadyMaxBacktrace(Backtrace* backtrace) {
return (backtrace->NumFrames() == MAX_BACKTRACE_FRAMES); return (backtrace->NumFrames() == MAX_BACKTRACE_FRAMES);
} }
void VerifyMaxDump(Backtrace* backtrace) { static void VerifyMaxDump(Backtrace* backtrace) {
ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)) ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
<< DumpFrames(backtrace); << DumpFrames(backtrace);
// Verify that the last frame is our recursive call. // Verify that the last frame is our recursive call.
@ -179,7 +201,7 @@ void VerifyMaxDump(Backtrace* backtrace) {
<< DumpFrames(backtrace); << DumpFrames(backtrace);
} }
void VerifyMaxBacktrace(void*) { static void VerifyMaxBacktrace(void*) {
std::unique_ptr<Backtrace> backtrace( std::unique_ptr<Backtrace> backtrace(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace.get() != nullptr);
@ -189,7 +211,7 @@ void VerifyMaxBacktrace(void*) {
VerifyMaxDump(backtrace.get()); VerifyMaxDump(backtrace.get());
} }
void ThreadSetState(void* data) { static void ThreadSetState(void* data) {
thread_t* thread = reinterpret_cast<thread_t*>(data); thread_t* thread = reinterpret_cast<thread_t*>(data);
android_atomic_acquire_store(1, &thread->state); android_atomic_acquire_store(1, &thread->state);
volatile int i = 0; volatile int i = 0;
@ -198,16 +220,7 @@ void ThreadSetState(void* data) {
} }
} }
void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(Backtrace*)) { static bool WaitForNonZero(int32_t* value, uint64_t seconds) {
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), tid));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
VerifyFunc(backtrace.get());
}
bool WaitForNonZero(int32_t* value, uint64_t seconds) {
uint64_t start = NanoTime(); uint64_t start = NanoTime();
do { do {
if (android_atomic_acquire_load(value)) { if (android_atomic_acquire_load(value)) {
@ -240,9 +253,8 @@ TEST(libbacktrace, local_trace) {
ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0); ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
} }
void VerifyIgnoreFrames( static void VerifyIgnoreFrames(Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2,
Backtrace* bt_all, Backtrace* bt_ign1, const char* cur_proc) {
Backtrace* bt_ign2, const char* cur_proc) {
EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1) EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1)
<< "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 1 backtrace:\n" << DumpFrames(bt_ign1); << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 1 backtrace:\n" << DumpFrames(bt_ign1);
EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2) EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2)
@ -266,7 +278,7 @@ void VerifyIgnoreFrames(
} }
} }
void VerifyLevelIgnoreFrames(void*) { static void VerifyLevelIgnoreFrames(void*) {
std::unique_ptr<Backtrace> all( std::unique_ptr<Backtrace> all(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(all.get() != nullptr); ASSERT_TRUE(all.get() != nullptr);
@ -296,9 +308,8 @@ TEST(libbacktrace, local_max_trace) {
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0); ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0);
} }
void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, static void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, bool (*ReadyFunc)(Backtrace*),
bool (*ReadyFunc)(Backtrace*), void (*VerifyFunc)(Backtrace*)) {
void (*VerifyFunc)(Backtrace*)) {
pid_t ptrace_tid; pid_t ptrace_tid;
if (tid < 0) { if (tid < 0) {
ptrace_tid = pid; ptrace_tid = pid;
@ -376,7 +387,7 @@ TEST(libbacktrace, ptrace_max_trace) {
ASSERT_EQ(waitpid(pid, &status, 0), pid); ASSERT_EQ(waitpid(pid, &status, 0), pid);
} }
void VerifyProcessIgnoreFrames(Backtrace* bt_all) { static void VerifyProcessIgnoreFrames(Backtrace* bt_all) {
std::unique_ptr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD)); std::unique_ptr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(ign1.get() != nullptr); ASSERT_TRUE(ign1.get() != nullptr);
ASSERT_TRUE(ign1->Unwind(1)); ASSERT_TRUE(ign1->Unwind(1));
@ -404,12 +415,12 @@ TEST(libbacktrace, ptrace_ignore_frames) {
} }
// Create a process with multiple threads and dump all of the threads. // Create a process with multiple threads and dump all of the threads.
void* PtraceThreadLevelRun(void*) { static void* PtraceThreadLevelRun(void*) {
EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0); EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
return nullptr; return nullptr;
} }
void GetThreads(pid_t pid, std::vector<pid_t>* threads) { static void GetThreads(pid_t pid, std::vector<pid_t>* threads) {
// Get the list of tasks. // Get the list of tasks.
char task_path[128]; char task_path[128];
snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid); snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
@ -461,11 +472,8 @@ TEST(libbacktrace, ptrace_threads) {
} }
VerifyProcTest(pid, *it, false, ReadyLevelBacktrace, VerifyLevelDump); VerifyProcTest(pid, *it, false, ReadyLevelBacktrace, VerifyLevelDump);
} }
ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
kill(pid, SIGKILL); FinishRemoteProcess(pid);
int status;
ASSERT_EQ(waitpid(pid, &status, 0), pid);
} }
void VerifyLevelThread(void*) { void VerifyLevelThread(void*) {
@ -481,7 +489,7 @@ TEST(libbacktrace, thread_current_level) {
ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, nullptr), 0); ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
} }
void VerifyMaxThread(void*) { static void VerifyMaxThread(void*) {
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid())); std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0)); ASSERT_TRUE(backtrace->Unwind(0));
@ -494,7 +502,7 @@ TEST(libbacktrace, thread_current_max) {
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, nullptr), 0); ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, nullptr), 0);
} }
void* ThreadLevelRun(void* data) { static void* ThreadLevelRun(void* data) {
thread_t* thread = reinterpret_cast<thread_t*>(data); thread_t* thread = reinterpret_cast<thread_t*>(data);
thread->tid = gettid(); thread->tid = gettid();
@ -585,7 +593,7 @@ TEST(libbacktrace, thread_ignore_frames) {
android_atomic_acquire_store(0, &thread_data.state); android_atomic_acquire_store(0, &thread_data.state);
} }
void* ThreadMaxRun(void* data) { static void* ThreadMaxRun(void* data) {
thread_t* thread = reinterpret_cast<thread_t*>(data); thread_t* thread = reinterpret_cast<thread_t*>(data);
thread->tid = gettid(); thread->tid = gettid();
@ -616,7 +624,7 @@ TEST(libbacktrace, thread_max_trace) {
android_atomic_acquire_store(0, &thread_data.state); android_atomic_acquire_store(0, &thread_data.state);
} }
void* ThreadDump(void* data) { static void* ThreadDump(void* data) {
dump_thread_t* dump = reinterpret_cast<dump_thread_t*>(data); dump_thread_t* dump = reinterpret_cast<dump_thread_t*>(data);
while (true) { while (true) {
if (android_atomic_acquire_load(dump->now)) { if (android_atomic_acquire_load(dump->now)) {
@ -873,11 +881,9 @@ struct map_test_t {
uintptr_t end; uintptr_t end;
}; };
bool map_sort(map_test_t i, map_test_t j) { static bool map_sort(map_test_t i, map_test_t j) { return i.start < j.start; }
return i.start < j.start;
}
void VerifyMap(pid_t pid) { static void VerifyMap(pid_t pid) {
char buffer[4096]; char buffer[4096];
snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid); snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);
@ -908,29 +914,15 @@ void VerifyMap(pid_t pid) {
TEST(libbacktrace, verify_map_remote) { TEST(libbacktrace, verify_map_remote) {
pid_t pid; pid_t pid;
CreateRemoteProcess(&pid);
if ((pid = fork()) == 0) {
while (true) {
}
_exit(0);
}
ASSERT_LT(0, pid);
ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
// Wait for the process to get to a stopping point.
WaitForStop(pid);
// The maps should match exactly since the forked process has been paused. // The maps should match exactly since the forked process has been paused.
VerifyMap(pid); VerifyMap(pid);
ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); FinishRemoteProcess(pid);
kill(pid, SIGKILL);
ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
} }
void InitMemory(uint8_t* memory, size_t bytes) { static void InitMemory(uint8_t* memory, size_t bytes) {
for (size_t i = 0; i < bytes; i++) { for (size_t i = 0; i < bytes; i++) {
memory[i] = i; memory[i] = i;
if (memory[i] == '\0') { if (memory[i] == '\0') {
@ -941,7 +933,7 @@ void InitMemory(uint8_t* memory, size_t bytes) {
} }
} }
void* ThreadReadTest(void* data) { static void* ThreadReadTest(void* data) {
thread_t* thread_data = reinterpret_cast<thread_t*>(data); thread_t* thread_data = reinterpret_cast<thread_t*>(data);
thread_data->tid = gettid(); thread_data->tid = gettid();
@ -982,7 +974,7 @@ void* ThreadReadTest(void* data) {
return nullptr; return nullptr;
} }
void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) { static void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) {
size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE)); size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
// Create a page of data to use to do quick compares. // Create a page of data to use to do quick compares.
@ -1043,7 +1035,7 @@ TEST(libbacktrace, thread_read) {
volatile uintptr_t g_ready = 0; volatile uintptr_t g_ready = 0;
volatile uintptr_t g_addr = 0; volatile uintptr_t g_addr = 0;
void ForkedReadTest() { static void ForkedReadTest() {
// Create two map pages. // Create two map pages.
size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE)); size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
uint8_t* memory; uint8_t* memory;
@ -1117,7 +1109,7 @@ TEST(libbacktrace, process_read) {
ASSERT_TRUE(test_executed); ASSERT_TRUE(test_executed);
} }
void VerifyFunctionsFound(const std::vector<std::string>& found_functions) { static void VerifyFunctionsFound(const std::vector<std::string>& found_functions) {
// We expect to find these functions in libbacktrace_test. If we don't // We expect to find these functions in libbacktrace_test. If we don't
// find them, that's a bug in the memory read handling code in libunwind. // find them, that's a bug in the memory read handling code in libunwind.
std::list<std::string> expected_functions; std::list<std::string> expected_functions;
@ -1137,7 +1129,7 @@ void VerifyFunctionsFound(const std::vector<std::string>& found_functions) {
ASSERT_TRUE(expected_functions.empty()) << "Not all functions found in shared library."; ASSERT_TRUE(expected_functions.empty()) << "Not all functions found in shared library.";
} }
const char* CopySharedLibrary() { static const char* CopySharedLibrary() {
#if defined(__LP64__) #if defined(__LP64__)
const char* lib_name = "lib64"; const char* lib_name = "lib64";
#else #else
@ -1293,7 +1285,7 @@ TEST(libbacktrace, check_unreadable_elf_remote) {
VerifyFunctionsFound(found_functions); VerifyFunctionsFound(found_functions);
} }
bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t* frame_num) { static bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t* frame_num) {
backtrace_map_t map; backtrace_map_t map;
backtrace->FillInMap(test_func, &map); backtrace->FillInMap(test_func, &map);
if (!BacktraceMap::IsValid(map)) { if (!BacktraceMap::IsValid(map)) {
@ -1312,7 +1304,7 @@ bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t*
return false; return false;
} }
void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t frame_num) { static void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t frame_num) {
ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)) ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
<< DumpFrames(backtrace); << DumpFrames(backtrace);
@ -1324,7 +1316,7 @@ void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t
ASSERT_LT(diff, 200U) << DumpFrames(backtrace); ASSERT_LT(diff, 200U) << DumpFrames(backtrace);
} }
void VerifyUnreadableElfBacktrace(uintptr_t test_func) { static void VerifyUnreadableElfBacktrace(uintptr_t test_func) {
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
BACKTRACE_CURRENT_THREAD)); BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace.get() != nullptr);
@ -1418,12 +1410,38 @@ TEST(libbacktrace, unwind_thread_doesnt_exist) {
ASSERT_EQ(BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST, backtrace->GetError()); ASSERT_EQ(BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST, backtrace->GetError());
} }
TEST(libbacktrace, local_get_function_name_before_unwind) {
std::unique_ptr<Backtrace> backtrace(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
// Verify that trying to get a function name before doing an unwind works.
uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
size_t offset;
ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
}
TEST(libbacktrace, remote_get_function_name_before_unwind) {
pid_t pid;
CreateRemoteProcess(&pid);
// Now create an unwind object.
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
// Verify that trying to get a function name before doing an unwind works.
uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
size_t offset;
ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
FinishRemoteProcess(pid);
}
#if defined(ENABLE_PSS_TESTS) #if defined(ENABLE_PSS_TESTS)
#include "GetPss.h" #include "GetPss.h"
#define MAX_LEAK_BYTES (32*1024UL) #define MAX_LEAK_BYTES (32*1024UL)
void CheckForLeak(pid_t pid, pid_t tid) { static void CheckForLeak(pid_t pid, pid_t tid) {
// Do a few runs to get the PSS stable. // Do a few runs to get the PSS stable.
for (size_t i = 0; i < 100; i++) { for (size_t i = 0; i < 100; i++) {
Backtrace* backtrace = Backtrace::Create(pid, tid); Backtrace* backtrace = Backtrace::Create(pid, tid);
@ -1472,24 +1490,10 @@ TEST(libbacktrace, check_for_leak_local_thread) {
TEST(libbacktrace, check_for_leak_remote) { TEST(libbacktrace, check_for_leak_remote) {
pid_t pid; pid_t pid;
CreateRemoteProcess(&pid);
if ((pid = fork()) == 0) {
while (true) {
}
_exit(0);
}
ASSERT_LT(0, pid);
ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
// Wait for the process to get to a stopping point.
WaitForStop(pid);
CheckForLeak(pid, BACKTRACE_CURRENT_THREAD); CheckForLeak(pid, BACKTRACE_CURRENT_THREAD);
ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); FinishRemoteProcess(pid);
kill(pid, SIGKILL);
ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
} }
#endif #endif