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 | |
16 | namespace fml { |
17 | |
18 | static std::string kKUnknownFrameName = "Unknown" ; |
19 | |
20 | static 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 | |
42 | static 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 | |
52 | std::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 | |
68 | static 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 | |
79 | static 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 | |
101 | static void ToggleSignalHandlers(bool set); |
102 | |
103 | static 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 | |
117 | static 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 | |
128 | void InstallCrashHandler() { |
129 | ToggleSignalHandlers(true); |
130 | } |
131 | |
132 | bool IsCrashHandlingSupported() { |
133 | return true; |
134 | } |
135 | |
136 | } // namespace fml |
137 | |