/*
- * Copyright 2012 Facebook, Inc.
+ * Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-
-#include "folly/experimental/exception_tracer/ExceptionTracer.h"
+#include <folly/experimental/exception_tracer/ExceptionTracer.h>
#include <dlfcn.h>
#include <exception>
+#include <iostream>
#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"
+#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 {
+using namespace ::folly::exception_tracer;
+using namespace ::folly::symbolizer;
+using namespace __cxxabiv1;
+
extern "C" {
-const StackTraceStack* getExceptionStackTraceStack(void) __attribute__((weak));
-typedef const StackTraceStack* (*GetExceptionStackTraceStackType)(void);
+StackTraceStack* getExceptionStackTraceStack(void) __attribute__((weak));
+typedef StackTraceStack* (*GetExceptionStackTraceStackType)(void);
GetExceptionStackTraceStackType getExceptionStackTraceStackFn;
}
} // namespace
-using namespace ::facebook::symbolizer;
-using namespace __cxxabiv1;
-
+namespace folly {
namespace exception_tracer {
std::ostream& operator<<(std::ostream& out, const ExceptionInfo& info) {
out << "Exception type: ";
if (info.type) {
- out << folly::demangle(*info.type) << "\n";
+ out << folly::demangle(*info.type);
} else {
- out << "(unknown type)\n";
+ out << "(unknown type)";
}
- 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);
+ out << " (" << info.frames.size()
+ << (info.frames.size() == 1 ? " frame" : " frames")
+ << ")\n";
+ try {
+ ssize_t frameCount = info.frames.size();
+ // Skip our own internal frames
+ static constexpr size_t skip = 3;
+
+ if (frameCount > skip) {
+ auto addresses = info.frames.data() + skip;
+ frameCount -= skip;
+
+ std::vector<SymbolizedFrame> frames;
+ frames.resize(frameCount);
+
+ Symbolizer symbolizer;
+ symbolizer.symbolize(addresses, frames.data(), frameCount);
+
+ OStreamSymbolizePrinter osp(out, SymbolizePrinter::COLOR_IF_TTY);
+ osp.println(addresses, frames.data(), frameCount);
+ }
+ } catch (const std::exception& e) {
+ out << "\n !! caught " << folly::exceptionStr(e) << "\n";
+ } catch (...) {
+ out << "\n !!! caught unexpected exception\n";
}
return out;
}
return exceptions;
}
- bool hasTraceStack = false;
- const StackTraceStack* traceStack = nullptr;
+ StackTraceStack* traceStack = nullptr;
if (!getExceptionStackTraceStackFn) {
static bool logged = false;
if (!logged) {
<< "Exception stack trace invalid, stack traces not available";
logged = true;
}
- } else {
- hasTraceStack = true;
}
+ StackTrace* trace = traceStack ? traceStack->top() : nullptr;
while (currentException) {
ExceptionInfo info;
// Dependent exceptions (thrown via std::rethrow_exception) aren't
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;
+ if (traceStack) {
+ CHECK(trace) << "Invalid trace stack!";
+ info.frames.assign(trace->addresses,
+ trace->addresses + trace->frameCount);
+ trace = traceStack->next(trace);
}
currentException = currentException->nextException;
exceptions.push_back(std::move(info));
}
-
- CHECK(!traceStack) << "Invalid trace stack!";
+ CHECK(!trace) << "Invalid trace stack!";
return exceptions;
}
if (exceptions.empty()) {
return;
}
- LOG(ERROR) << prefix << ", exception stack follows\n";
+ LOG(ERROR) << prefix << ", exception stack follows";
for (auto& exc : exceptions) {
LOG(ERROR) << exc << "\n";
}
+ LOG(ERROR) << "exception stack complete";
}
void terminateHandler() {
}
} // namespace exception_tracer
-
+} // namespace folly