2 * Copyright 2013 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/experimental/exception_tracer/StackTrace.h"
24 #include "folly/experimental/exception_tracer/ExceptionAbi.h"
25 #include "folly/experimental/exception_tracer/ExceptionTracer.h"
27 namespace __cxxabiv1 {
30 void __cxa_throw(void* thrownException, std::type_info* type,
31 void (*destructor)(void)) __attribute__((noreturn));
32 void* __cxa_begin_catch(void* excObj);
33 void __cxa_rethrow(void) __attribute__((noreturn));
34 void __cxa_end_catch(void);
37 } // namespace __cxxabiv1
41 __thread bool invalid;
42 __thread StackTraceStack* activeExceptions;
43 __thread StackTraceStack* caughtExceptions;
44 pthread_once_t initialized = PTHREAD_ONCE_INIT;
47 typedef void (*CxaThrowType)(void*, std::type_info*, void (*)(void))
48 __attribute__((noreturn));
49 typedef void* (*CxaBeginCatchType)(void*);
50 typedef void (*CxaRethrowType)(void)
51 __attribute__((noreturn));
52 typedef void (*CxaEndCatchType)(void);
54 CxaThrowType orig_cxa_throw;
55 CxaBeginCatchType orig_cxa_begin_catch;
56 CxaRethrowType orig_cxa_rethrow;
57 CxaEndCatchType orig_cxa_end_catch;
60 typedef void (*RethrowExceptionType)(std::exception_ptr)
61 __attribute__((noreturn));
62 RethrowExceptionType orig_rethrow_exception;
65 orig_cxa_throw = (CxaThrowType)dlsym(RTLD_NEXT, "__cxa_throw");
66 orig_cxa_begin_catch =
67 (CxaBeginCatchType)dlsym(RTLD_NEXT, "__cxa_begin_catch");
69 (CxaRethrowType)dlsym(RTLD_NEXT, "__cxa_rethrow");
70 orig_cxa_end_catch = (CxaEndCatchType)dlsym(RTLD_NEXT, "__cxa_end_catch");
71 // Mangled name for std::rethrow_exception
72 // TODO(tudorb): Dicey, as it relies on the fact that std::exception_ptr
73 // is typedef'ed to a type in namespace __exception_ptr
74 orig_rethrow_exception =
75 (RethrowExceptionType)dlsym(
77 "_ZSt17rethrow_exceptionNSt15__exception_ptr13exception_ptrE");
79 if (!orig_cxa_throw || !orig_cxa_begin_catch || !orig_cxa_rethrow ||
80 !orig_cxa_end_catch || !orig_rethrow_exception) {
81 abort(); // what else can we do?
87 // This function is exported and may be found via dlsym(RTLD_NEXT, ...)
88 extern "C" const StackTraceStack* getExceptionStackTraceStack() {
89 return caughtExceptions;
93 // Make sure we're counting stack frames correctly for the "skip" argument to
94 // pushCurrentStackTrace, don't inline.
95 void addActiveException() __attribute__((noinline));
97 void addActiveException() {
98 pthread_once(&initialized, initialize);
99 // Capture stack trace
101 if (pushCurrentStackTrace(3, &activeExceptions) != 0) {
102 clearStack(&activeExceptions);
103 clearStack(&caughtExceptions);
109 void moveTopException(StackTraceStack** from, StackTraceStack** to) {
113 if (moveTop(from, to) != 0) {
122 namespace __cxxabiv1 {
124 void __cxa_throw(void* thrownException, std::type_info* type,
125 void (*destructor)(void)) {
126 addActiveException();
127 orig_cxa_throw(thrownException, type, destructor);
130 void __cxa_rethrow() {
131 // __cxa_rethrow leaves the current exception on the caught stack,
132 // and __cxa_begin_catch recognizes that case. We could do the same, but
133 // we'll implement something simpler (and slower): we pop the exception from
134 // the caught stack, and push it back onto the active stack; this way, our
135 // implementation of __cxa_begin_catch doesn't have to do anything special.
136 moveTopException(&caughtExceptions, &activeExceptions);
140 void* __cxa_begin_catch(void *excObj) {
141 // excObj is a pointer to the unwindHeader in __cxa_exception
142 moveTopException(&activeExceptions, &caughtExceptions);
143 return orig_cxa_begin_catch(excObj);
146 void __cxa_end_catch() {
148 __cxa_exception* top = __cxa_get_globals_fast()->caughtExceptions;
149 // This is gcc specific and not specified in the ABI:
150 // abs(handlerCount) is the number of active handlers, it's negative
151 // for rethrown exceptions and positive (always 1) for regular exceptions.
152 // In the rethrow case, we've already popped the exception off the
153 // caught stack, so we don't do anything here.
154 if (top->handlerCount == 1) {
155 popStackTrace(&caughtExceptions);
158 orig_cxa_end_catch();
161 } // namespace __cxxabiv1
165 void rethrow_exception(std::exception_ptr ep) {
166 addActiveException();
167 orig_rethrow_exception(ep);
178 ::folly::exception_tracer::installHandlers();
184 Initializer initializer;