blob: 70616b0dc74f3692eb97ef4ad09be5105a572deb [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(
Christopher Ferris98464972014-01-06 19:16:33 -0800117 BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
118 backtrace_map_info_t* map_info)
119 : BacktraceCurrent(impl, map_info), thread_intf_(thread_intf) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700120 backtrace_.tid = tid;
121}
122
123BacktraceThread::~BacktraceThread() {
124}
125
126void BacktraceThread::FinishUnwind() {
127 for (size_t i = 0; i < NumFrames(); i++) {
128 backtrace_frame_data_t* frame = &backtrace_.frames[i];
129
130 frame->map_offset = 0;
131 uintptr_t map_start;
132 frame->map_name = GetMapName(frame->pc, &map_start);
133 if (frame->map_name) {
134 frame->map_offset = frame->pc - map_start;
135 }
136
137 frame->func_offset = 0;
138 std::string func_name = GetFunctionName(frame->pc, &frame->func_offset);
139 if (!func_name.empty()) {
140 frame->func_name = strdup(func_name.c_str());
141 }
142 }
143}
144
145bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700146 entry->state = STATE_WAITING;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700147
148 if (tgkill(Pid(), Tid(), SIGURG) != 0) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700149 BACK_LOGW("tgkill failed %s", strerror(errno));
Christopher Ferris17e91d42013-10-21 13:30:52 -0700150 return false;
151 }
152
Christopher Ferris8ed46272013-10-29 15:44:25 -0700153 // Allow up to ten seconds for the dump to start.
154 int wait_millis = 10000;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700155 int32_t state;
156 while (true) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700157 state = android_atomic_acquire_load(&entry->state);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700158 if (state != STATE_WAITING) {
159 break;
160 }
161 if (wait_millis--) {
162 usleep(1000);
163 } else {
164 break;
165 }
166 }
167
168 bool cancelled = false;
169 if (state == STATE_WAITING) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700170 if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) {
171 BACK_LOGW("Cancelled dump of thread %d", entry->tid);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700172 state = STATE_CANCEL;
173 cancelled = true;
174 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700175 state = android_atomic_acquire_load(&entry->state);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700176 }
177 }
178
Christopher Ferris8ed46272013-10-29 15:44:25 -0700179 // Wait for at most ten seconds for the cancel or dump to finish.
180 wait_millis = 10000;
181 while (android_atomic_acquire_load(&entry->state) != STATE_DONE) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700182 if (wait_millis--) {
183 usleep(1000);
184 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700185 BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
Christopher Ferris17e91d42013-10-21 13:30:52 -0700186 break;
187 }
188 }
189 return !cancelled;
190}
191
192bool BacktraceThread::Unwind(size_t num_ignore_frames) {
193 if (!thread_intf_->Init()) {
194 return false;
195 }
196
197 ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
198 thread_intf_, Pid(), Tid(), num_ignore_frames);
199 if (!entry) {
200 return false;
201 }
202
Christopher Ferris8ed46272013-10-29 15:44:25 -0700203 // Prevent multiple threads trying to set the trigger action on different
204 // threads at the same time.
Christopher Ferris17e91d42013-10-21 13:30:52 -0700205 bool retval = false;
Christopher Ferris8ed46272013-10-29 15:44:25 -0700206 if (pthread_mutex_lock(&g_sigaction_mutex) == 0) {
207 struct sigaction act, oldact;
208 memset(&act, 0, sizeof(act));
209 act.sa_sigaction = SignalHandler;
210 act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
211 sigemptyset(&act.sa_mask);
212 if (sigaction(SIGURG, &act, &oldact) == 0) {
213 retval = TriggerUnwindOnThread(entry);
214 sigaction(SIGURG, &oldact, NULL);
215 } else {
216 BACK_LOGW("sigaction failed %s", strerror(errno));
217 }
218 pthread_mutex_unlock(&g_sigaction_mutex);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700219 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700220 BACK_LOGW("unable to acquire sigaction mutex.");
Christopher Ferris17e91d42013-10-21 13:30:52 -0700221 }
222
223 if (retval) {
224 FinishUnwind();
225 }
226 delete entry;
227
228 return retval;
229}