• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // crash_handler_posix:
7 //    ANGLE's crash handling and stack walking code. Modified from Skia's:
8 //     https://github.com/google/skia/blob/master/tools/CrashHandler.cpp
9 //
10 
11 #include "util/test_utils.h"
12 
13 #include "common/angleutils.h"
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 
18 #if !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA)
19 #    if defined(ANGLE_PLATFORM_APPLE)
20 // We only use local unwinding, so we can define this to select a faster implementation.
21 #        define UNW_LOCAL_ONLY
22 #        include <cxxabi.h>
23 #        include <libunwind.h>
24 #        include <signal.h>
25 #    elif defined(ANGLE_PLATFORM_POSIX)
26 // We'd use libunwind here too, but it's a pain to get installed for
27 // both 32 and 64 bit on bots.  Doesn't matter much: catchsegv is best anyway.
28 #        include <cxxabi.h>
29 #        include <dlfcn.h>
30 #        include <execinfo.h>
31 #        include <signal.h>
32 #        include <string.h>
33 #    endif  // defined(ANGLE_PLATFORM_APPLE)
34 #endif      // !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA)
35 
36 namespace angle
37 {
38 #if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_FUCHSIA)
39 
PrintStackBacktrace()40 void PrintStackBacktrace()
41 {
42     // No implementations yet.
43 }
44 
InitCrashHandler(CrashCallback * callback)45 void InitCrashHandler(CrashCallback *callback)
46 {
47     // No implementations yet.
48 }
49 
TerminateCrashHandler()50 void TerminateCrashHandler()
51 {
52     // No implementations yet.
53 }
54 
55 #else
56 namespace
57 {
58 CrashCallback *gCrashHandlerCallback;
59 }  // namespace
60 
61 #    if defined(ANGLE_PLATFORM_APPLE)
62 
63 void PrintStackBacktrace()
64 {
65     printf("Backtrace:\n");
66 
67     unw_context_t context;
68     unw_getcontext(&context);
69 
70     unw_cursor_t cursor;
71     unw_init_local(&cursor, &context);
72 
73     while (unw_step(&cursor) > 0)
74     {
75         static const size_t kMax = 256;
76         char mangled[kMax], demangled[kMax];
77         unw_word_t offset;
78         unw_get_proc_name(&cursor, mangled, kMax, &offset);
79 
80         int ok;
81         size_t len = kMax;
82         abi::__cxa_demangle(mangled, demangled, &len, &ok);
83 
84         printf("    %s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
85     }
86     printf("\n");
87 }
88 
89 static void Handler(int sig)
90 {
91     if (gCrashHandlerCallback)
92     {
93         (*gCrashHandlerCallback)();
94     }
95 
96     printf("\nSignal %d:\n", sig);
97     PrintStackBacktrace();
98 
99     // Exit NOW.  Don't notify other threads, don't call anything registered with atexit().
100     _Exit(sig);
101 }
102 
103 #    elif defined(ANGLE_PLATFORM_POSIX)
104 
105 void PrintStackBacktrace()
106 {
107     printf("Backtrace:\n");
108 
109     void *stack[64];
110     const int count = backtrace(stack, ArraySize(stack));
111     char **symbols  = backtrace_symbols(stack, count);
112 
113     for (int i = 0; i < count; i++)
114     {
115         Dl_info info;
116         if (dladdr(stack[i], &info) && info.dli_sname)
117         {
118             // Make sure this is large enough to hold the fully demangled names, otherwise we could
119             // segault/hang here. For example, Vulkan validation layer errors can be deep enough
120             // into the stack that very large symbol names are generated.
121             char demangled[4096];
122             size_t len = ArraySize(demangled);
123             int ok;
124 
125             abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
126             if (ok == 0)
127             {
128                 printf("    %s\n", demangled);
129                 continue;
130             }
131         }
132         printf("    %s\n", symbols[i]);
133     }
134 }
135 
136 static void Handler(int sig)
137 {
138     if (gCrashHandlerCallback)
139     {
140         (*gCrashHandlerCallback)();
141     }
142 
143     printf("\nSignal %d [%s]:\n", sig, strsignal(sig));
144     PrintStackBacktrace();
145 
146     // Exit NOW.  Don't notify other threads, don't call anything registered with atexit().
147     _Exit(sig);
148 }
149 
150 #    endif  // defined(ANGLE_PLATFORM_APPLE)
151 
152 static constexpr int kSignals[] = {
153     SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP,
154 };
155 
156 void InitCrashHandler(CrashCallback *callback)
157 {
158     gCrashHandlerCallback = callback;
159     for (int sig : kSignals)
160     {
161         // Register our signal handler unless something's already done so (e.g. catchsegv).
162         void (*prev)(int) = signal(sig, Handler);
163         if (prev != SIG_DFL)
164         {
165             signal(sig, prev);
166         }
167     }
168 }
169 
170 void TerminateCrashHandler()
171 {
172     gCrashHandlerCallback = nullptr;
173     for (int sig : kSignals)
174     {
175         void (*prev)(int) = signal(sig, SIG_DFL);
176         if (prev != Handler && prev != SIG_DFL)
177         {
178             signal(sig, prev);
179         }
180     }
181 }
182 
183 #endif  // defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_FUCHSIA)
184 
185 }  // namespace angle
186