Permalink
Browse files

Move exception tracer library to folly/experimental

Summary:
This change is mostly mechanical (moving files, changing include paths,
etc).  I made some changes to TARGETS to make it easier for the library
to be linked in (instead of LD_PRELOADed)

Test Plan: by hand

Reviewed By: simpkins@fb.com

FB internal diff: D562196
  • Loading branch information...
1 parent b94353f commit e8cabb32411a5e4f7928496faa64cecc999dfcd7 @tudor tudor committed with jdelong Aug 30, 2012
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef FOLLY_EXPERIMENTAL_EXCEPTION_TRACER_EXCEPTIONABI_H_
+#define FOLLY_EXPERIMENTAL_EXCEPTION_TRACER_EXCEPTIONABI_H_
+
+// A clone of the relevant parts of unwind-cxx.h from libstdc++
+// The layout of these structures is defined by the ABI.
+
+#include <exception>
+#include <typeinfo>
+
+#include <unwind.h>
+
+namespace __cxxabiv1 {
+
+struct __cxa_exception {
+ std::type_info* exceptionType;
+ void (*exceptionDestructor) (void*);
+ std::unexpected_handler unexpectedHandler;
+ std::terminate_handler terminateHandler;
+ __cxa_exception* nextException;
+
+ int handlerCount;
+ int handlerSwitchValue;
+ const char* actionRecord;
+ const char* languageSpecificData;
+ void* catchTemp;
+ void* adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+struct __cxa_eh_globals {
+ __cxa_exception* caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+
+extern "C" {
+__cxa_eh_globals* __cxa_get_globals(void);
+__cxa_eh_globals* __cxa_get_globals_fast(void);
+}
+
+} // namespace __cxxabiv1
+
+#endif /* FOLLY_EXPERIMENTAL_EXCEPTION_TRACER_EXCEPTIONABI_H_ */
+
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2012 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "folly/experimental/exception_tracer/ExceptionTracer.h"
+
+#include <dlfcn.h>
+#include <exception>
+#include <glog/logging.h>
+
+#include "folly/experimental/exception_tracer/ExceptionAbi.h"
+#include "folly/experimental/exception_tracer/StackTrace.h"
+#include "folly/experimental/symbolizer/Symbolizer.h"
+#include "folly/String.h"
+
+namespace {
+
+extern "C" {
+const StackTraceStack* getExceptionStackTraceStack(void) __attribute__((weak));
+typedef const StackTraceStack* (*GetExceptionStackTraceStackType)(void);
+GetExceptionStackTraceStackType getExceptionStackTraceStackFn;
+}
+
+} // namespace
+
+using namespace ::facebook::symbolizer;
+using namespace __cxxabiv1;
+
+namespace exception_tracer {
+
+std::ostream& operator<<(std::ostream& out, const ExceptionInfo& info) {
+ out << "Exception type: ";
+ if (info.type) {
+ out << folly::demangle(*info.type) << "\n";
+ } else {
+ out << "(unknown type)\n";
+ }
+ Symbolizer symbolizer;
+ folly::StringPiece symbolName;
+ Dwarf::LocationInfo location;
+ for (auto ip : info.frames) {
+ // Symbolize the previous address because the IP might be in the
+ // next function, per glog/src/signalhandler.cc
+ symbolizer.symbolize(ip-1, symbolName, location);
+ Symbolizer::write(out, ip, symbolName, location);
+ }
+ return out;
+}
+
+namespace {
+
+/**
+ * Is this a standard C++ ABI exception?
+ *
+ * Dependent exceptions (thrown via std::rethrow_exception) aren't --
+ * exc doesn't actually point to a __cxa_exception structure, but
+ * the offset of unwindHeader is correct, so exc->unwindHeader actually
+ * returns a _Unwind_Exception object. Yeah, it's ugly like that.
+ */
+bool isAbiCppException(const __cxa_exception* exc) {
+ // The least significant four bytes must be "C++\0"
+ static const uint64_t cppClass =
+ ((uint64_t)'C' << 24) |
+ ((uint64_t)'+' << 16) |
+ ((uint64_t)'+' << 8);
+ return (exc->unwindHeader.exception_class & 0xffffffff) == cppClass;
+}
+
+} // namespace
+
+std::vector<ExceptionInfo> getCurrentExceptions() {
+ struct Once {
+ Once() {
+ // See if linked in with us (getExceptionStackTraceStack is weak)
+ getExceptionStackTraceStackFn = getExceptionStackTraceStack;
+
+ if (!getExceptionStackTraceStackFn) {
+ // Nope, see if it's in a shared library
+ getExceptionStackTraceStackFn =
+ (GetExceptionStackTraceStackType)dlsym(
+ RTLD_NEXT, "getExceptionStackTraceStack");
+ }
+ }
+ };
+ static Once once;
+
+ std::vector<ExceptionInfo> exceptions;
+ auto currentException = __cxa_get_globals()->caughtExceptions;
+ if (!currentException) {
+ return exceptions;
+ }
+
+ bool hasTraceStack = false;
+ const StackTraceStack* traceStack = nullptr;
+ if (!getExceptionStackTraceStackFn) {
+ static bool logged = false;
+ if (!logged) {
+ LOG(WARNING)
+ << "Exception tracer library not linked, stack traces not available";
+ logged = true;
+ }
+ } else if ((traceStack = getExceptionStackTraceStackFn()) == nullptr) {
+ static bool logged = false;
+ if (!logged) {
+ LOG(WARNING)
+ << "Exception stack trace invalid, stack traces not available";
+ logged = true;
+ }
+ } else {
+ hasTraceStack = true;
+ }
+
+ while (currentException) {
+ ExceptionInfo info;
+ // Dependent exceptions (thrown via std::rethrow_exception) aren't
+ // standard ABI __cxa_exception objects, and are correctly labeled as
+ // such in the exception_class field. We could try to extract the
+ // primary exception type in horribly hacky ways, but, for now, NULL.
+ info.type =
+ isAbiCppException(currentException) ?
+ currentException->exceptionType :
+ nullptr;
+ if (hasTraceStack) {
+ CHECK(traceStack) << "Invalid trace stack!";
+ info.frames.assign(
+ traceStack->trace.frameIPs,
+ traceStack->trace.frameIPs + traceStack->trace.frameCount);
+ traceStack = traceStack->next;
+ }
+ currentException = currentException->nextException;
+ exceptions.push_back(std::move(info));
+ }
+
+ CHECK(!traceStack) << "Invalid trace stack!";
+
+ return exceptions;
+}
+
+namespace {
+
+std::terminate_handler origTerminate = abort;
+std::unexpected_handler origUnexpected = abort;
+
+void dumpExceptionStack(const char* prefix) {
+ auto exceptions = getCurrentExceptions();
+ if (exceptions.empty()) {
+ return;
+ }
+ LOG(ERROR) << prefix << ", exception stack follows\n";
+ for (auto& exc : exceptions) {
+ LOG(ERROR) << exc << "\n";
+ }
+}
+
+void terminateHandler() {
+ dumpExceptionStack("terminate() called");
+ origTerminate();
+}
+
+void unexpectedHandler() {
+ dumpExceptionStack("Unexpected exception");
+ origUnexpected();
+}
+
+} // namespace
+
+void installHandlers() {
+ struct Once {
+ Once() {
+ origTerminate = std::set_terminate(terminateHandler);
+ origUnexpected = std::set_unexpected(unexpectedHandler);
+ }
+ };
+ static Once once;
+}
+
+} // namespace exception_tracer
+
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Exception tracer library.
+
+#ifndef FOLLY_EXPERIMENTAL_EXCEPTION_TRACER_EXCEPTIONTRACER_H_
+#define FOLLY_EXPERIMENTAL_EXCEPTION_TRACER_EXCEPTIONTRACER_H_
+
+#include <vector>
+#include <iostream>
+
+namespace exception_tracer {
+
+struct ExceptionInfo {
+ const std::type_info* type;
+ // The values in frames are IP (instruction pointer) addresses.
+ // They are only filled if the low-level exception tracer library is
+ // linked in or LD_PRELOADed.
+ std::vector<uintptr_t> frames; // front() is top of stack
+};
+
+std::ostream& operator<<(std::ostream& out, const ExceptionInfo& info);
+
+/**
+ * Get current exceptions being handled. front() is the most recent exception.
+ * There should be at most one unless rethrowing.
+ */
+std::vector<ExceptionInfo> getCurrentExceptions();
+
+/**
+ * Install the terminate / unexpected handlers to dump exceptions.
+ */
+void installHandlers();
+
+} // namespace exception_tracer
+
+#endif /* FOLLY_EXPERIMENTAL_EXCEPTION_TRACER_EXCEPTIONTRACER_H_ */
+
Oops, something went wrong.

0 comments on commit e8cabb3

Please sign in to comment.