fix some of the warning/errors clang 3.1 reports - 2
[folly.git] / folly / experimental / exception_tracer / ExceptionTracerLib.cpp
1 /*
2  * Copyright 2013 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 <dlfcn.h>
18 #include <pthread.h>
19 #include <stdlib.h>
20
21 #include <glog/logging.h>
22
23 #include "folly/experimental/exception_tracer/StackTrace.h"
24 #include "folly/experimental/exception_tracer/ExceptionAbi.h"
25 #include "folly/experimental/exception_tracer/ExceptionTracer.h"
26
27 namespace __cxxabiv1 {
28
29 extern "C" {
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);
35 }
36
37 }  // namespace __cxxabiv1
38
39 namespace {
40
41 __thread bool invalid;
42 __thread StackTraceStack* activeExceptions;
43 __thread StackTraceStack* caughtExceptions;
44 pthread_once_t initialized = PTHREAD_ONCE_INIT;
45
46 extern "C" {
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);
53
54 CxaThrowType orig_cxa_throw;
55 CxaBeginCatchType orig_cxa_begin_catch;
56 CxaRethrowType orig_cxa_rethrow;
57 CxaEndCatchType orig_cxa_end_catch;
58 }  // extern "C"
59
60 typedef void (*RethrowExceptionType)(std::exception_ptr)
61   __attribute__((noreturn));
62 RethrowExceptionType orig_rethrow_exception;
63
64 void initialize() {
65   orig_cxa_throw = (CxaThrowType)dlsym(RTLD_NEXT, "__cxa_throw");
66   orig_cxa_begin_catch =
67     (CxaBeginCatchType)dlsym(RTLD_NEXT, "__cxa_begin_catch");
68   orig_cxa_rethrow =
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(
76         RTLD_NEXT,
77         "_ZSt17rethrow_exceptionNSt15__exception_ptr13exception_ptrE");
78
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?
82   }
83 }
84
85 }  // namespace
86
87 // This function is exported and may be found via dlsym(RTLD_NEXT, ...)
88 extern "C" const StackTraceStack* getExceptionStackTraceStack() {
89   return caughtExceptions;
90 }
91
92 namespace {
93 // Make sure we're counting stack frames correctly for the "skip" argument to
94 // pushCurrentStackTrace, don't inline.
95 void addActiveException() __attribute__((noinline));
96
97 void addActiveException() {
98   pthread_once(&initialized, initialize);
99   // Capture stack trace
100   if (!invalid) {
101     if (pushCurrentStackTrace(3, &activeExceptions) != 0) {
102       clearStack(&activeExceptions);
103       clearStack(&caughtExceptions);
104       invalid = true;
105     }
106   }
107 }
108
109 void moveTopException(StackTraceStack** from, StackTraceStack** to) {
110   if (invalid) {
111     return;
112   }
113   if (moveTop(from, to) != 0) {
114     clearStack(from);
115     clearStack(to);
116     invalid = true;
117   }
118 }
119
120 }  // namespace
121
122 namespace __cxxabiv1 {
123
124 void __cxa_throw(void* thrownException, std::type_info* type,
125                  void (*destructor)(void)) {
126   addActiveException();
127   orig_cxa_throw(thrownException, type, destructor);
128 }
129
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);
137   orig_cxa_rethrow();
138 }
139
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);
144 }
145
146 void __cxa_end_catch() {
147   if (!invalid) {
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);
156     }
157   }
158   orig_cxa_end_catch();
159 }
160
161 }  // namespace __cxxabiv1
162
163 namespace std {
164
165 void rethrow_exception(std::exception_ptr ep) {
166   addActiveException();
167   orig_rethrow_exception(ep);
168 }
169
170 }  // namespace std
171
172
173 namespace {
174
175 struct Initializer {
176   Initializer() {
177     try {
178       ::folly::exception_tracer::installHandlers();
179     } catch (...) {
180     }
181   }
182 };
183
184 Initializer initializer;
185
186 }  // namespace