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