Home | History | Annotate | Download | only in debug
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/debug/stack_trace.h"
      6 
      7 #include <string.h>
      8 
      9 #include <algorithm>
     10 #include <sstream>
     11 
     12 #include "base/macros.h"
     13 
     14 #if HAVE_TRACE_STACK_FRAME_POINTERS && defined(OS_ANDROID)
     15 #include <pthread.h>
     16 #include "base/process/process_handle.h"
     17 #include "base/threading/platform_thread.h"
     18 #endif
     19 
     20 namespace base {
     21 namespace debug {
     22 
     23 StackTrace::StackTrace(const void* const* trace, size_t count) {
     24   count = std::min(count, arraysize(trace_));
     25   if (count)
     26     memcpy(trace_, trace, count * sizeof(trace_[0]));
     27   count_ = count;
     28 }
     29 
     30 StackTrace::~StackTrace() {
     31 }
     32 
     33 const void *const *StackTrace::Addresses(size_t* count) const {
     34   *count = count_;
     35   if (count_)
     36     return trace_;
     37   return NULL;
     38 }
     39 
     40 std::string StackTrace::ToString() const {
     41   std::stringstream stream;
     42 #if !defined(__UCLIBC__)
     43   OutputToStream(&stream);
     44 #endif
     45   return stream.str();
     46 }
     47 
     48 #if HAVE_TRACE_STACK_FRAME_POINTERS
     49 
     50 #if defined(OS_ANDROID)
     51 
     52 static uintptr_t GetStackEnd() {
     53   // Bionic reads proc/maps on every call to pthread_getattr_np() when called
     54   // from the main thread. So we need to cache end of stack in that case to get
     55   // acceptable performance.
     56   // For all other threads pthread_getattr_np() is fast enough as it just reads
     57   // values from its pthread_t argument.
     58   static uintptr_t main_stack_end = 0;
     59 
     60   bool is_main_thread = GetCurrentProcId() == PlatformThread::CurrentId();
     61 
     62   if (is_main_thread && main_stack_end) {
     63     return main_stack_end;
     64   }
     65 
     66   uintptr_t stack_begin = 0;
     67   size_t stack_size = 0;
     68   pthread_attr_t attributes;
     69   int error = pthread_getattr_np(pthread_self(), &attributes);
     70   if (!error) {
     71     error = pthread_attr_getstack(
     72         &attributes,
     73         reinterpret_cast<void**>(&stack_begin),
     74         &stack_size);
     75     pthread_attr_destroy(&attributes);
     76   }
     77   DCHECK(!error);
     78 
     79   uintptr_t stack_end = stack_begin + stack_size;
     80   if (is_main_thread) {
     81     main_stack_end = stack_end;
     82   }
     83   return stack_end;
     84 }
     85 
     86 #endif  // defined(OS_ANDROID)
     87 
     88 size_t TraceStackFramePointers(const void** out_trace,
     89                                size_t max_depth,
     90                                size_t skip_initial) {
     91   // Usage of __builtin_frame_address() enables frame pointers in this
     92   // function even if they are not enabled globally. So 'sp' will always
     93   // be valid.
     94   uintptr_t sp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
     95 
     96 #if defined(OS_ANDROID)
     97   uintptr_t stack_end = GetStackEnd();
     98 #endif
     99 
    100   size_t depth = 0;
    101   while (depth < max_depth) {
    102 #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__)
    103     // GCC and LLVM generate slightly different frames on ARM, see
    104     // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates
    105     // x86-compatible frame, while GCC needs adjustment.
    106     sp -= sizeof(uintptr_t);
    107 #endif
    108 
    109 #if defined(OS_ANDROID)
    110     // Both sp[0] and s[1] must be valid.
    111     if (sp + 2 * sizeof(uintptr_t) > stack_end) {
    112       break;
    113     }
    114 #endif
    115 
    116     if (skip_initial != 0) {
    117       skip_initial--;
    118     } else {
    119       out_trace[depth++] = reinterpret_cast<const void**>(sp)[1];
    120     }
    121 
    122     // Find out next frame pointer
    123     // (heuristics are from TCMalloc's stacktrace functions)
    124     {
    125       uintptr_t next_sp = reinterpret_cast<const uintptr_t*>(sp)[0];
    126 
    127       // With the stack growing downwards, older stack frame must be
    128       // at a greater address that the current one.
    129       if (next_sp <= sp) break;
    130 
    131       // Assume stack frames larger than 100,000 bytes are bogus.
    132       if (next_sp - sp > 100000) break;
    133 
    134       // Check alignment.
    135       if (sp & (sizeof(void*) - 1)) break;
    136 
    137       sp = next_sp;
    138     }
    139   }
    140 
    141   return depth;
    142 }
    143 
    144 #endif  // HAVE_TRACE_STACK_FRAME_POINTERS
    145 
    146 }  // namespace debug
    147 }  // namespace base
    148