am 36a4e408: am aaf89887: am 6fe31b2f: am d391c9b4: Merge "Re-enable libunwind for arm."

* commit '36a4e4085e55048ee2a78c7d5b50f7395e547fa2':
  Re-enable libunwind for arm.
This commit is contained in:
Christopher Ferris 2014-01-29 12:19:59 +00:00 committed by Android Git Automerger
commit 96a0bf1e94
18 changed files with 300 additions and 122 deletions

View file

@ -619,12 +619,9 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a
dump_fault_addr(log, tid, signal);
}
BacktraceMap* map = NULL;
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid));
UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
if (backtrace->Unwind(0)) {
// Grab the map that was created and share it with the siblings.
map = backtrace->TakeMapOwnership();
dump_abort_message(backtrace.get(), log, abort_msg_address);
dump_thread(backtrace.get(), log, SCOPE_AT_FAULT, total_sleep_time_usec);
}
@ -635,12 +632,9 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a
bool detach_failed = false;
if (dump_sibling_threads) {
detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec, map);
detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec, map.get());
}
// Destroy the BacktraceMap object.
delete map;
if (want_logs) {
dump_logs(log, pid, 0);
}

View file

@ -64,10 +64,6 @@ public:
// Find the map associated with the given pc.
virtual const backtrace_map_t* FindMap(uintptr_t pc);
// Take ownership of the BacktraceMap object associated with the backtrace.
// If this is called, the caller must handle deleting the object themselves.
virtual BacktraceMap* TakeMapOwnership();
// Read the data at a specific address.
virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;

View file

@ -28,8 +28,8 @@
#include <sys/mman.h>
#endif
#include <deque>
#include <string>
#include <vector>
struct backtrace_map_t {
uintptr_t start;
@ -40,7 +40,8 @@ struct backtrace_map_t {
class BacktraceMap {
public:
BacktraceMap(pid_t pid);
static BacktraceMap* Create(pid_t pid);
virtual ~BacktraceMap();
// Get the map data structure for the given address.
@ -60,20 +61,22 @@ public:
bool IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }
typedef std::vector<backtrace_map_t>::iterator iterator;
typedef std::deque<backtrace_map_t>::iterator iterator;
iterator begin() { return maps_.begin(); }
iterator end() { return maps_.end(); }
typedef std::vector<backtrace_map_t>::const_iterator const_iterator;
typedef std::deque<backtrace_map_t>::const_iterator const_iterator;
const_iterator begin() const { return maps_.begin(); }
const_iterator end() const { return maps_.end(); }
virtual bool Build();
protected:
BacktraceMap(pid_t pid);
virtual bool ParseLine(const char* line, backtrace_map_t* map);
std::vector<backtrace_map_t> maps_;
std::deque<backtrace_map_t> maps_;
pid_t pid_;
};

View file

@ -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 := \

View file

@ -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.
//-------------------------------------------------------------------------

View file

@ -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

View file

@ -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

View file

@ -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) {

View file

@ -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;
};

View file

@ -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;
}

View file

@ -26,26 +26,9 @@
#include <corkscrew/backtrace.h>
#include "Backtrace.h"
#include "BacktraceImpl.h"
#include "BacktraceThread.h"
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 {
public:
CorkscrewCurrent();
virtual ~CorkscrewCurrent();
virtual bool Unwind(size_t num_ignore_threads);
virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
};
class CorkscrewMap : public BacktraceMap {
public:
CorkscrewMap(pid_t pid);
@ -59,17 +42,28 @@ private:
map_info_t* map_info_;
};
class CorkscrewCommon : public BacktraceImpl {
public:
bool GenerateFrameData(backtrace_frame_t* cork_frames, ssize_t num_frames);
};
class CorkscrewCurrent : public CorkscrewCommon {
public:
CorkscrewCurrent();
virtual ~CorkscrewCurrent();
virtual bool Unwind(size_t num_ignore_threads);
virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
};
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 {

View file

@ -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);

View file

@ -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);
};

110
libbacktrace/UnwindMap.cpp Normal file
View file

@ -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;
}

39
libbacktrace/UnwindMap.h Normal file
View file

@ -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

View file

@ -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 {

View file

@ -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_;

View file

@ -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);