diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d0dc78817b..9229656df9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -367,6 +367,15 @@ if(HAVE_LIBEXECINFO) set(HAVE_BACKTRACE_SYMBOLS TRUE) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + set(ICINGA2_STACKTRACE_USE_BACKTRACE_SYMBOLS TRUE) + add_definitions(-D_GNU_SOURCE) +endif() + +if(ICINGA2_STACKTRACE_USE_BACKTRACE_SYMBOLS AND NOT HAVE_BACKTRACE_SYMBOLS) + message(FATAL_ERROR "ICINGA2_STACKTRACE_USE_BACKTRACE_SYMBOLS is set but backtrace_symbols() was not found") +endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") exec_program(${CMAKE_CXX_COMPILER} ARGS -dumpversion diff --git a/config.h.cmake b/config.h.cmake index 16fa190f17e..3ed2ae46df1 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -12,6 +12,7 @@ #cmakedefine HAVE_SYSTEMD #cmakedefine ICINGA2_UNITY_BUILD +#cmakedefine ICINGA2_STACKTRACE_USE_BACKTRACE_SYMBOLS #define ICINGA_CONFIGDIR "${ICINGA2_FULL_CONFIGDIR}" #define ICINGA_DATADIR "${ICINGA2_FULL_DATADIR}" diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index ed8576b563f..108ca27c13e 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -64,6 +64,7 @@ set(base_SOURCES shared-object.hpp singleton.hpp socket.cpp socket.hpp + stacktrace.cpp stacktrace.hpp statsfunction.hpp stdiostream.cpp stdiostream.hpp stream.cpp stream.hpp diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 06265ec0e4b..c70926c6d8d 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -2,6 +2,7 @@ #include "base/application.hpp" #include "base/application-ti.cpp" +#include "base/stacktrace.hpp" #include "base/timer.hpp" #include "base/logger.hpp" #include "base/exception.hpp" @@ -763,7 +764,7 @@ void Application::SigAbrtHandler(int) DisplayInfoMessage(ofs); - ofs << "\nStacktrace:\n" << boost::stacktrace::stacktrace() << "\n"; + ofs << "\nStacktrace:\n" << StackTraceFormatter(boost::stacktrace::stacktrace()) << "\n"; DisplayBugMessage(ofs); @@ -954,7 +955,7 @@ LONG CALLBACK Application::SEHUnhandledExceptionFilter(PEXCEPTION_POINTERS exi) << " Flags: " << exi->ExceptionRecord->ExceptionFlags << "\n"; ofs.flags(savedflags); - ofs << "\nStacktrace:\n" << boost::stacktrace::stacktrace() << "\n"; + ofs << "\nStacktrace:\n" << StackTraceFormatter(boost::stacktrace::stacktrace()) << "\n"; DisplayBugMessage(ofs); diff --git a/lib/base/exception.cpp b/lib/base/exception.cpp index 17921a2f6ca..a194dafd590 100644 --- a/lib/base/exception.cpp +++ b/lib/base/exception.cpp @@ -1,6 +1,7 @@ /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #include "base/exception.hpp" +#include "base/stacktrace.hpp" #include #include @@ -248,7 +249,7 @@ String icinga::DiagnosticInformation(const std::exception& ex, bool verbose, boo } if (st && !st->empty()) { - result << "\nStacktrace:\n" << *st; + result << "\nStacktrace:\n" << StackTraceFormatter(*st); } } diff --git a/lib/base/stacktrace.cpp b/lib/base/stacktrace.cpp new file mode 100644 index 00000000000..01e3988bb03 --- /dev/null +++ b/lib/base/stacktrace.cpp @@ -0,0 +1,36 @@ +/* Icinga 2 | (c) 2020 Icinga GmbH | GPLv2+ */ + +#include +#include "base/stacktrace.hpp" +#include +#include +#include + +#ifdef HAVE_BACKTRACE_SYMBOLS +# include +#endif /* HAVE_BACKTRACE_SYMBOLS */ + +using namespace icinga; + +std::ostream &icinga::operator<<(std::ostream &os, const StackTraceFormatter &f) +{ + const boost::stacktrace::stacktrace &stack = f.m_Stack; + +#ifdef ICINGA2_STACKTRACE_USE_BACKTRACE_SYMBOLS + std::vector addrs; + addrs.reserve(stack.size()); + std::transform(stack.begin(), stack.end(), std::back_inserter(addrs), [](const boost::stacktrace::frame &f) { + return const_cast(f.address()); + }); + + char **symbols = backtrace_symbols(addrs.data(), addrs.size()); + for (size_t i = 0; i < addrs.size(); i++) { + os << std::setw(2) << i << "# " << symbols[i] << std::endl; + } + std::free(symbols); +#else /* ICINGA2_STACKTRACE_USE_BACKTRACE_SYMBOLS */ + os << stack; +#endif /* ICINGA2_STACKTRACE_USE_BACKTRACE_SYMBOLS */ + + return os; +} diff --git a/lib/base/stacktrace.hpp b/lib/base/stacktrace.hpp new file mode 100644 index 00000000000..53a9b898b45 --- /dev/null +++ b/lib/base/stacktrace.hpp @@ -0,0 +1,25 @@ +/* Icinga 2 | (c) 2020 Icinga GmbH | GPLv2+ */ + +#ifndef STACKTRACE_H +#define STACKTRACE_H + +#include + +namespace icinga +{ + +class StackTraceFormatter { +public: + StackTraceFormatter(const boost::stacktrace::stacktrace &stack) : m_Stack(stack) {} + +private: + const boost::stacktrace::stacktrace &m_Stack; + + friend std::ostream &operator<<(std::ostream &os, const StackTraceFormatter &f); +}; + +std::ostream& operator<<(std::ostream& os, const StackTraceFormatter &f); + +} + +#endif /* STACKTRACE_H */