From 82f3bbdc25253ee299207acd22b074bbe39bf2c6 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 14 Mar 2017 15:22:26 -0700 Subject: [PATCH] Allow calling GetFunctionName before unwinding. Some extra initialization needs to occur before calling the local/remote GetFunctioneName. Also, cleanup the test code a bit: - Make all local functions static. - Create a common function to create and finish remote processes. - Remove unused function. - Fix the formatting a bit by making it match clang format. Test: Ran the unit tests. Change-Id: I998bed1378d582df59fdf9263df6f208db5d795a --- libbacktrace/BacktraceCurrent.h | 6 +- libbacktrace/BacktracePtrace.h | 2 +- libbacktrace/ThreadEntry.h | 4 +- libbacktrace/UnwindCurrent.cpp | 17 ++++ libbacktrace/UnwindCurrent.h | 6 +- libbacktrace/UnwindMap.h | 12 +-- libbacktrace/UnwindPtrace.cpp | 47 ++++++--- libbacktrace/UnwindPtrace.h | 6 +- libbacktrace/backtrace_test.cpp | 172 ++++++++++++++++---------------- 9 files changed, 160 insertions(+), 112 deletions(-) diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h index 8aad36d00..072ffd26a 100644 --- a/libbacktrace/BacktraceCurrent.h +++ b/libbacktrace/BacktraceCurrent.h @@ -36,7 +36,7 @@ class BacktraceMap; class BacktraceCurrent : public Backtrace { -public: + public: BacktraceCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {} virtual ~BacktraceCurrent() {} @@ -46,10 +46,10 @@ public: bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override; -protected: + protected: bool DiscardFrame(const backtrace_frame_data_t& frame); -private: + private: bool UnwindThread(size_t num_ignore_frames); virtual bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) = 0; diff --git a/libbacktrace/BacktracePtrace.h b/libbacktrace/BacktracePtrace.h index 1d498115e..760817b8e 100644 --- a/libbacktrace/BacktracePtrace.h +++ b/libbacktrace/BacktracePtrace.h @@ -25,7 +25,7 @@ class BacktraceMap; class BacktracePtrace : public Backtrace { -public: + public: BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {} virtual ~BacktracePtrace() {} diff --git a/libbacktrace/ThreadEntry.h b/libbacktrace/ThreadEntry.h index 11924a3ad..caa549715 100644 --- a/libbacktrace/ThreadEntry.h +++ b/libbacktrace/ThreadEntry.h @@ -22,7 +22,7 @@ #include class ThreadEntry { -public: + public: static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true); static void Remove(ThreadEntry* entry); @@ -47,7 +47,7 @@ public: inline ucontext_t* GetUcontext() { return &ucontext_; } -private: + private: ThreadEntry(pid_t pid, pid_t tid); ~ThreadEntry(); diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp index 666c481ce..4862d9dab 100644 --- a/libbacktrace/UnwindCurrent.cpp +++ b/libbacktrace/UnwindCurrent.cpp @@ -23,12 +23,23 @@ #define UNW_LOCAL_ONLY #include +#include #include #include "BacktraceLog.h" #include "UnwindCurrent.h" 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 cursor(new unw_cursor_t); + if (unw_init_local(cursor.get(), &context_) < 0) { + return ""; + } + initialized_ = true; + } + *offset = 0; char buf[512]; 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; return false; } + initialized_ = true; size_t num_frames = 0; do { @@ -124,6 +136,11 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucon num_frames++; } else { 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()); diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h index 302399684..3656104b0 100644 --- a/libbacktrace/UnwindCurrent.h +++ b/libbacktrace/UnwindCurrent.h @@ -32,18 +32,20 @@ #include class UnwindCurrent : public BacktraceCurrent { -public: + public: UnwindCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {} virtual ~UnwindCurrent() {} std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override; -private: + private: void GetUnwContextFromUcontext(const ucontext_t* ucontext); bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override; unw_context_t context_; + + bool initialized_ = false; }; #endif // _LIBBACKTRACE_UNWIND_CURRENT_H diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h index d5bec069b..6ffdafd18 100644 --- a/libbacktrace/UnwindMap.h +++ b/libbacktrace/UnwindMap.h @@ -28,28 +28,28 @@ // libunwind.h first then this header. class UnwindMap : public BacktraceMap { -public: + public: explicit UnwindMap(pid_t pid); unw_map_cursor_t* GetMapCursor() { return &map_cursor_; } -protected: + protected: unw_map_cursor_t map_cursor_; }; class UnwindMapRemote : public UnwindMap { -public: + public: explicit UnwindMapRemote(pid_t pid); virtual ~UnwindMapRemote(); bool Build() override; -private: + private: bool GenerateMap(); }; class UnwindMapLocal : public UnwindMap { -public: + public: UnwindMapLocal(); virtual ~UnwindMapLocal(); @@ -60,7 +60,7 @@ public: void LockIterator() override { pthread_rwlock_rdlock(&map_lock_); } void UnlockIterator() override { pthread_rwlock_unlock(&map_lock_); } -private: + private: bool GenerateMap(); bool map_created_; diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp index 306d2acf0..5c73bd66b 100644 --- a/libbacktrace/UnwindPtrace.cpp +++ b/libbacktrace/UnwindPtrace.cpp @@ -37,6 +37,7 @@ UnwindPtrace::~UnwindPtrace() { _UPT_destroy(upt_info_); upt_info_ = nullptr; } + if (addr_space_) { // Remove the map from the address space before destroying it. // 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) { - if (GetMap() == nullptr) { - // Without a map object, we can't do anything. - error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING; - return false; +bool UnwindPtrace::Init() { + if (upt_info_) { + return true; } - error_ = BACKTRACE_UNWIND_NO_ERROR; - - if (ucontext) { - BACK_LOGW("Unwinding from a specified context not supported yet."); - error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION; + if (addr_space_) { + // If somehow the addr_space_ gets initialized but upt_info_ doesn't, + // then that indicates there is some kind of failure. return false; } @@ -79,6 +76,28 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { 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; int ret = unw_init_remote(&cursor, addr_space_, upt_info_); 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; } - frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); - FillInMap(frame->pc, &frame->map); + frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); + num_frames++; } else { 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) { + if (!Init()) { + return ""; + } + *offset = 0; char buf[512]; unw_word_t value; diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h index ab04abf92..46881101f 100644 --- a/libbacktrace/UnwindPtrace.h +++ b/libbacktrace/UnwindPtrace.h @@ -30,7 +30,7 @@ #include "BacktracePtrace.h" class UnwindPtrace : public BacktracePtrace { -public: + public: UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map); virtual ~UnwindPtrace(); @@ -38,7 +38,9 @@ public: std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override; -private: + private: + bool Init(); + unw_addr_space_t addr_space_; struct UPT_info* upt_info_; }; diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index e25c8e966..9ca373a7e 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -85,13 +86,13 @@ int test_level_one(int, int, int, int, void (*)(void*), void*); int test_recursive_call(int, void (*)(void*), void*); } -uint64_t NanoTime() { +static uint64_t NanoTime() { struct timespec t = { 0, 0 }; clock_gettime(CLOCK_MONOTONIC, &t); return static_cast(t.tv_sec * NS_PER_SEC + t.tv_nsec); } -std::string DumpFrames(Backtrace* backtrace) { +static std::string DumpFrames(Backtrace* backtrace) { if (backtrace->NumFrames() == 0) { return " No frames to dump.\n"; } @@ -103,7 +104,7 @@ std::string DumpFrames(Backtrace* backtrace) { return frame; } -void WaitForStop(pid_t pid) { +static void WaitForStop(pid_t pid) { uint64_t start = NanoTime(); 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. bool found = false; for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) { @@ -129,7 +151,7 @@ bool ReadyLevelBacktrace(Backtrace* backtrace) { return found; } -void VerifyLevelDump(Backtrace* backtrace) { +static void VerifyLevelDump(Backtrace* backtrace) { ASSERT_GT(backtrace->NumFrames(), static_cast(0)) << DumpFrames(backtrace); ASSERT_LT(backtrace->NumFrames(), static_cast(MAX_BACKTRACE_FRAMES)) @@ -157,7 +179,7 @@ void VerifyLevelDump(Backtrace* backtrace) { << DumpFrames(backtrace); } -void VerifyLevelBacktrace(void*) { +static void VerifyLevelBacktrace(void*) { std::unique_ptr backtrace( Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); ASSERT_TRUE(backtrace.get() != nullptr); @@ -167,11 +189,11 @@ void VerifyLevelBacktrace(void*) { VerifyLevelDump(backtrace.get()); } -bool ReadyMaxBacktrace(Backtrace* backtrace) { +static bool ReadyMaxBacktrace(Backtrace* backtrace) { return (backtrace->NumFrames() == MAX_BACKTRACE_FRAMES); } -void VerifyMaxDump(Backtrace* backtrace) { +static void VerifyMaxDump(Backtrace* backtrace) { ASSERT_EQ(backtrace->NumFrames(), static_cast(MAX_BACKTRACE_FRAMES)) << DumpFrames(backtrace); // Verify that the last frame is our recursive call. @@ -179,7 +201,7 @@ void VerifyMaxDump(Backtrace* backtrace) { << DumpFrames(backtrace); } -void VerifyMaxBacktrace(void*) { +static void VerifyMaxBacktrace(void*) { std::unique_ptr backtrace( Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); ASSERT_TRUE(backtrace.get() != nullptr); @@ -189,7 +211,7 @@ void VerifyMaxBacktrace(void*) { VerifyMaxDump(backtrace.get()); } -void ThreadSetState(void* data) { +static void ThreadSetState(void* data) { thread_t* thread = reinterpret_cast(data); android_atomic_acquire_store(1, &thread->state); volatile int i = 0; @@ -198,16 +220,7 @@ void ThreadSetState(void* data) { } } -void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(Backtrace*)) { - std::unique_ptr 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) { +static bool WaitForNonZero(int32_t* value, uint64_t seconds) { uint64_t start = NanoTime(); do { 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); } -void VerifyIgnoreFrames( - Backtrace* bt_all, Backtrace* bt_ign1, - Backtrace* bt_ign2, const char* cur_proc) { +static void VerifyIgnoreFrames(Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2, + const char* cur_proc) { EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1) << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 1 backtrace:\n" << DumpFrames(bt_ign1); 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 all( Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); 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); } -void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, - bool (*ReadyFunc)(Backtrace*), - void (*VerifyFunc)(Backtrace*)) { +static void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, bool (*ReadyFunc)(Backtrace*), + void (*VerifyFunc)(Backtrace*)) { pid_t ptrace_tid; if (tid < 0) { ptrace_tid = pid; @@ -376,7 +387,7 @@ TEST(libbacktrace, ptrace_max_trace) { ASSERT_EQ(waitpid(pid, &status, 0), pid); } -void VerifyProcessIgnoreFrames(Backtrace* bt_all) { +static void VerifyProcessIgnoreFrames(Backtrace* bt_all) { std::unique_ptr ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD)); ASSERT_TRUE(ign1.get() != nullptr); 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. -void* PtraceThreadLevelRun(void*) { +static void* PtraceThreadLevelRun(void*) { EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0); return nullptr; } -void GetThreads(pid_t pid, std::vector* threads) { +static void GetThreads(pid_t pid, std::vector* threads) { // Get the list of tasks. char task_path[128]; snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid); @@ -461,11 +472,8 @@ TEST(libbacktrace, ptrace_threads) { } VerifyProcTest(pid, *it, false, ReadyLevelBacktrace, VerifyLevelDump); } - ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); - kill(pid, SIGKILL); - int status; - ASSERT_EQ(waitpid(pid, &status, 0), pid); + FinishRemoteProcess(pid); } void VerifyLevelThread(void*) { @@ -481,7 +489,7 @@ TEST(libbacktrace, thread_current_level) { ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, nullptr), 0); } -void VerifyMaxThread(void*) { +static void VerifyMaxThread(void*) { std::unique_ptr backtrace(Backtrace::Create(getpid(), gettid())); ASSERT_TRUE(backtrace.get() != nullptr); 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); } -void* ThreadLevelRun(void* data) { +static void* ThreadLevelRun(void* data) { thread_t* thread = reinterpret_cast(data); thread->tid = gettid(); @@ -585,7 +593,7 @@ TEST(libbacktrace, thread_ignore_frames) { android_atomic_acquire_store(0, &thread_data.state); } -void* ThreadMaxRun(void* data) { +static void* ThreadMaxRun(void* data) { thread_t* thread = reinterpret_cast(data); thread->tid = gettid(); @@ -616,7 +624,7 @@ TEST(libbacktrace, thread_max_trace) { android_atomic_acquire_store(0, &thread_data.state); } -void* ThreadDump(void* data) { +static void* ThreadDump(void* data) { dump_thread_t* dump = reinterpret_cast(data); while (true) { if (android_atomic_acquire_load(dump->now)) { @@ -873,11 +881,9 @@ struct map_test_t { uintptr_t end; }; -bool map_sort(map_test_t i, map_test_t j) { - return i.start < j.start; -} +static bool map_sort(map_test_t i, map_test_t j) { return i.start < j.start; } -void VerifyMap(pid_t pid) { +static void VerifyMap(pid_t pid) { char buffer[4096]; snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid); @@ -908,29 +914,15 @@ void VerifyMap(pid_t pid) { TEST(libbacktrace, verify_map_remote) { pid_t 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); + CreateRemoteProcess(&pid); // The maps should match exactly since the forked process has been paused. VerifyMap(pid); - ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); - - kill(pid, SIGKILL); - ASSERT_EQ(waitpid(pid, nullptr, 0), pid); + FinishRemoteProcess(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++) { memory[i] = i; 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(data); thread_data->tid = gettid(); @@ -982,7 +974,7 @@ void* ThreadReadTest(void* data) { return nullptr; } -void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) { +static void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) { size_t pagesize = static_cast(sysconf(_SC_PAGE_SIZE)); // 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_addr = 0; -void ForkedReadTest() { +static void ForkedReadTest() { // Create two map pages. size_t pagesize = static_cast(sysconf(_SC_PAGE_SIZE)); uint8_t* memory; @@ -1117,7 +1109,7 @@ TEST(libbacktrace, process_read) { ASSERT_TRUE(test_executed); } -void VerifyFunctionsFound(const std::vector& found_functions) { +static void VerifyFunctionsFound(const std::vector& found_functions) { // 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. std::list expected_functions; @@ -1137,7 +1129,7 @@ void VerifyFunctionsFound(const std::vector& found_functions) { ASSERT_TRUE(expected_functions.empty()) << "Not all functions found in shared library."; } -const char* CopySharedLibrary() { +static const char* CopySharedLibrary() { #if defined(__LP64__) const char* lib_name = "lib64"; #else @@ -1293,7 +1285,7 @@ TEST(libbacktrace, check_unreadable_elf_remote) { 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->FillInMap(test_func, &map); if (!BacktraceMap::IsValid(map)) { @@ -1312,7 +1304,7 @@ bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t* 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(MAX_BACKTRACE_FRAMES)) << DumpFrames(backtrace); @@ -1324,7 +1316,7 @@ void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t ASSERT_LT(diff, 200U) << DumpFrames(backtrace); } -void VerifyUnreadableElfBacktrace(uintptr_t test_func) { +static void VerifyUnreadableElfBacktrace(uintptr_t test_func) { std::unique_ptr backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); 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()); } +TEST(libbacktrace, local_get_function_name_before_unwind) { + std::unique_ptr 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(&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::Create(pid, pid)); + + // Verify that trying to get a function name before doing an unwind works. + uintptr_t cur_func_offset = reinterpret_cast(&test_level_one) + 1; + size_t offset; + ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset)); + + FinishRemoteProcess(pid); +} + #if defined(ENABLE_PSS_TESTS) #include "GetPss.h" #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. for (size_t i = 0; i < 100; i++) { Backtrace* backtrace = Backtrace::Create(pid, tid); @@ -1472,24 +1490,10 @@ TEST(libbacktrace, check_for_leak_local_thread) { TEST(libbacktrace, check_for_leak_remote) { pid_t 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); + CreateRemoteProcess(&pid); CheckForLeak(pid, BACKTRACE_CURRENT_THREAD); - ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); - - kill(pid, SIGKILL); - ASSERT_EQ(waitpid(pid, nullptr, 0), pid); + FinishRemoteProcess(pid); } #endif