UnwindCurrent.cpp revision 20303f856f1f1cdb5af58af0b116b8c598f0ea5c
1/* 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 30// Define the ucontext_t structures needed for each supported arch. 31#if defined(__arm__) 32 // The current version of the <signal.h> doesn't define ucontext_t. 33 #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; 43#elif defined(__i386__) 44 #include <asm/sigcontext.h> 45 #include <asm/ucontext.h> 46 typedef struct ucontext ucontext_t; 47#elif !defined(__mips__) 48 #error Unsupported architecture. 49#endif 50 51//------------------------------------------------------------------------- 52// UnwindCurrent functions. 53//------------------------------------------------------------------------- 54UnwindCurrent::UnwindCurrent() { 55} 56 57UnwindCurrent::~UnwindCurrent() { 58} 59 60bool UnwindCurrent::Unwind(size_t num_ignore_frames) { 61 int ret = unw_getcontext(&context_); 62 if (ret < 0) { 63 BACK_LOGW("unw_getcontext failed %d", ret); 64 return false; 65 } 66 return UnwindFromContext(num_ignore_frames, true); 67} 68 69std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { 70 *offset = 0; 71 char buf[512]; 72 unw_word_t value; 73 if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf), 74 &value, &context_) >= 0 && buf[0] != '\0') { 75 *offset = static_cast<uintptr_t>(value); 76 return buf; 77 } 78 return ""; 79} 80 81bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) { 82 backtrace_t* backtrace = GetBacktraceData(); 83 backtrace->num_frames = 0; 84 85 // The cursor structure is pretty large, do not put it on the stack. 86 unw_cursor_t* cursor = new unw_cursor_t; 87 int ret = unw_init_local(cursor, &context_); 88 if (ret < 0) { 89 BACK_LOGW("unw_init_local failed %d", ret); 90 delete cursor; 91 return false; 92 } 93 94 do { 95 unw_word_t pc; 96 ret = unw_get_reg(cursor, UNW_REG_IP, &pc); 97 if (ret < 0) { 98 BACK_LOGW("Failed to read IP %d", ret); 99 break; 100 } 101 unw_word_t sp; 102 ret = unw_get_reg(cursor, UNW_REG_SP, &sp); 103 if (ret < 0) { 104 BACK_LOGW("Failed to read SP %d", ret); 105 break; 106 } 107 108 if (num_ignore_frames == 0) { 109 size_t num_frames = backtrace->num_frames; 110 backtrace_frame_data_t* frame = &backtrace->frames[num_frames]; 111 frame->num = num_frames; 112 frame->pc = static_cast<uintptr_t>(pc); 113 frame->sp = static_cast<uintptr_t>(sp); 114 frame->stack_size = 0; 115 frame->map_name = NULL; 116 frame->map_offset = 0; 117 frame->func_name = NULL; 118 frame->func_offset = 0; 119 120 if (num_frames > 0) { 121 // Set the stack size for the previous frame. 122 backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1]; 123 prev->stack_size = frame->sp - prev->sp; 124 } 125 126 if (resolve) { 127 std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); 128 if (!func_name.empty()) { 129 frame->func_name = strdup(func_name.c_str()); 130 } 131 132 uintptr_t map_start; 133 frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start); 134 if (frame->map_name) { 135 frame->map_offset = frame->pc - map_start; 136 } 137 } 138 139 backtrace->num_frames++; 140 } else { 141 num_ignore_frames--; 142 } 143 ret = unw_step (cursor); 144 } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES); 145 146 delete cursor; 147 return true; 148} 149 150void UnwindCurrent::ExtractContext(void* sigcontext) { 151 unw_tdep_context_t* context = reinterpret_cast<unw_tdep_context_t*>(&context_); 152 const ucontext_t* uc = reinterpret_cast<const ucontext_t*>(sigcontext); 153 154#if defined(__arm__) 155 context->regs[0] = uc->uc_mcontext.arm_r0; 156 context->regs[1] = uc->uc_mcontext.arm_r1; 157 context->regs[2] = uc->uc_mcontext.arm_r2; 158 context->regs[3] = uc->uc_mcontext.arm_r3; 159 context->regs[4] = uc->uc_mcontext.arm_r4; 160 context->regs[5] = uc->uc_mcontext.arm_r5; 161 context->regs[6] = uc->uc_mcontext.arm_r6; 162 context->regs[7] = uc->uc_mcontext.arm_r7; 163 context->regs[8] = uc->uc_mcontext.arm_r8; 164 context->regs[9] = uc->uc_mcontext.arm_r9; 165 context->regs[10] = uc->uc_mcontext.arm_r10; 166 context->regs[11] = uc->uc_mcontext.arm_fp; 167 context->regs[12] = uc->uc_mcontext.arm_ip; 168 context->regs[13] = uc->uc_mcontext.arm_sp; 169 context->regs[14] = uc->uc_mcontext.arm_lr; 170 context->regs[15] = uc->uc_mcontext.arm_pc; 171#elif defined(__mips__) || defined(__i386__) 172 context->uc_mcontext = uc->uc_mcontext; 173#endif 174} 175 176//------------------------------------------------------------------------- 177// UnwindThread functions. 178//------------------------------------------------------------------------- 179UnwindThread::UnwindThread() { 180} 181 182UnwindThread::~UnwindThread() { 183} 184 185bool UnwindThread::Init() { 186 return true; 187} 188 189void UnwindThread::ThreadUnwind( 190 siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) { 191 ExtractContext(sigcontext); 192 UnwindFromContext(num_ignore_frames, false); 193} 194 195//------------------------------------------------------------------------- 196// C++ object creation function. 197//------------------------------------------------------------------------- 198Backtrace* CreateCurrentObj(backtrace_map_info_t* map_info) { 199 return new BacktraceCurrent(new UnwindCurrent(), map_info); 200} 201 202Backtrace* CreateThreadObj(pid_t tid, backtrace_map_info_t* map_info) { 203 UnwindThread* thread_obj = new UnwindThread(); 204 return new BacktraceThread(thread_obj, thread_obj, tid, map_info); 205} 206