BacktraceThread.cpp revision e48460762273586744a79d146c2916bcfca7e9e4
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <errno.h> 18#include <inttypes.h> 19#include <limits.h> 20#include <linux/futex.h> 21#include <pthread.h> 22#include <signal.h> 23#include <string.h> 24#include <sys/syscall.h> 25#include <sys/time.h> 26#include <sys/types.h> 27#include <ucontext.h> 28 29#include <cutils/atomic.h> 30 31#include "BacktraceLog.h" 32#include "BacktraceThread.h" 33#include "thread_utils.h" 34 35static inline int futex(volatile int* uaddr, int op, int val, const struct timespec* ts, volatile int* uaddr2, int val3) { 36 return syscall(__NR_futex, uaddr, op, val, ts, uaddr2, val3); 37} 38 39//------------------------------------------------------------------------- 40// ThreadEntry implementation. 41//------------------------------------------------------------------------- 42ThreadEntry* ThreadEntry::list_ = NULL; 43pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER; 44 45// Assumes that ThreadEntry::list_mutex_ has already been locked before 46// creating a ThreadEntry object. 47ThreadEntry::ThreadEntry(pid_t pid, pid_t tid) 48 : pid_(pid), tid_(tid), futex_(0), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), next_(ThreadEntry::list_), prev_(NULL) { 49 // Add ourselves to the list. 50 if (ThreadEntry::list_) { 51 ThreadEntry::list_->prev_ = this; 52 } 53 ThreadEntry::list_ = this; 54} 55 56ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) { 57 pthread_mutex_lock(&ThreadEntry::list_mutex_); 58 ThreadEntry* entry = list_; 59 while (entry != NULL) { 60 if (entry->Match(pid, tid)) { 61 break; 62 } 63 entry = entry->next_; 64 } 65 66 if (!entry) { 67 if (create) { 68 entry = new ThreadEntry(pid, tid); 69 } 70 } else { 71 entry->ref_count_++; 72 } 73 pthread_mutex_unlock(&ThreadEntry::list_mutex_); 74 75 return entry; 76} 77 78void ThreadEntry::Remove(ThreadEntry* entry) { 79 pthread_mutex_unlock(&entry->mutex_); 80 81 pthread_mutex_lock(&ThreadEntry::list_mutex_); 82 if (--entry->ref_count_ == 0) { 83 delete entry; 84 } 85 pthread_mutex_unlock(&ThreadEntry::list_mutex_); 86} 87 88// Assumes that ThreadEntry::list_mutex_ has already been locked before 89// deleting a ThreadEntry object. 90ThreadEntry::~ThreadEntry() { 91 if (list_ == this) { 92 list_ = next_; 93 } else { 94 if (next_) { 95 next_->prev_ = prev_; 96 } 97 prev_->next_ = next_; 98 } 99 100 next_ = NULL; 101 prev_ = NULL; 102} 103 104void ThreadEntry::Wait(int value) { 105 timespec ts; 106 ts.tv_sec = 10; 107 ts.tv_nsec = 0; 108 errno = 0; 109 futex(&futex_, FUTEX_WAIT, value, &ts, NULL, 0); 110 if (errno != 0 && errno != EWOULDBLOCK) { 111 BACK_LOGW("futex wait failed, futex = %d: %s", futex_, strerror(errno)); 112 } 113} 114 115void ThreadEntry::Wake() { 116 futex_++; 117 futex(&futex_, FUTEX_WAKE, INT_MAX, NULL, NULL, 0); 118} 119 120void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) { 121 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext); 122 // The only thing the unwinder cares about is the mcontext data. 123 memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext)); 124} 125 126//------------------------------------------------------------------------- 127// BacktraceThread functions. 128//------------------------------------------------------------------------- 129static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER; 130 131static void SignalHandler(int, siginfo_t*, void* sigcontext) { 132 ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false); 133 if (!entry) { 134 BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid()); 135 return; 136 } 137 138 entry->CopyUcontextFromSigcontext(sigcontext); 139 140 // Indicate the ucontext is now valid. 141 entry->Wake(); 142 143 // Pause the thread until the unwind is complete. This avoids having 144 // the thread run ahead causing problems. 145 entry->Wait(1); 146 147 ThreadEntry::Remove(entry); 148} 149 150BacktraceThread::BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map) 151 : BacktraceCurrent(impl, map) { 152 tid_ = tid; 153} 154 155BacktraceThread::~BacktraceThread() { 156} 157 158bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { 159 if (ucontext) { 160 // Unwind using an already existing ucontext. 161 return impl_->Unwind(num_ignore_frames, ucontext); 162 } 163 164 // Prevent multiple threads trying to set the trigger action on different 165 // threads at the same time. 166 if (pthread_mutex_lock(&g_sigaction_mutex) < 0) { 167 BACK_LOGW("sigaction failed: %s", strerror(errno)); 168 return false; 169 } 170 171 ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid()); 172 entry->Lock(); 173 174 struct sigaction act, oldact; 175 memset(&act, 0, sizeof(act)); 176 act.sa_sigaction = SignalHandler; 177 act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; 178 sigemptyset(&act.sa_mask); 179 if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) { 180 BACK_LOGW("sigaction failed %s", strerror(errno)); 181 entry->Unlock(); 182 ThreadEntry::Remove(entry); 183 pthread_mutex_unlock(&g_sigaction_mutex); 184 return false; 185 } 186 187 if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) { 188 BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno)); 189 sigaction(THREAD_SIGNAL, &oldact, NULL); 190 entry->Unlock(); 191 ThreadEntry::Remove(entry); 192 pthread_mutex_unlock(&g_sigaction_mutex); 193 return false; 194 } 195 196 // Wait for the thread to get the ucontext. 197 entry->Wait(0); 198 199 // After the thread has received the signal, allow other unwinders to 200 // continue. 201 sigaction(THREAD_SIGNAL, &oldact, NULL); 202 pthread_mutex_unlock(&g_sigaction_mutex); 203 204 bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext()); 205 206 // Tell the signal handler to exit and release the entry. 207 entry->Wake(); 208 209 return unwind_done; 210} 211