blob: 5ffe516e3ab64d4f4b075e78c7fc187bd6df6065 [file] [log] [blame]
Christopher Ferris17e91d42013-10-21 13:30:52 -07001/*
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 <pthread.h>
20#include <signal.h>
21#include <string.h>
22#include <sys/types.h>
23
24#include <cutils/atomic.h>
Christopher Ferris17e91d42013-10-21 13:30:52 -070025
26#include "BacktraceThread.h"
27#include "thread_utils.h"
28
29//-------------------------------------------------------------------------
30// ThreadEntry implementation.
31//-------------------------------------------------------------------------
32static ThreadEntry* g_list = NULL;
Christopher Ferris8ed46272013-10-29 15:44:25 -070033static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER;
34static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
Christopher Ferris17e91d42013-10-21 13:30:52 -070035
36ThreadEntry::ThreadEntry(
37 BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames)
Christopher Ferris8ed46272013-10-29 15:44:25 -070038 : thread_intf(intf), pid(pid), tid(tid), next(NULL), prev(NULL),
39 state(STATE_WAITING), num_ignore_frames(num_ignore_frames) {
Christopher Ferris17e91d42013-10-21 13:30:52 -070040}
41
42ThreadEntry::~ThreadEntry() {
Christopher Ferris8ed46272013-10-29 15:44:25 -070043 pthread_mutex_lock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -070044 if (g_list == this) {
Christopher Ferris8ed46272013-10-29 15:44:25 -070045 g_list = next;
Christopher Ferris17e91d42013-10-21 13:30:52 -070046 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -070047 if (next) {
48 next->prev = prev;
Christopher Ferris17e91d42013-10-21 13:30:52 -070049 }
Christopher Ferris8ed46272013-10-29 15:44:25 -070050 prev->next = next;
Christopher Ferris17e91d42013-10-21 13:30:52 -070051 }
Christopher Ferris8ed46272013-10-29 15:44:25 -070052 pthread_mutex_unlock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -070053
Christopher Ferris8ed46272013-10-29 15:44:25 -070054 next = NULL;
55 prev = NULL;
Christopher Ferris17e91d42013-10-21 13:30:52 -070056}
57
58ThreadEntry* ThreadEntry::AddThreadToUnwind(
59 BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) {
60 ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames);
61
Christopher Ferris8ed46272013-10-29 15:44:25 -070062 pthread_mutex_lock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -070063 ThreadEntry* cur_entry = g_list;
64 while (cur_entry != NULL) {
65 if (cur_entry->Match(pid, tid)) {
66 // There is already an entry for this pid/tid, this is bad.
Christopher Ferris8ed46272013-10-29 15:44:25 -070067 BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid);
Christopher Ferris17e91d42013-10-21 13:30:52 -070068
Christopher Ferris8ed46272013-10-29 15:44:25 -070069 pthread_mutex_unlock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -070070 return NULL;
71 }
Christopher Ferris8ed46272013-10-29 15:44:25 -070072 cur_entry = cur_entry->next;
Christopher Ferris17e91d42013-10-21 13:30:52 -070073 }
74
75 // Add the entry to the list.
Christopher Ferris8ed46272013-10-29 15:44:25 -070076 entry->next = g_list;
Christopher Ferris17e91d42013-10-21 13:30:52 -070077 if (g_list) {
Christopher Ferris8ed46272013-10-29 15:44:25 -070078 g_list->prev = entry;
Christopher Ferris17e91d42013-10-21 13:30:52 -070079 }
80 g_list = entry;
Christopher Ferris8ed46272013-10-29 15:44:25 -070081 pthread_mutex_unlock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -070082
83 return entry;
84}
85
86//-------------------------------------------------------------------------
87// BacktraceThread functions.
88//-------------------------------------------------------------------------
89static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
90 void* sigcontext) {
Christopher Ferris8ed46272013-10-29 15:44:25 -070091 if (pthread_mutex_lock(&g_entry_mutex) == 0) {
Christopher Ferris17e91d42013-10-21 13:30:52 -070092 pid_t pid = getpid();
93 pid_t tid = gettid();
94 ThreadEntry* cur_entry = g_list;
95 while (cur_entry) {
96 if (cur_entry->Match(pid, tid)) {
97 break;
98 }
Christopher Ferris8ed46272013-10-29 15:44:25 -070099 cur_entry = cur_entry->next;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700100 }
Christopher Ferris8ed46272013-10-29 15:44:25 -0700101 pthread_mutex_unlock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700102 if (!cur_entry) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700103 BACK_LOGW("Unable to find pid %d tid %d information", pid, tid);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700104 return;
105 }
106
Christopher Ferris8ed46272013-10-29 15:44:25 -0700107 if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state) == 0) {
108 cur_entry->thread_intf->ThreadUnwind(siginfo, sigcontext,
109 cur_entry->num_ignore_frames);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700110 }
Christopher Ferris8ed46272013-10-29 15:44:25 -0700111 android_atomic_release_store(STATE_DONE, &cur_entry->state);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700112 }
113}
114
115BacktraceThread::BacktraceThread(
Christopher Ferris98464972014-01-06 19:16:33 -0800116 BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
Christopher Ferris46756822014-01-14 20:16:30 -0800117 BacktraceMap* map)
118 : BacktraceCurrent(impl, map), thread_intf_(thread_intf) {
119 tid_ = tid;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700120}
121
122BacktraceThread::~BacktraceThread() {
123}
124
125void BacktraceThread::FinishUnwind() {
Christopher Ferris46756822014-01-14 20:16:30 -0800126 for (std::vector<backtrace_frame_data_t>::iterator it = frames_.begin();
127 it != frames_.end(); ++it) {
128 it->map = FindMap(it->pc);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700129
Christopher Ferris46756822014-01-14 20:16:30 -0800130 it->func_offset = 0;
131 it->func_name = GetFunctionName(it->pc, &it->func_offset);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700132 }
133}
134
135bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700136 entry->state = STATE_WAITING;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700137
138 if (tgkill(Pid(), Tid(), SIGURG) != 0) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700139 BACK_LOGW("tgkill failed %s", strerror(errno));
Christopher Ferris17e91d42013-10-21 13:30:52 -0700140 return false;
141 }
142
Christopher Ferris8ed46272013-10-29 15:44:25 -0700143 // Allow up to ten seconds for the dump to start.
144 int wait_millis = 10000;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700145 int32_t state;
146 while (true) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700147 state = android_atomic_acquire_load(&entry->state);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700148 if (state != STATE_WAITING) {
149 break;
150 }
151 if (wait_millis--) {
152 usleep(1000);
153 } else {
154 break;
155 }
156 }
157
158 bool cancelled = false;
159 if (state == STATE_WAITING) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700160 if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) {
161 BACK_LOGW("Cancelled dump of thread %d", entry->tid);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700162 state = STATE_CANCEL;
163 cancelled = true;
164 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700165 state = android_atomic_acquire_load(&entry->state);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700166 }
167 }
168
Christopher Ferris8ed46272013-10-29 15:44:25 -0700169 // Wait for at most ten seconds for the cancel or dump to finish.
170 wait_millis = 10000;
171 while (android_atomic_acquire_load(&entry->state) != STATE_DONE) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700172 if (wait_millis--) {
173 usleep(1000);
174 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700175 BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
Christopher Ferris17e91d42013-10-21 13:30:52 -0700176 break;
177 }
178 }
179 return !cancelled;
180}
181
182bool BacktraceThread::Unwind(size_t num_ignore_frames) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700183 ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
184 thread_intf_, Pid(), Tid(), num_ignore_frames);
185 if (!entry) {
186 return false;
187 }
188
Christopher Ferris8ed46272013-10-29 15:44:25 -0700189 // Prevent multiple threads trying to set the trigger action on different
190 // threads at the same time.
Christopher Ferris17e91d42013-10-21 13:30:52 -0700191 bool retval = false;
Christopher Ferris8ed46272013-10-29 15:44:25 -0700192 if (pthread_mutex_lock(&g_sigaction_mutex) == 0) {
193 struct sigaction act, oldact;
194 memset(&act, 0, sizeof(act));
195 act.sa_sigaction = SignalHandler;
196 act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
197 sigemptyset(&act.sa_mask);
198 if (sigaction(SIGURG, &act, &oldact) == 0) {
199 retval = TriggerUnwindOnThread(entry);
200 sigaction(SIGURG, &oldact, NULL);
201 } else {
202 BACK_LOGW("sigaction failed %s", strerror(errno));
203 }
204 pthread_mutex_unlock(&g_sigaction_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700205 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700206 BACK_LOGW("unable to acquire sigaction mutex.");
Christopher Ferris17e91d42013-10-21 13:30:52 -0700207 }
208
209 if (retval) {
210 FinishUnwind();
211 }
212 delete entry;
213
214 return retval;
215}