diff options
-rw-r--r-- | include/backtrace/Backtrace.h | 23 | ||||
-rw-r--r-- | libbacktrace/Backtrace.cpp | 23 | ||||
-rw-r--r-- | libbacktrace/Backtrace.h | 4 | ||||
-rw-r--r-- | libbacktrace/BacktraceThread.cpp | 106 | ||||
-rw-r--r-- | libbacktrace/BacktraceThread.h | 19 | ||||
-rw-r--r-- | libbacktrace/Corkscrew.cpp | 4 | ||||
-rw-r--r-- | libbacktrace/UnwindCurrent.cpp | 49 | ||||
-rw-r--r-- | libbacktrace/UnwindPtrace.cpp | 10 |
8 files changed, 117 insertions, 121 deletions
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h index 0b75e834b..b15678c08 100644 --- a/include/backtrace/Backtrace.h +++ b/include/backtrace/Backtrace.h @@ -25,7 +25,16 @@ class BacktraceImpl; class Backtrace { public: - Backtrace(BacktraceImpl* impl); + // Create the correct Backtrace object based on what is to be unwound. + // If pid < 0 or equals the current pid, then the Backtrace object + // corresponds to the current process. + // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace + // object corresponds to a thread in the current process. + // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a + // different process. + // Tracing a thread in a different process is not supported. + static Backtrace* Create(pid_t pid, pid_t tid); + virtual ~Backtrace(); // Get the current stack trace and store in the backtrace_ structure. @@ -60,17 +69,9 @@ public: return &backtrace_.frames[frame_num]; } - // Create the correct Backtrace object based on what is to be unwound. - // If pid < 0 or equals the current pid, then the Backtrace object - // corresponds to the current process. - // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace - // object corresponds to a thread in the current process. - // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a - // different process. - // Tracing a thread in a different process is not supported. - static Backtrace* Create(pid_t pid, pid_t tid); - protected: + Backtrace(BacktraceImpl* impl); + virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value); BacktraceImpl* impl_; diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp index eca1c3d77..17d9e1d90 100644 --- a/libbacktrace/Backtrace.cpp +++ b/libbacktrace/Backtrace.cpp @@ -72,10 +72,8 @@ bool Backtrace::Unwind(size_t num_ignore_frames) { return impl_->Unwind(num_ignore_frames); } -__BEGIN_DECLS -extern char* __cxa_demangle (const char* mangled, char* buf, size_t* len, - int* status); -__END_DECLS +extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len, + int* status); std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) { std::string func_name = impl_->GetFunctionNameRaw(pc, offset); @@ -97,7 +95,7 @@ std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) { bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) { if (ptr & 3) { - ALOGW("Backtrace::verifyReadWordArgs: invalid pointer %p", (void*)ptr); + BACK_LOGW("invalid pointer %p", (void*)ptr); *out_value = (uint32_t)-1; return false; } @@ -172,7 +170,7 @@ bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) { *out_value = *reinterpret_cast<uint32_t*>(ptr); return true; } else { - ALOGW("BacktraceCurrent::readWord: pointer %p not in a readbale map", reinterpret_cast<void*>(ptr)); + BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr)); *out_value = static_cast<uint32_t>(-1); return false; } @@ -198,7 +196,7 @@ bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) { } #if defined(__APPLE__) - ALOGW("BacktracePtrace::readWord: MacOS does not support reading from another pid.\n"); + BACK_LOGW("MacOS does not support reading from another pid."); return false; #else // ptrace() returns -1 and sets errno when the operation fails. @@ -206,8 +204,8 @@ bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) { errno = 0; *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL); if (*out_value == static_cast<uint32_t>(-1) && errno) { - ALOGW("BacktracePtrace::readWord: invalid pointer 0x%08x reading from tid %d, " - "ptrace() errno=%d", ptr, Tid(), errno); + BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s", + reinterpret_cast<void*>(ptr), Tid(), strerror(errno)); return false; } return true; @@ -295,11 +293,8 @@ void backtrace_format_frame_data( const backtrace_context_t* context, size_t frame_num, char* buf, size_t buf_size) { if (buf_size == 0 || buf == NULL) { - ALOGW("backtrace_format_frame_data: bad call buf %p buf_size %zu\n", - buf, buf_size); - return; - } - if (context->data) { + BACK_LOGW("bad call buf %p buf_size %zu", buf, buf_size); + } else if (context->data) { Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); std::string line = backtrace->FormatFrameData(frame_num); if (line.size() > buf_size) { diff --git a/libbacktrace/Backtrace.h b/libbacktrace/Backtrace.h index b89bc8939..00f0a10ed 100644 --- a/libbacktrace/Backtrace.h +++ b/libbacktrace/Backtrace.h @@ -21,6 +21,10 @@ #include <sys/types.h> +// Macro to log the function name along with the warning message. +#define BACK_LOGW(format, ...) \ + ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__) + class BacktraceImpl { public: virtual ~BacktraceImpl() { } diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp index 6c3641ecd..8e664c44e 100644 --- a/libbacktrace/BacktraceThread.cpp +++ b/libbacktrace/BacktraceThread.cpp @@ -31,55 +31,55 @@ // ThreadEntry implementation. //------------------------------------------------------------------------- static ThreadEntry* g_list = NULL; -static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER; ThreadEntry::ThreadEntry( BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) - : thread_intf_(intf), pid_(pid), tid_(tid), next_(NULL), prev_(NULL), - state_(STATE_WAITING), num_ignore_frames_(num_ignore_frames) { + : thread_intf(intf), pid(pid), tid(tid), next(NULL), prev(NULL), + state(STATE_WAITING), num_ignore_frames(num_ignore_frames) { } ThreadEntry::~ThreadEntry() { - pthread_mutex_lock(&g_mutex); + pthread_mutex_lock(&g_entry_mutex); if (g_list == this) { - g_list = next_; + g_list = next; } else { - if (next_) { - next_->prev_ = prev_; + if (next) { + next->prev = prev; } - prev_->next_ = next_; + prev->next = next; } - pthread_mutex_unlock(&g_mutex); + pthread_mutex_unlock(&g_entry_mutex); - next_ = NULL; - prev_ = NULL; + next = NULL; + prev = NULL; } ThreadEntry* ThreadEntry::AddThreadToUnwind( BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) { ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames); - pthread_mutex_lock(&g_mutex); + pthread_mutex_lock(&g_entry_mutex); ThreadEntry* cur_entry = g_list; while (cur_entry != NULL) { if (cur_entry->Match(pid, tid)) { // There is already an entry for this pid/tid, this is bad. - ALOGW("%s::%s(): Entry for pid %d tid %d already exists.\n", - __FILE__, __FUNCTION__, pid, tid); + BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid); - pthread_mutex_unlock(&g_mutex); + pthread_mutex_unlock(&g_entry_mutex); return NULL; } - cur_entry = cur_entry->next_; + cur_entry = cur_entry->next; } // Add the entry to the list. - entry->next_ = g_list; + entry->next = g_list; if (g_list) { - g_list->prev_ = entry; + g_list->prev = entry; } g_list = entry; - pthread_mutex_unlock(&g_mutex); + pthread_mutex_unlock(&g_entry_mutex); return entry; } @@ -89,7 +89,7 @@ ThreadEntry* ThreadEntry::AddThreadToUnwind( //------------------------------------------------------------------------- static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo, void* sigcontext) { - if (pthread_mutex_lock(&g_mutex) == 0) { + if (pthread_mutex_lock(&g_entry_mutex) == 0) { pid_t pid = getpid(); pid_t tid = gettid(); ThreadEntry* cur_entry = g_list; @@ -97,20 +97,19 @@ static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo, if (cur_entry->Match(pid, tid)) { break; } - cur_entry = cur_entry->next_; + cur_entry = cur_entry->next; } - pthread_mutex_unlock(&g_mutex); + pthread_mutex_unlock(&g_entry_mutex); if (!cur_entry) { - ALOGW("%s::%s(): Unable to find pid %d tid %d information\n", - __FILE__, __FUNCTION__, pid, tid); + BACK_LOGW("Unable to find pid %d tid %d information", pid, tid); return; } - if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state_) == 0) { - cur_entry->thread_intf_->ThreadUnwind(siginfo, sigcontext, - cur_entry->num_ignore_frames_); + if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state) == 0) { + cur_entry->thread_intf->ThreadUnwind(siginfo, sigcontext, + cur_entry->num_ignore_frames); } - android_atomic_release_store(STATE_DONE, &cur_entry->state_); + android_atomic_release_store(STATE_DONE, &cur_entry->state); } } @@ -143,18 +142,18 @@ void BacktraceThread::FinishUnwind() { } bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) { - entry->state_ = STATE_WAITING; + entry->state = STATE_WAITING; if (tgkill(Pid(), Tid(), SIGURG) != 0) { - ALOGW("%s::%s(): tgkill failed %s\n", __FILE__, __FUNCTION__, strerror(errno)); + BACK_LOGW("tgkill failed %s", strerror(errno)); return false; } - // Allow up to a second for the dump to occur. - int wait_millis = 1000; + // Allow up to ten seconds for the dump to start. + int wait_millis = 10000; int32_t state; while (true) { - state = android_atomic_acquire_load(&entry->state_); + state = android_atomic_acquire_load(&entry->state); if (state != STATE_WAITING) { break; } @@ -167,24 +166,22 @@ bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) { bool cancelled = false; if (state == STATE_WAITING) { - if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state_) == 0) { - ALOGW("%s::%s(): Cancelled dump of thread %d\n", __FILE__, __FUNCTION__, - entry->tid_); + if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) { + BACK_LOGW("Cancelled dump of thread %d", entry->tid); state = STATE_CANCEL; cancelled = true; } else { - state = android_atomic_acquire_load(&entry->state_); + state = android_atomic_acquire_load(&entry->state); } } - // Wait for at most one minute for the dump to finish. - wait_millis = 60000; - while (android_atomic_acquire_load(&entry->state_) != STATE_DONE) { + // Wait for at most ten seconds for the cancel or dump to finish. + wait_millis = 10000; + while (android_atomic_acquire_load(&entry->state) != STATE_DONE) { if (wait_millis--) { usleep(1000); } else { - ALOGW("%s::%s(): Didn't finish thread unwind in 60 seconds.\n", - __FILE__, __FUNCTION__); + BACK_LOGW("Didn't finish thread unwind in 60 seconds."); break; } } @@ -202,17 +199,24 @@ bool BacktraceThread::Unwind(size_t num_ignore_frames) { return false; } + // Prevent multiple threads trying to set the trigger action on different + // threads at the same time. bool retval = false; - struct sigaction act, oldact; - memset(&act, 0, sizeof(act)); - act.sa_sigaction = SignalHandler; - act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; - sigemptyset(&act.sa_mask); - if (sigaction(SIGURG, &act, &oldact) == 0) { - retval = TriggerUnwindOnThread(entry); - sigaction(SIGURG, &oldact, NULL); + if (pthread_mutex_lock(&g_sigaction_mutex) == 0) { + struct sigaction act, oldact; + memset(&act, 0, sizeof(act)); + act.sa_sigaction = SignalHandler; + act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; + sigemptyset(&act.sa_mask); + if (sigaction(SIGURG, &act, &oldact) == 0) { + retval = TriggerUnwindOnThread(entry); + sigaction(SIGURG, &oldact, NULL); + } else { + BACK_LOGW("sigaction failed %s", strerror(errno)); + } + pthread_mutex_unlock(&g_sigaction_mutex); } else { - ALOGW("%s::%s(): sigaction failed %s\n", __FILE__, __FUNCTION__, strerror(errno)); + BACK_LOGW("unable to acquire sigaction mutex."); } if (retval) { diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h index afea771a3..8ed112265 100644 --- a/libbacktrace/BacktraceThread.h +++ b/libbacktrace/BacktraceThread.h @@ -32,26 +32,25 @@ typedef enum { class BacktraceThreadInterface; -class ThreadEntry { -public: +struct ThreadEntry { ThreadEntry( BacktraceThreadInterface* impl, pid_t pid, pid_t tid, size_t num_ignore_frames); ~ThreadEntry(); - bool Match(pid_t pid, pid_t tid) { return (pid == pid_ && tid == tid_); } + bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid && chk_tid == tid); } static ThreadEntry* AddThreadToUnwind( BacktraceThreadInterface* thread_intf, pid_t pid, pid_t tid, size_t num_ignored_frames); - BacktraceThreadInterface* thread_intf_; - pid_t pid_; - pid_t tid_; - ThreadEntry* next_; - ThreadEntry* prev_; - int32_t state_; - int num_ignore_frames_; + BacktraceThreadInterface* thread_intf; + pid_t pid; + pid_t tid; + ThreadEntry* next; + ThreadEntry* prev; + int32_t state; + int num_ignore_frames; }; // Interface class that does not contain any local storage, only defines diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp index 8ba1e8097..9daa75221 100644 --- a/libbacktrace/Corkscrew.cpp +++ b/libbacktrace/Corkscrew.cpp @@ -37,7 +37,7 @@ bool CorkscrewCommon::GenerateFrameData( backtrace_frame_t* cork_frames, ssize_t num_frames) { if (num_frames < 0) { - ALOGW("CorkscrewCommon::GenerateFrameData: libcorkscrew unwind failed.\n"); + BACK_LOGW("libcorkscrew unwind failed."); return false; } @@ -184,7 +184,7 @@ std::string CorkscrewPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) } //------------------------------------------------------------------------- -// C++ object createion functions. +// C++ object creation functions. //------------------------------------------------------------------------- Backtrace* CreateCurrentObj() { return new BacktraceCurrent(new CorkscrewCurrent()); diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp index 0280e9315..d4ba68f18 100644 --- a/libbacktrace/UnwindCurrent.cpp +++ b/libbacktrace/UnwindCurrent.cpp @@ -27,9 +27,9 @@ #include "UnwindCurrent.h" +// Define the ucontext_t structures needed for each supported arch. #if defined(__arm__) - #if !defined(__BIONIC_HAVE_UCONTEXT_T) - // The Current version of the Android <signal.h> doesn't define ucontext_t. + // The current version of the <signal.h> doesn't define ucontext_t. #include <asm/sigcontext.h> // Ensure 'struct sigcontext' is defined. // Machine context at the time a signal was raised. @@ -40,8 +40,19 @@ struct sigcontext uc_mcontext; uint32_t uc_sigmask; } ucontext_t; - #endif // !__BIONIC_HAVE_UCONTEXT_T -#endif // defined(__arm__) +#elif defined(__mips__) + typedef struct ucontext { + uint32_t sp; + uint32_t ra; + uint32_t pc; + } ucontext_t; +#elif defined(__i386__) + #include <asm/sigcontext.h> + #include <asm/ucontext.h> + typedef struct ucontext ucontext_t; +#else + #error Unsupported architecture. +#endif //------------------------------------------------------------------------- // UnwindCurrent functions. @@ -55,7 +66,7 @@ UnwindCurrent::~UnwindCurrent() { bool UnwindCurrent::Unwind(size_t num_ignore_frames) { int ret = unw_getcontext(&context_); if (ret < 0) { - ALOGW("UnwindCurrent::Unwind: unw_getcontext failed %d\n", ret); + BACK_LOGW("unw_getcontext failed %d", ret); return false; } return UnwindFromContext(num_ignore_frames, true); @@ -81,7 +92,7 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) { unw_cursor_t* cursor = new unw_cursor_t; int ret = unw_init_local(cursor, &context_); if (ret < 0) { - ALOGW("UnwindCurrent::UnwindWithContext: unw_init_local failed %d\n", ret); + BACK_LOGW("unw_init_local failed %d", ret); return false; } @@ -89,13 +100,13 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) { unw_word_t pc; ret = unw_get_reg(cursor, UNW_REG_IP, &pc); if (ret < 0) { - ALOGW("UnwindCurrent::UnwindWithContext: Failed to read IP %d\n", ret); + BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(cursor, UNW_REG_SP, &sp); if (ret < 0) { - ALOGW("UnwindCurrent::UnwindWithContext: Failed to read SP %d\n", ret); + BACK_LOGW("Failed to read SP %d", ret); break; } @@ -142,10 +153,9 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) { void UnwindCurrent::ExtractContext(void* sigcontext) { unw_tdep_context_t* context = reinterpret_cast<unw_tdep_context_t*>(&context_); - -#if defined(__arm__) const ucontext_t* uc = reinterpret_cast<const ucontext_t*>(sigcontext); +#if defined(__arm__) context->regs[0] = uc->uc_mcontext.arm_r0; context->regs[1] = uc->uc_mcontext.arm_r1; context->regs[2] = uc->uc_mcontext.arm_r2; @@ -162,28 +172,11 @@ void UnwindCurrent::ExtractContext(void* sigcontext) { context->regs[13] = uc->uc_mcontext.arm_sp; context->regs[14] = uc->uc_mcontext.arm_lr; context->regs[15] = uc->uc_mcontext.arm_pc; - #elif defined(__mips__) - - typedef struct ucontext { - uint32_t sp; - uint32_t ra; - uint32_t pc; - } ucontext_t; - - const ucontext_t* uc = (const ucontext_t*)sigcontext; - context->uc_mcontext.sp = uc->sp; context->uc_mcontext.pc = uc->pc; context->uc_mcontext.ra = uc->ra; -#elif defined(__x86__) - - #include <asm/sigcontext.h> - #include <asm/ucontext.h> - typedef struct ucontext ucontext_t; - - const ucontext_t* uc = (const ucontext_t*)sigcontext; - +#elif defined(__i386__) context->uc_mcontext.gregs[REG_EBP] = uc->uc_mcontext.gregs[REG_EBP]; context->uc_mcontext.gregs[REG_ESP] = uc->uc_mcontext.gregs[REG_ESP]; context->uc_mcontext.gregs[REG_EIP] = uc->uc_mcontext.gregs[REG_EIP]; diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp index 628caa04b..a734a2483 100644 --- a/libbacktrace/UnwindPtrace.cpp +++ b/libbacktrace/UnwindPtrace.cpp @@ -45,13 +45,13 @@ UnwindPtrace::~UnwindPtrace() { bool UnwindPtrace::Unwind(size_t num_ignore_frames) { addr_space_ = unw_create_addr_space(&_UPT_accessors, 0); if (!addr_space_) { - ALOGW("UnwindPtrace::Unwind: unw_create_addr_space failed.\n"); + BACK_LOGW("unw_create_addr_space failed."); return false; } upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(backtrace_obj_->Tid())); if (!upt_info_) { - ALOGW("UnwindPtrace::Unwind: Failed to create upt info.\n"); + BACK_LOGW("Failed to create upt info."); return false; } @@ -61,7 +61,7 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames) { unw_cursor_t cursor; int ret = unw_init_remote(&cursor, addr_space_, upt_info_); if (ret < 0) { - ALOGW("UnwindPtrace::Unwind: unw_init_remote failed %d\n", ret); + BACK_LOGW("unw_init_remote failed %d", ret); return false; } @@ -69,13 +69,13 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames) { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { - ALOGW("UnwindPtrace::Unwind: Failed to read IP %d\n", ret); + BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); if (ret < 0) { - ALOGW("UnwindPtrace::Unwind: Failed to read SP %d\n", ret); + BACK_LOGW("Failed to read SP %d", ret); break; } |