blob: c70225c35addeff5e4d9f022c2b3a5946f2bb045 [file] [log] [blame]
Primiano Tucci89d765f2017-11-27 17:51:38 +00001/*
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 <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24#include <unwind.h>
25
26#if defined(NDEBUG)
27#error This translation unit should not be used in release builds
28#endif
29
30namespace {
31
32constexpr size_t kDemangledNameLen = 4096;
33
34bool g_sighandler_registered = false;
35char* g_demangled_name = nullptr;
36
37struct SigHandler {
38 int sig_num;
39 struct sigaction old_handler;
40};
41
42SigHandler g_signals[] = {{SIGSEGV}, {SIGILL}, {SIGTRAP},
43 {SIGABRT}, {SIGBUS}, {SIGFPE}};
44
45template <typename T>
46void Print(const T& str) {
47 write(STDERR_FILENO, str, sizeof(str));
48}
49
50template <typename T>
51void PrintHex(T n) {
52 for (unsigned i = 0; i < sizeof(n) * 8; i += 4) {
53 char nibble = static_cast<char>(n >> (sizeof(n) * 8 - i - 4)) & 0x0F;
54 char c = (nibble < 10) ? '0' + nibble : 'A' + nibble - 10;
55 write(STDERR_FILENO, &c, 1);
56 }
57}
58
59struct StackCrawlState {
60 StackCrawlState(uintptr_t* frames_arg, size_t max_depth_arg)
61 : frames(frames_arg),
62 frame_count(0),
63 max_depth(max_depth_arg),
64 skip_count(1) {}
65
66 uintptr_t* frames;
67 size_t frame_count;
68 size_t max_depth;
69 size_t skip_count;
70};
71
72_Unwind_Reason_Code TraceStackFrame(_Unwind_Context* context, void* arg) {
73 StackCrawlState* state = static_cast<StackCrawlState*>(arg);
74 uintptr_t ip = _Unwind_GetIP(context);
75
76 if (ip != 0 && state->skip_count) {
77 state->skip_count--;
78 return _URC_NO_REASON;
79 }
80
81 state->frames[state->frame_count++] = ip;
82 if (state->frame_count >= state->max_depth)
83 return _URC_END_OF_STACK;
84 return _URC_NO_REASON;
85}
86
87// Note: use only async-safe functions inside this.
88void SignalHandler(int sig_num, siginfo_t* info, void* ucontext) {
89 // Restore the old handlers.
90 for (size_t i = 0; i < sizeof(g_signals) / sizeof(g_signals[0]); i++)
91 sigaction(g_signals[i].sig_num, &g_signals[i].old_handler, nullptr);
92
93 Print("\n------------------ BEGINNING OF CRASH ------------------\n");
94 Print("Signal: ");
95 if (sig_num == SIGSEGV) {
96 Print("Segmentation fault");
97 } else if (sig_num == SIGILL) {
98 Print("Illegal instruction (possibly unaligned access)");
99 } else if (sig_num == SIGTRAP) {
100 Print("Trap");
101 } else if (sig_num == SIGABRT) {
102 Print("Abort");
103 } else if (sig_num == SIGBUS) {
104 Print("Bus Error (possibly unmapped memory access)");
105 } else if (sig_num == SIGFPE) {
106 Print("Floating point exception");
107 } else {
108 Print("Unexpected signal ");
109 PrintHex(static_cast<uint32_t>(sig_num));
110 }
111
112 Print("\n");
113
114 Print("Fault addr: ");
115 PrintHex(reinterpret_cast<uintptr_t>(info->si_addr));
116 Print("\n\nBacktrace:\n");
117
118 const size_t kMaxFrames = 32;
119 uintptr_t frames[kMaxFrames];
120 StackCrawlState unwind_state(frames, kMaxFrames);
121 _Unwind_Backtrace(&TraceStackFrame, &unwind_state);
122
123 for (uint8_t i = 0; i < unwind_state.frame_count; i++) {
124 Dl_info sym_info = {};
125 int res = dladdr(reinterpret_cast<void*>(frames[i]), &sym_info);
126 Print("\n#");
127 PrintHex(i);
128 Print(" ");
Primiano Tucci60af59d2017-11-28 12:53:55 +0000129 const char* sym_name = res ? sym_info.dli_sname : nullptr;
130
131 if (sym_name) {
Primiano Tucci89d765f2017-11-27 17:51:38 +0000132 int ignored;
133 size_t len = kDemangledNameLen;
134 char* demangled = abi::__cxa_demangle(sym_info.dli_sname,
135 g_demangled_name, &len, &ignored);
136 if (demangled) {
137 sym_name = demangled;
138 // In the exceptional case of demangling something > kDemangledNameLen,
139 // __cxa_demangle will realloc(). In that case the malloc()-ed pointer
140 // might be moved.
141 g_demangled_name = demangled;
142 }
143 write(STDERR_FILENO, sym_name, strlen(sym_name));
144 } else {
145 Print("???");
146 }
147 Print("\n");
148 }
149
150 Print("------------------ END OF CRASH ------------------\n");
151}
152
153// __attribute__((constructor)) causes a static initializer that automagically
154// early runs this function before the main().
155void __attribute__((constructor)) EnableStacktraceOnCrashForDebug();
156
157void EnableStacktraceOnCrashForDebug() {
158 if (g_sighandler_registered)
159 return;
160 g_sighandler_registered = true;
161
162 // Pre-allocate the string for __cxa_demangle() to reduce the risk of that
163 // invoking realloc() within the signal handler.
164 g_demangled_name = reinterpret_cast<char*>(malloc(kDemangledNameLen));
165 struct sigaction sigact;
166 sigact.sa_sigaction = &SignalHandler;
167 sigact.sa_flags = static_cast<decltype(sigact.sa_flags)>(
168 SA_RESTART | SA_SIGINFO | SA_RESETHAND);
169 for (size_t i = 0; i < sizeof(g_signals) / sizeof(g_signals[0]); i++)
170 sigaction(g_signals[i].sig_num, &sigact, &g_signals[i].old_handler);
171}
172
173} // namespace