2 * Copyright 2014 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <glog/logging.h>
23 #include <folly/Portability.h>
24 #include <folly/experimental/exception_tracer/StackTrace.h>
25 #include <folly/experimental/exception_tracer/ExceptionAbi.h>
26 #include <folly/experimental/exception_tracer/ExceptionTracer.h>
27 #include <folly/experimental/symbolizer/Symbolizer.h>
29 namespace __cxxabiv1 {
32 FOLLY_NORETURN void __cxa_throw(void* thrownException,
34 void (*destructor)(void*));
35 void* __cxa_begin_catch(void* excObj);
36 FOLLY_NORETURN void __cxa_rethrow(void);
37 void __cxa_end_catch(void);
40 } // namespace __cxxabiv1
42 using namespace folly::exception_tracer;
46 FOLLY_TLS bool invalid;
47 FOLLY_TLS StackTraceStack activeExceptions;
48 FOLLY_TLS StackTraceStack caughtExceptions;
49 pthread_once_t initialized = PTHREAD_ONCE_INIT;
52 FOLLY_NORETURN typedef void (*CxaThrowType)(void*,
55 typedef void* (*CxaBeginCatchType)(void*);
56 FOLLY_NORETURN typedef void (*CxaRethrowType)(void);
57 typedef void (*CxaEndCatchType)(void);
59 CxaThrowType orig_cxa_throw;
60 CxaBeginCatchType orig_cxa_begin_catch;
61 CxaRethrowType orig_cxa_rethrow;
62 CxaEndCatchType orig_cxa_end_catch;
65 FOLLY_NORETURN typedef void (*RethrowExceptionType)(std::exception_ptr);
66 RethrowExceptionType orig_rethrow_exception;
69 orig_cxa_throw = (CxaThrowType)dlsym(RTLD_NEXT, "__cxa_throw");
70 orig_cxa_begin_catch =
71 (CxaBeginCatchType)dlsym(RTLD_NEXT, "__cxa_begin_catch");
73 (CxaRethrowType)dlsym(RTLD_NEXT, "__cxa_rethrow");
74 orig_cxa_end_catch = (CxaEndCatchType)dlsym(RTLD_NEXT, "__cxa_end_catch");
75 // Mangled name for std::rethrow_exception
76 // TODO(tudorb): Dicey, as it relies on the fact that std::exception_ptr
77 // is typedef'ed to a type in namespace __exception_ptr
78 orig_rethrow_exception =
79 (RethrowExceptionType)dlsym(
81 "_ZSt17rethrow_exceptionNSt15__exception_ptr13exception_ptrE");
83 if (!orig_cxa_throw || !orig_cxa_begin_catch || !orig_cxa_rethrow ||
84 !orig_cxa_end_catch || !orig_rethrow_exception) {
85 abort(); // what else can we do?
91 // This function is exported and may be found via dlsym(RTLD_NEXT, ...)
92 extern "C" StackTraceStack* getExceptionStackTraceStack() {
93 return invalid ? nullptr : &caughtExceptions;
98 // Make sure we're counting stack frames correctly, don't inline.
99 FOLLY_NOINLINE void addActiveException();
101 void addActiveException() {
102 pthread_once(&initialized, initialize);
103 // Capture stack trace
105 if (!activeExceptions.pushCurrent()) {
106 activeExceptions.clear();
107 caughtExceptions.clear();
113 void moveTopException(StackTraceStack& from, StackTraceStack& to) {
117 if (!to.moveTopFrom(from)) {
126 namespace __cxxabiv1 {
128 void __cxa_throw(void* thrownException,
129 std::type_info* type,
130 void (*destructor)(void*)) {
131 addActiveException();
132 orig_cxa_throw(thrownException, type, destructor);
135 void __cxa_rethrow() {
136 // __cxa_rethrow leaves the current exception on the caught stack,
137 // and __cxa_begin_catch recognizes that case. We could do the same, but
138 // we'll implement something simpler (and slower): we pop the exception from
139 // the caught stack, and push it back onto the active stack; this way, our
140 // implementation of __cxa_begin_catch doesn't have to do anything special.
141 moveTopException(caughtExceptions, activeExceptions);
145 void* __cxa_begin_catch(void *excObj) {
146 // excObj is a pointer to the unwindHeader in __cxa_exception
147 moveTopException(activeExceptions, caughtExceptions);
148 return orig_cxa_begin_catch(excObj);
151 void __cxa_end_catch() {
153 __cxa_exception* top = __cxa_get_globals_fast()->caughtExceptions;
154 // This is gcc specific and not specified in the ABI:
155 // abs(handlerCount) is the number of active handlers, it's negative
156 // for rethrown exceptions and positive (always 1) for regular exceptions.
157 // In the rethrow case, we've already popped the exception off the
158 // caught stack, so we don't do anything here.
159 if (top->handlerCount == 1) {
160 if (!caughtExceptions.pop()) {
161 activeExceptions.clear();
166 orig_cxa_end_catch();
169 } // namespace __cxxabiv1
173 void rethrow_exception(std::exception_ptr ep) {
174 addActiveException();
175 orig_rethrow_exception(ep);
186 ::folly::exception_tracer::installHandlers();
192 Initializer initializer;