Use backtrace_symbols() when printing stack traces on FreeBSD

Unfortunately, the symbol resolution of boost::stacktrace is broken on
FreeBSD, therefore fall back to using backtrace_symbols() to print the
stack trace saved by Boost.

Additionally, -D_GNU_SOURCE is required on FreeBSD for the
_Unwind_Backtrace function used by boost::stacktrace.
This commit is contained in:
Julian Brost 2020-10-23 13:08:43 +02:00
parent 7d3885d05c
commit b931194f59
7 changed files with 77 additions and 3 deletions

View File

@ -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

View File

@ -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}"

View File

@ -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

View File

@ -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);

View File

@ -1,6 +1,7 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "base/exception.hpp"
#include "base/stacktrace.hpp"
#include <boost/thread/tss.hpp>
#include <utility>
@ -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);
}
}

36
lib/base/stacktrace.cpp Normal file
View File

@ -0,0 +1,36 @@
/* Icinga 2 | (c) 2020 Icinga GmbH | GPLv2+ */
#include <base/i2-base.hpp>
#include "base/stacktrace.hpp"
#include <iostream>
#include <iomanip>
#include <vector>
#ifdef HAVE_BACKTRACE_SYMBOLS
# include <execinfo.h>
#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<void *> addrs;
addrs.reserve(stack.size());
std::transform(stack.begin(), stack.end(), std::back_inserter(addrs), [](const boost::stacktrace::frame &f) {
return const_cast<void *>(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;
}

25
lib/base/stacktrace.hpp Normal file
View File

@ -0,0 +1,25 @@
/* Icinga 2 | (c) 2020 Icinga GmbH | GPLv2+ */
#ifndef STACKTRACE_H
#define STACKTRACE_H
#include <boost/stacktrace.hpp>
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 */