Replace icinga::StackTrace with boost::stacktrace::stacktrace

Provides roughly the same functionality but works better on certain
platforms (especially Windows) and is less code to maintain.
This commit is contained in:
Julian Brost 2020-10-20 10:38:55 +02:00
parent e11b4b7b55
commit 5cb7c7cc09
8 changed files with 17 additions and 216 deletions

View File

@ -64,7 +64,6 @@ set(base_SOURCES
shared-object.hpp shared-object.hpp
singleton.hpp singleton.hpp
socket.cpp socket.hpp socket.cpp socket.hpp
stacktrace.cpp stacktrace.hpp
statsfunction.hpp statsfunction.hpp
stdiostream.cpp stdiostream.hpp stdiostream.cpp stdiostream.hpp
stream.cpp stream.hpp stream.cpp stream.hpp

View File

@ -2,7 +2,6 @@
#include "base/application.hpp" #include "base/application.hpp"
#include "base/application-ti.cpp" #include "base/application-ti.cpp"
#include "base/stacktrace.hpp"
#include "base/timer.hpp" #include "base/timer.hpp"
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/exception.hpp" #include "base/exception.hpp"
@ -761,9 +760,7 @@ void Application::SigAbrtHandler(int)
DisplayInfoMessage(ofs); DisplayInfoMessage(ofs);
StackTrace trace; ofs << "\nStacktrace:\n" << boost::stacktrace::stacktrace() << "\n";
ofs << "Stacktrace:" << "\n";
trace.Print(ofs, 1);
DisplayBugMessage(ofs); DisplayBugMessage(ofs);

View File

@ -14,7 +14,7 @@
using namespace icinga; using namespace icinga;
static boost::thread_specific_ptr<StackTrace> l_LastExceptionStack; static boost::thread_specific_ptr<boost::stacktrace::stacktrace> l_LastExceptionStack;
static boost::thread_specific_ptr<ContextTrace> l_LastExceptionContext; static boost::thread_specific_ptr<ContextTrace> l_LastExceptionContext;
#ifdef HAVE_CXXABI_H #ifdef HAVE_CXXABI_H
@ -113,7 +113,7 @@ void __cxa_throw(void *obj, TYPEINFO_TYPE *pvtinfo, void (*dest)(void *))
if (!uex) { if (!uex) {
#endif /* NO_CAST_EXCEPTION */ #endif /* NO_CAST_EXCEPTION */
StackTrace stack; boost::stacktrace::stacktrace stack;
SetLastExceptionStack(stack); SetLastExceptionStack(stack);
#ifndef NO_CAST_EXCEPTION #ifndef NO_CAST_EXCEPTION
@ -134,14 +134,14 @@ void __cxa_throw(void *obj, TYPEINFO_TYPE *pvtinfo, void (*dest)(void *))
} }
#endif /* HAVE_CXXABI_H */ #endif /* HAVE_CXXABI_H */
StackTrace *icinga::GetLastExceptionStack() boost::stacktrace::stacktrace *icinga::GetLastExceptionStack()
{ {
return l_LastExceptionStack.get(); return l_LastExceptionStack.get();
} }
void icinga::SetLastExceptionStack(const StackTrace& trace) void icinga::SetLastExceptionStack(const boost::stacktrace::stacktrace& trace)
{ {
l_LastExceptionStack.reset(new StackTrace(trace)); l_LastExceptionStack.reset(new boost::stacktrace::stacktrace(trace));
} }
ContextTrace *icinga::GetLastExceptionContext() ContextTrace *icinga::GetLastExceptionContext()
@ -154,7 +154,7 @@ void icinga::SetLastExceptionContext(const ContextTrace& context)
l_LastExceptionContext.reset(new ContextTrace(context)); l_LastExceptionContext.reset(new ContextTrace(context));
} }
String icinga::DiagnosticInformation(const std::exception& ex, bool verbose, StackTrace *stack, ContextTrace *context) String icinga::DiagnosticInformation(const std::exception& ex, bool verbose, boost::stacktrace::stacktrace *stack, ContextTrace *context)
{ {
std::ostringstream result; std::ostringstream result;
@ -216,7 +216,7 @@ String icinga::DiagnosticInformation(const std::exception& ex, bool verbose, Sta
const auto *pex = dynamic_cast<const posix_error *>(&ex); const auto *pex = dynamic_cast<const posix_error *>(&ex);
if (!uex && !pex && verbose) { if (!uex && !pex && verbose) {
const StackTrace *st = boost::get_error_info<StackTraceErrorInfo>(ex); const boost::stacktrace::stacktrace *st = boost::get_error_info<StackTraceErrorInfo>(ex);
if (st) { if (st) {
result << *st; result << *st;
@ -251,8 +251,8 @@ String icinga::DiagnosticInformation(const std::exception& ex, bool verbose, Sta
String icinga::DiagnosticInformation(const boost::exception_ptr& eptr, bool verbose) String icinga::DiagnosticInformation(const boost::exception_ptr& eptr, bool verbose)
{ {
StackTrace *pt = GetLastExceptionStack(); boost::stacktrace::stacktrace *pt = GetLastExceptionStack();
StackTrace stack; boost::stacktrace::stacktrace stack;
ContextTrace *pc = GetLastExceptionContext(); ContextTrace *pc = GetLastExceptionContext();
ContextTrace context; ContextTrace context;

View File

@ -5,7 +5,6 @@
#include "base/i2-base.hpp" #include "base/i2-base.hpp"
#include "base/string.hpp" #include "base/string.hpp"
#include "base/stacktrace.hpp"
#include "base/context.hpp" #include "base/context.hpp"
#include "base/debuginfo.hpp" #include "base/debuginfo.hpp"
#include "base/dictionary.hpp" #include "base/dictionary.hpp"
@ -15,6 +14,7 @@
#include <boost/exception/errinfo_file_name.hpp> #include <boost/exception/errinfo_file_name.hpp>
#include <boost/exception/diagnostic_information.hpp> #include <boost/exception/diagnostic_information.hpp>
#include <boost/exception_ptr.hpp> #include <boost/exception_ptr.hpp>
#include <boost/stacktrace.hpp>
#ifdef _WIN32 #ifdef _WIN32
# include <boost/algorithm/string/trim.hpp> # include <boost/algorithm/string/trim.hpp>
@ -76,15 +76,16 @@ private:
Dictionary::Ptr m_DebugHint; Dictionary::Ptr m_DebugHint;
}; };
StackTrace *GetLastExceptionStack(); boost::stacktrace::stacktrace *GetLastExceptionStack();
void SetLastExceptionStack(const StackTrace& trace); void SetLastExceptionStack(const boost::stacktrace::stacktrace& trace);
ContextTrace *GetLastExceptionContext(); ContextTrace *GetLastExceptionContext();
void SetLastExceptionContext(const ContextTrace& context); void SetLastExceptionContext(const ContextTrace& context);
void RethrowUncaughtException(); void RethrowUncaughtException();
typedef boost::error_info<StackTrace, StackTrace> StackTraceErrorInfo; struct errinfo_stacktrace_;
typedef boost::error_info<struct errinfo_stacktrace_, boost::stacktrace::stacktrace> StackTraceErrorInfo;
std::string to_string(const StackTraceErrorInfo&); std::string to_string(const StackTraceErrorInfo&);
@ -92,7 +93,8 @@ typedef boost::error_info<ContextTrace, ContextTrace> ContextTraceErrorInfo;
std::string to_string(const ContextTraceErrorInfo& e); std::string to_string(const ContextTraceErrorInfo& e);
String DiagnosticInformation(const std::exception& ex, bool verbose = true, StackTrace *stack = nullptr, ContextTrace *context = nullptr); String DiagnosticInformation(const std::exception& ex, bool verbose = true,
boost::stacktrace::stacktrace *stack = nullptr, ContextTrace *context = nullptr);
String DiagnosticInformation(const boost::exception_ptr& eptr, bool verbose = true); String DiagnosticInformation(const boost::exception_ptr& eptr, bool verbose = true);
class posix_error : virtual public std::exception, virtual public boost::exception { class posix_error : virtual public std::exception, virtual public boost::exception {

View File

@ -1,139 +0,0 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "base/stacktrace.hpp"
#include "base/utility.hpp"
#include "base/initialize.hpp"
#ifdef HAVE_BACKTRACE_SYMBOLS
# include <execinfo.h>
#endif /* HAVE_BACKTRACE_SYMBOLS */
using namespace icinga;
#ifdef _MSC_VER
# pragma optimize("", off)
#endif /* _MSC_VER */
StackTrace::StackTrace()
{
#ifdef HAVE_BACKTRACE_SYMBOLS
m_Count = backtrace(m_Frames, sizeof(m_Frames) / sizeof(m_Frames[0]));
#else /* HAVE_BACKTRACE_SYMBOLS */
# ifdef _WIN32
m_Count = CaptureStackBackTrace(0, sizeof(m_Frames) / sizeof(m_Frames), m_Frames, nullptr);
# else /* _WIN32 */
m_Count = 0;
# endif /* _WIN32 */
#endif /* HAVE_BACKTRACE_SYMBOLS */
}
#ifdef _MSC_VER
# pragma optimize("", on)
#endif /* _MSC_VER */
#ifdef _WIN32
StackTrace::StackTrace(PEXCEPTION_POINTERS exi)
{
STACKFRAME64 frame;
int architecture;
#ifdef _WIN64
architecture = IMAGE_FILE_MACHINE_AMD64;
frame.AddrPC.Offset = exi->ContextRecord->Rip;
frame.AddrFrame.Offset = exi->ContextRecord->Rbp;
frame.AddrStack.Offset = exi->ContextRecord->Rsp;
#else /* _WIN64 */
architecture = IMAGE_FILE_MACHINE_I386;
frame.AddrPC.Offset = exi->ContextRecord->Eip;
frame.AddrFrame.Offset = exi->ContextRecord->Ebp;
frame.AddrStack.Offset = exi->ContextRecord->Esp;
#endif /* _WIN64 */
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Mode = AddrModeFlat;
m_Count = 0;
while (StackWalk64(architecture, GetCurrentProcess(), GetCurrentThread(),
&frame, exi->ContextRecord, nullptr, &SymFunctionTableAccess64,
&SymGetModuleBase64, nullptr) && m_Count < sizeof(m_Frames) / sizeof(m_Frames[0])) {
m_Frames[m_Count] = reinterpret_cast<void *>(frame.AddrPC.Offset);
m_Count++;
}
}
#endif /* _WIN32 */
#ifdef _WIN32
INITIALIZE_ONCE([]() {
(void) SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
(void) SymInitialize(GetCurrentProcess(), nullptr, TRUE);
});
#endif /* _WIN32 */
/**
* Prints a stacktrace to the specified stream.
*
* @param fp The stream.
* @param ignoreFrames The number of stackframes to ignore (in addition to
* the one this function is executing in).
* @returns true if the stacktrace was printed, false otherwise.
*/
void StackTrace::Print(std::ostream& fp, int ignoreFrames) const
{
fp << std::endl;
#ifndef _WIN32
# ifdef HAVE_BACKTRACE_SYMBOLS
char **messages = backtrace_symbols(m_Frames, m_Count);
for (int i = ignoreFrames + 1; i < m_Count && messages; ++i) {
String message = messages[i];
char *sym_begin = strchr(messages[i], '(');
if (sym_begin) {
char *sym_end = strchr(sym_begin, '+');
if (sym_end) {
String sym = String(sym_begin + 1, sym_end);
String sym_demangled = Utility::DemangleSymbolName(sym);
if (sym_demangled.IsEmpty())
sym_demangled = "<unknown function>";
String path = String(messages[i], sym_begin);
size_t slashp = path.RFind("/");
if (slashp != String::NPos)
path = path.SubStr(slashp + 1);
message = path + ": " + sym_demangled + " (" + String(sym_end);
}
}
fp << "\t(" << i - ignoreFrames - 1 << ") " << message << std::endl;
}
std::free(messages);
fp << std::endl;
# else /* HAVE_BACKTRACE_SYMBOLS */
fp << "(not available)" << std::endl;
# endif /* HAVE_BACKTRACE_SYMBOLS */
#else /* _WIN32 */
for (int i = ignoreFrames + 1; i < m_Count; i++) {
fp << "\t(" << i - ignoreFrames - 1 << "): " << Utility::GetSymbolName(m_Frames[i]) << std::endl;
}
#endif /* _WIN32 */
}
std::ostream& icinga::operator<<(std::ostream& stream, const StackTrace& trace)
{
trace.Print(stream, 1);
return stream;
}

View File

@ -1,38 +0,0 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#ifndef STACKTRACE_H
#define STACKTRACE_H
#include "base/i2-base.hpp"
#include <iosfwd>
namespace icinga
{
/**
* A stacktrace.
*
* @ingroup base
*/
class StackTrace
{
public:
StackTrace();
#ifdef _WIN32
explicit StackTrace(PEXCEPTION_POINTERS exi);
#endif /* _WIN32 */
void Print(std::ostream& fp, int ignoreFrames = 0) const;
static void StaticInitialize();
private:
void *m_Frames[64];
int m_Count;
};
std::ostream& operator<<(std::ostream& stream, const StackTrace& trace);
}
#endif /* UTILITY_H */

View File

@ -16,7 +16,6 @@ set(base_test_SOURCES
base-object-packer.cpp base-object-packer.cpp
base-serialize.cpp base-serialize.cpp
base-shellescape.cpp base-shellescape.cpp
base-stacktrace.cpp
base-stream.cpp base-stream.cpp
base-string.cpp base-string.cpp
base-timer.cpp base-timer.cpp
@ -90,7 +89,6 @@ add_boost_test(base
base_serialize/object base_serialize/object
base_shellescape/escape_basic base_shellescape/escape_basic
base_shellescape/escape_quoted base_shellescape/escape_quoted
base_stacktrace/stacktrace
base_stream/readline_stdio base_stream/readline_stdio
base_string/construct base_string/construct
base_string/equal base_string/equal

View File

@ -1,18 +0,0 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "base/stacktrace.hpp"
#include <BoostTestTargetConfig.h>
using namespace icinga;
BOOST_AUTO_TEST_SUITE(base_stacktrace)
BOOST_AUTO_TEST_CASE(stacktrace)
{
StackTrace st;
std::ostringstream obuf;
obuf << st;
BOOST_CHECK(obuf.str().size() > 0);
}
BOOST_AUTO_TEST_SUITE_END()