119 lines
4.3 KiB
C++
119 lines
4.3 KiB
C++
/**
|
|
* @file llexception.cpp
|
|
* @author Nat Goodspeed
|
|
* @date 2016-08-12
|
|
* @brief Implementation for llexception.
|
|
*
|
|
* $LicenseInfo:firstyear=2016&license=viewerlgpl$
|
|
* Copyright (c) 2016, Linden Research, Inc.
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
// Precompiled header
|
|
#include "linden_common.h"
|
|
// associated header
|
|
#include "llexception.h"
|
|
// STL headers
|
|
// std headers
|
|
#include <typeinfo>
|
|
// external library headers
|
|
#include <boost/exception/diagnostic_information.hpp>
|
|
#include <boost/exception/error_info.hpp>
|
|
// On Mac, got:
|
|
// #error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define
|
|
// `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if
|
|
// _Unwind_Backtrace is available without `_GNU_SOURCE`."
|
|
#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
|
|
|
|
#if LL_WINDOWS
|
|
// On Windows, header-only implementation causes macro collisions -- use
|
|
// prebuilt library
|
|
#define BOOST_STACKTRACE_LINK
|
|
#include <excpt.h>
|
|
#endif // LL_WINDOWS
|
|
|
|
#include <boost/stacktrace.hpp>
|
|
// other Linden headers
|
|
#include "llerror.h"
|
|
#include "llerrorcontrol.h"
|
|
|
|
|
|
// used to attach and extract stacktrace information to/from boost::exception,
|
|
// see https://www.boost.org/doc/libs/release/doc/html/stacktrace/getting_started.html#stacktrace.getting_started.exceptions_with_stacktrace
|
|
// apparently the struct passed as the first template param needs no definition?
|
|
typedef boost::error_info<struct errinfo_stacktrace_, boost::stacktrace::stacktrace>
|
|
errinfo_stacktrace;
|
|
|
|
namespace {
|
|
// used by crash_on_unhandled_exception_() and log_unhandled_exception_()
|
|
void log_unhandled_exception_(LLError::ELevel level,
|
|
const char* file, int line, const char* pretty_function,
|
|
const std::string& context)
|
|
{
|
|
// log same message but allow caller-specified severity level
|
|
LL_VLOGS(level, "LLException") << LLError::abbreviateFile(file)
|
|
<< "(" << line << "): Unhandled exception caught in " << pretty_function;
|
|
if (! context.empty())
|
|
{
|
|
LL_CONT << ": " << context;
|
|
}
|
|
LL_CONT << ":\n" << boost::current_exception_diagnostic_information() << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
void crash_on_unhandled_exception_(const char* file, int line, const char* pretty_function,
|
|
const std::string& context)
|
|
{
|
|
// LL_ERRS() terminates and propagates message into crash dump.
|
|
log_unhandled_exception_(LLError::LEVEL_ERROR, file, line, pretty_function, context);
|
|
}
|
|
|
|
void log_unhandled_exception_(const char* file, int line, const char* pretty_function,
|
|
const std::string& context)
|
|
{
|
|
// Use LL_WARNS() because we seriously do not expect this to happen
|
|
// routinely, but we DO expect to return from this function.
|
|
log_unhandled_exception_(LLError::LEVEL_WARN, file, line, pretty_function, context);
|
|
}
|
|
|
|
void annotate_exception_(boost::exception& exc)
|
|
{
|
|
// https://www.boost.org/doc/libs/release/libs/exception/doc/tutorial_transporting_data.html
|
|
// "Adding of Arbitrary Data to Active Exception Objects"
|
|
// Given a boost::exception&, we can add boost::error_info items to it
|
|
// without knowing its leaf type.
|
|
// The stacktrace constructor that lets us skip a level -- and why would
|
|
// we always include annotate_exception_()? -- also requires a max depth.
|
|
// For the nullary constructor, the stacktrace class declaration itself
|
|
// passes static_cast<std::size_t>(-1), but that's kind of dubious.
|
|
// Anyway, which of us is really going to examine more than 100 frames?
|
|
exc << errinfo_stacktrace(boost::stacktrace::stacktrace(1, 100));
|
|
}
|
|
|
|
#if LL_WINDOWS
|
|
|
|
// For windows SEH exception handling we sometimes need a filter that will
|
|
// separate C++ exceptions from C SEH exceptions
|
|
static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
|
|
|
|
U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)
|
|
{
|
|
const auto stack = to_string(boost::stacktrace::stacktrace());
|
|
LL_WARNS() << "SEH Exception handled (that probably shouldn't be): Code " << code
|
|
<< "\n Stack trace: \n"
|
|
<< stack << LL_ENDL;
|
|
|
|
if (code == STATUS_MSC_EXCEPTION)
|
|
{
|
|
// C++ exception, go on
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
else
|
|
{
|
|
// handle it
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
}
|
|
|
|
#endif //LL_WINDOWS
|