* commit '6fe31b2f830309c2a8e0035c07b6b2bb44e081c9': Re-enable libunwind for arm.
This commit is contained in:
commit
aaf898877c
18 changed files with 300 additions and 122 deletions
|
|
@ -625,12 +625,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);
|
dump_fault_addr(log, tid, signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
BacktraceMap* map = NULL;
|
UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
|
||||||
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid));
|
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
|
||||||
if (backtrace->Unwind(0)) {
|
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_abort_message(backtrace.get(), log, abort_msg_address);
|
||||||
dump_thread(backtrace.get(), log, SCOPE_AT_FAULT, total_sleep_time_usec);
|
dump_thread(backtrace.get(), log, SCOPE_AT_FAULT, total_sleep_time_usec);
|
||||||
}
|
}
|
||||||
|
|
@ -641,12 +638,9 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a
|
||||||
|
|
||||||
bool detach_failed = false;
|
bool detach_failed = false;
|
||||||
if (dump_sibling_threads) {
|
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) {
|
if (want_logs) {
|
||||||
dump_logs(log, pid, 0);
|
dump_logs(log, pid, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,6 @@ public:
|
||||||
// Find the map associated with the given pc.
|
// Find the map associated with the given pc.
|
||||||
virtual const backtrace_map_t* FindMap(uintptr_t 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.
|
// Read the data at a specific address.
|
||||||
virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;
|
virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
struct backtrace_map_t {
|
struct backtrace_map_t {
|
||||||
uintptr_t start;
|
uintptr_t start;
|
||||||
|
|
@ -40,7 +40,8 @@ struct backtrace_map_t {
|
||||||
|
|
||||||
class BacktraceMap {
|
class BacktraceMap {
|
||||||
public:
|
public:
|
||||||
BacktraceMap(pid_t pid);
|
static BacktraceMap* Create(pid_t pid);
|
||||||
|
|
||||||
virtual ~BacktraceMap();
|
virtual ~BacktraceMap();
|
||||||
|
|
||||||
// Get the map data structure for the given address.
|
// 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 IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
|
||||||
bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }
|
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 begin() { return maps_.begin(); }
|
||||||
iterator end() { return maps_.end(); }
|
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 begin() const { return maps_.begin(); }
|
||||||
const_iterator end() const { return maps_.end(); }
|
const_iterator end() const { return maps_.end(); }
|
||||||
|
|
||||||
virtual bool Build();
|
virtual bool Build();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
BacktraceMap(pid_t pid);
|
||||||
|
|
||||||
virtual bool ParseLine(const char* line, backtrace_map_t* map);
|
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_;
|
pid_t pid_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
LOCAL_PATH:= $(call my-dir)
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
|
||||||
common_src := \
|
common_src := \
|
||||||
Backtrace.cpp \
|
BacktraceImpl.cpp \
|
||||||
BacktraceMap.cpp \
|
BacktraceMap.cpp \
|
||||||
BacktraceThread.cpp \
|
BacktraceThread.cpp \
|
||||||
thread_utils.c \
|
thread_utils.c \
|
||||||
|
|
@ -23,7 +23,7 @@ common_shared_libs := \
|
||||||
liblog \
|
liblog \
|
||||||
|
|
||||||
# To enable using libunwind on each arch, add it to this list.
|
# 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)))
|
ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),$(libunwind_architectures)))
|
||||||
|
|
||||||
|
|
@ -35,6 +35,7 @@ include $(CLEAR_VARS)
|
||||||
LOCAL_SRC_FILES:= \
|
LOCAL_SRC_FILES:= \
|
||||||
$(common_src) \
|
$(common_src) \
|
||||||
UnwindCurrent.cpp \
|
UnwindCurrent.cpp \
|
||||||
|
UnwindMap.cpp \
|
||||||
UnwindPtrace.cpp \
|
UnwindPtrace.cpp \
|
||||||
|
|
||||||
LOCAL_CFLAGS := \
|
LOCAL_CFLAGS := \
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
#include <backtrace/Backtrace.h>
|
#include <backtrace/Backtrace.h>
|
||||||
#include <backtrace/BacktraceMap.h>
|
#include <backtrace/BacktraceMap.h>
|
||||||
|
|
||||||
#include "Backtrace.h"
|
#include "BacktraceImpl.h"
|
||||||
#include "thread_utils.h"
|
#include "thread_utils.h"
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
@ -40,21 +40,21 @@ Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map)
|
||||||
impl_->SetParent(this);
|
impl_->SetParent(this);
|
||||||
|
|
||||||
if (map_ == NULL) {
|
if (map_ == NULL) {
|
||||||
// The map will be created when needed.
|
map_ = BacktraceMap::Create(pid);
|
||||||
map_shared_ = false;
|
map_shared_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Backtrace::~Backtrace() {
|
Backtrace::~Backtrace() {
|
||||||
if (map_ && !map_shared_) {
|
|
||||||
delete map_;
|
|
||||||
map_ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (impl_) {
|
if (impl_) {
|
||||||
delete impl_;
|
delete impl_;
|
||||||
impl_ = NULL;
|
impl_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (map_ && !map_shared_) {
|
||||||
|
delete map_;
|
||||||
|
map_ = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Backtrace::Unwind(size_t num_ignore_frames) {
|
bool Backtrace::Unwind(size_t num_ignore_frames) {
|
||||||
|
|
@ -129,30 +129,10 @@ std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
|
||||||
return buf;
|
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) {
|
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);
|
return map_->Find(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
BacktraceMap* Backtrace::TakeMapOwnership() {
|
|
||||||
map_shared_ = true;
|
|
||||||
return map_;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// BacktraceCurrent functions.
|
// BacktraceCurrent functions.
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LIBBACKTRACE_BACKTRACE_H
|
#ifndef _LIBBACKTRACE_BACKTRACE_IMPL_H
|
||||||
#define _LIBBACKTRACE_BACKTRACE_H
|
#define _LIBBACKTRACE_BACKTRACE_IMPL_H
|
||||||
|
|
||||||
#include <backtrace/Backtrace.h>
|
#include <backtrace/Backtrace.h>
|
||||||
#include <backtrace/BacktraceMap.h>
|
#include <backtrace/BacktraceMap.h>
|
||||||
|
|
@ -39,13 +39,20 @@ public:
|
||||||
|
|
||||||
void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; }
|
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:
|
protected:
|
||||||
inline std::vector<backtrace_frame_data_t>* GetFrames() { return &backtrace_obj_->frames_; }
|
inline std::vector<backtrace_frame_data_t>* GetFrames() { return &backtrace_obj_->frames_; }
|
||||||
|
|
||||||
inline bool BuildMap() { return backtrace_obj_->BuildMap(); }
|
|
||||||
|
|
||||||
Backtrace* backtrace_obj_;
|
Backtrace* backtrace_obj_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -69,4 +76,4 @@ Backtrace* CreateCurrentObj(BacktraceMap* map);
|
||||||
Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map);
|
Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map);
|
||||||
Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map);
|
Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map);
|
||||||
|
|
||||||
#endif // _LIBBACKTRACE_BACKTRACE_H
|
#endif // _LIBBACKTRACE_BACKTRACE_IMPL_H
|
||||||
|
|
@ -21,9 +21,13 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <backtrace/backtrace_constants.h>
|
||||||
#include <backtrace/BacktraceMap.h>
|
#include <backtrace/BacktraceMap.h>
|
||||||
#include <log/log.h>
|
#include <log/log.h>
|
||||||
|
|
||||||
|
#include "thread_utils.h"
|
||||||
|
#include "BacktraceImpl.h"
|
||||||
|
|
||||||
BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) {
|
BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) {
|
||||||
if (pid_ < 0) {
|
if (pid_ < 0) {
|
||||||
pid_ = getpid();
|
pid_ = getpid();
|
||||||
|
|
@ -128,3 +132,16 @@ bool BacktraceMap::Build() {
|
||||||
|
|
||||||
return true;
|
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
|
||||||
|
|
|
||||||
|
|
@ -180,10 +180,6 @@ bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BacktraceThread::Unwind(size_t num_ignore_frames) {
|
bool BacktraceThread::Unwind(size_t num_ignore_frames) {
|
||||||
if (!thread_intf_->Init()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
|
ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
|
||||||
thread_intf_, Pid(), Tid(), num_ignore_frames);
|
thread_intf_, Pid(), Tid(), num_ignore_frames);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "Backtrace.h"
|
#include "BacktraceImpl.h"
|
||||||
|
|
||||||
enum state_e {
|
enum state_e {
|
||||||
STATE_WAITING = 0,
|
STATE_WAITING = 0,
|
||||||
|
|
@ -58,8 +58,6 @@ class BacktraceThreadInterface {
|
||||||
public:
|
public:
|
||||||
virtual ~BacktraceThreadInterface() { }
|
virtual ~BacktraceThreadInterface() { }
|
||||||
|
|
||||||
virtual bool Init() = 0;
|
|
||||||
|
|
||||||
virtual void ThreadUnwind(
|
virtual void ThreadUnwind(
|
||||||
siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) = 0;
|
siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) = 0;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,8 @@ bool CorkscrewMap::Build() {
|
||||||
}
|
}
|
||||||
map.name = cur_map->name;
|
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;
|
cur_map = cur_map->next;
|
||||||
}
|
}
|
||||||
|
|
@ -93,8 +94,8 @@ bool CorkscrewCommon::GenerateFrameData(
|
||||||
it->stack_size = cork_frames[i].stack_size;
|
it->stack_size = cork_frames[i].stack_size;
|
||||||
it->func_offset = 0;
|
it->func_offset = 0;
|
||||||
|
|
||||||
it->map = backtrace_obj_->FindMap(it->pc);
|
it->map = FindMap(it->pc);
|
||||||
it->func_name = backtrace_obj_->GetFunctionName(it->pc, &it->func_offset);
|
it->func_name = GetFunctionName(it->pc, &it->func_offset);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +120,7 @@ std::string CorkscrewCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset
|
||||||
*offset = 0;
|
*offset = 0;
|
||||||
|
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
const backtrace_map_t* map = backtrace_obj_->FindMap(pc);
|
const backtrace_map_t* map = FindMap(pc);
|
||||||
if (map) {
|
if (map) {
|
||||||
if (dladdr((const void*)pc, &info)) {
|
if (dladdr((const void*)pc, &info)) {
|
||||||
if (info.dli_sname) {
|
if (info.dli_sname) {
|
||||||
|
|
@ -158,19 +159,10 @@ CorkscrewThread::CorkscrewThread() {
|
||||||
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(
|
void CorkscrewThread::ThreadUnwind(
|
||||||
siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
|
siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
|
||||||
backtrace_frame_t cork_frames[MAX_BACKTRACE_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(
|
ssize_t num_frames = unwind_backtrace_signal_arch(
|
||||||
siginfo, sigcontext, map->GetMapInfo(), cork_frames,
|
siginfo, sigcontext, map->GetMapInfo(), cork_frames,
|
||||||
num_ignore_frames, MAX_BACKTRACE_FRAMES);
|
num_ignore_frames, MAX_BACKTRACE_FRAMES);
|
||||||
|
|
@ -204,12 +196,11 @@ CorkscrewPtrace::~CorkscrewPtrace() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CorkscrewPtrace::Unwind(size_t num_ignore_frames) {
|
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];
|
backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
|
||||||
ssize_t num_frames = unwind_backtrace_ptrace(
|
ssize_t num_frames = unwind_backtrace_ptrace(
|
||||||
backtrace_obj_->Tid(), ptrace_context_, frames, num_ignore_frames,
|
Tid(), ptrace_context_, frames, num_ignore_frames, MAX_BACKTRACE_FRAMES);
|
||||||
MAX_BACKTRACE_FRAMES);
|
|
||||||
|
|
||||||
return GenerateFrameData(frames, num_frames);
|
return GenerateFrameData(frames, num_frames);
|
||||||
}
|
}
|
||||||
|
|
@ -246,3 +237,15 @@ Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
|
||||||
CorkscrewThread* thread_obj = new CorkscrewThread();
|
CorkscrewThread* thread_obj = new CorkscrewThread();
|
||||||
return new BacktraceThread(thread_obj, thread_obj, tid, map);
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,26 +26,9 @@
|
||||||
|
|
||||||
#include <corkscrew/backtrace.h>
|
#include <corkscrew/backtrace.h>
|
||||||
|
|
||||||
#include "Backtrace.h"
|
#include "BacktraceImpl.h"
|
||||||
#include "BacktraceThread.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 {
|
class CorkscrewMap : public BacktraceMap {
|
||||||
public:
|
public:
|
||||||
CorkscrewMap(pid_t pid);
|
CorkscrewMap(pid_t pid);
|
||||||
|
|
@ -59,17 +42,28 @@ private:
|
||||||
map_info_t* map_info_;
|
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 {
|
class CorkscrewThread : public CorkscrewCurrent, public BacktraceThreadInterface {
|
||||||
public:
|
public:
|
||||||
CorkscrewThread();
|
CorkscrewThread();
|
||||||
virtual ~CorkscrewThread();
|
virtual ~CorkscrewThread();
|
||||||
|
|
||||||
virtual bool Init();
|
|
||||||
|
|
||||||
virtual void ThreadUnwind(
|
virtual void ThreadUnwind(
|
||||||
siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
|
siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
|
||||||
|
|
||||||
virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new CorkscrewMap(pid); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CorkscrewPtrace : public CorkscrewCommon {
|
class CorkscrewPtrace : public CorkscrewCommon {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include <libunwind.h>
|
#include <libunwind.h>
|
||||||
|
|
||||||
#include "UnwindCurrent.h"
|
#include "UnwindCurrent.h"
|
||||||
|
#include "UnwindMap.h"
|
||||||
|
|
||||||
// Define the ucontext_t structures needed for each supported arch.
|
// Define the ucontext_t structures needed for each supported arch.
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
|
|
@ -119,8 +120,8 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolve) {
|
if (resolve) {
|
||||||
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);
|
||||||
} else {
|
} else {
|
||||||
frame->map = NULL;
|
frame->map = NULL;
|
||||||
frame->func_offset = 0;
|
frame->func_offset = 0;
|
||||||
|
|
@ -171,10 +172,6 @@ UnwindThread::UnwindThread() {
|
||||||
UnwindThread::~UnwindThread() {
|
UnwindThread::~UnwindThread() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnwindThread::Init() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnwindThread::ThreadUnwind(
|
void UnwindThread::ThreadUnwind(
|
||||||
siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) {
|
siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) {
|
||||||
ExtractContext(sigcontext);
|
ExtractContext(sigcontext);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Backtrace.h"
|
#include "BacktraceImpl.h"
|
||||||
#include "BacktraceThread.h"
|
#include "BacktraceThread.h"
|
||||||
|
|
||||||
#define UNW_LOCAL_ONLY
|
#define UNW_LOCAL_ONLY
|
||||||
|
|
@ -38,8 +38,6 @@ public:
|
||||||
|
|
||||||
void ExtractContext(void* sigcontext);
|
void ExtractContext(void* sigcontext);
|
||||||
|
|
||||||
virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new BacktraceMap(pid); }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
unw_context_t context_;
|
unw_context_t context_;
|
||||||
};
|
};
|
||||||
|
|
@ -49,8 +47,6 @@ public:
|
||||||
UnwindThread();
|
UnwindThread();
|
||||||
virtual ~UnwindThread();
|
virtual ~UnwindThread();
|
||||||
|
|
||||||
virtual bool Init();
|
|
||||||
|
|
||||||
virtual void ThreadUnwind(
|
virtual void ThreadUnwind(
|
||||||
siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
|
siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
110
libbacktrace/UnwindMap.cpp
Normal file
110
libbacktrace/UnwindMap.cpp
Normal 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
39
libbacktrace/UnwindMap.h
Normal 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
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include <libunwind.h>
|
#include <libunwind.h>
|
||||||
#include <libunwind-ptrace.h>
|
#include <libunwind-ptrace.h>
|
||||||
|
|
||||||
|
#include "UnwindMap.h"
|
||||||
#include "UnwindPtrace.h"
|
#include "UnwindPtrace.h"
|
||||||
|
|
||||||
UnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) {
|
UnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) {
|
||||||
|
|
@ -36,6 +37,10 @@ UnwindPtrace::~UnwindPtrace() {
|
||||||
upt_info_ = NULL;
|
upt_info_ = NULL;
|
||||||
}
|
}
|
||||||
if (addr_space_) {
|
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_);
|
unw_destroy_addr_space(addr_space_);
|
||||||
addr_space_ = NULL;
|
addr_space_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +53,10 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames) {
|
||||||
return false;
|
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_) {
|
if (!upt_info_) {
|
||||||
BACK_LOGW("Failed to create upt info.");
|
BACK_LOGW("Failed to create upt info.");
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -91,9 +99,9 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames) {
|
||||||
prev->stack_size = frame->sp - prev->sp;
|
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++;
|
num_frames++;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Backtrace.h"
|
#include "BacktraceImpl.h"
|
||||||
|
|
||||||
#include <libunwind.h>
|
#include <libunwind.h>
|
||||||
|
|
||||||
|
|
@ -32,8 +32,6 @@ public:
|
||||||
|
|
||||||
virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
|
virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
|
||||||
|
|
||||||
virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new BacktraceMap(pid); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unw_addr_space_t addr_space_;
|
unw_addr_space_t addr_space_;
|
||||||
struct UPT_info* upt_info_;
|
struct UPT_info* upt_info_;
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ TEST(libbacktrace, local_max_trace) {
|
||||||
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, NULL), 0);
|
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*),
|
bool (*ReadyFunc)(Backtrace*),
|
||||||
void (*VerifyFunc)(Backtrace*)) {
|
void (*VerifyFunc)(Backtrace*)) {
|
||||||
pid_t ptrace_tid;
|
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.
|
// Wait for the process to get to a stopping point.
|
||||||
WaitForStop(ptrace_tid);
|
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->Unwind(0));
|
||||||
ASSERT_TRUE(backtrace.get() != NULL);
|
ASSERT_TRUE(backtrace.get() != NULL);
|
||||||
if (ReadyFunc(backtrace.get())) {
|
if (ReadyFunc(backtrace.get())) {
|
||||||
|
|
@ -285,7 +289,21 @@ TEST(libbacktrace, ptrace_trace) {
|
||||||
ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
|
ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
|
||||||
exit(1);
|
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);
|
kill(pid, SIGKILL);
|
||||||
int status;
|
int status;
|
||||||
|
|
@ -298,7 +316,7 @@ TEST(libbacktrace, ptrace_max_trace) {
|
||||||
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0);
|
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump);
|
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyMaxBacktrace, VerifyMaxDump);
|
||||||
|
|
||||||
kill(pid, SIGKILL);
|
kill(pid, SIGKILL);
|
||||||
int status;
|
int status;
|
||||||
|
|
@ -323,7 +341,7 @@ TEST(libbacktrace, ptrace_ignore_frames) {
|
||||||
ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
|
ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
|
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
|
||||||
|
|
||||||
kill(pid, SIGKILL);
|
kill(pid, SIGKILL);
|
||||||
int status;
|
int status;
|
||||||
|
|
@ -387,7 +405,7 @@ TEST(libbacktrace, ptrace_threads) {
|
||||||
if (pid == *it) {
|
if (pid == *it) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump);
|
VerifyProcTest(pid, *it, false, ReadyLevelBacktrace, VerifyLevelDump);
|
||||||
}
|
}
|
||||||
ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
|
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) {
|
TEST(libbacktrace, format_test) {
|
||||||
UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
|
UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
|
||||||
ASSERT_TRUE(backtrace.get() != NULL);
|
ASSERT_TRUE(backtrace.get() != NULL);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue