blob: 8e664c44e4c96cb787c5b31de0ab5c34a83fe10e [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>
25#include <cutils/log.h>
26
27#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(
117 BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid)
118 : BacktraceCurrent(impl), thread_intf_(thread_intf) {
119 backtrace_.tid = tid;
120}
121
122BacktraceThread::~BacktraceThread() {
123}
124
125void BacktraceThread::FinishUnwind() {
126 for (size_t i = 0; i < NumFrames(); i++) {
127 backtrace_frame_data_t* frame = &backtrace_.frames[i];
128
129 frame->map_offset = 0;
130 uintptr_t map_start;
131 frame->map_name = GetMapName(frame->pc, &map_start);
132 if (frame->map_name) {
133 frame->map_offset = frame->pc - map_start;
134 }
135
136 frame->func_offset = 0;
137 std::string func_name = GetFunctionName(frame->pc, &frame->func_offset);
138 if (!func_name.empty()) {
139 frame->func_name = strdup(func_name.c_str());
140 }
141 }
142}
143
144bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700145 entry->state = STATE_WAITING;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700146
147 if (tgkill(Pid(), Tid(), SIGURG) != 0) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700148 BACK_LOGW("tgkill failed %s", strerror(errno));
Christopher Ferris17e91d42013-10-21 13:30:52 -0700149 return false;
150 }
151
Christopher Ferris8ed46272013-10-29 15:44:25 -0700152 // Allow up to ten seconds for the dump to start.
153 int wait_millis = 10000;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700154 int32_t state;
155 while (true) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700156 state = android_atomic_acquire_load(&entry->state);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700157 if (state != STATE_WAITING) {
158 break;
159 }
160 if (wait_millis--) {
161 usleep(1000);
162 } else {
163 break;
164 }
165 }
166
167 bool cancelled = false;
168 if (state == STATE_WAITING) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700169 if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) {
170 BACK_LOGW("Cancelled dump of thread %d", entry->tid);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700171 state = STATE_CANCEL;
172 cancelled = true;
173 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700174 state = android_atomic_acquire_load(&entry->state);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700175 }
176 }
177
Christopher Ferris8ed46272013-10-29 15:44:25 -0700178 // Wait for at most ten seconds for the cancel or dump to finish.
179 wait_millis = 10000;
180 while (android_atomic_acquire_load(&entry->state) != STATE_DONE) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700181 if (wait_millis--) {
182 usleep(1000);
183 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700184 BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
Christopher Ferris17e91d42013-10-21 13:30:52 -0700185 break;
186 }
187 }
188 return !cancelled;
189}
190
191bool BacktraceThread::Unwind(size_t num_ignore_frames) {
192 if (!thread_intf_->Init()) {
193 return false;
194 }
195
196 ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
197 thread_intf_, Pid(), Tid(), num_ignore_frames);
198 if (!entry) {
199 return false;
200 }
201
Christopher Ferris8ed46272013-10-29 15:44:25 -0700202 // Prevent multiple threads trying to set the trigger action on different
203 // threads at the same time.
Christopher Ferris17e91d42013-10-21 13:30:52 -0700204 bool retval = false;
Christopher Ferris8ed46272013-10-29 15:44:25 -0700205 if (pthread_mutex_lock(&g_sigaction_mutex) == 0) {
206 struct sigaction act, oldact;
207 memset(&act, 0, sizeof(act));
208 act.sa_sigaction = SignalHandler;
209 act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
210 sigemptyset(&act.sa_mask);
211 if (sigaction(SIGURG, &act, &oldact) == 0) {
212 retval = TriggerUnwindOnThread(entry);
213 sigaction(SIGURG, &oldact, NULL);
214 } else {
215 BACK_LOGW("sigaction failed %s", strerror(errno));
216 }
217 pthread_mutex_unlock(&g_sigaction_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700218 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700219 BACK_LOGW("unable to acquire sigaction mutex.");
Christopher Ferris17e91d42013-10-21 13:30:52 -0700220 }
221
222 if (retval) {
223 FinishUnwind();
224 }
225 delete entry;
226
227 return retval;
228}