1/* 2 * Copyright (C) 2011 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#define LOG_TAG "Corkscrew" 18//#define LOG_NDEBUG 0 19 20#include "backtrace-arch.h" 21#include "backtrace-helper.h" 22#include "ptrace-arch.h" 23#include <corkscrew/map_info.h> 24#include <corkscrew/symbol_table.h> 25#include <corkscrew/ptrace.h> 26#include <corkscrew/demangle.h> 27 28#include <unistd.h> 29#include <signal.h> 30#include <stdlib.h> 31#include <string.h> 32#include <pthread.h> 33#include <unwind.h> 34#include <cutils/log.h> 35#include <cutils/atomic.h> 36#include <elf.h> 37 38#define __USE_GNU // For dladdr(3) in glibc. 39#include <dlfcn.h> 40 41#if defined(__BIONIC__) 42 43// Bionic implements and exports gettid but only implements tgkill. 44extern int tgkill(int tgid, int tid, int sig); 45 46#else 47 48// glibc doesn't implement or export either gettid or tgkill. 49 50#include <unistd.h> 51#include <sys/syscall.h> 52 53static pid_t gettid() { 54 return syscall(__NR_gettid); 55} 56 57static int tgkill(int tgid, int tid, int sig) { 58 return syscall(__NR_tgkill, tgid, tid, sig); 59} 60 61#endif 62 63typedef struct { 64 backtrace_frame_t* backtrace; 65 size_t ignore_depth; 66 size_t max_depth; 67 size_t ignored_frames; 68 size_t returned_frames; 69 memory_t memory; 70} backtrace_state_t; 71 72static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* context, void* arg) { 73 backtrace_state_t* state = (backtrace_state_t*)arg; 74 uintptr_t pc = _Unwind_GetIP(context); 75 if (pc) { 76 // TODO: Get information about the stack layout from the _Unwind_Context. 77 // This will require a new architecture-specific function to query 78 // the appropriate registers. Current callers of unwind_backtrace 79 // don't need this information, so we won't bother collecting it just yet. 80 add_backtrace_entry(rewind_pc_arch(&state->memory, pc), state->backtrace, 81 state->ignore_depth, state->max_depth, 82 &state->ignored_frames, &state->returned_frames); 83 } 84 return state->returned_frames < state->max_depth ? _URC_NO_REASON : _URC_END_OF_STACK; 85} 86 87ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) { 88 ALOGV("Unwinding current thread %d.", gettid()); 89 90 map_info_t* milist = acquire_my_map_info_list(); 91 92 backtrace_state_t state; 93 state.backtrace = backtrace; 94 state.ignore_depth = ignore_depth; 95 state.max_depth = max_depth; 96 state.ignored_frames = 0; 97 state.returned_frames = 0; 98 init_memory(&state.memory, milist); 99 100 _Unwind_Reason_Code rc =_Unwind_Backtrace(unwind_backtrace_callback, &state); 101 102 release_my_map_info_list(milist); 103 104 if (state.returned_frames) { 105 return state.returned_frames; 106 } 107 return rc == _URC_END_OF_STACK ? 0 : -1; 108} 109 110#ifdef CORKSCREW_HAVE_ARCH 111static const int32_t STATE_DUMPING = -1; 112static const int32_t STATE_DONE = -2; 113static const int32_t STATE_CANCEL = -3; 114 115static pthread_mutex_t g_unwind_signal_mutex = PTHREAD_MUTEX_INITIALIZER; 116static volatile struct { 117 int32_t tid_state; 118 const map_info_t* map_info_list; 119 backtrace_frame_t* backtrace; 120 size_t ignore_depth; 121 size_t max_depth; 122 size_t returned_frames; 123} g_unwind_signal_state; 124 125static void unwind_backtrace_thread_signal_handler(int n __attribute__((unused)), siginfo_t* siginfo, void* sigcontext) { 126 if (!android_atomic_acquire_cas(gettid(), STATE_DUMPING, &g_unwind_signal_state.tid_state)) { 127 g_unwind_signal_state.returned_frames = unwind_backtrace_signal_arch( 128 siginfo, sigcontext, 129 g_unwind_signal_state.map_info_list, 130 g_unwind_signal_state.backtrace, 131 g_unwind_signal_state.ignore_depth, 132 g_unwind_signal_state.max_depth); 133 android_atomic_release_store(STATE_DONE, &g_unwind_signal_state.tid_state); 134 } else { 135 ALOGV("Received spurious SIGURG on thread %d that was intended for thread %d.", 136 gettid(), android_atomic_acquire_load(&g_unwind_signal_state.tid_state)); 137 } 138} 139#endif 140 141ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace, 142 size_t ignore_depth, size_t max_depth) { 143 if (tid == gettid()) { 144 return unwind_backtrace(backtrace, ignore_depth + 1, max_depth); 145 } 146 147 ALOGV("Unwinding thread %d from thread %d.", tid, gettid()); 148 149#ifdef CORKSCREW_HAVE_ARCH 150 struct sigaction act; 151 struct sigaction oact; 152 memset(&act, 0, sizeof(act)); 153 act.sa_sigaction = unwind_backtrace_thread_signal_handler; 154 act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; 155 sigemptyset(&act.sa_mask); 156 157 pthread_mutex_lock(&g_unwind_signal_mutex); 158 map_info_t* milist = acquire_my_map_info_list(); 159 160 ssize_t frames = -1; 161 if (!sigaction(SIGURG, &act, &oact)) { 162 g_unwind_signal_state.map_info_list = milist; 163 g_unwind_signal_state.backtrace = backtrace; 164 g_unwind_signal_state.ignore_depth = ignore_depth; 165 g_unwind_signal_state.max_depth = max_depth; 166 g_unwind_signal_state.returned_frames = 0; 167 android_atomic_release_store(tid, &g_unwind_signal_state.tid_state); 168 169 // Signal the specific thread that we want to dump. 170 int32_t tid_state = tid; 171 if (tgkill(getpid(), tid, SIGURG)) { 172 ALOGV("Failed to send SIGURG to thread %d.", tid); 173 } else { 174 // Wait for the other thread to start dumping the stack, or time out. 175 int wait_millis = 250; 176 for (;;) { 177 tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state); 178 if (tid_state != tid) { 179 break; 180 } 181 if (wait_millis--) { 182 ALOGV("Waiting for thread %d to start dumping the stack...", tid); 183 usleep(1000); 184 } else { 185 ALOGV("Timed out waiting for thread %d to start dumping the stack.", tid); 186 break; 187 } 188 } 189 } 190 191 // Try to cancel the dump if it has not started yet. 192 if (tid_state == tid) { 193 if (!android_atomic_acquire_cas(tid, STATE_CANCEL, &g_unwind_signal_state.tid_state)) { 194 ALOGV("Canceled thread %d stack dump.", tid); 195 tid_state = STATE_CANCEL; 196 } else { 197 tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state); 198 } 199 } 200 201 // Wait indefinitely for the dump to finish or be canceled. 202 // We cannot apply a timeout here because the other thread is accessing state that 203 // is owned by this thread, such as milist. It should not take very 204 // long to take the dump once started. 205 while (tid_state == STATE_DUMPING) { 206 ALOGV("Waiting for thread %d to finish dumping the stack...", tid); 207 usleep(1000); 208 tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state); 209 } 210 211 if (tid_state == STATE_DONE) { 212 frames = g_unwind_signal_state.returned_frames; 213 } 214 215 sigaction(SIGURG, &oact, NULL); 216 } 217 218 release_my_map_info_list(milist); 219 pthread_mutex_unlock(&g_unwind_signal_mutex); 220 return frames; 221#else 222 return -1; 223#endif 224} 225 226ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context, 227 backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) { 228#ifdef CORKSCREW_HAVE_ARCH 229 return unwind_backtrace_ptrace_arch(tid, context, backtrace, ignore_depth, max_depth); 230#else 231 return -1; 232#endif 233} 234 235static void init_backtrace_symbol(backtrace_symbol_t* symbol, uintptr_t pc) { 236 symbol->relative_pc = pc; 237 symbol->relative_symbol_addr = 0; 238 symbol->map_name = NULL; 239 symbol->symbol_name = NULL; 240 symbol->demangled_name = NULL; 241} 242 243void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames, 244 backtrace_symbol_t* backtrace_symbols) { 245 map_info_t* milist = acquire_my_map_info_list(); 246 for (size_t i = 0; i < frames; i++) { 247 const backtrace_frame_t* frame = &backtrace[i]; 248 backtrace_symbol_t* symbol = &backtrace_symbols[i]; 249 init_backtrace_symbol(symbol, frame->absolute_pc); 250 251 const map_info_t* mi = find_map_info(milist, frame->absolute_pc); 252 if (mi) { 253 symbol->relative_pc = frame->absolute_pc - mi->start; 254 if (mi->name[0]) { 255 symbol->map_name = strdup(mi->name); 256 } 257 Dl_info info; 258 if (dladdr((const void*)frame->absolute_pc, &info) && info.dli_sname) { 259 symbol->relative_symbol_addr = (uintptr_t)info.dli_saddr 260 - (uintptr_t)info.dli_fbase; 261 symbol->symbol_name = strdup(info.dli_sname); 262 symbol->demangled_name = demangle_symbol_name(symbol->symbol_name); 263 } 264 } 265 } 266 release_my_map_info_list(milist); 267} 268 269void get_backtrace_symbols_ptrace(const ptrace_context_t* context, 270 const backtrace_frame_t* backtrace, size_t frames, 271 backtrace_symbol_t* backtrace_symbols) { 272 for (size_t i = 0; i < frames; i++) { 273 const backtrace_frame_t* frame = &backtrace[i]; 274 backtrace_symbol_t* symbol = &backtrace_symbols[i]; 275 init_backtrace_symbol(symbol, frame->absolute_pc); 276 277 const map_info_t* mi; 278 const symbol_t* s; 279 find_symbol_ptrace(context, frame->absolute_pc, &mi, &s); 280 if (mi) { 281 symbol->relative_pc = frame->absolute_pc - mi->start; 282 if (mi->name[0]) { 283 symbol->map_name = strdup(mi->name); 284 } 285 } 286 if (s) { 287 symbol->relative_symbol_addr = s->start; 288 symbol->symbol_name = strdup(s->name); 289 symbol->demangled_name = demangle_symbol_name(symbol->symbol_name); 290 } 291 } 292} 293 294void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames) { 295 for (size_t i = 0; i < frames; i++) { 296 backtrace_symbol_t* symbol = &backtrace_symbols[i]; 297 free(symbol->map_name); 298 free(symbol->symbol_name); 299 free(symbol->demangled_name); 300 init_backtrace_symbol(symbol, 0); 301 } 302} 303 304void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame __attribute__((unused)), 305 const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize) { 306 const char* mapName = symbol->map_name ? symbol->map_name : "<unknown>"; 307 const char* symbolName = symbol->demangled_name ? symbol->demangled_name : symbol->symbol_name; 308 size_t fieldWidth = (bufferSize - 80) / 2; 309 if (symbolName) { 310 uint32_t pc_offset = symbol->relative_pc - symbol->relative_symbol_addr; 311 if (pc_offset) { 312 snprintf(buffer, bufferSize, "#%02d pc %08x %.*s (%.*s+%u)", 313 frameNumber, symbol->relative_pc, fieldWidth, mapName, 314 fieldWidth, symbolName, pc_offset); 315 } else { 316 snprintf(buffer, bufferSize, "#%02d pc %08x %.*s (%.*s)", 317 frameNumber, symbol->relative_pc, fieldWidth, mapName, 318 fieldWidth, symbolName); 319 } 320 } else { 321 snprintf(buffer, bufferSize, "#%02d pc %08x %.*s", 322 frameNumber, symbol->relative_pc, fieldWidth, mapName); 323 } 324} 325