Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2017 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 <cxxabi.h>
     18 #include <dlfcn.h>
     19 #include <signal.h>
     20 #include <stdint.h>
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <sys/syscall.h>
     25 #include <sys/types.h>
     26 #include <unistd.h>
     27 #include <unwind.h>
     28 
     29 #include "perfetto/base/build_config.h"
     30 
     31 // Some glibc headers hit this when using signals.
     32 #pragma GCC diagnostic push
     33 #if defined(__clang__)
     34 #pragma GCC diagnostic ignored "-Wdisabled-macro-expansion"
     35 #endif
     36 
     37 #if defined(NDEBUG)
     38 #error This translation unit should not be used in release builds
     39 #endif
     40 
     41 #if PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD) || \
     42     PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
     43 #error This translation unit should not be used in non-standalone builds
     44 #endif
     45 
     46 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
     47     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
     48 #include <backtrace.h>
     49 #endif
     50 
     51 namespace {
     52 
     53 constexpr size_t kDemangledNameLen = 4096;
     54 
     55 bool g_sighandler_registered = false;
     56 char* g_demangled_name = nullptr;
     57 
     58 struct SigHandler {
     59   int sig_num;
     60   struct sigaction old_handler;
     61 };
     62 
     63 SigHandler g_signals[] = {{SIGSEGV, {}}, {SIGILL, {}}, {SIGTRAP, {}},
     64                           {SIGABRT, {}}, {SIGBUS, {}}, {SIGFPE, {}}};
     65 
     66 template <typename T>
     67 void Print(const T& str) {
     68   write(STDERR_FILENO, str, sizeof(str));
     69 }
     70 
     71 template <typename T>
     72 void PrintHex(T n) {
     73   for (unsigned i = 0; i < sizeof(n) * 8; i += 4) {
     74     char nibble = static_cast<char>(n >> (sizeof(n) * 8 - i - 4)) & 0x0F;
     75     char c = (nibble < 10) ? '0' + nibble : 'A' + nibble - 10;
     76     write(STDERR_FILENO, &c, 1);
     77   }
     78 }
     79 
     80 struct StackCrawlState {
     81   StackCrawlState(uintptr_t* frames_arg, size_t max_depth_arg)
     82       : frames(frames_arg),
     83         frame_count(0),
     84         max_depth(max_depth_arg),
     85         skip_count(1) {}
     86 
     87   uintptr_t* frames;
     88   size_t frame_count;
     89   size_t max_depth;
     90   size_t skip_count;
     91 };
     92 
     93 _Unwind_Reason_Code TraceStackFrame(_Unwind_Context* context, void* arg) {
     94   StackCrawlState* state = static_cast<StackCrawlState*>(arg);
     95   uintptr_t ip = _Unwind_GetIP(context);
     96 
     97   if (ip != 0 && state->skip_count) {
     98     state->skip_count--;
     99     return _URC_NO_REASON;
    100   }
    101 
    102   state->frames[state->frame_count++] = ip;
    103   if (state->frame_count >= state->max_depth)
    104     return _URC_END_OF_STACK;
    105   return _URC_NO_REASON;
    106 }
    107 
    108 // Note: use only async-safe functions inside this.
    109 void SignalHandler(int sig_num, siginfo_t* info, void* /*ucontext*/) {
    110   // Restore the old handlers.
    111   for (size_t i = 0; i < sizeof(g_signals) / sizeof(g_signals[0]); i++)
    112     sigaction(g_signals[i].sig_num, &g_signals[i].old_handler, nullptr);
    113 
    114   Print("\n------------------ BEGINNING OF CRASH ------------------\n");
    115   Print("Signal: ");
    116   if (sig_num == SIGSEGV) {
    117     Print("Segmentation fault");
    118   } else if (sig_num == SIGILL) {
    119     Print("Illegal instruction (possibly unaligned access)");
    120   } else if (sig_num == SIGTRAP) {
    121     Print("Trap");
    122   } else if (sig_num == SIGABRT) {
    123     Print("Abort");
    124   } else if (sig_num == SIGBUS) {
    125     Print("Bus Error (possibly unmapped memory access)");
    126   } else if (sig_num == SIGFPE) {
    127     Print("Floating point exception");
    128   } else {
    129     Print("Unexpected signal ");
    130     PrintHex(static_cast<uint32_t>(sig_num));
    131   }
    132 
    133   Print("\n");
    134 
    135   Print("Fault addr: ");
    136   PrintHex(reinterpret_cast<uintptr_t>(info->si_addr));
    137   Print("\n\nBacktrace:\n");
    138 
    139   const size_t kMaxFrames = 64;
    140   uintptr_t frames[kMaxFrames];
    141   StackCrawlState unwind_state(frames, kMaxFrames);
    142   _Unwind_Backtrace(&TraceStackFrame, &unwind_state);
    143 
    144 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
    145     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
    146   auto bt_error = [](void*, const char* msg, int) { Print(msg); };
    147   struct backtrace_state* bt_state =
    148       backtrace_create_state(nullptr, 0, bt_error, nullptr);
    149 #endif
    150 
    151   for (uint8_t i = 0; i < unwind_state.frame_count; i++) {
    152     struct SymbolInfo {
    153       char sym_name[255];
    154       char file_name[255];
    155     };
    156     SymbolInfo sym{{}, {}};
    157 
    158 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
    159     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
    160     auto symbolize_callback = [](void* data, uintptr_t /*pc*/,
    161                                  const char* filename, int lineno,
    162                                  const char* function) -> int {
    163       SymbolInfo* psym = reinterpret_cast<SymbolInfo*>(data);
    164       if (function)
    165         strncpy(psym->sym_name, function, sizeof(psym->sym_name));
    166       if (filename) {
    167         snprintf(psym->file_name, sizeof(psym->file_name), "%s:%d", filename,
    168                  lineno);
    169       }
    170       return 0;
    171     };
    172     backtrace_pcinfo(bt_state, frames[i], symbolize_callback, bt_error, &sym);
    173 #else
    174     Dl_info dl_info = {};
    175     int res = dladdr(reinterpret_cast<void*>(frames[i]), &dl_info);
    176     if (res && dl_info.dli_sname)
    177       strncpy(sym.sym_name, dl_info.dli_sname, sizeof(sym.sym_name));
    178 #endif
    179 
    180     Print("\n#");
    181     PrintHex(i);
    182     Print("  ");
    183 
    184     if (sym.sym_name[0]) {
    185       int ignored;
    186       size_t len = kDemangledNameLen;
    187       char* demangled =
    188           abi::__cxa_demangle(sym.sym_name, g_demangled_name, &len, &ignored);
    189       if (demangled) {
    190         strncpy(sym.sym_name, demangled, sizeof(sym.sym_name));
    191         // In the exceptional case of demangling something > kDemangledNameLen,
    192         // __cxa_demangle will realloc(). In that case the malloc()-ed pointer
    193         // might be moved.
    194         g_demangled_name = demangled;
    195       }
    196       write(STDERR_FILENO, sym.sym_name, strlen(sym.sym_name));
    197     } else {
    198       Print("0x");
    199       PrintHex(frames[i]);
    200     }
    201     if (sym.file_name[0]) {
    202       Print("\n     ");
    203       write(STDERR_FILENO, sym.file_name, strlen(sym.file_name));
    204     }
    205     Print("\n");
    206   }
    207 
    208   Print("------------------ END OF CRASH ------------------\n");
    209 
    210   // info->si_code <= 0 iff SI_FROMUSER (SI_FROMKERNEL otherwise).
    211   if (info->si_code <= 0 || sig_num == SIGABRT) {
    212 // This signal was triggered by somebody sending us the signal with kill().
    213 // In order to retrigger it, we have to queue a new signal by calling
    214 // kill() ourselves.  The special case (si_pid == 0 && sig == SIGABRT) is
    215 // due to the kernel sending a SIGABRT from a user request via SysRQ.
    216 #if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
    217     if (kill(getpid(), sig_num) < 0) {
    218 #else
    219     if (syscall(__NR_tgkill, getpid(), syscall(__NR_gettid), sig_num) < 0) {
    220 #endif
    221       // If we failed to kill ourselves (e.g. because a sandbox disallows us
    222       // to do so), we instead resort to terminating our process. This will
    223       // result in an incorrect exit code.
    224       _exit(1);
    225     }
    226   }
    227 }
    228 
    229 // __attribute__((constructor)) causes a static initializer that automagically
    230 // early runs this function before the main().
    231 void __attribute__((constructor)) EnableStacktraceOnCrashForDebug();
    232 
    233 void EnableStacktraceOnCrashForDebug() {
    234   if (g_sighandler_registered)
    235     return;
    236   g_sighandler_registered = true;
    237 
    238   // Pre-allocate the string for __cxa_demangle() to reduce the risk of that
    239   // invoking realloc() within the signal handler.
    240   g_demangled_name = reinterpret_cast<char*>(malloc(kDemangledNameLen));
    241   struct sigaction sigact = {};
    242   sigact.sa_sigaction = &SignalHandler;
    243   sigact.sa_flags = static_cast<decltype(sigact.sa_flags)>(
    244       SA_RESTART | SA_SIGINFO | SA_RESETHAND);
    245   for (size_t i = 0; i < sizeof(g_signals) / sizeof(g_signals[0]); i++)
    246     sigaction(g_signals[i].sig_num, &sigact, &g_signals[i].old_handler);
    247 }
    248 
    249 }  // namespace
    250 
    251 #pragma GCC diagnostic pop
    252