Commit b404e159 authored by Chad Austin's avatar Chad Austin Committed by Facebook GitHub Bot

enable FOLLY_USE_SYMBOLIZER on macOS

Summary:
Enable FOLLY_USE_SYMBOLIZER on macOS and teach SafeStackTracePrinter
to use `backtrace_symbols_fd` on non-ELF platforms.

Reviewed By: luciang

Differential Revision: D23017169

fbshipit-source-id: 1ad6cbf6d9ad11276d95b821095e37a86c8bb862
parent 40eff3a7
......@@ -155,9 +155,10 @@ if (LIBUNWIND_FOUND)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${UNWIND_LIBRARIES})
endif()
find_package(Backtrace)
set(FOLLY_HAVE_BACKTRACE ${Backtrace_FOUND})
set(FOLLY_HAVE_DWARF ${LIBDWARF_FOUND})
if (FOLLY_HAVE_ELF AND FOLLY_HAVE_DWARF AND FOLLY_HAVE_BACKTRACE AND LIBUNWIND_FOUND)
if (APPLE OR (FOLLY_HAVE_ELF AND FOLLY_HAVE_DWARF AND FOLLY_HAVE_BACKTRACE AND LIBUNWIND_FOUND))
set(FOLLY_USE_SYMBOLIZER ON)
endif()
message(STATUS "Setting FOLLY_USE_SYMBOLIZER: ${FOLLY_USE_SYMBOLIZER}")
......
......@@ -24,7 +24,7 @@ namespace folly {
namespace detail {
std::string getSingletonStackTrace() {
#if FOLLY_USE_SYMBOLIZER
#if FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
// Get and symbolize stack trace
constexpr size_t kMaxStackTraceDepth = 100;
......@@ -48,7 +48,7 @@ std::string getSingletonStackTrace() {
return "";
#endif
#endif // FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
}
} // namespace detail
......
......@@ -521,7 +521,7 @@ void installFatalSignalHandler(std::bitset<64> signals) {
// If a small sigaltstack is enabled (ex. Rust stdlib might use sigaltstack
// to set a small stack), the default SafeStackTracePrinter would likely
// stack overflow. Replace it with the unsafe self-allocate printer.
bool useUnsafePrinter = isSmallSigAltStackEnabled();
bool useUnsafePrinter = kIsLinux && isSmallSigAltStackEnabled();
if (useUnsafePrinter) {
gStackTracePrinter = new UnsafeSelfAllocateStackTracePrinter();
} else {
......
......@@ -126,7 +126,16 @@ ssize_t getStackTraceInPlace(
ssize_t getStackTraceSafe(
FOLLY_MAYBE_UNUSED uintptr_t* addresses,
FOLLY_MAYBE_UNUSED size_t maxAddresses) {
#if FOLLY_HAVE_LIBUNWIND
#if defined(__APPLE__) && FOLLY_USE_SYMBOLIZER
// While Apple platforms support libunwind, the unw_init_local,
// unw_step step loop does not cross the boundary from async signal
// handlers to the aborting code, while `backtrace` from execinfo.h
// does. `backtrace` is not explicitly documented on either macOS or
// Linux to be async-signal-safe, but the implementation in
// https://opensource.apple.com/source/Libc/Libc-1353.60.8/, and it is
// widely used in signal handlers in practice.
return backtrace(reinterpret_cast<void**>(addresses), maxAddresses);
#elif FOLLY_HAVE_LIBUNWIND
unw_context_t context;
unw_cursor_t cursor;
return getStackTraceInPlace(context, cursor, addresses, maxAddresses);
......
......@@ -35,13 +35,22 @@
#include <folly/portability/SysMman.h>
#include <folly/portability/Unistd.h>
#ifndef _WIN32
// folly/portability/Config.h (thus features.h) must be included
// first, and _XOPEN_SOURCE must be defined to unable the context
// functions on macOS.
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE
#endif
#include <ucontext.h>
#endif
#if FOLLY_HAVE_BACKTRACE
#include <execinfo.h>
#endif
#if FOLLY_HAVE_ELF
#include <link.h>
#include <ucontext.h>
#endif
#if defined(__linux__) && FOLLY_USE_SYMBOLIZER
......@@ -243,6 +252,48 @@ size_t Symbolizer::symbolize(
return addrCount;
}
FastStackTracePrinter::FastStackTracePrinter(
std::unique_ptr<SymbolizePrinter> printer,
size_t symbolCacheSize)
: printer_(std::move(printer)),
symbolizer_(defaultElfCache(), LocationInfoMode::FULL, symbolCacheSize) {}
FastStackTracePrinter::~FastStackTracePrinter() = default;
void FastStackTracePrinter::printStackTrace(bool symbolize) {
SCOPE_EXIT {
printer_->flush();
};
FrameArray<kMaxStackTraceDepth> addresses;
if (!getStackTraceSafe(addresses)) {
printer_->print("(error retrieving stack trace)\n");
} else if (symbolize) {
symbolizer_.symbolize(addresses);
// Skip the top 2 frames:
// getStackTraceSafe
// FastStackTracePrinter::printStackTrace (here)
printer_->println(addresses, 2);
} else {
printer_->print("(safe mode, symbolizer not available)\n");
AddressFormatter formatter;
for (size_t i = 0; i < addresses.frameCount; ++i) {
printer_->print(formatter.format(addresses.addresses[i]));
printer_->print("\n");
}
}
}
void FastStackTracePrinter::flush() {
printer_->flush();
}
#endif // FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
#if FOLLY_USE_SYMBOLIZER
SafeStackTracePrinter::SafeStackTracePrinter(int fd)
: fd_(fd),
printer_(
......@@ -257,6 +308,7 @@ void SafeStackTracePrinter::flush() {
}
void SafeStackTracePrinter::printSymbolizedStackTrace() {
#if FOLLY_HAVE_ELF
// This function might run on an alternative stack allocated by
// UnsafeSelfAllocateStackTracePrinter. Capturing a stack from
// here is probably wrong.
......@@ -273,6 +325,16 @@ void SafeStackTracePrinter::printSymbolizedStackTrace() {
//
// Leaving signalHandler on the stack for clarity, I think.
printer_.println(*addresses_, 2);
#else
// `backtrace_symbols_fd` from execinfo.h is not explicitly
// documented on either macOS or Linux to be async-signal-safe, but
// the implementation in opensource.apple.com Libc-1353.60.8 appears
// safe.
::backtrace_symbols_fd(
reinterpret_cast<void**>(addresses_->addresses),
addresses_->frameCount,
fd_);
#endif
}
void SafeStackTracePrinter::printUnsymbolizedStackTrace() {
......@@ -311,44 +373,6 @@ void SafeStackTracePrinter::printStackTrace(bool symbolize) {
}
}
FastStackTracePrinter::FastStackTracePrinter(
std::unique_ptr<SymbolizePrinter> printer,
size_t symbolCacheSize)
: printer_(std::move(printer)),
symbolizer_(defaultElfCache(), LocationInfoMode::FULL, symbolCacheSize) {}
FastStackTracePrinter::~FastStackTracePrinter() = default;
void FastStackTracePrinter::printStackTrace(bool symbolize) {
SCOPE_EXIT {
printer_->flush();
};
FrameArray<kMaxStackTraceDepth> addresses;
if (!getStackTraceSafe(addresses)) {
printer_->print("(error retrieving stack trace)\n");
} else if (symbolize) {
symbolizer_.symbolize(addresses);
// Skip the top 2 frames:
// getStackTraceSafe
// FastStackTracePrinter::printStackTrace (here)
printer_->println(addresses, 2);
} else {
printer_->print("(safe mode, symbolizer not available)\n");
AddressFormatter formatter;
for (size_t i = 0; i < addresses.frameCount; ++i) {
printer_->print(formatter.format(addresses.addresses[i]));
printer_->print("\n");
}
}
}
void FastStackTracePrinter::flush() {
printer_->flush();
}
// Stack utilities used by UnsafeSelfAllocateStackTracePrinter
namespace {
// Size of mmap-allocated stack. Not to confuse with sigaltstack.
......@@ -439,7 +463,7 @@ void UnsafeSelfAllocateStackTracePrinter::printSymbolizedStackTrace() {
}
}
#endif // FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
#endif // FOLLY_USE_SYMBOLIZER
} // namespace symbolizer
} // namespace folly
......@@ -157,6 +157,42 @@ class Symbolizer {
folly::Optional<Synchronized<SymbolCache>> symbolCache_;
};
/**
* Use this class to print a stack trace from normal code. It will malloc and
* won't flush or sync.
*
* These methods are thread safe, through locking. However, they are not signal
* safe.
*/
class FastStackTracePrinter {
public:
static constexpr size_t kDefaultSymbolCacheSize = 10000;
explicit FastStackTracePrinter(
std::unique_ptr<SymbolizePrinter> printer,
size_t symbolCacheSize = kDefaultSymbolCacheSize);
~FastStackTracePrinter();
/**
* This is NOINLINE to make sure it shows up in the stack we grab, which makes
* it easy to skip printing it.
*/
FOLLY_NOINLINE void printStackTrace(bool symbolize);
void flush();
private:
static constexpr size_t kMaxStackTraceDepth = 100;
const std::unique_ptr<SymbolizePrinter> printer_;
Symbolizer symbolizer_;
};
#endif // FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
#if FOLLY_USE_SYMBOLIZER
/**
* Use this class to print a stack trace from a signal handler, or other place
* where you shouldn't allocate memory on the heap, and fsync()ing your file
......@@ -206,38 +242,6 @@ class SafeStackTracePrinter {
std::unique_ptr<FrameArray<kMaxStackTraceDepth>> addresses_;
};
/**
* Use this class to print a stack trace from normal code. It will malloc and
* won't flush or sync.
*
* These methods are thread safe, through locking. However, they are not signal
* safe.
*/
class FastStackTracePrinter {
public:
static constexpr size_t kDefaultSymbolCacheSize = 10000;
explicit FastStackTracePrinter(
std::unique_ptr<SymbolizePrinter> printer,
size_t symbolCacheSize = kDefaultSymbolCacheSize);
~FastStackTracePrinter();
/**
* This is NOINLINE to make sure it shows up in the stack we grab, which makes
* it easy to skip printing it.
*/
FOLLY_NOINLINE void printStackTrace(bool symbolize);
void flush();
private:
static constexpr size_t kMaxStackTraceDepth = 100;
const std::unique_ptr<SymbolizePrinter> printer_;
Symbolizer symbolizer_;
};
/**
* Use this class in rare situations where signal handlers are running in a
* tiny stack specified by sigaltstack.
......@@ -254,7 +258,7 @@ class UnsafeSelfAllocateStackTracePrinter : public SafeStackTracePrinter {
const long pageSizeUnchecked_ = sysconf(_SC_PAGESIZE);
};
#endif // FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
#endif // FOLLY_USE_SYMBOLIZER
} // namespace symbolizer
} // namespace folly
......@@ -25,7 +25,7 @@
#include <folly/synchronization/HazptrThreadPoolExecutor.h>
#ifndef _WIN32
#include <folly/experimental/symbolizer/SignalHandler.h> // @manual
#include <folly/experimental/symbolizer/SignalHandler.h>
#endif
#include <folly/portability/GFlags.h>
......@@ -33,7 +33,7 @@ DEFINE_string(logging, "", "Logging configuration");
namespace folly {
const unsigned long kAllFatalSignals =
#if FOLLY_USE_SYMBOLIZER
#ifndef _WIN32
symbolizer::kAllFatalSignals;
#else
0;
......@@ -48,12 +48,10 @@ void init(int* argc, char*** argv, bool removeFlags) {
}
void init(int* argc, char*** argv, InitOptions options) {
#if FOLLY_USE_SYMBOLIZER
#ifndef _WIN32
// Install the handler now, to trap errors received during startup.
// The callbacks, if any, can be installed later
folly::symbolizer::installFatalSignalHandler(options.fatal_signals);
#elif !defined(_WIN32)
google::InstallFailureSignalHandler();
#endif
// Indicate ProcessPhase::Regular and register handler to
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment