proxygen
ExceptionTracer.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 <exception>
20 #include <iostream>
21 
22 #include <dlfcn.h>
23 
24 #include <glog/logging.h>
25 
26 #include <folly/String.h>
30 
31 namespace {
32 
33 using namespace ::folly::exception_tracer;
34 using namespace ::folly::symbolizer;
35 using namespace __cxxabiv1;
36 
37 extern "C" {
38 StackTraceStack* getExceptionStackTraceStack(void) __attribute__((__weak__));
39 typedef StackTraceStack* (*GetExceptionStackTraceStackType)();
40 GetExceptionStackTraceStackType getExceptionStackTraceStackFn;
41 }
42 
43 } // namespace
44 
45 namespace folly {
46 namespace exception_tracer {
47 
48 std::ostream& operator<<(std::ostream& out, const ExceptionInfo& info) {
49  printExceptionInfo(out, info, SymbolizePrinter::COLOR_IF_TTY);
50  return out;
51 }
52 
54  std::ostream& out,
55  const ExceptionInfo& info,
56  int options) {
57  out << "Exception type: ";
58  if (info.type) {
59  out << folly::demangle(*info.type);
60  } else {
61  out << "(unknown type)";
62  }
63  out << " (" << info.frames.size()
64  << (info.frames.size() == 1 ? " frame" : " frames") << ")\n";
65  try {
66  size_t frameCount = info.frames.size();
67 
68  // Skip our own internal frames
69  static constexpr size_t kInternalFramesNumber = 3;
70  if (frameCount > kInternalFramesNumber) {
71  auto addresses = info.frames.data() + kInternalFramesNumber;
72  frameCount -= kInternalFramesNumber;
73 
74  std::vector<SymbolizedFrame> frames;
75  frames.resize(frameCount);
76 
77  Symbolizer symbolizer(
78  (options & SymbolizePrinter::NO_FILE_AND_LINE)
79  ? Dwarf::LocationInfoMode::DISABLED
80  : Symbolizer::kDefaultLocationInfoMode);
81  symbolizer.symbolize(addresses, frames.data(), frameCount);
82 
83  OStreamSymbolizePrinter osp(out, options);
84  osp.println(addresses, frames.data(), frameCount);
85  }
86  } catch (const std::exception& e) {
87  out << "\n !! caught " << folly::exceptionStr(e) << "\n";
88  } catch (...) {
89  out << "\n !!! caught unexpected exception\n";
90  }
91 }
92 
93 namespace {
94 
103 bool isAbiCppException(const __cxa_exception* exc) {
104  // The least significant four bytes must be "C++\0"
105  static const uint64_t cppClass =
106  ((uint64_t)'C' << 24) | ((uint64_t)'+' << 16) | ((uint64_t)'+' << 8);
107  return (exc->unwindHeader.exception_class & 0xffffffff) == cppClass;
108 }
109 
110 } // namespace
111 
112 std::vector<ExceptionInfo> getCurrentExceptions() {
113  struct Once {
114  Once() {
115  // See if linked in with us (getExceptionStackTraceStack is weak)
116  getExceptionStackTraceStackFn = getExceptionStackTraceStack;
117 
118  if (!getExceptionStackTraceStackFn) {
119  // Nope, see if it's in a shared library
120  getExceptionStackTraceStackFn = (GetExceptionStackTraceStackType)dlsym(
121  RTLD_NEXT, "getExceptionStackTraceStack");
122  }
123  }
124  };
125  static Once once;
126 
127  std::vector<ExceptionInfo> exceptions;
128  auto currentException = __cxa_get_globals()->caughtExceptions;
129  if (!currentException) {
130  return exceptions;
131  }
132 
133  StackTraceStack* traceStack = nullptr;
134  if (!getExceptionStackTraceStackFn) {
135  static bool logged = false;
136  if (!logged) {
137  LOG(WARNING)
138  << "Exception tracer library not linked, stack traces not available";
139  logged = true;
140  }
141  } else if ((traceStack = getExceptionStackTraceStackFn()) == nullptr) {
142  static bool logged = false;
143  if (!logged) {
144  LOG(WARNING)
145  << "Exception stack trace invalid, stack traces not available";
146  logged = true;
147  }
148  }
149 
150  StackTrace* trace = traceStack ? traceStack->top() : nullptr;
151  while (currentException) {
153  // Dependent exceptions (thrown via std::rethrow_exception) aren't
154  // standard ABI __cxa_exception objects, and are correctly labeled as
155  // such in the exception_class field. We could try to extract the
156  // primary exception type in horribly hacky ways, but, for now, nullptr.
157  info.type = isAbiCppException(currentException)
158  ? currentException->exceptionType
159  : nullptr;
160 
161  if (traceStack) {
162  LOG_IF(DFATAL, !trace)
163  << "Invalid trace stack for exception of type: "
164  << (info.type ? folly::demangle(*info.type) : "null");
165 
166  if (!trace) {
167  return {};
168  }
169 
170  info.frames.assign(
171  trace->addresses, trace->addresses + trace->frameCount);
172  trace = traceStack->next(trace);
173  }
174  currentException = currentException->nextException;
175  exceptions.push_back(std::move(info));
176  }
177 
178  LOG_IF(DFATAL, trace) << "Invalid trace stack!";
179 
180  return exceptions;
181 }
182 
183 namespace {
184 
185 std::terminate_handler origTerminate = abort;
186 std::unexpected_handler origUnexpected = abort;
187 
188 void dumpExceptionStack(const char* prefix) {
189  auto exceptions = getCurrentExceptions();
190  if (exceptions.empty()) {
191  return;
192  }
193  LOG(ERROR) << prefix << ", exception stack follows";
194  for (auto& exc : exceptions) {
195  LOG(ERROR) << exc << "\n";
196  }
197  LOG(ERROR) << "exception stack complete";
198 }
199 
200 void terminateHandler() {
201  dumpExceptionStack("terminate() called");
202  origTerminate();
203 }
204 
205 void unexpectedHandler() {
206  dumpExceptionStack("Unexpected exception");
207  origUnexpected();
208 }
209 
210 } // namespace
211 
213  struct Once {
214  Once() {
215  origTerminate = std::set_terminate(terminateHandler);
216  origUnexpected = std::set_unexpected(unexpectedHandler);
217  }
218  };
219  static Once once;
220 }
221 
222 } // namespace exception_tracer
223 } // namespace folly
def info()
Definition: deadlock.py:447
_Unwind_Exception unwindHeader
Definition: ExceptionAbi.h:43
fbstring exceptionStr(const std::exception &e)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
bool prefix(Cursor &c, uint32_t expected)
uintptr_t addresses[kMaxFrames]
Definition: StackTrace.h:32
std::ostream & operator<<(std::ostream &out, const ExceptionInfo &info)
StackTrace * next(StackTrace *p)
Definition: StackTrace.cpp:106
StackTraceStack * getExceptionStackTraceStack()
std::vector< ExceptionInfo > getCurrentExceptions()
__cxa_eh_globals * __cxa_get_globals(void) noexcept
__attribute__((noinline, noclone)) VirtualBase *makeVirtual()
__cxa_exception * caughtExceptions
Definition: ExceptionAbi.h:47
void printExceptionInfo(std::ostream &out, const ExceptionInfo &info, int options)
fbstring demangle(const char *name)
Definition: Demangle.cpp:111