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