feat():initial version
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
||||
#include <boost/stacktrace/detail/try_dec_convert.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <cstdio>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
|
||||
#if defined(BOOST_STACKTRACE_ADDR2LINE_LOCATION) && !defined(BOOST_NO_CXX11_CONSTEXPR)
|
||||
|
||||
constexpr bool is_abs_path(const char* path) BOOST_NOEXCEPT {
|
||||
return *path != '\0' && (
|
||||
*path == ':' || *path == '/' || is_abs_path(path + 1)
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
class addr2line_pipe {
|
||||
::FILE* p;
|
||||
::pid_t pid;
|
||||
|
||||
public:
|
||||
explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) BOOST_NOEXCEPT
|
||||
: p(0)
|
||||
, pid(0)
|
||||
{
|
||||
int pdes[2];
|
||||
#ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION
|
||||
char prog_name[] = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION );
|
||||
#if !defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CXX11_STATIC_ASSERT)
|
||||
static_assert(
|
||||
boost::stacktrace::detail::is_abs_path( BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION ) ),
|
||||
"BOOST_STACKTRACE_ADDR2LINE_LOCATION must be an absolute path"
|
||||
);
|
||||
#endif
|
||||
|
||||
#else
|
||||
char prog_name[] = "/usr/bin/addr2line";
|
||||
#endif
|
||||
|
||||
char* argp[] = {
|
||||
prog_name,
|
||||
const_cast<char*>(flag),
|
||||
const_cast<char*>(exec_path),
|
||||
const_cast<char*>(addr),
|
||||
0
|
||||
};
|
||||
|
||||
if (::pipe(pdes) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
pid = ::fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
// Failed...
|
||||
::close(pdes[0]);
|
||||
::close(pdes[1]);
|
||||
return;
|
||||
|
||||
case 0:
|
||||
// We are the child.
|
||||
::close(STDERR_FILENO);
|
||||
::close(pdes[0]);
|
||||
if (pdes[1] != STDOUT_FILENO) {
|
||||
::dup2(pdes[1], STDOUT_FILENO);
|
||||
}
|
||||
|
||||
// Do not use `execlp()`, `execvp()`, and `execvpe()` here!
|
||||
// `exec*p*` functions are vulnerable to PATH variable evaluation attacks.
|
||||
::execv(prog_name, argp);
|
||||
::_exit(127);
|
||||
}
|
||||
|
||||
p = ::fdopen(pdes[0], "r");
|
||||
::close(pdes[1]);
|
||||
}
|
||||
|
||||
operator ::FILE*() const BOOST_NOEXCEPT {
|
||||
return p;
|
||||
}
|
||||
|
||||
~addr2line_pipe() BOOST_NOEXCEPT {
|
||||
if (p) {
|
||||
::fclose(p);
|
||||
int pstat = 0;
|
||||
::kill(pid, SIGKILL);
|
||||
::waitpid(pid, &pstat, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline std::string addr2line(const char* flag, const void* addr) {
|
||||
std::string res;
|
||||
|
||||
boost::stacktrace::detail::location_from_symbol loc(addr);
|
||||
if (!loc.empty()) {
|
||||
res = loc.name();
|
||||
} else {
|
||||
res.resize(16);
|
||||
int rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
|
||||
while (rlin_size == static_cast<int>(res.size() - 1)) {
|
||||
res.resize(res.size() * 4);
|
||||
rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
|
||||
}
|
||||
if (rlin_size == -1) {
|
||||
res.clear();
|
||||
return res;
|
||||
}
|
||||
res.resize(rlin_size);
|
||||
}
|
||||
|
||||
addr2line_pipe p(flag, res.c_str(), to_hex_array(addr).data());
|
||||
res.clear();
|
||||
|
||||
if (!p) {
|
||||
return res;
|
||||
}
|
||||
|
||||
char data[32];
|
||||
while (!::feof(p)) {
|
||||
if (::fgets(data, sizeof(data), p)) {
|
||||
res += data;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Trimming
|
||||
while (!res.empty() && (res[res.size() - 1] == '\n' || res[res.size() - 1] == '\r')) {
|
||||
res.erase(res.size() - 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
struct to_string_using_addr2line {
|
||||
std::string res;
|
||||
void prepare_function_name(const void* addr) {
|
||||
res = boost::stacktrace::frame(addr).name();
|
||||
}
|
||||
|
||||
bool prepare_source_location(const void* addr) {
|
||||
//return addr2line("-Cfipe", addr); // Does not seem to work in all cases
|
||||
std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", addr);
|
||||
if (!source_line.empty() && source_line[0] != '?') {
|
||||
res += " at ";
|
||||
res += source_line;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Base> class to_string_impl_base;
|
||||
typedef to_string_impl_base<to_string_using_addr2line> to_string_impl;
|
||||
|
||||
inline std::string name_impl(const void* addr) {
|
||||
std::string res = boost::stacktrace::detail::addr2line("-fe", addr);
|
||||
res = res.substr(0, res.find_last_of('\n'));
|
||||
res = boost::core::demangle(res.c_str());
|
||||
|
||||
if (res == "??") {
|
||||
res.clear();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
std::string frame::source_file() const {
|
||||
std::string res;
|
||||
res = boost::stacktrace::detail::addr2line("-e", addr_);
|
||||
res = res.substr(0, res.find_last_of(':'));
|
||||
if (res == "??") {
|
||||
res.clear();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
std::size_t line_num = 0;
|
||||
std::string res = boost::stacktrace::detail::addr2line("-e", addr_);
|
||||
const std::size_t last = res.find_last_of(':');
|
||||
if (last == std::string::npos) {
|
||||
return 0;
|
||||
}
|
||||
res = res.substr(last + 1);
|
||||
|
||||
if (!boost::stacktrace::detail::try_dec_convert(res.c_str(), line_num)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return line_num;
|
||||
}
|
||||
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_COLLECT_MSVC_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_COLLECT_MSVC_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
#include <boost/winapi/stack_backtrace.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT {
|
||||
return boost::winapi::RtlCaptureStackBackTrace(
|
||||
static_cast<boost::winapi::ULONG_>(skip),
|
||||
static_cast<boost::winapi::ULONG_>(max_frames_count),
|
||||
const_cast<boost::winapi::PVOID_*>(out_frames),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::stacktrace
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_COLLECT_MSVC_IPP
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_COLLECT_NOOP_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_COLLECT_NOOP_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t this_thread_frames::collect(native_frame_ptr_t* /*out_frames*/, std::size_t /*max_frames_count*/, std::size_t /*skip*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_COLLECT_NOOP_IPP
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_COLLECT_UNWIND_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_COLLECT_UNWIND_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
// On iOS 32-bit ARM architecture _Unwind_Backtrace function doesn't exist, symbol is undefined.
|
||||
// Forcing libc backtrace() function usage.
|
||||
#include <boost/predef.h>
|
||||
#if defined(BOOST_OS_IOS_AVAILABLE) && defined(BOOST_ARCH_ARM_AVAILABLE) && BOOST_VERSION_NUMBER_MAJOR(BOOST_ARCH_ARM) < 8
|
||||
#define BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
|
||||
#include <execinfo.h>
|
||||
#include <algorithm>
|
||||
#else
|
||||
#include <unwind.h>
|
||||
#endif
|
||||
#include <cstdio>
|
||||
|
||||
#if !defined(_GNU_SOURCE) && !defined(BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED) && !defined(BOOST_WINDOWS)
|
||||
#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`."
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
#if !defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
|
||||
struct unwind_state {
|
||||
std::size_t frames_to_skip;
|
||||
native_frame_ptr_t* current;
|
||||
native_frame_ptr_t* end;
|
||||
};
|
||||
|
||||
inline _Unwind_Reason_Code unwind_callback(::_Unwind_Context* context, void* arg) {
|
||||
// Note: do not write `::_Unwind_GetIP` because it is a macro on some platforms.
|
||||
// Use `_Unwind_GetIP` instead!
|
||||
unwind_state* const state = static_cast<unwind_state*>(arg);
|
||||
if (state->frames_to_skip) {
|
||||
--state->frames_to_skip;
|
||||
return _Unwind_GetIP(context) ? ::_URC_NO_REASON : ::_URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
*state->current = reinterpret_cast<native_frame_ptr_t>(
|
||||
_Unwind_GetIP(context)
|
||||
);
|
||||
|
||||
++state->current;
|
||||
if (!*(state->current - 1) || state->current == state->end) {
|
||||
return ::_URC_END_OF_STACK;
|
||||
}
|
||||
return ::_URC_NO_REASON;
|
||||
}
|
||||
#endif //!defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
|
||||
|
||||
std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT {
|
||||
std::size_t frames_count = 0;
|
||||
if (!max_frames_count) {
|
||||
return frames_count;
|
||||
}
|
||||
skip += 1;
|
||||
|
||||
#if defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
|
||||
// According to https://opensource.apple.com/source/Libc/Libc-1272.200.26/gen/backtrace.c.auto.html
|
||||
// it looks like the `::backtrace` is async signal safe.
|
||||
frames_count = static_cast<size_t>(::backtrace(const_cast<void **>(out_frames), static_cast<int>(max_frames_count)));
|
||||
|
||||
// NOTE: There is no way to pass "skip" count to backtrace function so we need to perform left shift operation.
|
||||
// If number of elements in result backtrace is >= max_frames_count then "skip" elements are wasted.
|
||||
if (frames_count && skip) {
|
||||
if (skip >= frames_count) {
|
||||
frames_count = 0;
|
||||
} else {
|
||||
std::copy(out_frames + skip, out_frames + frames_count, out_frames);
|
||||
frames_count -= skip;
|
||||
}
|
||||
}
|
||||
#else
|
||||
boost::stacktrace::detail::unwind_state state = { skip, out_frames, out_frames + max_frames_count };
|
||||
::_Unwind_Backtrace(&boost::stacktrace::detail::unwind_callback, &state);
|
||||
frames_count = state.current - out_frames;
|
||||
#endif //defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
|
||||
|
||||
if (frames_count && out_frames[frames_count - 1] == 0) {
|
||||
-- frames_count;
|
||||
}
|
||||
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#undef BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_COLLECT_UNWIND_IPP
|
||||
@@ -0,0 +1,159 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_FRAME_DECL_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_FRAME_DECL_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp> // boost::stacktrace::detail::native_frame_ptr_t
|
||||
#include <boost/stacktrace/detail/void_ptr_cast.hpp>
|
||||
|
||||
#include <boost/stacktrace/detail/push_options.h>
|
||||
|
||||
/// @file boost/stacktrace/detail/frame_decl.hpp
|
||||
/// Use <boost/stacktrace/frame.hpp> header instead of this one!
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
/// @class boost::stacktrace::frame boost/stacktrace/detail/frame_decl.hpp <boost/stacktrace/frame.hpp>
|
||||
/// @brief Class that stores frame/function address and can get information about it at runtime.
|
||||
class frame {
|
||||
public:
|
||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
||||
|
||||
private:
|
||||
/// @cond
|
||||
native_frame_ptr_t addr_;
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
/// @brief Constructs frame that references NULL address.
|
||||
/// Calls to source_file() and source_line() will return empty string.
|
||||
/// Calls to source_line() will return 0.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
BOOST_CONSTEXPR frame() BOOST_NOEXCEPT
|
||||
: addr_(0)
|
||||
{}
|
||||
|
||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||
/// @brief Copy constructs frame.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
constexpr frame(const frame&) = default;
|
||||
|
||||
/// @brief Copy assigns frame.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
constexpr frame& operator=(const frame&) = default;
|
||||
#endif
|
||||
|
||||
/// @brief Constructs frame that references addr and could later generate information about that address using platform specific features.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
BOOST_CONSTEXPR explicit frame(native_frame_ptr_t addr) BOOST_NOEXCEPT
|
||||
: addr_(addr)
|
||||
{}
|
||||
|
||||
/// @brief Constructs frame that references function_addr and could later generate information about that function using platform specific features.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
template <class T>
|
||||
explicit frame(T* function_addr) BOOST_NOEXCEPT
|
||||
: addr_(boost::stacktrace::detail::void_ptr_cast<native_frame_ptr_t>(function_addr))
|
||||
{}
|
||||
|
||||
/// @returns Name of the frame (function name in a human readable form).
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
/// @throws std::bad_alloc if not enough memory to construct resulting string.
|
||||
BOOST_STACKTRACE_FUNCTION std::string name() const;
|
||||
|
||||
/// @returns Address of the frame function.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
BOOST_CONSTEXPR native_frame_ptr_t address() const BOOST_NOEXCEPT {
|
||||
return addr_;
|
||||
}
|
||||
|
||||
/// @returns Path to the source file, were the function of the frame is defined. Returns empty string
|
||||
/// if this->source_line() == 0.
|
||||
/// @throws std::bad_alloc if not enough memory to construct resulting string.
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
BOOST_STACKTRACE_FUNCTION std::string source_file() const;
|
||||
|
||||
/// @returns Code line in the source file, were the function of the frame is defined.
|
||||
/// @throws std::bad_alloc if not enough memory to construct string for internal needs.
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t source_line() const;
|
||||
|
||||
/// @brief Checks that frame is not references NULL address.
|
||||
/// @returns `true` if `this->address() != 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL()
|
||||
|
||||
/// @brief Checks that frame references NULL address.
|
||||
/// @returns `true` if `this->address() == 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT { return !address(); }
|
||||
|
||||
/// @cond
|
||||
BOOST_CONSTEXPR bool operator!() const BOOST_NOEXCEPT { return !address(); }
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
|
||||
namespace detail {
|
||||
BOOST_STACKTRACE_FUNCTION std::string to_string(const frame* frames, std::size_t size);
|
||||
} // namespace detail
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
|
||||
#include <boost/stacktrace/detail/pop_options.h>
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_FRAME_DECL_HPP
|
||||
@@ -0,0 +1,403 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <windows.h>
|
||||
#include "dbgeng.h"
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma comment(lib, "ole32.lib")
|
||||
# pragma comment(lib, "Dbgeng.lib")
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __CRT_UUID_DECL // for __MINGW32__
|
||||
__CRT_UUID_DECL(IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8)
|
||||
__CRT_UUID_DECL(IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba)
|
||||
__CRT_UUID_DECL(IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50)
|
||||
#elif defined(DEFINE_GUID) && !defined(BOOST_MSVC)
|
||||
DEFINE_GUID(IID_IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8);
|
||||
DEFINE_GUID(IID_IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba);
|
||||
DEFINE_GUID(IID_IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Testing. Remove later
|
||||
//# define __uuidof(x) ::IID_ ## x
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
class com_global_initer: boost::noncopyable {
|
||||
bool ok_;
|
||||
|
||||
public:
|
||||
com_global_initer() BOOST_NOEXCEPT
|
||||
: ok_(false)
|
||||
{
|
||||
// COINIT_MULTITHREADED means that we must serialize access to the objects manually.
|
||||
// This is the fastest way to work. If user calls CoInitializeEx before us - we
|
||||
// can end up with other mode (which is OK for us).
|
||||
//
|
||||
// If we call CoInitializeEx befire user - user may end up with different mode, which is a problem.
|
||||
// So we need to call that initialization function as late as possible.
|
||||
const DWORD res = ::CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
ok_ = (res == S_OK || res == S_FALSE);
|
||||
}
|
||||
|
||||
~com_global_initer() BOOST_NOEXCEPT {
|
||||
if (ok_) {
|
||||
::CoUninitialize();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class com_holder: boost::noncopyable {
|
||||
T* holder_;
|
||||
|
||||
public:
|
||||
com_holder(const com_global_initer&) BOOST_NOEXCEPT
|
||||
: holder_(0)
|
||||
{}
|
||||
|
||||
T* operator->() const BOOST_NOEXCEPT {
|
||||
return holder_;
|
||||
}
|
||||
|
||||
void** to_void_ptr_ptr() BOOST_NOEXCEPT {
|
||||
return reinterpret_cast<void**>(&holder_);
|
||||
}
|
||||
|
||||
bool is_inited() const BOOST_NOEXCEPT {
|
||||
return !!holder_;
|
||||
}
|
||||
|
||||
~com_holder() BOOST_NOEXCEPT {
|
||||
if (holder_) {
|
||||
holder_->Release();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::string mingw_demangling_workaround(const std::string& s) {
|
||||
#ifdef BOOST_GCC
|
||||
if (s.empty()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
if (s[0] != '_') {
|
||||
return boost::core::demangle(('_' + s).c_str());
|
||||
}
|
||||
|
||||
return boost::core::demangle(s.c_str());
|
||||
#else
|
||||
return s;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void trim_right_zeroes(std::string& s) {
|
||||
// MSVC-9 does not have back() and pop_back() functions in std::string
|
||||
while (!s.empty()) {
|
||||
const std::size_t last = static_cast<std::size_t>(s.size() - 1);
|
||||
if (s[last] != '\0') {
|
||||
break;
|
||||
}
|
||||
s.resize(last);
|
||||
}
|
||||
}
|
||||
|
||||
class debugging_symbols: boost::noncopyable {
|
||||
static void try_init_com(com_holder< ::IDebugSymbols>& idebug, const com_global_initer& com) BOOST_NOEXCEPT {
|
||||
com_holder< ::IDebugClient> iclient(com);
|
||||
if (S_OK != ::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr())) {
|
||||
return;
|
||||
}
|
||||
|
||||
com_holder< ::IDebugControl> icontrol(com);
|
||||
const bool res0 = (S_OK == iclient->QueryInterface(
|
||||
__uuidof(IDebugControl),
|
||||
icontrol.to_void_ptr_ptr()
|
||||
));
|
||||
if (!res0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool res1 = (S_OK == iclient->AttachProcess(
|
||||
0,
|
||||
::GetCurrentProcessId(),
|
||||
DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND
|
||||
));
|
||||
if (!res1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (S_OK != icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No cheking: QueryInterface sets the output parameter to NULL in case of error.
|
||||
iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr());
|
||||
}
|
||||
|
||||
#ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
|
||||
|
||||
boost::stacktrace::detail::com_global_initer com_;
|
||||
com_holder< ::IDebugSymbols> idebug_;
|
||||
public:
|
||||
debugging_symbols() BOOST_NOEXCEPT
|
||||
: com_()
|
||||
, idebug_(com_)
|
||||
{
|
||||
try_init_com(idebug_, com_);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef BOOST_NO_CXX11_THREAD_LOCAL
|
||||
# error Your compiler does not support C++11 thread_local storage. It`s impossible to build with BOOST_STACKTRACE_USE_WINDBG_CACHED.
|
||||
#endif
|
||||
|
||||
static com_holder< ::IDebugSymbols>& get_thread_local_debug_inst() BOOST_NOEXCEPT {
|
||||
// [class.mfct]: A static local variable or local type in a member function always refers to the same entity, whether
|
||||
// or not the member function is inline.
|
||||
static thread_local boost::stacktrace::detail::com_global_initer com;
|
||||
static thread_local com_holder< ::IDebugSymbols> idebug(com);
|
||||
|
||||
if (!idebug.is_inited()) {
|
||||
try_init_com(idebug, com);
|
||||
}
|
||||
|
||||
return idebug;
|
||||
}
|
||||
|
||||
com_holder< ::IDebugSymbols>& idebug_;
|
||||
public:
|
||||
debugging_symbols() BOOST_NOEXCEPT
|
||||
: idebug_( get_thread_local_debug_inst() )
|
||||
{}
|
||||
|
||||
#endif // #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
|
||||
|
||||
bool is_inited() const BOOST_NOEXCEPT {
|
||||
return idebug_.is_inited();
|
||||
}
|
||||
|
||||
std::string get_name_impl(const void* addr, std::string* module_name = 0) const {
|
||||
std::string result;
|
||||
if (!is_inited()) {
|
||||
return result;
|
||||
}
|
||||
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
|
||||
|
||||
char name[256];
|
||||
name[0] = '\0';
|
||||
ULONG size = 0;
|
||||
bool res = (S_OK == idebug_->GetNameByOffset(
|
||||
offset,
|
||||
name,
|
||||
sizeof(name),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
|
||||
if (!res && size != 0) {
|
||||
result.resize(size);
|
||||
res = (S_OK == idebug_->GetNameByOffset(
|
||||
offset,
|
||||
&result[0],
|
||||
static_cast<ULONG>(result.size()),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
trim_right_zeroes(result);
|
||||
} else if (res) {
|
||||
result = name;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
result.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::size_t delimiter = result.find_first_of('!');
|
||||
if (module_name) {
|
||||
*module_name = result.substr(0, delimiter);
|
||||
}
|
||||
|
||||
if (delimiter == std::string::npos) {
|
||||
// If 'delimiter' is equal to 'std::string::npos' then we have only module name.
|
||||
result.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mingw_demangling_workaround(
|
||||
result.substr(delimiter + 1)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::size_t get_line_impl(const void* addr) const BOOST_NOEXCEPT {
|
||||
ULONG result = 0;
|
||||
if (!is_inited()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const bool is_ok = (S_OK == idebug_->GetLineByOffset(
|
||||
reinterpret_cast<ULONG64>(addr),
|
||||
&result,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
));
|
||||
|
||||
return (is_ok ? result : 0);
|
||||
}
|
||||
|
||||
std::pair<std::string, std::size_t> get_source_file_line_impl(const void* addr) const {
|
||||
std::pair<std::string, std::size_t> result;
|
||||
if (!is_inited()) {
|
||||
return result;
|
||||
}
|
||||
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
|
||||
|
||||
char name[256];
|
||||
name[0] = 0;
|
||||
ULONG size = 0;
|
||||
ULONG line_num = 0;
|
||||
bool res = (S_OK == idebug_->GetLineByOffset(
|
||||
offset,
|
||||
&line_num,
|
||||
name,
|
||||
sizeof(name),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
|
||||
if (res) {
|
||||
result.first = name;
|
||||
result.second = line_num;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!res && size == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.first.resize(size);
|
||||
res = (S_OK == idebug_->GetLineByOffset(
|
||||
offset,
|
||||
&line_num,
|
||||
&result.first[0],
|
||||
static_cast<ULONG>(result.first.size()),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
trim_right_zeroes(result.first);
|
||||
result.second = line_num;
|
||||
|
||||
if (!res) {
|
||||
result.first.clear();
|
||||
result.second = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void to_string_impl(const void* addr, std::string& res) const {
|
||||
if (!is_inited()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string module_name;
|
||||
std::string name = this->get_name_impl(addr, &module_name);
|
||||
if (!name.empty()) {
|
||||
res += name;
|
||||
} else {
|
||||
res += to_hex_array(addr).data();
|
||||
}
|
||||
|
||||
std::pair<std::string, std::size_t> source_line = this->get_source_file_line_impl(addr);
|
||||
if (!source_line.first.empty() && source_line.second) {
|
||||
res += " at ";
|
||||
res += source_line.first;
|
||||
res += ':';
|
||||
res += boost::stacktrace::detail::to_dec_array(source_line.second).data();
|
||||
} else if (!module_name.empty()) {
|
||||
res += " in ";
|
||||
res += module_name;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::string to_string(const frame* frames, std::size_t size) {
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
if (!idebug.is_inited()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string res;
|
||||
res.reserve(64 * size);
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
if (i < 10) {
|
||||
res += ' ';
|
||||
}
|
||||
res += boost::stacktrace::detail::to_dec_array(i).data();
|
||||
res += '#';
|
||||
res += ' ';
|
||||
idebug.to_string_impl(frames[i].address(), res);
|
||||
res += '\n';
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
std::string frame::name() const {
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
return idebug.get_name_impl(addr_);
|
||||
}
|
||||
|
||||
|
||||
std::string frame::source_file() const {
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
return idebug.get_source_file_line_impl(addr_).first;
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
return idebug.get_line_impl(addr_);
|
||||
}
|
||||
|
||||
std::string to_string(const frame& f) {
|
||||
std::string res;
|
||||
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
idebug.to_string_impl(f.address(), res);
|
||||
return res;
|
||||
}
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_FRAME_NOOP_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_FRAME_NOOP_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::string to_string(const frame* /*frames*/, std::size_t /*count*/) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
std::string frame::name() const {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string frame::source_file() const {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string to_string(const frame& /*f*/) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_FRAME_NOOP_IPP
|
||||
@@ -0,0 +1,114 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_FRAME_UNWIND_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_FRAME_UNWIND_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/stacktrace/detail/location_from_symbol.hpp>
|
||||
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef BOOST_STACKTRACE_USE_BACKTRACE
|
||||
# include <boost/stacktrace/detail/libbacktrace_impls.hpp>
|
||||
#elif defined(BOOST_STACKTRACE_USE_ADDR2LINE)
|
||||
# include <boost/stacktrace/detail/addr2line_impls.hpp>
|
||||
#else
|
||||
# include <boost/stacktrace/detail/unwind_base_impls.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
template <class Base>
|
||||
class to_string_impl_base: private Base {
|
||||
public:
|
||||
std::string operator()(boost::stacktrace::detail::native_frame_ptr_t addr) {
|
||||
Base::res.clear();
|
||||
Base::prepare_function_name(addr);
|
||||
if (!Base::res.empty()) {
|
||||
Base::res = boost::core::demangle(Base::res.c_str());
|
||||
} else {
|
||||
Base::res = to_hex_array(addr).data();
|
||||
}
|
||||
|
||||
if (Base::prepare_source_location(addr)) {
|
||||
return Base::res;
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::location_from_symbol loc(addr);
|
||||
if (!loc.empty()) {
|
||||
Base::res += " in ";
|
||||
Base::res += loc.name();
|
||||
}
|
||||
|
||||
return Base::res;
|
||||
}
|
||||
};
|
||||
|
||||
std::string to_string(const frame* frames, std::size_t size) {
|
||||
std::string res;
|
||||
if (size == 0) {
|
||||
return res;
|
||||
}
|
||||
res.reserve(64 * size);
|
||||
|
||||
to_string_impl impl;
|
||||
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
if (i < 10) {
|
||||
res += ' ';
|
||||
}
|
||||
res += boost::stacktrace::detail::to_dec_array(i).data();
|
||||
res += '#';
|
||||
res += ' ';
|
||||
res += impl(frames[i].address());
|
||||
res += '\n';
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
std::string frame::name() const {
|
||||
if (!addr_) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
::Dl_info dli;
|
||||
const bool dl_ok = !!::dladdr(const_cast<void*>(addr_), &dli); // `dladdr` on Solaris accepts nonconst addresses
|
||||
if (dl_ok && dli.dli_sname) {
|
||||
return boost::core::demangle(dli.dli_sname);
|
||||
}
|
||||
#endif
|
||||
return boost::stacktrace::detail::name_impl(addr_);
|
||||
}
|
||||
|
||||
std::string to_string(const frame& f) {
|
||||
if (!f) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::to_string_impl impl;
|
||||
return impl(f.address());
|
||||
}
|
||||
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_FRAME_UNWIND_IPP
|
||||
@@ -0,0 +1,244 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
||||
#include <boost/stacktrace/detail/location_from_symbol.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
|
||||
#ifdef BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
|
||||
# include BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
|
||||
#else
|
||||
# include <backtrace.h>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
|
||||
struct pc_data {
|
||||
std::string* function;
|
||||
std::string* filename;
|
||||
std::size_t line;
|
||||
};
|
||||
|
||||
inline void libbacktrace_syminfo_callback(void *data, uintptr_t /*pc*/, const char *symname, uintptr_t /*symval*/, uintptr_t /*symsize*/) {
|
||||
pc_data& d = *static_cast<pc_data*>(data);
|
||||
if (d.function && symname) {
|
||||
*d.function = symname;
|
||||
}
|
||||
}
|
||||
|
||||
// Old versions of libbacktrace have different signature for the callback
|
||||
inline void libbacktrace_syminfo_callback(void *data, uintptr_t pc, const char *symname, uintptr_t symval) {
|
||||
boost::stacktrace::detail::libbacktrace_syminfo_callback(data, pc, symname, symval, 0);
|
||||
}
|
||||
|
||||
inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *filename, int lineno, const char *function) {
|
||||
pc_data& d = *static_cast<pc_data*>(data);
|
||||
if (d.filename && filename) {
|
||||
*d.filename = filename;
|
||||
}
|
||||
if (d.function && function) {
|
||||
*d.function = function;
|
||||
}
|
||||
d.line = lineno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) BOOST_NOEXCEPT {
|
||||
// Do nothing, just return.
|
||||
}
|
||||
|
||||
// Not async-signal-safe, so this method is not called from async-safe functions.
|
||||
//
|
||||
// This function is not async signal safe because:
|
||||
// * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
|
||||
// * No guarantees on `backtrace_create_state` function.
|
||||
//
|
||||
// Currently `backtrace_create_state` can not detect file name on Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82543
|
||||
// That's why we provide a `prog_location` here.
|
||||
BOOST_SYMBOL_VISIBLE inline ::backtrace_state* construct_state(const program_location& prog_location) BOOST_NOEXCEPT {
|
||||
// [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
|
||||
|
||||
// TODO: The most obvious solution:
|
||||
//
|
||||
//static ::backtrace_state* state = ::backtrace_create_state(
|
||||
// prog_location.name(),
|
||||
// 1, // allow safe concurrent usage of the same state
|
||||
// boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
// 0 // pointer to data that will be passed to callback
|
||||
//);
|
||||
//
|
||||
//
|
||||
// Unfortunately, that solution segfaults when `construct_state()` function is in .so file
|
||||
// and multiple threads concurrently work with state.
|
||||
|
||||
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
static
|
||||
#else
|
||||
|
||||
// Result of `construct_state()` invocation is not stored by the callers, so `thread_local`
|
||||
// gives a single `state` per thread and that state is not shared between threads in any way.
|
||||
|
||||
# ifndef BOOST_NO_CXX11_THREAD_LOCAL
|
||||
thread_local
|
||||
# elif defined(__GNUC__)
|
||||
static __thread
|
||||
# else
|
||||
/* just a local variable */
|
||||
# endif
|
||||
|
||||
#endif
|
||||
::backtrace_state* state = ::backtrace_create_state(
|
||||
prog_location.name(),
|
||||
0,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
0
|
||||
);
|
||||
return state;
|
||||
}
|
||||
|
||||
struct to_string_using_backtrace {
|
||||
std::string res;
|
||||
boost::stacktrace::detail::program_location prog_location;
|
||||
::backtrace_state* state;
|
||||
std::string filename;
|
||||
std::size_t line;
|
||||
|
||||
void prepare_function_name(const void* addr) {
|
||||
boost::stacktrace::detail::pc_data data = {&res, &filename, 0};
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
)
|
||||
||
|
||||
::backtrace_syminfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr),
|
||||
boost::stacktrace::detail::libbacktrace_syminfo_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
);
|
||||
}
|
||||
line = data.line;
|
||||
}
|
||||
|
||||
bool prepare_source_location(const void* /*addr*/) {
|
||||
if (filename.empty() || !line) {
|
||||
return false;
|
||||
}
|
||||
|
||||
res += " at ";
|
||||
res += filename;
|
||||
res += ':';
|
||||
res += boost::stacktrace::detail::to_dec_array(line).data();
|
||||
return true;
|
||||
}
|
||||
|
||||
to_string_using_backtrace() BOOST_NOEXCEPT {
|
||||
state = boost::stacktrace::detail::construct_state(prog_location);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Base> class to_string_impl_base;
|
||||
typedef to_string_impl_base<to_string_using_backtrace> to_string_impl;
|
||||
|
||||
inline std::string name_impl(const void* addr) {
|
||||
std::string res;
|
||||
|
||||
boost::stacktrace::detail::program_location prog_location;
|
||||
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
|
||||
|
||||
boost::stacktrace::detail::pc_data data = {&res, 0, 0};
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
)
|
||||
||
|
||||
::backtrace_syminfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr),
|
||||
boost::stacktrace::detail::libbacktrace_syminfo_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
);
|
||||
}
|
||||
if (!res.empty()) {
|
||||
res = boost::core::demangle(res.c_str());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
std::string frame::source_file() const {
|
||||
std::string res;
|
||||
|
||||
if (!addr_) {
|
||||
return res;
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::program_location prog_location;
|
||||
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
|
||||
|
||||
boost::stacktrace::detail::pc_data data = {0, &res, 0};
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr_),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
if (!addr_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::program_location prog_location;
|
||||
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
|
||||
|
||||
boost::stacktrace::detail::pc_data data = {0, 0, 0};
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr_),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
);
|
||||
}
|
||||
|
||||
return data.line;
|
||||
}
|
||||
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP
|
||||
@@ -0,0 +1,105 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
# include <dlfcn.h>
|
||||
#else
|
||||
# include <boost/winapi/dll.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
class location_from_symbol {
|
||||
::Dl_info dli_;
|
||||
|
||||
public:
|
||||
explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT
|
||||
: dli_()
|
||||
{
|
||||
if (!::dladdr(const_cast<void*>(addr), &dli_)) { // `dladdr` on Solaris accepts nonconst addresses
|
||||
dli_.dli_fname = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const BOOST_NOEXCEPT {
|
||||
return !dli_.dli_fname;
|
||||
}
|
||||
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
return dli_.dli_fname;
|
||||
}
|
||||
};
|
||||
|
||||
class program_location {
|
||||
public:
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class location_from_symbol {
|
||||
BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
|
||||
char file_name_[DEFAULT_PATH_SIZE_];
|
||||
|
||||
public:
|
||||
explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT {
|
||||
file_name_[0] = '\0';
|
||||
|
||||
boost::winapi::MEMORY_BASIC_INFORMATION_ mbi;
|
||||
if (!boost::winapi::VirtualQuery(addr, &mbi, sizeof(mbi))) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::winapi::HMODULE_ handle = reinterpret_cast<boost::winapi::HMODULE_>(mbi.AllocationBase);
|
||||
if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
|
||||
file_name_[0] = '\0';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const BOOST_NOEXCEPT {
|
||||
return file_name_[0] == '\0';
|
||||
}
|
||||
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
return file_name_;
|
||||
}
|
||||
};
|
||||
|
||||
class program_location {
|
||||
BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
|
||||
char file_name_[DEFAULT_PATH_SIZE_];
|
||||
|
||||
public:
|
||||
program_location() BOOST_NOEXCEPT {
|
||||
file_name_[0] = '\0';
|
||||
|
||||
const boost::winapi::HMODULE_ handle = 0;
|
||||
if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
|
||||
file_name_[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
return file_name_[0] ? file_name_ : 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// No include guards! Intentionally.
|
||||
|
||||
#ifdef BOOST_STACKTRACE_FUNCTION
|
||||
# undef BOOST_STACKTRACE_FUNCTION
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// No include guards! Intentionally.
|
||||
|
||||
// Link or header only
|
||||
#if !defined(BOOST_STACKTRACE_LINK) && defined(BOOST_STACKTRACE_DYN_LINK)
|
||||
# define BOOST_STACKTRACE_LINK
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_STACKTRACE_LINK) && !defined(BOOST_STACKTRACE_DYN_LINK) && defined(BOOST_ALL_DYN_LINK)
|
||||
# define BOOST_STACKTRACE_DYN_LINK
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_STACKTRACE_LINK
|
||||
# if defined(BOOST_STACKTRACE_DYN_LINK)
|
||||
# ifdef BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
|
||||
# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_EXPORT
|
||||
# else
|
||||
# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_IMPORT
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_STACKTRACE_FUNCTION
|
||||
# endif
|
||||
#elif !defined(BOOST_STACKTRACE_DOXYGEN_INVOKED)
|
||||
# define BOOST_STACKTRACE_FUNCTION inline
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_SAFE_DUMP_NOOP_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_SAFE_DUMP_NOOP_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
|
||||
#if defined(BOOST_WINDOWS)
|
||||
std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
std::size_t dump(int /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_SAFE_DUMP_NOOP_IPP
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_SAFE_DUMP_POSIX_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_SAFE_DUMP_POSIX_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
#include <unistd.h> // ::write
|
||||
#include <fcntl.h> // ::open
|
||||
#include <sys/stat.h> // S_IWUSR and friends
|
||||
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
|
||||
// We do not retry, because this function must be typically called from signal handler so it's:
|
||||
// * to scary to continue in case of EINTR
|
||||
// * EAGAIN or EWOULDBLOCK may occur only in case of O_NONBLOCK is set for fd,
|
||||
// so it seems that user does not want to block
|
||||
if (::write(fd, frames, sizeof(native_frame_ptr_t) * frames_count) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
|
||||
const int fd = ::open(
|
||||
file,
|
||||
O_CREAT | O_WRONLY | O_TRUNC,
|
||||
#if defined(S_IWUSR) && defined(S_IRUSR) // Workarounds for some Android OSes
|
||||
S_IWUSR | S_IRUSR
|
||||
#elif defined(S_IWRITE) && defined(S_IREAD)
|
||||
S_IWRITE | S_IREAD
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
);
|
||||
if (fd == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::size_t size = boost::stacktrace::detail::dump(fd, frames, frames_count);
|
||||
::close(fd);
|
||||
return size;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_SAFE_DUMP_POSIX_IPP
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_SAFE_DUMP_WIN_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_SAFE_DUMP_WIN_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
|
||||
#include <boost/winapi/get_current_process.hpp>
|
||||
#include <boost/winapi/file_management.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/access_rights.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
#if 0 // This code potentially could cause deadlocks (according to the MSDN). Disabled
|
||||
boost::winapi::DWORD_ written;
|
||||
const boost::winapi::DWORD_ bytes_to_write = static_cast<boost::winapi::DWORD_>(
|
||||
sizeof(native_frame_ptr_t) * frames_count
|
||||
);
|
||||
if (!boost::winapi::WriteFile(fd, frames, bytes_to_write, &written, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return frames_count;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
#if 0 // This code causing deadlocks on some platforms. Disabled
|
||||
void* const fd = boost::winapi::CreateFileA(
|
||||
file,
|
||||
boost::winapi::GENERIC_WRITE_,
|
||||
0,
|
||||
0,
|
||||
boost::winapi::CREATE_ALWAYS_,
|
||||
boost::winapi::FILE_ATTRIBUTE_NORMAL_,
|
||||
0
|
||||
);
|
||||
|
||||
if (fd == boost::winapi::invalid_handle_value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::size_t size = boost::stacktrace::detail::dump(fd, frames, frames_count);
|
||||
boost::winapi::CloseHandle(fd);
|
||||
return size;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_SAFE_DUMP_WIN_IPP
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_TO_DEC_ARRAY_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_TO_DEC_ARRAY_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/array.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
// We do not use boost::lexical_cast in this function to reduce module dependencies
|
||||
inline boost::array<char, 40> to_dec_array(std::size_t value) BOOST_NOEXCEPT {
|
||||
boost::array<char, 40> ret;
|
||||
if (!value) {
|
||||
ret[0] = '0';
|
||||
ret[1] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::size_t digits = 0;
|
||||
for (std::size_t value_copy = value; value_copy; value_copy /= 10) {
|
||||
++ digits;
|
||||
}
|
||||
|
||||
for (std::size_t i = 1; i <= digits; ++i) {
|
||||
ret[digits - i] = static_cast<char>('0' + (value % 10));
|
||||
value /= 10;
|
||||
}
|
||||
|
||||
ret[digits] = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_TO_DEC_ARRAY_HPP
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_TO_HEX_ARRAY_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_TO_HEX_ARRAY_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/make_unsigned.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
BOOST_STATIC_CONSTEXPR char to_hex_array_bytes[] = "0123456789ABCDEF";
|
||||
|
||||
template <class T>
|
||||
inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(T addr) BOOST_NOEXCEPT {
|
||||
boost::array<char, 2 + sizeof(void*) * 2 + 1> ret = {"0x"};
|
||||
ret.back() = '\0';
|
||||
BOOST_STATIC_ASSERT_MSG(!boost::is_pointer<T>::value, "");
|
||||
|
||||
const std::size_t s = sizeof(T);
|
||||
|
||||
char* out = ret.data() + s * 2 + 1;
|
||||
|
||||
for (std::size_t i = 0; i < s; ++i) {
|
||||
const unsigned char tmp_addr = (addr & 0xFFu);
|
||||
*out = to_hex_array_bytes[tmp_addr & 0xF];
|
||||
-- out;
|
||||
*out = to_hex_array_bytes[tmp_addr >> 4];
|
||||
-- out;
|
||||
addr >>= 8;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(const void* addr) BOOST_NOEXCEPT {
|
||||
return to_hex_array(
|
||||
reinterpret_cast< boost::make_unsigned<std::ptrdiff_t>::type >(addr)
|
||||
);
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_TO_HEX_ARRAY_HPP
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_TRY_DEC_CONVERT_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_TRY_DEC_CONVERT_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
// We do not use boost::lexical_cast in this function to reduce module dependencies
|
||||
inline bool try_dec_convert(const char* s, std::size_t& res) BOOST_NOEXCEPT {
|
||||
char* end_ptr = 0;
|
||||
res = std::strtoul(s, &end_ptr, 10);
|
||||
return *end_ptr == '\0';
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_TRY_DEC_CONVERT_HPP
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_UNWIND_BASE_IMPLS_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_UNWIND_BASE_IMPLS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct to_string_using_nothing {
|
||||
std::string res;
|
||||
|
||||
void prepare_function_name(const void* addr) {
|
||||
res = boost::stacktrace::frame(addr).name();
|
||||
}
|
||||
|
||||
bool prepare_source_location(const void* /*addr*/) const BOOST_NOEXCEPT {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Base> class to_string_impl_base;
|
||||
typedef to_string_impl_base<to_string_using_nothing> to_string_impl;
|
||||
|
||||
inline std::string name_impl(const void* /*addr*/) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
std::string frame::source_file() const {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_UNWIND_BASE_IMPLS_HPP
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
|
||||
// Copyright 2015-2019 Antony Polukhin.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_VOID_PTR_CAST_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_VOID_PTR_CAST_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ * 100 + __GNUC_MINOR__ > 301)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
// GCC warns when reinterpret_cast between function pointer and object pointer occur.
|
||||
// This functionsuppress the warnings and ensures that such casts are safe.
|
||||
template <class To, class From>
|
||||
To void_ptr_cast(From* v) BOOST_NOEXCEPT {
|
||||
BOOST_STATIC_ASSERT_MSG(
|
||||
boost::is_pointer<To>::value,
|
||||
"`void_ptr_cast` function must be used only for casting to or from void pointers."
|
||||
);
|
||||
|
||||
BOOST_STATIC_ASSERT_MSG(
|
||||
sizeof(From*) == sizeof(To),
|
||||
"Pointer to function and pointer to object differ in size on your platform."
|
||||
);
|
||||
|
||||
return reinterpret_cast<To>(v);
|
||||
}
|
||||
|
||||
|
||||
}}} // boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_VOID_PTR_CAST_HPP
|
||||
|
||||
67
install/boost_1_75_0/include/boost/stacktrace/frame.hpp
Normal file
67
install/boost_1_75_0/include/boost/stacktrace/frame.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_FRAME_HPP
|
||||
#define BOOST_STACKTRACE_FRAME_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp> // boost::stacktrace::detail::native_frame_ptr_t
|
||||
|
||||
#include <boost/stacktrace/detail/frame_decl.hpp>
|
||||
#include <boost/stacktrace/detail/push_options.h>
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
/// Comparison operators that provide platform dependant ordering and have O(1) complexity; are Async-Handler-Safe.
|
||||
BOOST_CONSTEXPR inline bool operator< (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() < rhs.address(); }
|
||||
BOOST_CONSTEXPR inline bool operator> (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return rhs < lhs; }
|
||||
BOOST_CONSTEXPR inline bool operator<=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); }
|
||||
BOOST_CONSTEXPR inline bool operator>=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); }
|
||||
BOOST_CONSTEXPR inline bool operator==(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() == rhs.address(); }
|
||||
BOOST_CONSTEXPR inline bool operator!=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); }
|
||||
|
||||
/// Fast hashing support, O(1) complexity; Async-Handler-Safe.
|
||||
inline std::size_t hash_value(const frame& f) BOOST_NOEXCEPT {
|
||||
return reinterpret_cast<std::size_t>(f.address());
|
||||
}
|
||||
|
||||
/// Outputs stacktrace::frame in a human readable format to string; unsafe to use in async handlers.
|
||||
BOOST_STACKTRACE_FUNCTION std::string to_string(const frame& f);
|
||||
|
||||
/// Outputs stacktrace::frame in a human readable format to output stream; unsafe to use in async handlers.
|
||||
template <class CharT, class TraitsT>
|
||||
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const frame& f) {
|
||||
return os << boost::stacktrace::to_string(f);
|
||||
}
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
/// @cond
|
||||
|
||||
#include <boost/stacktrace/detail/pop_options.h>
|
||||
|
||||
#ifndef BOOST_STACKTRACE_LINK
|
||||
# if defined(BOOST_STACKTRACE_USE_NOOP)
|
||||
# include <boost/stacktrace/detail/frame_noop.ipp>
|
||||
# elif defined(BOOST_MSVC) || defined(BOOST_STACKTRACE_USE_WINDBG) || defined(BOOST_STACKTRACE_USE_WINDBG_CACHED)
|
||||
# include <boost/stacktrace/detail/frame_msvc.ipp>
|
||||
# else
|
||||
# include <boost/stacktrace/detail/frame_unwind.ipp>
|
||||
# endif
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
|
||||
#endif // BOOST_STACKTRACE_FRAME_HPP
|
||||
222
install/boost_1_75_0/include/boost/stacktrace/safe_dump_to.hpp
Normal file
222
install/boost_1_75_0/include/boost/stacktrace/safe_dump_to.hpp
Normal file
@@ -0,0 +1,222 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_SAFE_DUMP_TO_HPP
|
||||
#define BOOST_STACKTRACE_SAFE_DUMP_TO_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_WINDOWS)
|
||||
#include <boost/winapi/config.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/push_options.h>
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
|
||||
#endif
|
||||
|
||||
/// @file safe_dump_to.hpp This header contains low-level async-signal-safe functions for dumping call stacks. Dumps are binary serialized arrays of `void*`,
|
||||
/// so you could read them by using 'od -tx8 -An stacktrace_dump_failename' Linux command or using boost::stacktrace::stacktrace::from_dump functions.
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
/// @cond
|
||||
namespace detail {
|
||||
|
||||
typedef const void* native_frame_ptr_t; // TODO: change to `typedef void(*native_frame_ptr_t)();`
|
||||
enum helper{ max_frames_dump = 128 };
|
||||
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t from_dump(const char* filename, native_frame_ptr_t* out_frames);
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
|
||||
#if defined(BOOST_WINDOWS)
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(void* fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
|
||||
#else
|
||||
// POSIX
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
|
||||
struct this_thread_frames { // struct is required to avoid warning about usage of inline+BOOST_NOINLINE
|
||||
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT;
|
||||
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(void* memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
|
||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
||||
|
||||
if (size < sizeof(native_frame_ptr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
native_frame_ptr_t* mem = static_cast<native_frame_ptr_t*>(memory);
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(mem, size / sizeof(native_frame_ptr_t) - 1, skip + 1);
|
||||
mem[frames_count] = 0;
|
||||
return frames_count + 1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) BOOST_NOEXCEPT {
|
||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
||||
|
||||
native_frame_ptr_t buffer[boost::stacktrace::detail::max_frames_dump + 1];
|
||||
if (max_depth > boost::stacktrace::detail::max_frames_dump) {
|
||||
max_depth = boost::stacktrace::detail::max_frames_dump;
|
||||
}
|
||||
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, max_depth, skip + 1);
|
||||
buffer[frames_count] = 0;
|
||||
return boost::stacktrace::detail::dump(file, buffer, frames_count + 1);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
/// @endcond
|
||||
|
||||
/// @brief Stores current function call sequence into the memory.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth including terminating zero frame. To get the actually consumed bytes multiply this value by the sizeof(boost::stacktrace::frame::native_frame_ptr_t)
|
||||
///
|
||||
/// @param memory Preallocated buffer to store current function call sequence into.
|
||||
///
|
||||
/// @param size Size of the preallocated buffer.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, 0);
|
||||
}
|
||||
|
||||
/// @brief Stores current function call sequence into the memory.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth including terminating zero frame. To get the actually consumed bytes multiply this value by the sizeof(boost::stacktrace::frame::native_frame_ptr_t)
|
||||
///
|
||||
/// @param skip How many top calls to skip and do not store.
|
||||
///
|
||||
/// @param memory Preallocated buffer to store current function call sequence into.
|
||||
///
|
||||
/// @param size Size of the preallocated buffer.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, void* memory, std::size_t size) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, skip);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
/// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param skip How many top calls to skip and do not store.
|
||||
///
|
||||
/// @param max_depth Max call sequence depth to collect.
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, const char* file) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, skip, max_depth);
|
||||
}
|
||||
|
||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||
|
||||
/// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) BOOST_NOEXCEPT;
|
||||
|
||||
/// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param skip How many top calls to skip and do not store.
|
||||
///
|
||||
/// @param max_depth Max call sequence depth to collect.
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, platform_specific_descriptor fd) BOOST_NOEXCEPT;
|
||||
|
||||
#elif defined(BOOST_WINDOWS)
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(void* fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, void* fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// POSIX
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(int fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, int fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/pop_options.h>
|
||||
|
||||
#if !defined(BOOST_STACKTRACE_LINK) || defined(BOOST_STACKTRACE_INTERNAL_BUILD_LIBS)
|
||||
# if defined(BOOST_STACKTRACE_USE_NOOP)
|
||||
# include <boost/stacktrace/detail/safe_dump_noop.ipp>
|
||||
# include <boost/stacktrace/detail/collect_noop.ipp>
|
||||
# else
|
||||
# if defined(BOOST_WINDOWS)
|
||||
# include <boost/stacktrace/detail/safe_dump_win.ipp>
|
||||
# else
|
||||
# include <boost/stacktrace/detail/safe_dump_posix.ipp>
|
||||
# endif
|
||||
# if defined(BOOST_WINDOWS) && !defined(BOOST_WINAPI_IS_MINGW) // MinGW does not provide RtlCaptureStackBackTrace. MinGW-w64 does.
|
||||
# include <boost/stacktrace/detail/collect_msvc.ipp>
|
||||
# else
|
||||
# include <boost/stacktrace/detail/collect_unwind.ipp>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif // BOOST_STACKTRACE_SAFE_DUMP_TO_HPP
|
||||
422
install/boost_1_75_0/include/boost/stacktrace/stacktrace.hpp
Normal file
422
install/boost_1_75_0/include/boost/stacktrace/stacktrace.hpp
Normal file
@@ -0,0 +1,422 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_STACKTRACE_HPP
|
||||
#define BOOST_STACKTRACE_STACKTRACE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
||||
# include <type_traits>
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/stacktrace_fwd.hpp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
#include <boost/stacktrace/detail/frame_decl.hpp>
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
/// Class that on construction copies minimal information about call stack into its internals and provides access to that information.
|
||||
/// @tparam Allocator Allocator to use during stack capture.
|
||||
template <class Allocator>
|
||||
class basic_stacktrace {
|
||||
std::vector<boost::stacktrace::frame, Allocator> impl_;
|
||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
||||
|
||||
/// @cond
|
||||
void fill(native_frame_ptr_t* begin, std::size_t size) {
|
||||
if (!size) {
|
||||
return;
|
||||
}
|
||||
|
||||
impl_.reserve(static_cast<std::size_t>(size));
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
if (!begin[i]) {
|
||||
return;
|
||||
}
|
||||
impl_.push_back(
|
||||
frame(begin[i])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) BOOST_NOEXCEPT {
|
||||
const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0);
|
||||
return (ret > 1024 ? 1024 : ret); // Dealing with suspiciously big sizes
|
||||
}
|
||||
|
||||
BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) {
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t buffer_size = 128;
|
||||
if (!max_depth) {
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_TRY {
|
||||
{ // Fast path without additional allocations
|
||||
native_frame_ptr_t buffer[buffer_size];
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size < max_depth ? buffer_size : max_depth, frames_to_skip + 1);
|
||||
if (buffer_size > frames_count || frames_count == max_depth) {
|
||||
fill(buffer, frames_count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Failed to fit in `buffer_size`. Allocating memory:
|
||||
#ifdef BOOST_NO_CXX11_ALLOCATOR
|
||||
typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t;
|
||||
#else
|
||||
typedef typename std::allocator_traits<Allocator>::template rebind_alloc<native_frame_ptr_t> allocator_void_t;
|
||||
#endif
|
||||
std::vector<native_frame_ptr_t, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
|
||||
do {
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(&buf[0], buf.size() < max_depth ? buf.size() : max_depth, frames_to_skip + 1);
|
||||
if (buf.size() > frames_count || frames_count == max_depth) {
|
||||
fill(&buf[0], frames_count);
|
||||
return;
|
||||
}
|
||||
|
||||
buf.resize(buf.size() * 2);
|
||||
} while (buf.size() < buf.max_size()); // close to `true`, but suppresses `C4127: conditional expression is constant`.
|
||||
} BOOST_CATCH (...) {
|
||||
// ignore exception
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::value_type value_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::allocator_type allocator_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer pointer;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer const_pointer;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference reference;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference const_reference;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::size_type size_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::difference_type difference_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator iterator;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator const_iterator;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator reverse_iterator;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
/// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
BOOST_FORCEINLINE basic_stacktrace() BOOST_NOEXCEPT
|
||||
: impl_()
|
||||
{
|
||||
init(0 , static_cast<std::size_t>(-1));
|
||||
}
|
||||
|
||||
/// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
///
|
||||
/// @param a Allocator that would be passed to underlying storeage.
|
||||
BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) BOOST_NOEXCEPT
|
||||
: impl_(a)
|
||||
{
|
||||
init(0 , static_cast<std::size_t>(-1));
|
||||
}
|
||||
|
||||
/// @brief Stores [skip, skip + max_depth) of the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
///
|
||||
/// @param skip How many top calls to skip and do not store in *this.
|
||||
///
|
||||
/// @param max_depth Max call sequence depth to collect.
|
||||
///
|
||||
/// @param a Allocator that would be passed to underlying storeage.
|
||||
///
|
||||
/// @throws Nothing. Note that default construction of allocator may throw, however it is
|
||||
/// performed outside the constructor and exception in `allocator_type()` would not result in calling `std::terminate`.
|
||||
BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) BOOST_NOEXCEPT
|
||||
: impl_(a)
|
||||
{
|
||||
init(skip , max_depth);
|
||||
}
|
||||
|
||||
/// @b Complexity: O(st.size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
basic_stacktrace(const basic_stacktrace& st)
|
||||
: impl_(st.impl_)
|
||||
{}
|
||||
|
||||
/// @b Complexity: O(st.size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
basic_stacktrace& operator=(const basic_stacktrace& st) {
|
||||
impl_ = st.impl_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator::deallocate is async signal safe.
|
||||
~basic_stacktrace() BOOST_NOEXCEPT = default;
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
|
||||
basic_stacktrace(basic_stacktrace&& st) BOOST_NOEXCEPT
|
||||
: impl_(std::move(st.impl_))
|
||||
{}
|
||||
|
||||
/// @b Complexity: O(st.size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
|
||||
basic_stacktrace& operator=(basic_stacktrace&& st)
|
||||
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
||||
BOOST_NOEXCEPT_IF(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
|
||||
#else
|
||||
BOOST_NOEXCEPT
|
||||
#endif
|
||||
{
|
||||
impl_ = std::move(st.impl_);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @returns Number of function names stored inside the class.
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
size_type size() const BOOST_NOEXCEPT {
|
||||
return impl_.size();
|
||||
}
|
||||
|
||||
/// @param frame_no Zero based index of frame to return. 0
|
||||
/// is the function index where stacktrace was constructed and
|
||||
/// index close to this->size() contains function `main()`.
|
||||
/// @returns frame that references the actual frame info, stored inside *this.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_reference operator[](std::size_t frame_no) const BOOST_NOEXCEPT {
|
||||
return impl_[frame_no];
|
||||
}
|
||||
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_iterator begin() const BOOST_NOEXCEPT { return impl_.begin(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_iterator cbegin() const BOOST_NOEXCEPT { return impl_.begin(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_iterator end() const BOOST_NOEXCEPT { return impl_.end(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_iterator cend() const BOOST_NOEXCEPT { return impl_.end(); }
|
||||
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_reverse_iterator rend() const BOOST_NOEXCEPT { return impl_.rend(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_reverse_iterator crend() const BOOST_NOEXCEPT { return impl_.rend(); }
|
||||
|
||||
|
||||
/// @brief Allows to check that stack trace capturing was successful.
|
||||
/// @returns `true` if `this->size() != 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
|
||||
/// @brief Allows to check that stack trace failed.
|
||||
/// @returns `true` if `this->size() == 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
bool empty() const BOOST_NOEXCEPT { return !size(); }
|
||||
|
||||
/// @cond
|
||||
bool operator!() const BOOST_NOEXCEPT { return !size(); }
|
||||
/// @endcond
|
||||
|
||||
const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const BOOST_NOEXCEPT {
|
||||
return impl_;
|
||||
}
|
||||
|
||||
/// Constructs stacktrace from basic_istreamable that references the dumped stacktrace. Terminating zero frame is discarded.
|
||||
///
|
||||
/// @b Complexity: O(N)
|
||||
template <class Char, class Trait>
|
||||
static basic_stacktrace from_dump(std::basic_istream<Char, Trait>& in, const allocator_type& a = allocator_type()) {
|
||||
typedef typename std::basic_istream<Char, Trait>::pos_type pos_type;
|
||||
basic_stacktrace ret(0, 0, a);
|
||||
|
||||
// reserving space
|
||||
const pos_type pos = in.tellg();
|
||||
in.seekg(0, in.end);
|
||||
const std::size_t frames_count = frames_count_from_buffer_size(static_cast<std::size_t>(in.tellg()));
|
||||
in.seekg(pos);
|
||||
|
||||
if (!frames_count) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
native_frame_ptr_t ptr = 0;
|
||||
ret.impl_.reserve(frames_count);
|
||||
while (in.read(reinterpret_cast<Char*>(&ptr), sizeof(ptr))) {
|
||||
if (!ptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret.impl_.push_back(frame(ptr));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Constructs stacktrace from raw memory dump. Terminating zero frame is discarded.
|
||||
///
|
||||
/// @param begin Begining of the memory where the stacktrace was saved using the boost::stacktrace::safe_dump_to
|
||||
///
|
||||
/// @param buffer_size_in_bytes Size of the memory. Usually the same value that was passed to the boost::stacktrace::safe_dump_to
|
||||
///
|
||||
/// @b Complexity: O(size) in worst case
|
||||
static basic_stacktrace from_dump(const void* begin, std::size_t buffer_size_in_bytes, const allocator_type& a = allocator_type()) {
|
||||
basic_stacktrace ret(0, 0, a);
|
||||
const native_frame_ptr_t* first = static_cast<const native_frame_ptr_t*>(begin);
|
||||
const std::size_t frames_count = frames_count_from_buffer_size(buffer_size_in_bytes);
|
||||
if (!frames_count) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const native_frame_ptr_t* const last = first + frames_count;
|
||||
ret.impl_.reserve(frames_count);
|
||||
for (; first != last; ++first) {
|
||||
if (!*first) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret.impl_.push_back(frame(*first));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Compares stacktraces for less, order is platform dependent.
|
||||
///
|
||||
/// @b Complexity: Amortized O(1); worst case O(size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
return lhs.size() < rhs.size() || (lhs.size() == rhs.size() && lhs.as_vector() < rhs.as_vector());
|
||||
}
|
||||
|
||||
/// @brief Compares stacktraces for equality.
|
||||
///
|
||||
/// @b Complexity: Amortized O(1); worst case O(size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
return lhs.as_vector() == rhs.as_vector();
|
||||
}
|
||||
|
||||
|
||||
/// Comparison operators that provide platform dependant ordering and have amortized O(1) complexity; O(size()) worst case complexity; are Async-Handler-Safe.
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/// Fast hashing support, O(st.size()) complexity; Async-Handler-Safe.
|
||||
template <class Allocator>
|
||||
std::size_t hash_value(const basic_stacktrace<Allocator>& st) BOOST_NOEXCEPT {
|
||||
return boost::hash_range(st.as_vector().begin(), st.as_vector().end());
|
||||
}
|
||||
|
||||
/// Returns std::string with the stacktrace in a human readable format; unsafe to use in async handlers.
|
||||
template <class Allocator>
|
||||
std::string to_string(const basic_stacktrace<Allocator>& bt) {
|
||||
if (!bt) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size());
|
||||
}
|
||||
|
||||
/// Outputs stacktrace in a human readable format to the output stream `os`; unsafe to use in async handlers.
|
||||
template <class CharT, class TraitsT, class Allocator>
|
||||
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) {
|
||||
return os << boost::stacktrace::to_string(bt);
|
||||
}
|
||||
|
||||
/// This is the typedef to use unless you'd like to provide a specific allocator to boost::stacktrace::basic_stacktrace.
|
||||
typedef basic_stacktrace<> stacktrace;
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // BOOST_STACKTRACE_STACKTRACE_HPP
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_STACKTRACE_FWD_HPP
|
||||
#define BOOST_STACKTRACE_STACKTRACE_FWD_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
/// @file stacktrace_fwd.hpp This header contains only forward declarations of
|
||||
/// boost::stacktrace::frame, boost::stacktrace::basic_stacktrace, boost::stacktrace::stacktrace
|
||||
/// and does not include any other Boost headers.
|
||||
|
||||
/// @cond
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
class frame;
|
||||
template <class Allocator = std::allocator<frame> > class basic_stacktrace;
|
||||
typedef basic_stacktrace<> stacktrace;
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
/// @endcond
|
||||
|
||||
|
||||
#endif // BOOST_STACKTRACE_STACKTRACE_FWD_HPP
|
||||
Reference in New Issue
Block a user