blob: 4cda19ec24d8ef038902080158087e7529f7ce5e [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
Christopher Ferrise2960912014-03-07 19:42:19 -080026#include "BacktraceLog.h"
Christopher Ferris17e91d42013-10-21 13:30:52 -070027#include "BacktraceThread.h"
28#include "thread_utils.h"
29
30//-------------------------------------------------------------------------
31// ThreadEntry implementation.
32//-------------------------------------------------------------------------
33static ThreadEntry* g_list = NULL;
Christopher Ferris8ed46272013-10-29 15:44:25 -070034static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER;
35static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
Christopher Ferris17e91d42013-10-21 13:30:52 -070036
37ThreadEntry::ThreadEntry(
38 BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames)
Christopher Ferris8ed46272013-10-29 15:44:25 -070039 : thread_intf(intf), pid(pid), tid(tid), next(NULL), prev(NULL),
40 state(STATE_WAITING), num_ignore_frames(num_ignore_frames) {
Christopher Ferris17e91d42013-10-21 13:30:52 -070041}
42
43ThreadEntry::~ThreadEntry() {
Christopher Ferris8ed46272013-10-29 15:44:25 -070044 pthread_mutex_lock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -070045 if (g_list == this) {
Christopher Ferris8ed46272013-10-29 15:44:25 -070046 g_list = next;
Christopher Ferris17e91d42013-10-21 13:30:52 -070047 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -070048 if (next) {
49 next->prev = prev;
Christopher Ferris17e91d42013-10-21 13:30:52 -070050 }
Christopher Ferris8ed46272013-10-29 15:44:25 -070051 prev->next = next;
Christopher Ferris17e91d42013-10-21 13:30:52 -070052 }
Christopher Ferris8ed46272013-10-29 15:44:25 -070053 pthread_mutex_unlock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -070054
Christopher Ferris8ed46272013-10-29 15:44:25 -070055 next = NULL;
56 prev = NULL;
Christopher Ferris17e91d42013-10-21 13:30:52 -070057}
58
59ThreadEntry* ThreadEntry::AddThreadToUnwind(
60 BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) {
61 ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames);
62
Christopher Ferris8ed46272013-10-29 15:44:25 -070063 pthread_mutex_lock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -070064 ThreadEntry* cur_entry = g_list;
65 while (cur_entry != NULL) {
66 if (cur_entry->Match(pid, tid)) {
67 // There is already an entry for this pid/tid, this is bad.
Christopher Ferris8ed46272013-10-29 15:44:25 -070068 BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid);
Christopher Ferris17e91d42013-10-21 13:30:52 -070069
Christopher Ferris8ed46272013-10-29 15:44:25 -070070 pthread_mutex_unlock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -070071 return NULL;
72 }
Christopher Ferris8ed46272013-10-29 15:44:25 -070073 cur_entry = cur_entry->next;
Christopher Ferris17e91d42013-10-21 13:30:52 -070074 }
75
76 // Add the entry to the list.
Christopher Ferris8ed46272013-10-29 15:44:25 -070077 entry->next = g_list;
Christopher Ferris17e91d42013-10-21 13:30:52 -070078 if (g_list) {
Christopher Ferris8ed46272013-10-29 15:44:25 -070079 g_list->prev = entry;
Christopher Ferris17e91d42013-10-21 13:30:52 -070080 }
81 g_list = entry;
Christopher Ferris8ed46272013-10-29 15:44:25 -070082 pthread_mutex_unlock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -070083
84 return entry;
85}
86
87//-------------------------------------------------------------------------
88// BacktraceThread functions.
89//-------------------------------------------------------------------------
90static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
91 void* sigcontext) {
Christopher Ferris8ed46272013-10-29 15:44:25 -070092 if (pthread_mutex_lock(&g_entry_mutex) == 0) {
Christopher Ferris17e91d42013-10-21 13:30:52 -070093 pid_t pid = getpid();
94 pid_t tid = gettid();
95 ThreadEntry* cur_entry = g_list;
96 while (cur_entry) {
97 if (cur_entry->Match(pid, tid)) {
98 break;
99 }
Christopher Ferris8ed46272013-10-29 15:44:25 -0700100 cur_entry = cur_entry->next;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700101 }
Christopher Ferris8ed46272013-10-29 15:44:25 -0700102 pthread_mutex_unlock(&g_entry_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700103 if (!cur_entry) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700104 BACK_LOGW("Unable to find pid %d tid %d information", pid, tid);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700105 return;
106 }
107
Christopher Ferris8ed46272013-10-29 15:44:25 -0700108 if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state) == 0) {
109 cur_entry->thread_intf->ThreadUnwind(siginfo, sigcontext,
110 cur_entry->num_ignore_frames);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700111 }
Christopher Ferris8ed46272013-10-29 15:44:25 -0700112 android_atomic_release_store(STATE_DONE, &cur_entry->state);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700113 }
114}
115
116BacktraceThread::BacktraceThread(
Christopher Ferris98464972014-01-06 19:16:33 -0800117 BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
Christopher Ferris46756822014-01-14 20:16:30 -0800118 BacktraceMap* map)
119 : BacktraceCurrent(impl, map), thread_intf_(thread_intf) {
120 tid_ = tid;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700121}
122
123BacktraceThread::~BacktraceThread() {
124}
125
126void BacktraceThread::FinishUnwind() {
Christopher Ferris46756822014-01-14 20:16:30 -0800127 for (std::vector<backtrace_frame_data_t>::iterator it = frames_.begin();
128 it != frames_.end(); ++it) {
129 it->map = FindMap(it->pc);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700130
Christopher Ferris46756822014-01-14 20:16:30 -0800131 it->func_offset = 0;
132 it->func_name = GetFunctionName(it->pc, &it->func_offset);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700133 }
134}
135
136bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700137 entry->state = STATE_WAITING;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700138
139 if (tgkill(Pid(), Tid(), SIGURG) != 0) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700140 BACK_LOGW("tgkill failed %s", strerror(errno));
Christopher Ferris17e91d42013-10-21 13:30:52 -0700141 return false;
142 }
143
Christopher Ferris8ed46272013-10-29 15:44:25 -0700144 // Allow up to ten seconds for the dump to start.
145 int wait_millis = 10000;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700146 int32_t state;
147 while (true) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700148 state = android_atomic_acquire_load(&entry->state);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700149 if (state != STATE_WAITING) {
150 break;
151 }
152 if (wait_millis--) {
153 usleep(1000);
154 } else {
155 break;
156 }
157 }
158
159 bool cancelled = false;
160 if (state == STATE_WAITING) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700161 if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) {
162 BACK_LOGW("Cancelled dump of thread %d", entry->tid);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700163 state = STATE_CANCEL;
164 cancelled = true;
165 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700166 state = android_atomic_acquire_load(&entry->state);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700167 }
168 }
169
Christopher Ferris8ed46272013-10-29 15:44:25 -0700170 // Wait for at most ten seconds for the cancel or dump to finish.
171 wait_millis = 10000;
172 while (android_atomic_acquire_load(&entry->state) != STATE_DONE) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700173 if (wait_millis--) {
174 usleep(1000);
175 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700176 BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
Christopher Ferris17e91d42013-10-21 13:30:52 -0700177 break;
178 }
179 }
180 return !cancelled;
181}
182
183bool BacktraceThread::Unwind(size_t num_ignore_frames) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700184 ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
185 thread_intf_, Pid(), Tid(), num_ignore_frames);
186 if (!entry) {
187 return false;
188 }
189
Christopher Ferris8ed46272013-10-29 15:44:25 -0700190 // Prevent multiple threads trying to set the trigger action on different
191 // threads at the same time.
Christopher Ferris17e91d42013-10-21 13:30:52 -0700192 bool retval = false;
Christopher Ferris8ed46272013-10-29 15:44:25 -0700193 if (pthread_mutex_lock(&g_sigaction_mutex) == 0) {
194 struct sigaction act, oldact;
195 memset(&act, 0, sizeof(act));
196 act.sa_sigaction = SignalHandler;
197 act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
198 sigemptyset(&act.sa_mask);
199 if (sigaction(SIGURG, &act, &oldact) == 0) {
200 retval = TriggerUnwindOnThread(entry);
201 sigaction(SIGURG, &oldact, NULL);
202 } else {
203 BACK_LOGW("sigaction failed %s", strerror(errno));
204 }
205 pthread_mutex_unlock(&g_sigaction_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700206 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700207 BACK_LOGW("unable to acquire sigaction mutex.");
Christopher Ferris17e91d42013-10-21 13:30:52 -0700208 }
209
210 if (retval) {
211 FinishUnwind();
212 }
213 delete entry;
214
215 return retval;
216}