summaryrefslogtreecommitdiffstats
path: root/libbacktrace
diff options
context:
space:
mode:
Diffstat (limited to 'libbacktrace')
-rw-r--r--libbacktrace/Android.mk5
-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.cpp17
-rw-r--r--libbacktrace/BacktraceThread.cpp4
-rw-r--r--libbacktrace/BacktraceThread.h4
-rw-r--r--libbacktrace/Corkscrew.cpp37
-rw-r--r--libbacktrace/Corkscrew.h34
-rw-r--r--libbacktrace/UnwindCurrent.cpp9
-rw-r--r--libbacktrace/UnwindCurrent.h6
-rw-r--r--libbacktrace/UnwindMap.cpp110
-rw-r--r--libbacktrace/UnwindMap.h39
-rw-r--r--libbacktrace/UnwindPtrace.cpp14
-rw-r--r--libbacktrace/UnwindPtrace.h4
-rw-r--r--libbacktrace/backtrace_test.cpp53
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);