Apply clang-format to folly/experimental/exception_tracer/ (headers)
[folly.git] / folly / experimental / exception_tracer / ExceptionStackTraceLib.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
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 <exception>
18
19 #include <folly/experimental/exception_tracer/ExceptionAbi.h>
20 #include <folly/experimental/exception_tracer/ExceptionTracer.h>
21 #include <folly/experimental/exception_tracer/ExceptionTracerLib.h>
22 #include <folly/experimental/exception_tracer/StackTrace.h>
23 #include <folly/experimental/symbolizer/Symbolizer.h>
24
25 using namespace folly::exception_tracer;
26
27 namespace {
28
29 // If we somehow ended up in an invalid state, we don't want to print any stack
30 // trace at all because in could be bogus
31 FOLLY_TLS bool invalid;
32
33 FOLLY_TLS StackTraceStack activeExceptions;
34 FOLLY_TLS StackTraceStack caughtExceptions;
35
36 } // namespace
37
38 // This function is exported and may be found via dlsym(RTLD_NEXT, ...)
39 extern "C" StackTraceStack* getExceptionStackTraceStack() {
40   return invalid ? nullptr : &caughtExceptions;
41 }
42
43 namespace {
44
45 void addActiveException() {
46   // Capture stack trace
47   if (!invalid) {
48     if (!activeExceptions.pushCurrent()) {
49       activeExceptions.clear();
50       caughtExceptions.clear();
51       invalid = true;
52     }
53   }
54 }
55
56 void moveTopException(StackTraceStack& from, StackTraceStack& to) {
57   if (invalid) {
58     return;
59   }
60   if (!to.moveTopFrom(from)) {
61     from.clear();
62     to.clear();
63     invalid = true;
64   }
65 }
66
67 struct Initializer {
68   Initializer() {
69     registerCxaThrowCallback(
70         [](void*, std::type_info*, void (*)(void*)) { addActiveException(); });
71
72     registerCxaBeginCatchCallback(
73         [](void*) { moveTopException(activeExceptions, caughtExceptions); });
74
75     registerCxaRethrowCallback(
76         []() { moveTopException(caughtExceptions, activeExceptions); });
77
78     registerCxaEndCatchCallback([]() {
79       if (invalid) {
80         return;
81       }
82
83       __cxxabiv1::__cxa_exception* top =
84           __cxxabiv1::__cxa_get_globals_fast()->caughtExceptions;
85       // This is gcc specific and not specified in the ABI:
86       // abs(handlerCount) is the number of active handlers, it's negative
87       // for rethrown exceptions and positive (always 1) for regular
88       // exceptions.
89       // In the rethrow case, we've already popped the exception off the
90       // caught stack, so we don't do anything here.
91       if (top->handlerCount == 1) {
92         if (!caughtExceptions.pop()) {
93           activeExceptions.clear();
94           invalid = true;
95         }
96       }
97     });
98
99     registerRethrowExceptionCallback(
100         [](std::exception_ptr) { addActiveException(); });
101
102     try {
103       ::folly::exception_tracer::installHandlers();
104     } catch (...) {
105     }
106   }
107 };
108
109 Initializer initializer;
110
111 } // namespace