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