proxygen
ExceptionTracerLib.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2012-present 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 
18 
19 #include <dlfcn.h>
20 
21 #include <vector>
22 
23 #include <folly/Indestructible.h>
24 #include <folly/Portability.h>
25 #include <folly/SharedMutex.h>
26 #include <folly/Synchronized.h>
27 
28 namespace __cxxabiv1 {
29 
30 extern "C" {
31 void __cxa_throw(
32  void* thrownException,
33  std::type_info* type,
34  void (*destructor)(void*)) __attribute__((__noreturn__));
35 void* __cxa_begin_catch(void* excObj) throw();
36 void __cxa_rethrow(void) __attribute__((__noreturn__));
37 void __cxa_end_catch(void);
38 }
39 
40 } // namespace __cxxabiv1
41 
42 using namespace folly::exception_tracer;
43 
44 namespace {
45 
46 template <typename Function>
47 class CallbackHolder {
48  public:
49  void registerCallback(Function f) {
50  callbacks_.wlock()->push_back(std::move(f));
51  }
52 
53  // always inline to enforce kInternalFramesNumber
54  template <typename... Args>
55  FOLLY_ALWAYS_INLINE void invoke(Args... args) {
56  auto callbacksLock = callbacks_.rlock();
57  for (auto& cb : *callbacksLock) {
58  cb(args...);
59  }
60  }
61 
62  private:
64 };
65 
66 } // namespace
67 
68 namespace folly {
69 namespace exception_tracer {
70 
71 #define DECLARE_CALLBACK(NAME) \
72  CallbackHolder<NAME##Type>& get##NAME##Callbacks() { \
73  static Indestructible<CallbackHolder<NAME##Type>> Callbacks; \
74  return *Callbacks; \
75  } \
76  void register##NAME##Callback(NAME##Type callback) { \
77  get##NAME##Callbacks().registerCallback(callback); \
78  }
79 
81 DECLARE_CALLBACK(CxaBeginCatch)
82 DECLARE_CALLBACK(CxaRethrow)
83 DECLARE_CALLBACK(CxaEndCatch)
84 DECLARE_CALLBACK(RethrowException)
85 
86 } // namespace exception_tracer
87 } // namespace folly
88 
89 // Clang is smart enough to understand that the symbols we're loading
90 // are [[noreturn]], but GCC is not. In order to be able to build with
91 // -Wunreachable-code enable for Clang, these __builtin_unreachable()
92 // calls need to go away. Everything else is messy though, so just
93 // #define it to an empty macro under Clang and be done with it.
94 #ifdef __clang__
95 #define __builtin_unreachable()
96 #endif
97 
98 namespace __cxxabiv1 {
99 
101  void* thrownException,
102  std::type_info* type,
103  void (*destructor)(void*)) {
104  static auto orig_cxa_throw =
105  reinterpret_cast<decltype(&__cxa_throw)>(dlsym(RTLD_NEXT, "__cxa_throw"));
106  getCxaThrowCallbacks().invoke(thrownException, type, destructor);
107  orig_cxa_throw(thrownException, type, destructor);
108  __builtin_unreachable(); // orig_cxa_throw never returns
109 }
110 
112  // __cxa_rethrow leaves the current exception on the caught stack,
113  // and __cxa_begin_catch recognizes that case. We could do the same, but
114  // we'll implement something simpler (and slower): we pop the exception from
115  // the caught stack, and push it back onto the active stack; this way, our
116  // implementation of __cxa_begin_catch doesn't have to do anything special.
117  static auto orig_cxa_rethrow = reinterpret_cast<decltype(&__cxa_rethrow)>(
118  dlsym(RTLD_NEXT, "__cxa_rethrow"));
119  getCxaRethrowCallbacks().invoke();
120  orig_cxa_rethrow();
121  __builtin_unreachable(); // orig_cxa_rethrow never returns
122 }
123 
124 void* __cxa_begin_catch(void* excObj) throw() {
125  // excObj is a pointer to the unwindHeader in __cxa_exception
126  static auto orig_cxa_begin_catch =
127  reinterpret_cast<decltype(&__cxa_begin_catch)>(
128  dlsym(RTLD_NEXT, "__cxa_begin_catch"));
129  getCxaBeginCatchCallbacks().invoke(excObj);
130  return orig_cxa_begin_catch(excObj);
131 }
132 
134  static auto orig_cxa_end_catch = reinterpret_cast<decltype(&__cxa_end_catch)>(
135  dlsym(RTLD_NEXT, "__cxa_end_catch"));
136  getCxaEndCatchCallbacks().invoke();
137  orig_cxa_end_catch();
138 }
139 
140 } // namespace __cxxabiv1
141 
142 namespace std {
143 
144 void rethrow_exception(std::exception_ptr ep) {
145  // Mangled name for std::rethrow_exception
146  // TODO(tudorb): Dicey, as it relies on the fact that std::exception_ptr
147  // is typedef'ed to a type in namespace __exception_ptr
148  static auto orig_rethrow_exception =
149  reinterpret_cast<decltype(&rethrow_exception)>(dlsym(
150  RTLD_NEXT,
151  "_ZSt17rethrow_exceptionNSt15__exception_ptr13exception_ptrE"));
152  getRethrowExceptionCallbacks().invoke(ep);
153  orig_rethrow_exception(ep);
154  __builtin_unreachable(); // orig_rethrow_exception never returns
155 }
156 
157 } // namespace std
void * __cxa_begin_catch(void *excObj)
PUSHMI_INLINE_VAR constexpr struct folly::pushmi::invoke_fn invoke
auto f
void rethrow_exception(std::exception_ptr ep)
#define FOLLY_ALWAYS_INLINE
Definition: CPortability.h:151
void __cxa_rethrow(void) __attribute__((__noreturn__))
PskType type
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
STL namespace.
CallbackHolder< CxaEndCatchType > & getCxaEndCatchCallbacks()
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
CallbackHolder< CxaBeginCatchType > & getCxaBeginCatchCallbacks()
CallbackHolder< CxaRethrowType > & getCxaRethrowCallbacks()
CallbackHolder< CxaThrowType > & getCxaThrowCallbacks()
#define DECLARE_CALLBACK(NAME)
#define throw
Definition: FBString.h:89
CallbackHolder< RethrowExceptionType > & getRethrowExceptionCallbacks()
__attribute__((noinline, noclone)) VirtualBase *makeVirtual()
void __cxa_end_catch(void)
void __cxa_throw(void *thrownException, std::type_info *type, void(*destructor)(void *)) __attribute__((__noreturn__))