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

unconditionally build symbolizer sources even if FOLLY_USE_SYMBOLIZER is unset...

unconditionally build symbolizer sources even if FOLLY_USE_SYMBOLIZER is unset or the platform is non-ELF

Summary:
Rather than conditionally include the folly symbolizer sources in the
CMake build, always build them, and add appropriate dependency defines
to conditionally enable functionality.

Reviewed By: yfeldblum

Differential Revision: D22970595

fbshipit-source-id: 957242b7fde28584edd78a1a6dbe9f830e98e726
parent 6da515d7
......@@ -67,6 +67,9 @@
#cmakedefine FOLLY_USE_LIBCPP 1
#cmakedefine HAVE_VSNPRINTF_ERRORS 1
#cmakedefine FOLLY_HAVE_LIBUNWIND 1
#cmakedefine FOLLY_HAVE_DWARF 1
#cmakedefine FOLLY_HAVE_ELF 1
#cmakedefine FOLLY_USE_SYMBOLIZER 1
#define FOLLY_DEMANGLE_MAX_SYMBOL_SIZE 1024
......
......@@ -156,10 +156,13 @@ if (LIBUNWIND_FOUND)
endif()
find_package(Backtrace)
set(FOLLY_HAVE_BACKTRACE ${Backtrace_FOUND})
if (FOLLY_HAVE_ELF AND FOLLY_HAVE_BACKTRACE AND LIBUNWIND_FOUND AND LIBDWARF_FOUND)
set(FOLLY_HAVE_DWARF ${LIBDWARF_FOUND})
if (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}")
message(STATUS "Setting FOLLY_HAVE_ELF: ${FOLLY_HAVE_ELF}")
message(STATUS "Setting FOLLY_HAVE_DWARF: ${FOLLY_HAVE_DWARF}")
# Using clang with libstdc++ requires explicitly linking against libatomic
check_cxx_source_compiles("
......
......@@ -198,15 +198,6 @@ list(APPEND hfiles
# Exclude specific sources if we do not have third-party libraries
# required to build them.
if (NOT FOLLY_USE_SYMBOLIZER)
REMOVE_MATCHES_FROM_LISTS(files hfiles
MATCHES
"^${FOLLY_DIR}/experimental/symbolizer/"
)
list(REMOVE_ITEM files
${FOLLY_DIR}/SingletonStackTrace.cpp
)
endif()
if (NOT ${LIBAIO_FOUND})
list(REMOVE_ITEM files
${FOLLY_DIR}/experimental/io/AsyncIO.cpp
......
......@@ -16,13 +16,10 @@
#include <folly/detail/SingletonStackTrace.h>
#include <folly/experimental/symbolizer/ElfCache.h>
#include <folly/experimental/symbolizer/Symbolizer.h>
#include <folly/portability/Config.h>
#if FOLLY_USE_SYMBOLIZER
#include <folly/experimental/symbolizer/ElfCache.h> // @manual
#include <folly/experimental/symbolizer/Symbolizer.h> // @manual
#endif
namespace folly {
namespace detail {
......
......@@ -17,10 +17,14 @@
#include <folly/experimental/symbolizer/Dwarf.h>
#include <array>
#include <type_traits>
#include <dwarf.h>
#include <folly/Optional.h>
#include <type_traits>
#include <folly/portability/Config.h>
#if FOLLY_HAVE_DWARF
#include <dwarf.h>
namespace folly {
namespace symbolizer {
......@@ -1357,3 +1361,5 @@ bool Dwarf::LineNumberVM::findAddress(
} // namespace symbolizer
} // namespace folly
#endif // FOLLY_HAVE_DWARF
......@@ -28,6 +28,8 @@
namespace folly {
namespace symbolizer {
#if FOLLY_HAVE_DWARF
namespace detail {
// A top level chunk in the .debug_info that contains a compilation unit.
......@@ -326,5 +328,7 @@ class Dwarf::LineNumberVM {
uint64_t discriminator_;
};
#endif
} // namespace symbolizer
} // namespace folly
......@@ -17,10 +17,8 @@
#include <folly/experimental/symbolizer/Elf.h>
#include <fcntl.h>
#include <folly/portability/SysMman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cstring>
#include <string>
......@@ -29,6 +27,10 @@
#include <folly/Conv.h>
#include <folly/Exception.h>
#include <folly/ScopeGuard.h>
#include <folly/portability/Config.h>
#include <folly/portability/SysMman.h>
#if FOLLY_HAVE_ELF
#ifndef STT_GNU_IFUNC
#define STT_GNU_IFUNC 10
......@@ -430,3 +432,5 @@ const char* ElfFile::getSymbolName(Symbol symbol) const noexcept {
} // namespace symbolizer
} // namespace folly
#endif // FOLLY_HAVE_ELF
......@@ -19,9 +19,6 @@
#pragma once
#define FOLLY_EXPERIMENTAL_SYMBOLIZER_ELF_H_
#include <elf.h>
#include <link.h> // For ElfW()
#include <cstdio>
#include <initializer_list>
#include <stdexcept>
......@@ -31,6 +28,12 @@
#include <folly/Likely.h>
#include <folly/Range.h>
#include <folly/lang/SafeAssert.h>
#include <folly/portability/Config.h>
#if FOLLY_HAVE_ELF
#include <elf.h>
#include <link.h> // For ElfW()
namespace folly {
namespace symbolizer {
......@@ -284,7 +287,7 @@ class ElfFile {
sizeof(msg),
"Offset (%zu + %zu) is not contained within our mmapped"
" file (%s) of length %zu",
offset,
static_cast<size_t>(offset),
sizeof(T),
filepath_,
length_);
......@@ -330,3 +333,5 @@ class ElfFile {
} // namespace folly
#include <folly/experimental/symbolizer/Elf-inl.h>
#endif // FOLLY_HAVE_ELF
......@@ -19,8 +19,11 @@
#include <signal.h>
#include <folly/ScopeGuard.h>
#include <folly/portability/Config.h>
#include <folly/portability/SysMman.h>
#if FOLLY_HAVE_ELF
namespace folly {
namespace symbolizer {
......@@ -105,3 +108,5 @@ std::shared_ptr<ElfFile> ElfCache::filePtr(const std::shared_ptr<Entry>& e) {
}
} // namespace symbolizer
} // namespace folly
#endif // FOLLY_HAVE_ELF
......@@ -29,10 +29,13 @@
#include <folly/experimental/symbolizer/Elf.h>
#include <folly/hash/Hash.h>
#include <folly/memory/ReentrantAllocator.h>
#include <folly/portability/Config.h>
namespace folly {
namespace symbolizer {
#if FOLLY_HAVE_ELF
class ElfCacheBase {
public:
virtual std::shared_ptr<ElfFile> getFile(StringPiece path) = 0;
......@@ -132,5 +135,8 @@ class ElfCache : public ElfCacheBase {
std::unordered_map<StringPiece, std::shared_ptr<Entry>, Hash> files_;
};
#endif // FOLLY_HAVE_ELF
} // namespace symbolizer
} // namespace folly
......@@ -39,10 +39,14 @@
namespace folly {
namespace symbolizer {
#ifndef _WIN32
const unsigned long kAllFatalSignals = (1UL << SIGSEGV) | (1UL << SIGILL) |
(1UL << SIGFPE) | (1UL << SIGABRT) | (1UL << SIGBUS) | (1UL << SIGTERM) |
(1UL << SIGQUIT);
#endif
namespace {
/**
......@@ -99,6 +103,20 @@ FatalSignalCallbackRegistry* getFatalSignalCallbackRegistry() {
return fatalSignalCallbackRegistry;
}
} // namespace
void addFatalSignalCallback(SignalCallback cb) {
getFatalSignalCallbackRegistry()->add(cb);
}
void installFatalSignalCallbacks() {
getFatalSignalCallbackRegistry()->markInstalled();
}
#ifndef _WIN32
namespace {
struct {
int number;
const char* name;
......@@ -114,7 +132,7 @@ struct {
{0, nullptr, {}},
};
void callPreviousSignalHandler(int signum) {
FOLLY_MAYBE_UNUSED void callPreviousSignalHandler(int signum) {
// Restore disposition to old disposition, then kill ourselves with the same
// signal. The signal will be blocked until we return from our handler,
// then it will invoke the default handler and abort.
......@@ -134,6 +152,8 @@ void callPreviousSignalHandler(int signum) {
raise(signum);
}
#if FOLLY_USE_SYMBOLIZER
// Note: not thread-safe, but that's okay, as we only let one thread
// in our signal handler at a time.
//
......@@ -142,6 +162,14 @@ void callPreviousSignalHandler(int signum) {
// Initialized by installFatalSignalHandler
SafeStackTracePrinter* gStackTracePrinter;
void print(StringPiece sp) {
gStackTracePrinter->print(sp);
}
void flush() {
gStackTracePrinter->flush();
}
void printDec(uint64_t val) {
char buf[20];
uint32_t n = uint64ToBufferUnsafe(val, buf);
......@@ -165,14 +193,6 @@ void printHex(uint64_t val) {
gStackTracePrinter->print(StringPiece(p, end));
}
void print(StringPiece sp) {
gStackTracePrinter->print(sp);
}
void flush() {
gStackTracePrinter->flush();
}
void dumpTimeInfo() {
SCOPE_EXIT {
flush();
......@@ -460,26 +480,14 @@ void signalHandler(int signum, siginfo_t* info, void* uctx) {
callPreviousSignalHandler(signum);
}
} // namespace
void addFatalSignalCallback(SignalCallback cb) {
getFatalSignalCallbackRegistry()->add(cb);
}
void installFatalSignalCallbacks() {
getFatalSignalCallbackRegistry()->markInstalled();
}
namespace {
std::atomic<bool> gAlreadyInstalled;
#endif // FOLLY_USE_SYMBOLIZER
// Small sigaltstack size threshold.
// 8931 is known to cause the signal handler to stack overflow during
// symbolization even for a simple one-liner "kill(getpid(), SIGTERM)".
const size_t kSmallSigAltStackSize = 8931;
constexpr size_t kSmallSigAltStackSize = 8931;
bool isSmallSigAltStackEnabled() {
FOLLY_MAYBE_UNUSED bool isSmallSigAltStackEnabled() {
stack_t ss;
if (sigaltstack(nullptr, &ss) != 0) {
return false;
......@@ -492,6 +500,12 @@ bool isSmallSigAltStackEnabled() {
} // namespace
#endif // _WIN32
namespace {
std::atomic<bool> gAlreadyInstalled;
}
void installFatalSignalHandler(std::bitset<64> signals) {
if (gAlreadyInstalled.exchange(true)) {
// Already done.
......@@ -503,6 +517,7 @@ void installFatalSignalHandler(std::bitset<64> signals) {
gFatalSignalCallbackRegistry.store(
getFatalSignalCallbackRegistry(), std::memory_order_release);
#if FOLLY_USE_SYMBOLIZER
// 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.
......@@ -538,6 +553,7 @@ void installFatalSignalHandler(std::bitset<64> signals) {
CHECK_ERR(sigaction(p->number, &sa, &p->oldAction));
}
}
#endif // FOLLY_USE_SYMBOLIZER
}
} // namespace symbolizer
} // namespace folly
......@@ -16,35 +16,56 @@
#include <folly/experimental/symbolizer/StackTrace.h>
#include <memory>
#include <folly/CppAttributes.h>
#include <folly/Portability.h>
#include <folly/portability/Config.h>
#if FOLLY_HAVE_LIBUNWIND
// Must be first to ensure that UNW_LOCAL_ONLY is defined
#define UNW_LOCAL_ONLY 1
#include <libunwind.h>
#endif
#ifdef __APPLE__
#if FOLLY_USE_SYMBOLIZER
#include <execinfo.h>
#endif
#include <folly/Portability.h>
#include <memory>
namespace folly {
namespace symbolizer {
ssize_t getStackTrace(uintptr_t* addresses, size_t maxAddresses) {
ssize_t getStackTrace(
FOLLY_MAYBE_UNUSED uintptr_t* addresses,
FOLLY_MAYBE_UNUSED size_t maxAddresses) {
static_assert(
sizeof(uintptr_t) == sizeof(void*), "uintptr_t / pointer size mismatch");
// The libunwind documentation says that unw_backtrace is async-signal-safe
// but, as of libunwind 1.0.1, it isn't (tdep_trace allocates memory on
// x86_64)
#ifdef __APPLE__
// The libunwind documentation says that unw_backtrace is
// async-signal-safe but, as of libunwind 1.0.1, it isn't
// (tdep_trace allocates memory on x86_64)
//
// There are two major variants of libunwind. libunwind on Linux
// (https://www.nongnu.org/libunwind/) provides unw_backtrace, and
// Apache/LLVM libunwind (notably used on Apple platforms)
// doesn't. They can be distinguished with the UNW_VERSION #define.
//
// When unw_backtrace is not available, fall back on the standard
// `backtrace` function from execinfo.h.
#if FOLLY_HAVE_LIBUNWIND && defined(UNW_VERSION)
int r = unw_backtrace(reinterpret_cast<void**>(addresses), maxAddresses);
return r < 0 ? -1 : r;
#elif FOLLY_USE_SYMBOLIZER
int r = backtrace(reinterpret_cast<void**>(addresses), maxAddresses);
return r < 0 ? -1 : r;
#else
int r = unw_backtrace(reinterpret_cast<void**>(addresses), maxAddresses);
return -1;
#endif
return r < 0 ? -1 : r;
}
namespace {
#if FOLLY_HAVE_LIBUNWIND
inline bool getFrameInfo(unw_cursor_t* cursor, uintptr_t& ip) {
unw_word_t uip;
if (unw_get_reg(cursor, UNW_REG_IP, &uip) < 0) {
......@@ -95,15 +116,27 @@ ssize_t getStackTraceInPlace(
}
return count;
}
#endif // FOLLY_HAVE_LIBUNWIND
} // namespace
ssize_t getStackTraceSafe(uintptr_t* addresses, size_t maxAddresses) {
ssize_t getStackTraceSafe(
FOLLY_MAYBE_UNUSED uintptr_t* addresses,
FOLLY_MAYBE_UNUSED size_t maxAddresses) {
#if FOLLY_HAVE_LIBUNWIND
unw_context_t context;
unw_cursor_t cursor;
return getStackTraceInPlace(context, cursor, addresses, maxAddresses);
#else
return -1;
#endif
}
ssize_t getStackTraceHeap(uintptr_t* addresses, size_t maxAddresses) {
ssize_t getStackTraceHeap(
FOLLY_MAYBE_UNUSED uintptr_t* addresses,
FOLLY_MAYBE_UNUSED size_t maxAddresses) {
#if FOLLY_HAVE_LIBUNWIND
struct Ctx {
unw_context_t context;
unw_cursor_t cursor;
......@@ -114,6 +147,9 @@ ssize_t getStackTraceHeap(uintptr_t* addresses, size_t maxAddresses) {
}
return getStackTraceInPlace(
ctx_ptr->context, ctx_ptr->cursor, addresses, maxAddresses);
#else
return -1;
#endif
}
} // namespace symbolizer
} // namespace folly
......@@ -20,6 +20,8 @@
#include <cstdint>
#include <cstdlib>
#include <folly/portability/SysTypes.h>
namespace folly {
namespace symbolizer {
......
......@@ -34,6 +34,12 @@ constexpr char kHexChars[] = "0123456789abcdef";
constexpr auto kAddressColor = SymbolizePrinter::Color::BLUE;
constexpr auto kFunctionColor = SymbolizePrinter::Color::PURPLE;
constexpr auto kFileColor = SymbolizePrinter::Color::DEFAULT;
#ifdef _WIN32
constexpr size_t kPathMax = 4096;
#else
constexpr size_t kPathMax = PATH_MAX;
#endif
} // namespace
constexpr char AddressFormatter::bufTemplate[];
......@@ -98,7 +104,7 @@ void SymbolizePrinter::print(const SymbolizedFrame& frame) {
if (!(options_ & NO_FILE_AND_LINE)) {
color(kFileColor);
char fileBuf[PATH_MAX];
char fileBuf[kPathMax];
fileBuf[0] = '\0';
if (frame.location.hasFileAndLine) {
frame.location.file.toBuffer(fileBuf, sizeof(fileBuf));
......@@ -119,7 +125,7 @@ void SymbolizePrinter::print(const SymbolizedFrame& frame) {
}
if (frame.location.hasMainFile && !(options_ & TERSE_FILE_AND_LINE)) {
char mainFileBuf[PATH_MAX];
char mainFileBuf[kPathMax];
mainFileBuf[0] = '\0';
frame.location.mainFile.toBuffer(mainFileBuf, sizeof(mainFileBuf));
if (!frame.location.hasFileAndLine || strcmp(fileBuf, mainFileBuf)) {
......
......@@ -16,9 +16,6 @@
#include <folly/experimental/symbolizer/Symbolizer.h>
#include <link.h>
#include <ucontext.h>
#include <climits>
#include <cstdio>
#include <cstdlib>
......@@ -34,20 +31,26 @@
#include <folly/experimental/symbolizer/ElfCache.h>
#include <folly/experimental/symbolizer/LineReader.h>
#include <folly/lang/SafeAssert.h>
#include <folly/portability/Config.h>
#include <folly/portability/SysMman.h>
#include <folly/portability/Unistd.h>
#if defined(__linux__)
#if FOLLY_HAVE_ELF
#include <link.h>
#include <ucontext.h>
#endif
#if defined(__linux__) && FOLLY_USE_SYMBOLIZER
static struct r_debug* get_r_debug() {
return &_r_debug;
}
#elif defined(__APPLE__)
#elif FOLLY_USE_SYMBOLIZER
extern struct r_debug _r_debug;
static struct r_debug* get_r_debug() {
FOLLY_MAYBE_UNUSED static struct r_debug* get_r_debug() {
return &_r_debug;
}
#else
static struct r_debug* get_r_debug() {
FOLLY_MAYBE_UNUSED static struct r_debug* get_r_debug() {
return nullptr;
}
#endif
......@@ -55,6 +58,8 @@ static struct r_debug* get_r_debug() {
namespace folly {
namespace symbolizer {
#if FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
namespace {
ElfCache* defaultElfCache() {
......@@ -414,5 +419,7 @@ void UnsafeSelfAllocateStackTracePrinter::printSymbolizedStackTrace() {
}
}
#endif // FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
} // namespace symbolizer
} // namespace folly
......@@ -32,6 +32,7 @@
#include <folly/experimental/symbolizer/SymbolizePrinter.h>
#include <folly/experimental/symbolizer/SymbolizedFrame.h>
#include <folly/io/IOBuf.h>
#include <folly/portability/Config.h>
namespace folly {
namespace symbolizer {
......@@ -86,6 +87,8 @@ inline bool getStackTraceHeap(FrameArray<N>& fa) {
return detail::fixFrameArray(fa, getStackTraceHeap(fa.addresses, N));
}
#if FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
class Symbolizer {
public:
static constexpr auto kDefaultLocationInfoMode = LocationInfoMode::FAST;
......@@ -250,5 +253,7 @@ class UnsafeSelfAllocateStackTracePrinter : public SafeStackTracePrinter {
const long pageSizeUnchecked_ = sysconf(_SC_PAGESIZE);
};
#endif // FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
} // namespace symbolizer
} // namespace folly
......@@ -24,7 +24,7 @@
#include <folly/portability/Config.h>
#include <folly/synchronization/HazptrThreadPoolExecutor.h>
#if FOLLY_USE_SYMBOLIZER
#ifndef _WIN32
#include <folly/experimental/symbolizer/SignalHandler.h> // @manual
#endif
#include <folly/portability/GFlags.h>
......
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