diff options
author | Christopher Ferris <cferris@google.com> | 2014-01-29 12:19:59 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-01-29 12:19:59 +0000 |
commit | 96a0bf1e94cbb8bc625333537ace11944e20c396 (patch) | |
tree | ee3362a677cb64691d845cf100b1aa1aa768597f /libbacktrace | |
parent | 8e4cdc1e8622f5c6ec1995f42b93489d58b982b9 (diff) | |
parent | 36a4e4085e55048ee2a78c7d5b50f7395e547fa2 (diff) | |
download | system_core-96a0bf1e94cbb8bc625333537ace11944e20c396.zip system_core-96a0bf1e94cbb8bc625333537ace11944e20c396.tar.gz system_core-96a0bf1e94cbb8bc625333537ace11944e20c396.tar.bz2 |
am 36a4e408: am aaf89887: am 6fe31b2f: am d391c9b4: Merge "Re-enable libunwind for arm."
* commit '36a4e4085e55048ee2a78c7d5b50f7395e547fa2':
Re-enable libunwind for arm.
Diffstat (limited to 'libbacktrace')
-rw-r--r-- | libbacktrace/Android.mk | 5 | ||||
-rw-r--r-- | libbacktrace/BacktraceImpl.cpp (renamed from libbacktrace/Backtrace.cpp) | 34 | ||||
-rw-r--r-- | libbacktrace/BacktraceImpl.h (renamed from libbacktrace/Backtrace.h) | 19 | ||||
-rw-r--r-- | libbacktrace/BacktraceMap.cpp | 17 | ||||
-rw-r--r-- | libbacktrace/BacktraceThread.cpp | 4 | ||||
-rw-r--r-- | libbacktrace/BacktraceThread.h | 4 | ||||
-rw-r--r-- | libbacktrace/Corkscrew.cpp | 37 | ||||
-rw-r--r-- | libbacktrace/Corkscrew.h | 34 | ||||
-rw-r--r-- | libbacktrace/UnwindCurrent.cpp | 9 | ||||
-rw-r--r-- | libbacktrace/UnwindCurrent.h | 6 | ||||
-rw-r--r-- | libbacktrace/UnwindMap.cpp | 110 | ||||
-rw-r--r-- | libbacktrace/UnwindMap.h | 39 | ||||
-rw-r--r-- | libbacktrace/UnwindPtrace.cpp | 14 | ||||
-rw-r--r-- | libbacktrace/UnwindPtrace.h | 4 | ||||
-rw-r--r-- | libbacktrace/backtrace_test.cpp | 53 |
15 files changed, 287 insertions, 102 deletions
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk index f23eefd..0ae8839 100644 --- a/libbacktrace/Android.mk +++ b/libbacktrace/Android.mk @@ -1,7 +1,7 @@ LOCAL_PATH:= $(call my-dir) common_src := \ - Backtrace.cpp \ + BacktraceImpl.cpp \ BacktraceMap.cpp \ BacktraceThread.cpp \ thread_utils.c \ @@ -23,7 +23,7 @@ common_shared_libs := \ liblog \ # To enable using libunwind on each arch, add it to this list. -libunwind_architectures := arm64 +libunwind_architectures := arm arm64 ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),$(libunwind_architectures))) @@ -35,6 +35,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ $(common_src) \ UnwindCurrent.cpp \ + UnwindMap.cpp \ UnwindPtrace.cpp \ LOCAL_CFLAGS := \ diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/BacktraceImpl.cpp index d7b40ab..39296b4 100644 --- a/libbacktrace/Backtrace.cpp +++ b/libbacktrace/BacktraceImpl.cpp @@ -29,7 +29,7 @@ #include <backtrace/Backtrace.h> #include <backtrace/BacktraceMap.h> -#include "Backtrace.h" +#include "BacktraceImpl.h" #include "thread_utils.h" //------------------------------------------------------------------------- @@ -40,21 +40,21 @@ Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map) impl_->SetParent(this); if (map_ == NULL) { - // The map will be created when needed. + map_ = BacktraceMap::Create(pid); map_shared_ = false; } } Backtrace::~Backtrace() { - if (map_ && !map_shared_) { - delete map_; - map_ = NULL; - } - if (impl_) { delete impl_; impl_ = NULL; } + + if (map_ && !map_shared_) { + delete map_; + map_ = NULL; + } } bool Backtrace::Unwind(size_t num_ignore_frames) { @@ -129,30 +129,10 @@ std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) { return buf; } -bool Backtrace::BuildMap() { - map_ = impl_->CreateBacktraceMap(pid_); - if (!map_->Build()) { - BACK_LOGW("Failed to build map for process %d", pid_); - return false; - } - return true; -} - const backtrace_map_t* Backtrace::FindMap(uintptr_t pc) { - if (map_ == NULL) { - // Lazy eval, time to build the map. - if (!BuildMap()) { - return NULL; - } - } return map_->Find(pc); } -BacktraceMap* Backtrace::TakeMapOwnership() { - map_shared_ = true; - return map_; -} - //------------------------------------------------------------------------- // BacktraceCurrent functions. //------------------------------------------------------------------------- diff --git a/libbacktrace/Backtrace.h b/libbacktrace/BacktraceImpl.h index 31fcaf2..af014d5 100644 --- a/libbacktrace/Backtrace.h +++ b/libbacktrace/BacktraceImpl.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef _LIBBACKTRACE_BACKTRACE_H -#define _LIBBACKTRACE_BACKTRACE_H +#ifndef _LIBBACKTRACE_BACKTRACE_IMPL_H +#define _LIBBACKTRACE_BACKTRACE_IMPL_H #include <backtrace/Backtrace.h> #include <backtrace/BacktraceMap.h> @@ -39,13 +39,20 @@ public: void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; } - virtual BacktraceMap* CreateBacktraceMap(pid_t pid) = 0; + inline pid_t Pid() { return backtrace_obj_->Pid(); } + inline pid_t Tid() { return backtrace_obj_->Tid(); } + + inline const backtrace_map_t* FindMap(uintptr_t addr) { + return backtrace_obj_->FindMap(addr); + } + inline std::string GetFunctionName(uintptr_t pc, uintptr_t* offset) { + return backtrace_obj_->GetFunctionName(pc, offset); + } + inline BacktraceMap* GetMap() { return backtrace_obj_->GetMap(); } protected: inline std::vector<backtrace_frame_data_t>* GetFrames() { return &backtrace_obj_->frames_; } - inline bool BuildMap() { return backtrace_obj_->BuildMap(); } - Backtrace* backtrace_obj_; }; @@ -69,4 +76,4 @@ Backtrace* CreateCurrentObj(BacktraceMap* map); Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map); Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map); -#endif // _LIBBACKTRACE_BACKTRACE_H +#endif // _LIBBACKTRACE_BACKTRACE_IMPL_H diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp index 78f5b6b..6320800 100644 --- a/libbacktrace/BacktraceMap.cpp +++ b/libbacktrace/BacktraceMap.cpp @@ -21,9 +21,13 @@ #include <string> #include <vector> +#include <backtrace/backtrace_constants.h> #include <backtrace/BacktraceMap.h> #include <log/log.h> +#include "thread_utils.h" +#include "BacktraceImpl.h" + BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) { if (pid_ < 0) { pid_ = getpid(); @@ -128,3 +132,16 @@ bool BacktraceMap::Build() { return true; } + +#if defined(__APPLE__) +// Corkscrew and libunwind don't compile on the mac, so create a generic +// map object. +BacktraceMap* BacktraceMap::Create(pid_t pid) { + BacktraceMap* map = new BacktraceMap(pid); + if (!map->Build()) { + delete map; + return NULL; + } + return map; +} +#endif diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp index 9953dc1..5ffe516 100644 --- a/libbacktrace/BacktraceThread.cpp +++ b/libbacktrace/BacktraceThread.cpp @@ -180,10 +180,6 @@ bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) { } bool BacktraceThread::Unwind(size_t num_ignore_frames) { - if (!thread_intf_->Init()) { - return false; - } - ThreadEntry* entry = ThreadEntry::AddThreadToUnwind( thread_intf_, Pid(), Tid(), num_ignore_frames); if (!entry) { diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h index cae496a..3412d58 100644 --- a/libbacktrace/BacktraceThread.h +++ b/libbacktrace/BacktraceThread.h @@ -20,7 +20,7 @@ #include <inttypes.h> #include <sys/types.h> -#include "Backtrace.h" +#include "BacktraceImpl.h" enum state_e { STATE_WAITING = 0, @@ -58,8 +58,6 @@ class BacktraceThreadInterface { public: virtual ~BacktraceThreadInterface() { } - virtual bool Init() = 0; - virtual void ThreadUnwind( siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) = 0; }; diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp index fd31a26..efeee2e 100644 --- a/libbacktrace/Corkscrew.cpp +++ b/libbacktrace/Corkscrew.cpp @@ -65,7 +65,8 @@ bool CorkscrewMap::Build() { } map.name = cur_map->name; - maps_.push_back(map); + // The maps are in descending order, but we want them in ascending order. + maps_.push_front(map); cur_map = cur_map->next; } @@ -93,8 +94,8 @@ bool CorkscrewCommon::GenerateFrameData( it->stack_size = cork_frames[i].stack_size; it->func_offset = 0; - it->map = backtrace_obj_->FindMap(it->pc); - it->func_name = backtrace_obj_->GetFunctionName(it->pc, &it->func_offset); + it->map = FindMap(it->pc); + it->func_name = GetFunctionName(it->pc, &it->func_offset); } return true; } @@ -119,7 +120,7 @@ std::string CorkscrewCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset *offset = 0; Dl_info info; - const backtrace_map_t* map = backtrace_obj_->FindMap(pc); + const backtrace_map_t* map = FindMap(pc); if (map) { if (dladdr((const void*)pc, &info)) { if (info.dli_sname) { @@ -158,19 +159,10 @@ CorkscrewThread::CorkscrewThread() { CorkscrewThread::~CorkscrewThread() { } -bool CorkscrewThread::Init() { - if (backtrace_obj_->GetMap() == NULL) { - // Trigger the map object creation, which will create the corkscrew - // map information. - return BuildMap(); - } - return true; -} - void CorkscrewThread::ThreadUnwind( siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) { backtrace_frame_t cork_frames[MAX_BACKTRACE_FRAMES]; - CorkscrewMap* map = static_cast<CorkscrewMap*>(backtrace_obj_->GetMap()); + CorkscrewMap* map = static_cast<CorkscrewMap*>(GetMap()); ssize_t num_frames = unwind_backtrace_signal_arch( siginfo, sigcontext, map->GetMapInfo(), cork_frames, num_ignore_frames, MAX_BACKTRACE_FRAMES); @@ -204,12 +196,11 @@ CorkscrewPtrace::~CorkscrewPtrace() { } bool CorkscrewPtrace::Unwind(size_t num_ignore_frames) { - ptrace_context_ = load_ptrace_context(backtrace_obj_->Tid()); + ptrace_context_ = load_ptrace_context(Tid()); backtrace_frame_t frames[MAX_BACKTRACE_FRAMES]; ssize_t num_frames = unwind_backtrace_ptrace( - backtrace_obj_->Tid(), ptrace_context_, frames, num_ignore_frames, - MAX_BACKTRACE_FRAMES); + Tid(), ptrace_context_, frames, num_ignore_frames, MAX_BACKTRACE_FRAMES); return GenerateFrameData(frames, num_frames); } @@ -246,3 +237,15 @@ Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) { CorkscrewThread* thread_obj = new CorkscrewThread(); return new BacktraceThread(thread_obj, thread_obj, tid, map); } + +//------------------------------------------------------------------------- +// BacktraceMap create function. +//------------------------------------------------------------------------- +BacktraceMap* BacktraceMap::Create(pid_t pid) { + BacktraceMap* map = new CorkscrewMap(pid); + if (!map->Build()) { + delete map; + return NULL; + } + return map; +} diff --git a/libbacktrace/Corkscrew.h b/libbacktrace/Corkscrew.h index 229bb01..1633398 100644 --- a/libbacktrace/Corkscrew.h +++ b/libbacktrace/Corkscrew.h @@ -26,14 +26,25 @@ #include <corkscrew/backtrace.h> -#include "Backtrace.h" +#include "BacktraceImpl.h" #include "BacktraceThread.h" +class CorkscrewMap : public BacktraceMap { +public: + CorkscrewMap(pid_t pid); + virtual ~CorkscrewMap(); + + virtual bool Build(); + + map_info_t* GetMapInfo() { return map_info_; } + +private: + map_info_t* map_info_; +}; + class CorkscrewCommon : public BacktraceImpl { public: bool GenerateFrameData(backtrace_frame_t* cork_frames, ssize_t num_frames); - - virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new BacktraceMap(pid); } }; class CorkscrewCurrent : public CorkscrewCommon { @@ -46,30 +57,13 @@ public: virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); }; -class CorkscrewMap : public BacktraceMap { -public: - CorkscrewMap(pid_t pid); - virtual ~CorkscrewMap(); - - virtual bool Build(); - - map_info_t* GetMapInfo() { return map_info_; } - -private: - map_info_t* map_info_; -}; - class CorkscrewThread : public CorkscrewCurrent, public BacktraceThreadInterface { public: CorkscrewThread(); virtual ~CorkscrewThread(); - virtual bool Init(); - virtual void ThreadUnwind( siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames); - - virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new CorkscrewMap(pid); } }; class CorkscrewPtrace : public CorkscrewCommon { diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp index d1195ee..17b71b9 100644 --- a/libbacktrace/UnwindCurrent.cpp +++ b/libbacktrace/UnwindCurrent.cpp @@ -25,6 +25,7 @@ #include <libunwind.h> #include "UnwindCurrent.h" +#include "UnwindMap.h" // Define the ucontext_t structures needed for each supported arch. #if defined(__arm__) @@ -119,8 +120,8 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) { } if (resolve) { - frame->func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); - frame->map = backtrace_obj_->FindMap(frame->pc); + frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); + frame->map = FindMap(frame->pc); } else { frame->map = NULL; frame->func_offset = 0; @@ -171,10 +172,6 @@ UnwindThread::UnwindThread() { UnwindThread::~UnwindThread() { } -bool UnwindThread::Init() { - return true; -} - void UnwindThread::ThreadUnwind( siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) { ExtractContext(sigcontext); diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h index 8302c0b..acce110 100644 --- a/libbacktrace/UnwindCurrent.h +++ b/libbacktrace/UnwindCurrent.h @@ -19,7 +19,7 @@ #include <string> -#include "Backtrace.h" +#include "BacktraceImpl.h" #include "BacktraceThread.h" #define UNW_LOCAL_ONLY @@ -38,8 +38,6 @@ public: void ExtractContext(void* sigcontext); - virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new BacktraceMap(pid); } - protected: unw_context_t context_; }; @@ -49,8 +47,6 @@ public: UnwindThread(); virtual ~UnwindThread(); - virtual bool Init(); - virtual void ThreadUnwind( siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames); }; diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp new file mode 100644 index 0000000..9c8193b --- /dev/null +++ b/libbacktrace/UnwindMap.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "libbacktrace" + +#include <pthread.h> +#include <sys/types.h> +#include <unistd.h> + +#include <backtrace/BacktraceMap.h> + +#include <libunwind.h> + +#include "UnwindMap.h" + +//------------------------------------------------------------------------- +// libunwind has a single shared address space for the current process +// aka local. If multiple maps are created for the current pid, then +// only update the local address space once, and keep a reference count +// of maps using the same map cursor. +//------------------------------------------------------------------------- +static pthread_mutex_t g_map_mutex = PTHREAD_MUTEX_INITIALIZER; +static unw_map_cursor_t* g_map_cursor = NULL; +static int g_map_references = 0; + +UnwindMap::UnwindMap(pid_t pid) : BacktraceMap(pid) { + map_cursor_.map_list = NULL; +} + +UnwindMap::~UnwindMap() { + if (pid_ == getpid()) { + pthread_mutex_lock(&g_map_mutex); + if (--g_map_references == 0) { + // Clear the local address space map. + unw_map_set(unw_local_addr_space, NULL); + unw_map_cursor_destroy(&map_cursor_); + } + pthread_mutex_unlock(&g_map_mutex); + } else { + unw_map_cursor_destroy(&map_cursor_); + } +} + +bool UnwindMap::Build() { + bool return_value = true; + if (pid_ == getpid()) { + pthread_mutex_lock(&g_map_mutex); + if (g_map_references == 0) { + return_value = (unw_map_cursor_create(&map_cursor_, pid_) == 0); + if (return_value) { + // Set the local address space to this cursor map. + unw_map_set(unw_local_addr_space, &map_cursor_); + g_map_references = 1; + g_map_cursor = &map_cursor_; + } + } else { + g_map_references++; + map_cursor_ = *g_map_cursor; + } + pthread_mutex_unlock(&g_map_mutex); + } else { + return_value = (unw_map_cursor_create(&map_cursor_, pid_) == 0); + } + + if (!return_value) + return false; + + // Use the map_cursor information to construct the BacktraceMap data + // rather than reparsing /proc/self/maps. + unw_map_cursor_reset(&map_cursor_); + unw_map_t unw_map; + while (unw_map_cursor_get(&map_cursor_, &unw_map)) { + backtrace_map_t map; + + map.start = unw_map.start; + map.end = unw_map.end; + map.flags = unw_map.flags; + map.name = unw_map.path; + + // The maps are in descending order, but we want them in ascending order. + maps_.push_front(map); + } + + return true; +} + +//------------------------------------------------------------------------- +// BacktraceMap create function. +//------------------------------------------------------------------------- +BacktraceMap* BacktraceMap::Create(pid_t pid) { + BacktraceMap* map = new UnwindMap(pid); + if (!map->Build()) { + delete map; + return NULL; + } + return map; +} diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h new file mode 100644 index 0000000..5a874e8 --- /dev/null +++ b/libbacktrace/UnwindMap.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBBACKTRACE_UNWIND_MAP_H +#define _LIBBACKTRACE_UNWIND_MAP_H + +#include <backtrace/BacktraceMap.h> + +// The unw_map_cursor_t structure is different depending on whether it is +// the local or remote version. In order to get the correct version, include +// libunwind.h first then this header. + +class UnwindMap : public BacktraceMap { +public: + UnwindMap(pid_t pid); + virtual ~UnwindMap(); + + virtual bool Build(); + + unw_map_cursor_t* GetMapCursor() { return &map_cursor_; } + +private: + unw_map_cursor_t map_cursor_; +}; + +#endif // _LIBBACKTRACE_UNWIND_MAP_H diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp index e45c5f8..732dae8 100644 --- a/libbacktrace/UnwindPtrace.cpp +++ b/libbacktrace/UnwindPtrace.cpp @@ -25,6 +25,7 @@ #include <libunwind.h> #include <libunwind-ptrace.h> +#include "UnwindMap.h" #include "UnwindPtrace.h" UnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) { @@ -36,6 +37,10 @@ UnwindPtrace::~UnwindPtrace() { upt_info_ = NULL; } if (addr_space_) { + // Remove the map from the address space before destroying it. + // It will be freed in the UnwindMap destructor. + unw_map_set(addr_space_, NULL); + unw_destroy_addr_space(addr_space_); addr_space_ = NULL; } @@ -48,7 +53,10 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames) { return false; } - upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(backtrace_obj_->Tid())); + UnwindMap* map = static_cast<UnwindMap*>(GetMap()); + unw_map_set(addr_space_, map->GetMapCursor()); + + upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid())); if (!upt_info_) { BACK_LOGW("Failed to create upt info."); return false; @@ -91,9 +99,9 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames) { prev->stack_size = frame->sp - prev->sp; } - frame->func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); + frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); - frame->map = backtrace_obj_->FindMap(frame->pc); + frame->map = FindMap(frame->pc); num_frames++; } else { diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h index 05375dd..1e82117 100644 --- a/libbacktrace/UnwindPtrace.h +++ b/libbacktrace/UnwindPtrace.h @@ -19,7 +19,7 @@ #include <string> -#include "Backtrace.h" +#include "BacktraceImpl.h" #include <libunwind.h> @@ -32,8 +32,6 @@ public: virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); - virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new BacktraceMap(pid); } - private: unw_addr_space_t addr_space_; struct UPT_info* upt_info_; diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index 0ff7897..23eaf92 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp @@ -247,7 +247,7 @@ TEST(libbacktrace, local_max_trace) { ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, NULL), 0); } -void VerifyProcTest(pid_t pid, pid_t tid, +void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, bool (*ReadyFunc)(Backtrace*), void (*VerifyFunc)(Backtrace*)) { pid_t ptrace_tid; @@ -264,7 +264,11 @@ void VerifyProcTest(pid_t pid, pid_t tid, // Wait for the process to get to a stopping point. WaitForStop(ptrace_tid); - UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid)); + UniquePtr<BacktraceMap> map; + if (share_map) { + map.reset(BacktraceMap::Create(pid)); + } + UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get())); ASSERT_TRUE(backtrace->Unwind(0)); ASSERT_TRUE(backtrace.get() != NULL); if (ReadyFunc(backtrace.get())) { @@ -285,7 +289,21 @@ TEST(libbacktrace, ptrace_trace) { ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); exit(1); } - VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump); + VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyLevelDump); + + kill(pid, SIGKILL); + int status; + ASSERT_EQ(waitpid(pid, &status, 0), pid); +} + +TEST(libbacktrace, ptrace_trace_shared_map) { + pid_t pid; + if ((pid = fork()) == 0) { + ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); + exit(1); + } + + VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, true, ReadyLevelBacktrace, VerifyLevelDump); kill(pid, SIGKILL); int status; @@ -298,7 +316,7 @@ TEST(libbacktrace, ptrace_max_trace) { ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0); exit(1); } - VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump); + VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyMaxBacktrace, VerifyMaxDump); kill(pid, SIGKILL); int status; @@ -323,7 +341,7 @@ TEST(libbacktrace, ptrace_ignore_frames) { ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); exit(1); } - VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames); + VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyProcessIgnoreFrames); kill(pid, SIGKILL); int status; @@ -387,7 +405,7 @@ TEST(libbacktrace, ptrace_threads) { if (pid == *it) { continue; } - VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump); + VerifyProcTest(pid, *it, false, ReadyLevelBacktrace, VerifyLevelDump); } ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); @@ -586,6 +604,29 @@ TEST(libbacktrace, thread_multiple_dump) { } } +// This test is for UnwindMaps that should share the same map cursor when +// multiple maps are created for the current process at the same time. +TEST(libbacktrace, simultaneous_maps) { + BacktraceMap* map1 = BacktraceMap::Create(getpid()); + BacktraceMap* map2 = BacktraceMap::Create(getpid()); + BacktraceMap* map3 = BacktraceMap::Create(getpid()); + + Backtrace* back1 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map1); + EXPECT_TRUE(back1->Unwind(0)); + delete back1; + delete map1; + + Backtrace* back2 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map2); + EXPECT_TRUE(back2->Unwind(0)); + delete back2; + delete map2; + + Backtrace* back3 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map3); + EXPECT_TRUE(back3->Unwind(0)); + delete back3; + delete map3; +} + TEST(libbacktrace, format_test) { UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD)); ASSERT_TRUE(backtrace.get() != NULL); |