Merge "Fix gcc build"
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 000579e..4b1a210 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -26,6 +26,12 @@
     "weak_ptr.h",
   ]
 
+  if (is_debug) {
+    deps = [
+      ":debug_crash_stack_trace",
+    ]
+  }
+
   if (target_os == "android") {
     sources += [
       "android_task_runner.cc",
@@ -35,6 +41,18 @@
   }
 }
 
+if (is_debug) {
+  source_set("debug_crash_stack_trace") {
+    sources = [
+      "debug_crash_stack_trace.cc",
+    ]
+    cflags = [
+      "-Wno-deprecated-dynamic-exception-spec",
+      "-Wno-disabled-macro-expansion",
+    ]
+  }
+}
+
 source_set("test_support") {
   testonly = true
   deps += [ ":base" ]
diff --git a/base/debug_crash_stack_trace.cc b/base/debug_crash_stack_trace.cc
new file mode 100644
index 0000000..2f729c1
--- /dev/null
+++ b/base/debug_crash_stack_trace.cc
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cxxabi.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <unwind.h>
+
+#if defined(NDEBUG)
+#error This translation unit should not be used in release builds
+#endif
+
+namespace {
+
+constexpr size_t kDemangledNameLen = 4096;
+
+bool g_sighandler_registered = false;
+char* g_demangled_name = nullptr;
+
+struct SigHandler {
+  int sig_num;
+  struct sigaction old_handler;
+};
+
+SigHandler g_signals[] = {{SIGSEGV}, {SIGILL}, {SIGTRAP},
+                          {SIGABRT}, {SIGBUS}, {SIGFPE}};
+
+template <typename T>
+void Print(const T& str) {
+  write(STDERR_FILENO, str, sizeof(str));
+}
+
+template <typename T>
+void PrintHex(T n) {
+  for (unsigned i = 0; i < sizeof(n) * 8; i += 4) {
+    char nibble = static_cast<char>(n >> (sizeof(n) * 8 - i - 4)) & 0x0F;
+    char c = (nibble < 10) ? '0' + nibble : 'A' + nibble - 10;
+    write(STDERR_FILENO, &c, 1);
+  }
+}
+
+struct StackCrawlState {
+  StackCrawlState(uintptr_t* frames_arg, size_t max_depth_arg)
+      : frames(frames_arg),
+        frame_count(0),
+        max_depth(max_depth_arg),
+        skip_count(1) {}
+
+  uintptr_t* frames;
+  size_t frame_count;
+  size_t max_depth;
+  size_t skip_count;
+};
+
+_Unwind_Reason_Code TraceStackFrame(_Unwind_Context* context, void* arg) {
+  StackCrawlState* state = static_cast<StackCrawlState*>(arg);
+  uintptr_t ip = _Unwind_GetIP(context);
+
+  if (ip != 0 && state->skip_count) {
+    state->skip_count--;
+    return _URC_NO_REASON;
+  }
+
+  state->frames[state->frame_count++] = ip;
+  if (state->frame_count >= state->max_depth)
+    return _URC_END_OF_STACK;
+  return _URC_NO_REASON;
+}
+
+// Note: use only async-safe functions inside this.
+void SignalHandler(int sig_num, siginfo_t* info, void* ucontext) {
+  // Restore the old handlers.
+  for (size_t i = 0; i < sizeof(g_signals) / sizeof(g_signals[0]); i++)
+    sigaction(g_signals[i].sig_num, &g_signals[i].old_handler, nullptr);
+
+  Print("\n------------------ BEGINNING OF CRASH ------------------\n");
+  Print("Signal: ");
+  if (sig_num == SIGSEGV) {
+    Print("Segmentation fault");
+  } else if (sig_num == SIGILL) {
+    Print("Illegal instruction (possibly unaligned access)");
+  } else if (sig_num == SIGTRAP) {
+    Print("Trap");
+  } else if (sig_num == SIGABRT) {
+    Print("Abort");
+  } else if (sig_num == SIGBUS) {
+    Print("Bus Error (possibly unmapped memory access)");
+  } else if (sig_num == SIGFPE) {
+    Print("Floating point exception");
+  } else {
+    Print("Unexpected signal ");
+    PrintHex(static_cast<uint32_t>(sig_num));
+  }
+
+  Print("\n");
+
+  Print("Fault addr: ");
+  PrintHex(reinterpret_cast<uintptr_t>(info->si_addr));
+  Print("\n\nBacktrace:\n");
+
+  const size_t kMaxFrames = 32;
+  uintptr_t frames[kMaxFrames];
+  StackCrawlState unwind_state(frames, kMaxFrames);
+  _Unwind_Backtrace(&TraceStackFrame, &unwind_state);
+
+  for (uint8_t i = 0; i < unwind_state.frame_count; i++) {
+    Dl_info sym_info = {};
+    int res = dladdr(reinterpret_cast<void*>(frames[i]), &sym_info);
+    Print("\n#");
+    PrintHex(i);
+    Print("  ");
+    if (res) {
+      const char* sym_name = sym_info.dli_sname;
+      int ignored;
+      size_t len = kDemangledNameLen;
+      char* demangled = abi::__cxa_demangle(sym_info.dli_sname,
+                                            g_demangled_name, &len, &ignored);
+      if (demangled) {
+        sym_name = demangled;
+        // In the exceptional case of demangling something > kDemangledNameLen,
+        // __cxa_demangle will realloc(). In that case the malloc()-ed pointer
+        // might be moved.
+        g_demangled_name = demangled;
+      }
+      write(STDERR_FILENO, sym_name, strlen(sym_name));
+    } else {
+      Print("???");
+    }
+    Print("\n");
+  }
+
+  Print("------------------ END OF CRASH ------------------\n");
+}
+
+// __attribute__((constructor)) causes a static initializer that automagically
+// early runs this function before the main().
+void __attribute__((constructor)) EnableStacktraceOnCrashForDebug();
+
+void EnableStacktraceOnCrashForDebug() {
+  if (g_sighandler_registered)
+    return;
+  g_sighandler_registered = true;
+
+  // Pre-allocate the string for __cxa_demangle() to reduce the risk of that
+  // invoking realloc() within the signal handler.
+  g_demangled_name = reinterpret_cast<char*>(malloc(kDemangledNameLen));
+  struct sigaction sigact;
+  sigact.sa_sigaction = &SignalHandler;
+  sigact.sa_flags = static_cast<decltype(sigact.sa_flags)>(
+      SA_RESTART | SA_SIGINFO | SA_RESETHAND);
+  for (size_t i = 0; i < sizeof(g_signals) / sizeof(g_signals[0]); i++)
+    sigaction(g_signals[i].sig_num, &sigact, &g_signals[i].old_handler);
+}
+
+}  // namespace
diff --git a/base/logging.h b/base/logging.h
index 5b7bac1..2b04056 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -40,7 +40,7 @@
   do {                                                \
     if (!__builtin_expect(!!(x), true)) {             \
       PERFETTO_DPLOG("%s", "PERFETTO_CHECK(" #x ")"); \
-      abort();                                        \
+      __builtin_trap();                               \
     }                                                 \
   } while (0)
 #else