1// Copyright 2013 The Flutter 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 "flutter/fml/backtrace.h"
6
7#include <cxxabi.h>
8#include <sstream>
9
10#include <dlfcn.h>
11#include <execinfo.h>
12#include <signal.h>
13
14#include "flutter/fml/logging.h"
15
16namespace fml {
17
18static std::string kKUnknownFrameName = "Unknown";
19
20static std::string DemangleSymbolName(const std::string& mangled) {
21 if (mangled == kKUnknownFrameName) {
22 return kKUnknownFrameName;
23 }
24
25 int status = 0;
26 size_t length = 0;
27 char* demangled = __cxxabiv1::__cxa_demangle(
28 mangled.data(), // mangled name
29 nullptr, // output buffer (malloc-ed if nullptr)
30 &length, // demangled length
31 &status);
32
33 if (demangled == nullptr || status != 0) {
34 return mangled;
35 }
36
37 auto demangled_string = std::string{demangled, length};
38 free(demangled);
39 return demangled_string;
40}
41
42static std::string GetSymbolName(void* symbol) {
43 Dl_info info = {};
44
45 if (::dladdr(symbol, &info) == 0) {
46 return kKUnknownFrameName;
47 }
48
49 return DemangleSymbolName({info.dli_sname});
50}
51
52std::string BacktraceHere(size_t offset) {
53 constexpr size_t kMaxFrames = 256;
54 void* symbols[kMaxFrames];
55 const auto available_frames = ::backtrace(symbols, kMaxFrames);
56 if (available_frames <= 0) {
57 return "";
58 }
59
60 std::stringstream stream;
61 for (int i = 1 + offset; i < available_frames; ++i) {
62 stream << "Frame " << i - 1 - offset << ": " << symbols[i] << " "
63 << GetSymbolName(symbols[i]) << std::endl;
64 }
65 return stream.str();
66}
67
68static size_t kKnownSignalHandlers[] = {
69 SIGABRT, // abort program
70 SIGFPE, // floating-point exception
71 SIGBUS, // bus error
72 SIGSEGV, // segmentation violation
73 SIGSYS, // non-existent system call invoked
74 SIGPIPE, // write on a pipe with no reader
75 SIGALRM, // real-time timer expired
76 SIGTERM, // software termination signal
77};
78
79static std::string SignalNameToString(int signal) {
80 switch (signal) {
81 case SIGABRT:
82 return "SIGABRT";
83 case SIGFPE:
84 return "SIGFPE";
85 case SIGBUS:
86 return "SIGBUS";
87 case SIGSEGV:
88 return "SIGSEGV";
89 case SIGSYS:
90 return "SIGSYS";
91 case SIGPIPE:
92 return "SIGPIPE";
93 case SIGALRM:
94 return "SIGALRM";
95 case SIGTERM:
96 return "SIGTERM";
97 };
98 return std::to_string(signal);
99}
100
101static void ToggleSignalHandlers(bool set);
102
103static void SignalHandler(int signal) {
104 // We are a crash signal handler. This can only happen once. Since we don't
105 // want to catch crashes while we are generating the crash reports, disable
106 // all set signal handlers to their default values before reporting the crash
107 // and re-raising the signal.
108 ToggleSignalHandlers(false);
109
110 FML_LOG(ERROR) << "Caught signal " << SignalNameToString(signal)
111 << " during program execution." << std::endl
112 << BacktraceHere(3);
113
114 ::raise(signal);
115}
116
117static void ToggleSignalHandlers(bool set) {
118 for (size_t i = 0; i < sizeof(kKnownSignalHandlers) / sizeof(size_t); ++i) {
119 auto signal_name = kKnownSignalHandlers[i];
120 auto handler = set ? &SignalHandler : SIG_DFL;
121
122 if (::signal(signal_name, handler) == SIG_ERR) {
123 FML_LOG(ERROR) << "Could not attach signal handler for " << signal_name;
124 }
125 }
126}
127
128void InstallCrashHandler() {
129 ToggleSignalHandlers(true);
130}
131
132bool IsCrashHandlingSupported() {
133 return true;
134}
135
136} // namespace fml
137