blob: d4ba68f1834d524c964ec92764f60236e7269515 [file] [log] [blame]
Christopher Ferris17e91d42013-10-21 13:30:52 -07001/*
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#define LOG_TAG "libbacktrace"
18
19#include <sys/types.h>
20
21#include <cutils/log.h>
22
23#include <backtrace/backtrace.h>
24
25#define UNW_LOCAL_ONLY
26#include <libunwind.h>
27
28#include "UnwindCurrent.h"
29
Christopher Ferris8ed46272013-10-29 15:44:25 -070030// Define the ucontext_t structures needed for each supported arch.
Christopher Ferris17e91d42013-10-21 13:30:52 -070031#if defined(__arm__)
Christopher Ferris8ed46272013-10-29 15:44:25 -070032 // The current version of the <signal.h> doesn't define ucontext_t.
Christopher Ferris17e91d42013-10-21 13:30:52 -070033 #include <asm/sigcontext.h> // Ensure 'struct sigcontext' is defined.
34
35 // Machine context at the time a signal was raised.
36 typedef struct ucontext {
37 uint32_t uc_flags;
38 struct ucontext* uc_link;
39 stack_t uc_stack;
40 struct sigcontext uc_mcontext;
41 uint32_t uc_sigmask;
42 } ucontext_t;
Christopher Ferris8ed46272013-10-29 15:44:25 -070043#elif defined(__mips__)
44 typedef struct ucontext {
45 uint32_t sp;
46 uint32_t ra;
47 uint32_t pc;
48 } ucontext_t;
49#elif defined(__i386__)
50 #include <asm/sigcontext.h>
51 #include <asm/ucontext.h>
52 typedef struct ucontext ucontext_t;
53#else
54 #error Unsupported architecture.
55#endif
Christopher Ferris17e91d42013-10-21 13:30:52 -070056
57//-------------------------------------------------------------------------
58// UnwindCurrent functions.
59//-------------------------------------------------------------------------
60UnwindCurrent::UnwindCurrent() {
61}
62
63UnwindCurrent::~UnwindCurrent() {
64}
65
66bool UnwindCurrent::Unwind(size_t num_ignore_frames) {
67 int ret = unw_getcontext(&context_);
68 if (ret < 0) {
Christopher Ferris8ed46272013-10-29 15:44:25 -070069 BACK_LOGW("unw_getcontext failed %d", ret);
Christopher Ferris17e91d42013-10-21 13:30:52 -070070 return false;
71 }
72 return UnwindFromContext(num_ignore_frames, true);
73}
74
75std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
76 *offset = 0;
77 char buf[512];
78 unw_word_t value;
79 if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
80 &value, &context_) >= 0 && buf[0] != '\0') {
81 *offset = static_cast<uintptr_t>(value);
82 return buf;
83 }
84 return "";
85}
86
87bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) {
88 backtrace_t* backtrace = GetBacktraceData();
89 backtrace->num_frames = 0;
90
91 // The cursor structure is pretty large, do not put it on the stack.
92 unw_cursor_t* cursor = new unw_cursor_t;
93 int ret = unw_init_local(cursor, &context_);
94 if (ret < 0) {
Christopher Ferris8ed46272013-10-29 15:44:25 -070095 BACK_LOGW("unw_init_local failed %d", ret);
Christopher Ferris17e91d42013-10-21 13:30:52 -070096 return false;
97 }
98
99 do {
100 unw_word_t pc;
101 ret = unw_get_reg(cursor, UNW_REG_IP, &pc);
102 if (ret < 0) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700103 BACK_LOGW("Failed to read IP %d", ret);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700104 break;
105 }
106 unw_word_t sp;
107 ret = unw_get_reg(cursor, UNW_REG_SP, &sp);
108 if (ret < 0) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700109 BACK_LOGW("Failed to read SP %d", ret);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700110 break;
111 }
112
113 if (num_ignore_frames == 0) {
114 size_t num_frames = backtrace->num_frames;
115 backtrace_frame_data_t* frame = &backtrace->frames[num_frames];
116 frame->pc = static_cast<uintptr_t>(pc);
117 frame->sp = static_cast<uintptr_t>(sp);
118 frame->stack_size = 0;
119 frame->map_name = NULL;
120 frame->map_offset = 0;
121 frame->func_name = NULL;
122 frame->func_offset = 0;
123
124 if (num_frames > 0) {
125 // Set the stack size for the previous frame.
126 backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1];
127 prev->stack_size = frame->sp - prev->sp;
128 }
129
130 if (resolve) {
131 std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
132 if (!func_name.empty()) {
133 frame->func_name = strdup(func_name.c_str());
134 }
135
136 uintptr_t map_start;
137 frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
138 if (frame->map_name) {
139 frame->map_offset = frame->pc - map_start;
140 }
141 }
142
143 backtrace->num_frames++;
144 } else {
145 num_ignore_frames--;
146 }
147 ret = unw_step (cursor);
148 } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
149
150 delete cursor;
151 return true;
152}
153
154void UnwindCurrent::ExtractContext(void* sigcontext) {
155 unw_tdep_context_t* context = reinterpret_cast<unw_tdep_context_t*>(&context_);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700156 const ucontext_t* uc = reinterpret_cast<const ucontext_t*>(sigcontext);
157
Christopher Ferris8ed46272013-10-29 15:44:25 -0700158#if defined(__arm__)
Christopher Ferris17e91d42013-10-21 13:30:52 -0700159 context->regs[0] = uc->uc_mcontext.arm_r0;
160 context->regs[1] = uc->uc_mcontext.arm_r1;
161 context->regs[2] = uc->uc_mcontext.arm_r2;
162 context->regs[3] = uc->uc_mcontext.arm_r3;
163 context->regs[4] = uc->uc_mcontext.arm_r4;
164 context->regs[5] = uc->uc_mcontext.arm_r5;
165 context->regs[6] = uc->uc_mcontext.arm_r6;
166 context->regs[7] = uc->uc_mcontext.arm_r7;
167 context->regs[8] = uc->uc_mcontext.arm_r8;
168 context->regs[9] = uc->uc_mcontext.arm_r9;
169 context->regs[10] = uc->uc_mcontext.arm_r10;
170 context->regs[11] = uc->uc_mcontext.arm_fp;
171 context->regs[12] = uc->uc_mcontext.arm_ip;
172 context->regs[13] = uc->uc_mcontext.arm_sp;
173 context->regs[14] = uc->uc_mcontext.arm_lr;
174 context->regs[15] = uc->uc_mcontext.arm_pc;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700175#elif defined(__mips__)
Christopher Ferris17e91d42013-10-21 13:30:52 -0700176 context->uc_mcontext.sp = uc->sp;
177 context->uc_mcontext.pc = uc->pc;
178 context->uc_mcontext.ra = uc->ra;
Christopher Ferris8ed46272013-10-29 15:44:25 -0700179#elif defined(__i386__)
Christopher Ferris17e91d42013-10-21 13:30:52 -0700180 context->uc_mcontext.gregs[REG_EBP] = uc->uc_mcontext.gregs[REG_EBP];
181 context->uc_mcontext.gregs[REG_ESP] = uc->uc_mcontext.gregs[REG_ESP];
182 context->uc_mcontext.gregs[REG_EIP] = uc->uc_mcontext.gregs[REG_EIP];
183#endif
184}
185
186//-------------------------------------------------------------------------
187// UnwindThread functions.
188//-------------------------------------------------------------------------
189UnwindThread::UnwindThread() {
190}
191
192UnwindThread::~UnwindThread() {
193}
194
195bool UnwindThread::Init() {
196 return true;
197}
198
199void UnwindThread::ThreadUnwind(
200 siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) {
201 ExtractContext(sigcontext);
202 UnwindFromContext(num_ignore_frames, false);
203}
204
205//-------------------------------------------------------------------------
206// C++ object creation function.
207//-------------------------------------------------------------------------
208Backtrace* CreateCurrentObj() {
209 return new BacktraceCurrent(new UnwindCurrent());
210}
211
212Backtrace* CreateThreadObj(pid_t tid) {
213 UnwindThread* thread_obj = new UnwindThread();
214 return new BacktraceThread(thread_obj, thread_obj, tid);
215}