2 * Copyright 2012 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.
22 #include <glog/logging.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"
28 namespace __cxxabiv1 {
31 void __cxa_throw(void* thrownException, std::type_info* type,
32 void (*destructor)(void)) __attribute__((noreturn));
33 void* __cxa_begin_catch(void* excObj);
34 void __cxa_rethrow(void) __attribute__((noreturn));
35 void __cxa_end_catch(void);
38 } // namespace __cxxabiv1
42 __thread bool invalid;
43 __thread StackTraceStack* activeExceptions;
44 __thread StackTraceStack* caughtExceptions;
45 pthread_once_t initialized = PTHREAD_ONCE_INIT;
48 typedef void (*CxaThrowType)(void*, std::type_info*, void (*)(void));
49 typedef void* (*CxaBeginCatchType)(void*);
50 typedef void (*CxaRethrowType)(void);
51 typedef void (*CxaEndCatchType)(void);
53 CxaThrowType orig_cxa_throw __attribute__((noreturn));
54 CxaBeginCatchType orig_cxa_begin_catch;
55 CxaRethrowType orig_cxa_rethrow __attribute__((noreturn));
56 CxaEndCatchType orig_cxa_end_catch;
59 typedef void (*RethrowExceptionType)(std::exception_ptr);
60 RethrowExceptionType orig_rethrow_exception __attribute__((noreturn));
63 orig_cxa_throw = (CxaThrowType)dlsym(RTLD_NEXT, "__cxa_throw");
64 orig_cxa_begin_catch =
65 (CxaBeginCatchType)dlsym(RTLD_NEXT, "__cxa_begin_catch");
67 (CxaRethrowType)dlsym(RTLD_NEXT, "__cxa_rethrow");
68 orig_cxa_end_catch = (CxaEndCatchType)dlsym(RTLD_NEXT, "__cxa_end_catch");
69 // Mangled name for std::rethrow_exception
70 // TODO(tudorb): Dicey, as it relies on the fact that std::exception_ptr
71 // is typedef'ed to a type in namespace __exception_ptr
72 orig_rethrow_exception =
73 (RethrowExceptionType)dlsym(
75 "_ZSt17rethrow_exceptionNSt15__exception_ptr13exception_ptrE");
77 if (!orig_cxa_throw || !orig_cxa_begin_catch || !orig_cxa_rethrow ||
78 !orig_cxa_end_catch || !orig_rethrow_exception) {
79 abort(); // what else can we do?
85 // This function is exported and may be found via dlsym(RTLD_NEXT, ...)
86 extern "C" const StackTraceStack* getExceptionStackTraceStack() {
87 return caughtExceptions;
91 // Make sure we're counting stack frames correctly for the "skip" argument to
92 // pushCurrentStackTrace, don't inline.
93 void addActiveException() __attribute__((noinline));
95 void addActiveException() {
96 pthread_once(&initialized, initialize);
97 // Capture stack trace
99 if (pushCurrentStackTrace(3, &activeExceptions) != 0) {
100 clearStack(&activeExceptions);
101 clearStack(&caughtExceptions);
107 void moveTopException(StackTraceStack** from, StackTraceStack** to) {
111 if (moveTop(from, to) != 0) {
120 namespace __cxxabiv1 {
122 void __cxa_throw(void* thrownException, std::type_info* type,
123 void (*destructor)(void)) {
124 addActiveException();
125 orig_cxa_throw(thrownException, type, destructor);
128 void __cxa_rethrow() {
129 // __cxa_rethrow leaves the current exception on the caught stack,
130 // and __cxa_begin_catch recognizes that case. We could do the same, but
131 // we'll implement something simpler (and slower): we pop the exception from
132 // the caught stack, and push it back onto the active stack; this way, our
133 // implementation of __cxa_begin_catch doesn't have to do anything special.
134 moveTopException(&caughtExceptions, &activeExceptions);
138 void* __cxa_begin_catch(void *excObj) {
139 // excObj is a pointer to the unwindHeader in __cxa_exception
140 moveTopException(&activeExceptions, &caughtExceptions);
141 return orig_cxa_begin_catch(excObj);
144 void __cxa_end_catch() {
146 __cxa_exception* top = __cxa_get_globals_fast()->caughtExceptions;
147 // This is gcc specific and not specified in the ABI:
148 // abs(handlerCount) is the number of active handlers, it's negative
149 // for rethrown exceptions and positive (always 1) for regular exceptions.
150 // In the rethrow case, we've already popped the exception off the
151 // caught stack, so we don't do anything here.
152 if (top->handlerCount == 1) {
153 popStackTrace(&caughtExceptions);
156 orig_cxa_end_catch();
159 } // namespace __cxxabiv1
163 void rethrow_exception(std::exception_ptr ep) {
164 addActiveException();
165 orig_rethrow_exception(ep);
176 ::folly::exception_tracer::installHandlers();
182 Initializer initializer;