backtrace.c revision f0c5872637a63e28e3cd314cfc915c07f76df9c6
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 <pthread.h> 31#include <unwind.h> 32#include <sys/exec_elf.h> 33#include <cutils/log.h> 34#include <cutils/atomic.h> 35 36#if HAVE_DLADDR 37#include <dlfcn.h> 38#endif 39 40typedef struct { 41 backtrace_frame_t* backtrace; 42 size_t ignore_depth; 43 size_t max_depth; 44 size_t ignored_frames; 45 size_t returned_frames; 46 memory_t memory; 47} backtrace_state_t; 48 49static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* context, void* arg) { 50 backtrace_state_t* state = (backtrace_state_t*)arg; 51 uintptr_t pc = _Unwind_GetIP(context); 52 if (pc) { 53 // TODO: Get information about the stack layout from the _Unwind_Context. 54 // This will require a new architecture-specific function to query 55 // the appropriate registers. Current callers of unwind_backtrace 56 // don't need this information, so we won't bother collecting it just yet. 57 add_backtrace_entry(rewind_pc_arch(&state->memory, pc), state->backtrace, 58 state->ignore_depth, state->max_depth, 59 &state->ignored_frames, &state->returned_frames); 60 } 61 return state->returned_frames < state->max_depth ? _URC_NO_REASON : _URC_END_OF_STACK; 62} 63 64ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) { 65 ALOGV("Unwinding current thread %d.", gettid()); 66 67 map_info_t* milist = acquire_my_map_info_list(); 68 69 backtrace_state_t state; 70 state.backtrace = backtrace; 71 state.ignore_depth = ignore_depth; 72 state.max_depth = max_depth; 73 state.ignored_frames = 0; 74 state.returned_frames = 0; 75 init_memory(&state.memory, milist); 76 77 _Unwind_Reason_Code rc =_Unwind_Backtrace(unwind_backtrace_callback, &state); 78 79 release_my_map_info_list(milist); 80 81 if (state.returned_frames) { 82 return state.returned_frames; 83 } 84 return rc == _URC_END_OF_STACK ? 0 : -1; 85} 86 87#ifdef CORKSCREW_HAVE_ARCH 88static pthread_mutex_t g_unwind_signal_mutex = PTHREAD_MUTEX_INITIALIZER; 89static volatile struct { 90 int32_t tid; 91 const map_info_t* map_info_list; 92 backtrace_frame_t* backtrace; 93 size_t ignore_depth; 94 size_t max_depth; 95 size_t returned_frames; 96} g_unwind_signal_state; 97 98static void unwind_backtrace_thread_signal_handler(int n, siginfo_t* siginfo, void* sigcontext) { 99 int32_t tid = android_atomic_acquire_load(&g_unwind_signal_state.tid); 100 if (tid == gettid()) { 101 g_unwind_signal_state.returned_frames = unwind_backtrace_signal_arch( 102 siginfo, sigcontext, 103 g_unwind_signal_state.map_info_list, 104 g_unwind_signal_state.backtrace, 105 g_unwind_signal_state.ignore_depth, 106 g_unwind_signal_state.max_depth); 107 android_atomic_release_store(-1, &g_unwind_signal_state.tid); 108 } else { 109 ALOGV("Received spurious SIGURG on thread %d that was intended for thread %d.", 110 gettid(), tid); 111 } 112} 113#endif 114 115ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace, 116 size_t ignore_depth, size_t max_depth) { 117 if (tid == gettid()) { 118 return unwind_backtrace(backtrace, ignore_depth + 1, max_depth); 119 } 120 121 ALOGV("Unwinding thread %d from thread %d.", tid, gettid()); 122 123#ifdef CORKSCREW_HAVE_ARCH 124 struct sigaction act; 125 struct sigaction oact; 126 memset(&act, 0, sizeof(act)); 127 act.sa_sigaction = unwind_backtrace_thread_signal_handler; 128 act.sa_flags = SA_RESTART | SA_SIGINFO; 129 sigemptyset(&act.sa_mask); 130 131 pthread_mutex_lock(&g_unwind_signal_mutex); 132 map_info_t* milist = acquire_my_map_info_list(); 133 134 ssize_t frames = -1; 135 if (!sigaction(SIGURG, &act, &oact)) { 136 g_unwind_signal_state.map_info_list = milist; 137 g_unwind_signal_state.backtrace = backtrace; 138 g_unwind_signal_state.ignore_depth = ignore_depth; 139 g_unwind_signal_state.max_depth = max_depth; 140 g_unwind_signal_state.returned_frames = 0; 141 android_atomic_release_store(tid, &g_unwind_signal_state.tid); 142 143 if (kill(tid, SIGURG)) { 144 ALOGV("Failed to send SIGURG to thread %d.", tid); 145 android_atomic_release_store(-1, &g_unwind_signal_state.tid); 146 } else { 147 while (android_atomic_acquire_load(&g_unwind_signal_state.tid) == tid) { 148 ALOGV("Waiting for response from thread %d...", tid); 149 usleep(1000); 150 } 151 frames = g_unwind_signal_state.returned_frames; 152 } 153 154 sigaction(SIGURG, &oact, NULL); 155 } 156 157 release_my_map_info_list(milist); 158 pthread_mutex_unlock(&g_unwind_signal_mutex); 159 return frames; 160#else 161 return -1; 162#endif 163} 164 165ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context, 166 backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) { 167#ifdef CORKSCREW_HAVE_ARCH 168 return unwind_backtrace_ptrace_arch(tid, context, backtrace, ignore_depth, max_depth); 169#else 170 return -1; 171#endif 172} 173 174static void init_backtrace_symbol(backtrace_symbol_t* symbol, uintptr_t pc) { 175 symbol->relative_pc = pc; 176 symbol->map_name = NULL; 177 symbol->name = NULL; 178 symbol->demangled_name = NULL; 179} 180 181void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames, 182 backtrace_symbol_t* backtrace_symbols) { 183 map_info_t* milist = acquire_my_map_info_list(); 184 for (size_t i = 0; i < frames; i++) { 185 const backtrace_frame_t* frame = &backtrace[i]; 186 backtrace_symbol_t* symbol = &backtrace_symbols[i]; 187 init_backtrace_symbol(symbol, frame->absolute_pc); 188 189 const map_info_t* mi = find_map_info(milist, frame->absolute_pc); 190 if (mi) { 191 symbol->relative_pc = frame->absolute_pc - mi->start; 192 if (mi->name[0]) { 193 symbol->map_name = strdup(mi->name); 194 } 195#if HAVE_DLADDR 196 Dl_info info; 197 if (dladdr((const void*)frame->absolute_pc, &info) && info.dli_sname) { 198 symbol->name = strdup(info.dli_sname); 199 symbol->demangled_name = demangle_symbol_name(symbol->name); 200 } 201#endif 202 } 203 } 204 release_my_map_info_list(milist); 205} 206 207void get_backtrace_symbols_ptrace(const ptrace_context_t* context, 208 const backtrace_frame_t* backtrace, size_t frames, 209 backtrace_symbol_t* backtrace_symbols) { 210 for (size_t i = 0; i < frames; i++) { 211 const backtrace_frame_t* frame = &backtrace[i]; 212 backtrace_symbol_t* symbol = &backtrace_symbols[i]; 213 init_backtrace_symbol(symbol, frame->absolute_pc); 214 215 const map_info_t* mi; 216 const symbol_t* s; 217 find_symbol_ptrace(context, frame->absolute_pc, &mi, &s); 218 if (mi) { 219 symbol->relative_pc = frame->absolute_pc - mi->start; 220 if (mi->name[0]) { 221 symbol->map_name = strdup(mi->name); 222 } 223 } 224 if (s) { 225 symbol->name = strdup(s->name); 226 symbol->demangled_name = demangle_symbol_name(symbol->name); 227 } 228 } 229} 230 231void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames) { 232 for (size_t i = 0; i < frames; i++) { 233 backtrace_symbol_t* symbol = &backtrace_symbols[i]; 234 free(symbol->map_name); 235 free(symbol->name); 236 free(symbol->demangled_name); 237 init_backtrace_symbol(symbol, 0); 238 } 239} 240