Home | History | Annotate | Download | only in libbacktrace
      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 #include <stdint.h>
     18 #include <ucontext.h>
     19 
     20 #include <memory>
     21 #include <string>
     22 
     23 #define UNW_LOCAL_ONLY
     24 #include <libunwind.h>
     25 
     26 #include <backtrace/Backtrace.h>
     27 
     28 #include "BacktraceLog.h"
     29 #include "UnwindCurrent.h"
     30 
     31 std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
     32   *offset = 0;
     33   char buf[512];
     34   unw_word_t value;
     35   if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
     36                               &value, &context_) >= 0 && buf[0] != '\0') {
     37     *offset = static_cast<uintptr_t>(value);
     38     return buf;
     39   }
     40   return "";
     41 }
     42 
     43 void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) {
     44   unw_tdep_context_t* unw_context = reinterpret_cast<unw_tdep_context_t*>(&context_);
     45 
     46 #if defined(__arm__)
     47   unw_context->regs[0] = ucontext->uc_mcontext.arm_r0;
     48   unw_context->regs[1] = ucontext->uc_mcontext.arm_r1;
     49   unw_context->regs[2] = ucontext->uc_mcontext.arm_r2;
     50   unw_context->regs[3] = ucontext->uc_mcontext.arm_r3;
     51   unw_context->regs[4] = ucontext->uc_mcontext.arm_r4;
     52   unw_context->regs[5] = ucontext->uc_mcontext.arm_r5;
     53   unw_context->regs[6] = ucontext->uc_mcontext.arm_r6;
     54   unw_context->regs[7] = ucontext->uc_mcontext.arm_r7;
     55   unw_context->regs[8] = ucontext->uc_mcontext.arm_r8;
     56   unw_context->regs[9] = ucontext->uc_mcontext.arm_r9;
     57   unw_context->regs[10] = ucontext->uc_mcontext.arm_r10;
     58   unw_context->regs[11] = ucontext->uc_mcontext.arm_fp;
     59   unw_context->regs[12] = ucontext->uc_mcontext.arm_ip;
     60   unw_context->regs[13] = ucontext->uc_mcontext.arm_sp;
     61   unw_context->regs[14] = ucontext->uc_mcontext.arm_lr;
     62   unw_context->regs[15] = ucontext->uc_mcontext.arm_pc;
     63 #else
     64   unw_context->uc_mcontext = ucontext->uc_mcontext;
     65 #endif
     66 }
     67 
     68 bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
     69   if (ucontext == nullptr) {
     70     int ret = unw_getcontext(&context_);
     71     if (ret < 0) {
     72       BACK_LOGW("unw_getcontext failed %d", ret);
     73       error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
     74       return false;
     75     }
     76   } else {
     77     GetUnwContextFromUcontext(ucontext);
     78   }
     79 
     80   // The cursor structure is pretty large, do not put it on the stack.
     81   std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
     82   int ret = unw_init_local(cursor.get(), &context_);
     83   if (ret < 0) {
     84     BACK_LOGW("unw_init_local failed %d", ret);
     85     error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
     86     return false;
     87   }
     88 
     89   size_t num_frames = 0;
     90   do {
     91     unw_word_t pc;
     92     ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc);
     93     if (ret < 0) {
     94       BACK_LOGW("Failed to read IP %d", ret);
     95       break;
     96     }
     97     unw_word_t sp;
     98     ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp);
     99     if (ret < 0) {
    100       BACK_LOGW("Failed to read SP %d", ret);
    101       break;
    102     }
    103 
    104     frames_.resize(num_frames+1);
    105     backtrace_frame_data_t* frame = &frames_.at(num_frames);
    106     frame->num = num_frames;
    107     frame->pc = static_cast<uintptr_t>(pc);
    108     frame->sp = static_cast<uintptr_t>(sp);
    109     frame->stack_size = 0;
    110 
    111     FillInMap(frame->pc, &frame->map);
    112     // Check to see if we should skip this frame because it's coming
    113     // from within the library, and we are doing a local unwind.
    114     if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) {
    115       if (num_ignore_frames == 0) {
    116         // GetFunctionName is an expensive call, only do it if we are
    117         // keeping the frame.
    118         frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
    119         if (num_frames > 0) {
    120           // Set the stack size for the previous frame.
    121           backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
    122           prev->stack_size = frame->sp - prev->sp;
    123         }
    124         num_frames++;
    125       } else {
    126         num_ignore_frames--;
    127       }
    128     }
    129     ret = unw_step (cursor.get());
    130   } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
    131 
    132   return true;
    133 }
    134