BacktraceThread.cpp revision 9846497f7926fc3240c2893d89e60880c22d1fd6
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 <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;
34static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER;
35static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
36
37ThreadEntry::ThreadEntry(
38    BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames)
39    : thread_intf(intf), pid(pid), tid(tid), next(NULL), prev(NULL),
40      state(STATE_WAITING), num_ignore_frames(num_ignore_frames) {
41}
42
43ThreadEntry::~ThreadEntry() {
44  pthread_mutex_lock(&g_entry_mutex);
45  if (g_list == this) {
46    g_list = next;
47  } else {
48    if (next) {
49      next->prev = prev;
50    }
51    prev->next = next;
52  }
53  pthread_mutex_unlock(&g_entry_mutex);
54
55  next = NULL;
56  prev = NULL;
57}
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
63  pthread_mutex_lock(&g_entry_mutex);
64  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.
68      BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid);
69
70      pthread_mutex_unlock(&g_entry_mutex);
71      return NULL;
72    }
73    cur_entry = cur_entry->next;
74  }
75
76  // Add the entry to the list.
77  entry->next = g_list;
78  if (g_list) {
79    g_list->prev = entry;
80  }
81  g_list = entry;
82  pthread_mutex_unlock(&g_entry_mutex);
83
84  return entry;
85}
86
87//-------------------------------------------------------------------------
88// BacktraceThread functions.
89//-------------------------------------------------------------------------
90static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
91                          void* sigcontext) {
92  if (pthread_mutex_lock(&g_entry_mutex) == 0) {
93    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      }
100      cur_entry = cur_entry->next;
101    }
102    pthread_mutex_unlock(&g_entry_mutex);
103    if (!cur_entry) {
104      BACK_LOGW("Unable to find pid %d tid %d information", pid, tid);
105      return;
106    }
107
108    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);
111    }
112    android_atomic_release_store(STATE_DONE, &cur_entry->state);
113  }
114}
115
116BacktraceThread::BacktraceThread(
117    BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
118    backtrace_map_info_t* map_info)
119    : BacktraceCurrent(impl, map_info), thread_intf_(thread_intf) {
120  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) {
146  entry->state = STATE_WAITING;
147
148  if (tgkill(Pid(), Tid(), SIGURG) != 0) {
149    BACK_LOGW("tgkill failed %s", strerror(errno));
150    return false;
151  }
152
153  // Allow up to ten seconds for the dump to start.
154  int wait_millis = 10000;
155  int32_t state;
156  while (true) {
157    state = android_atomic_acquire_load(&entry->state);
158    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) {
170    if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) {
171      BACK_LOGW("Cancelled dump of thread %d", entry->tid);
172      state = STATE_CANCEL;
173      cancelled = true;
174    } else {
175      state = android_atomic_acquire_load(&entry->state);
176    }
177  }
178
179  // 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) {
182    if (wait_millis--) {
183      usleep(1000);
184    } else {
185      BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
186      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
203  // Prevent multiple threads trying to set the trigger action on different
204  // threads at the same time.
205  bool retval = false;
206  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);
219  } else {
220    BACK_LOGW("unable to acquire sigaction mutex.");
221  }
222
223  if (retval) {
224    FinishUnwind();
225  }
226  delete entry;
227
228  return retval;
229}
230