* commit '36a4e4085e55048ee2a78c7d5b50f7395e547fa2': Re-enable libunwind for arm.
This commit is contained in:
commit
96a0bf1e94
18 changed files with 300 additions and 122 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 := \
|
||||
|
|
|
@ -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.
|
||||
//-------------------------------------------------------------------------
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
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-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 {
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue