blob: b03c43fb3beab9f28f2327a411e856b7d1d23093 [file] [log] [blame]
Jeff Brown501edd22011-10-19 20:35:35 -07001/*
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
35#if HAVE_DLADDR
36#include <dlfcn.h>
37#endif
38
39typedef struct {
40 backtrace_frame_t* backtrace;
41 size_t ignore_depth;
42 size_t max_depth;
43 size_t ignored_frames;
44 size_t returned_frames;
45} backtrace_state_t;
46
47static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* context, void* arg) {
48 backtrace_state_t* state = (backtrace_state_t*)arg;
49 uintptr_t pc = _Unwind_GetIP(context);
50 if (pc) {
51 // TODO: Get information about the stack layout from the _Unwind_Context.
52 // This will require a new architecture-specific function to query
53 // the appropriate registers. Current callers of unwind_backtrace
54 // don't need this information, so we won't bother collecting it just yet.
55 add_backtrace_entry(pc, state->backtrace,
56 state->ignore_depth, state->max_depth,
57 &state->ignored_frames, &state->returned_frames);
58 }
59 return state->returned_frames < state->max_depth ? _URC_NO_REASON : _URC_END_OF_STACK;
60}
61
62ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
63 backtrace_state_t state;
64 state.backtrace = backtrace;
65 state.ignore_depth = ignore_depth;
66 state.max_depth = max_depth;
67 state.ignored_frames = 0;
68 state.returned_frames = 0;
69
70 _Unwind_Reason_Code rc =_Unwind_Backtrace(unwind_backtrace_callback, &state);
71 if (state.returned_frames) {
72 return state.returned_frames;
73 }
74 return rc == _URC_END_OF_STACK ? 0 : -1;
75}
76
77#ifdef CORKSCREW_HAVE_ARCH
78static pthread_mutex_t g_unwind_signal_mutex = PTHREAD_MUTEX_INITIALIZER;
79static volatile struct {
80 backtrace_frame_t* backtrace;
81 size_t ignore_depth;
82 size_t max_depth;
83 size_t returned_frames;
84 bool done;
85} g_unwind_signal_state;
86
87static void unwind_backtrace_thread_signal_handler(int n, siginfo_t* siginfo, void* sigcontext) {
88 backtrace_frame_t* backtrace = g_unwind_signal_state.backtrace;
89 if (backtrace) {
90 g_unwind_signal_state.backtrace = NULL;
91 g_unwind_signal_state.returned_frames = unwind_backtrace_signal_arch(
92 siginfo, sigcontext, backtrace,
93 g_unwind_signal_state.ignore_depth,
94 g_unwind_signal_state.max_depth);
95 g_unwind_signal_state.done = true;
96 }
97}
98#endif
99
100ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace,
101 size_t ignore_depth, size_t max_depth) {
102#ifdef CORKSCREW_HAVE_ARCH
103 struct sigaction act;
104 struct sigaction oact;
105 memset(&act, 0, sizeof(act));
106 act.sa_sigaction = unwind_backtrace_thread_signal_handler;
107 act.sa_flags = SA_RESTART | SA_SIGINFO;
108 sigemptyset(&act.sa_mask);
109
110 pthread_mutex_lock(&g_unwind_signal_mutex);
111
112 g_unwind_signal_state.backtrace = backtrace;
113 g_unwind_signal_state.ignore_depth = ignore_depth;
114 g_unwind_signal_state.max_depth = max_depth;
115 g_unwind_signal_state.returned_frames = 0;
116 g_unwind_signal_state.done = false;
117
118 ssize_t frames = -1;
119 if (!sigaction(SIGURG, &act, &oact)) {
120 if (!kill(tid, SIGURG)) {
121 while (!g_unwind_signal_state.done) {
122 usleep(1000);
123 }
124 frames = g_unwind_signal_state.returned_frames;
125 }
126 sigaction(SIGURG, &oact, NULL);
127 }
128
129 g_unwind_signal_state.backtrace = NULL;
130
131 pthread_mutex_unlock(&g_unwind_signal_mutex);
132 return frames;
133#else
134 return -1;
135#endif
136}
137
138ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context,
139 backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
140#ifdef CORKSCREW_HAVE_ARCH
141 return unwind_backtrace_ptrace_arch(tid, context, backtrace, ignore_depth, max_depth);
142#else
143 return -1;
144#endif
145}
146
147static void init_backtrace_symbol(backtrace_symbol_t* symbol, uintptr_t pc) {
148 symbol->relative_pc = pc;
149 symbol->map_info = NULL;
150 symbol->name = NULL;
151 symbol->demangled_name = NULL;
152}
153
154void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames,
155 backtrace_symbol_t* backtrace_symbols) {
156 const map_info_t* milist = my_map_info_list();
157 for (size_t i = 0; i < frames; i++) {
158 const backtrace_frame_t* frame = &backtrace[i];
159 backtrace_symbol_t* symbol = &backtrace_symbols[i];
160 init_backtrace_symbol(symbol, frame->absolute_pc);
161
162 const map_info_t* mi = find_map_info(milist, frame->absolute_pc);
163 if (mi) {
164 symbol->relative_pc = frame->absolute_pc - mi->start;
165 symbol->map_info = mi;
166#if HAVE_DLADDR
167 Dl_info info;
168 if (dladdr((const void*)frame->absolute_pc, &info) && info.dli_sname) {
169 symbol->name = info.dli_sname;
170 symbol->demangled_name = demangle_symbol_name(symbol->name);
171 }
172#endif
173 }
174 }
175}
176
177void get_backtrace_symbols_ptrace(const ptrace_context_t* context,
178 const backtrace_frame_t* backtrace, size_t frames,
179 backtrace_symbol_t* backtrace_symbols) {
180 for (size_t i = 0; i < frames; i++) {
181 const backtrace_frame_t* frame = &backtrace[i];
182 backtrace_symbol_t* symbol = &backtrace_symbols[i];
183 init_backtrace_symbol(symbol, frame->absolute_pc);
184
185 const map_info_t* mi;
186 const symbol_t* s;
187 find_symbol_ptrace(context, frame->absolute_pc, &mi, &s);
188 if (mi) {
189 symbol->relative_pc = frame->absolute_pc - mi->start;
190 symbol->map_info = mi;
191 }
192 if (s) {
193 symbol->name = s->name;
194 symbol->demangled_name = demangle_symbol_name(symbol->name);
195 }
196 }
197}
198
199void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames) {
200 for (size_t i = 0; i < frames; i++) {
201 backtrace_symbol_t* symbol = &backtrace_symbols[i];
202 free(symbol->demangled_name);
203 init_backtrace_symbol(symbol, 0);
204 }
205}