Big refactoring to allow in the future to setup stacktrace depth

This commit is contained in:
Antony Polukhin
2016-11-22 22:02:03 +03:00
parent d7bd9eb125
commit 16214550fe
25 changed files with 830 additions and 1212 deletions

View File

@@ -1,64 +0,0 @@
// sym_from_addr.hpp --------------------------------------------------------------//
// Copyright 2016 Antony Polukhin
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_DETAIL_WINAPI_SYM_FROM_ADDR_HPP
#define BOOST_DETAIL_WINAPI_SYM_FROM_ADDR_HPP
#include <boost/detail/winapi/basic_types.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
#pragma once
#endif
#if !defined( BOOST_USE_WINDOWS_H )
extern "C" {
struct _SYMBOL_INFO;
BOOST_SYMBOL_IMPORT boost::detail::winapi::BOOL_ WINAPI SymFromAddr(
/*HANDLE*/ boost::detail::winapi::HANDLE_ hProcess,
/*DWORD64*/ boost::detail::winapi::ULONGLONG_ Address,
/*PDWORD64*/ boost::detail::winapi::ULONGLONG_* Displacement,
/*PSYMBOL_INFO*/ _SYMBOL_INFO* Symbol);
}
#endif
namespace boost {
namespace detail {
namespace winapi {
typedef struct BOOST_DETAIL_WINAPI_MAY_ALIAS _SYMBOL_INFO {
ULONG_ SizeOfStruct;
ULONG_ TypeIndex;
ULONGLONG_ Reserved[2];
ULONG_ Index;
ULONG_ Size;
ULONGLONG_ ModBase;
ULONG_ Flags;
ULONGLONG_ Value;
ULONGLONG_ Address;
ULONG_ Register;
ULONG_ Scope;
ULONG_ Tag;
ULONG_ NameLen;
ULONG_ MaxNameLen;
CHAR_ Name[1];
} SYMBOL_INFO_, *PSYMBOL_INFO_;
using ::SymFromAddr;
BOOST_FORCEINLINE BOOL_ SymFromAddr(HANDLE_ hProcess, ULONGLONG_ Address, ULONGLONG_* Displacement, PSYMBOL_INFO_ Symbol)
{
return ::SymFromAddr(hProcess, Address, Displacement, reinterpret_cast< ::_SYMBOL_INFO* >(Symbol));
}
}
}
}
#endif // BOOST_DETAIL_WINAPI_SYM_FROM_ADDR_HPP

View File

@@ -21,64 +21,7 @@
#include <iosfwd>
#include <string>
/// @cond
// 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
// Backend autodetection
#if !defined(BOOST_STACKTRACE_USE_NOOP) && !defined(BOOST_STACKTRACE_USE_WINDBG) && !defined(BOOST_STACKTRACE_USE_LIBUNWIND) \
&& !defined(BOOST_STACKTRACE_USE_BACKTRACE) &&!defined(BOOST_STACKTRACE_USE_HEADER)
#if defined(__has_include) && (!defined(__GNUC__) || __GNUC__ > 4 || BOOST_CLANG)
# if __has_include(<libunwind.h>)
# define BOOST_STACKTRACE_USE_LIBUNWIND
# elif __has_include(<execinfo.h>)
# define BOOST_STACKTRACE_USE_BACKTRACE
# elif __has_include("DbgHelp.h")
# define BOOST_STACKTRACE_USE_WINDBG
# endif
#else
# if defined(BOOST_WINDOWS)
# define BOOST_STACKTRACE_USE_WINDBG
# else
# define BOOST_STACKTRACE_USE_BACKTRACE
# endif
#endif
#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
#else
# define BOOST_STACKTRACE_FUNCTION inline
# if defined(BOOST_STACKTRACE_USE_NOOP)
# include <boost/stacktrace/detail/backtrace_holder_noop.hpp>
# elif defined(BOOST_STACKTRACE_USE_WINDBG)
# include <boost/stacktrace/detail/backtrace_holder_windows.hpp>
# elif defined(BOOST_STACKTRACE_USE_LIBUNWIND)
# include <boost/stacktrace/detail/backtrace_holder_libunwind.hpp>
# elif defined(BOOST_STACKTRACE_USE_BACKTRACE)
# include <boost/stacktrace/detail/backtrace_holder_linux.hpp>
# else
# error No suitable backtrace backend found
# endif
#endif
/// @endcond
#include <boost/stacktrace/detail/backend.hpp>
namespace boost { namespace stacktrace {
@@ -90,12 +33,12 @@ namespace detail { class iterator; }
/// Non-owning class that references the frame information stored inside the boost::stacktrace::stacktrace class.
class frame_view {
/// @cond
const stacktrace* impl_;
const boost::stacktrace::detail::backend* impl_;
std::size_t frame_no_;
frame_view(); // = delete
frame_view(const stacktrace* impl, std::size_t frame_no) BOOST_NOEXCEPT
frame_view(const boost::stacktrace::detail::backend* impl, std::size_t frame_no) BOOST_NOEXCEPT
: impl_(impl)
, frame_no_(frame_no)
{}
@@ -156,7 +99,7 @@ namespace detail {
frame_view f_;
iterator(const stacktrace* impl, std::size_t frame_no) BOOST_NOEXCEPT
iterator(const boost::stacktrace::detail::backend* impl, std::size_t frame_no) BOOST_NOEXCEPT
: f_(impl, frame_no)
{}
@@ -195,21 +138,11 @@ namespace detail {
/// Class that on construction copies minimal information about call stack into its internals and provides access to that information.
class stacktrace {
/// @cond
#ifdef BOOST_STACKTRACE_LINK
BOOST_STATIC_CONSTEXPR std::size_t max_implementation_size = sizeof(void*) * 110u;
boost::aligned_storage<max_implementation_size>::type impl_;
#else
boost::stacktrace::detail::backtrace_holder impl_;
#endif
std::size_t hash_code_;
boost::stacktrace::detail::backend back_;
BOOST_STACKTRACE_FUNCTION std::string get_name(std::size_t frame_no) const;
BOOST_STACKTRACE_FUNCTION const void* get_address(std::size_t frame_no) const BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION std::string get_source_file(std::size_t frame_no) const;
BOOST_STACKTRACE_FUNCTION std::size_t get_source_line(std::size_t frame_no) const BOOST_NOEXCEPT;
/// @endcond
friend class frame_view;
public:
typedef frame_view reference;
@@ -222,21 +155,35 @@ public:
/// @brief Stores the current function call sequence inside the class.
///
/// @b Complexity: O(N) where N is call seaquence length, O(1) for noop backend.
BOOST_STACKTRACE_FUNCTION stacktrace() BOOST_NOEXCEPT;
stacktrace() BOOST_NOEXCEPT
: impl_()
, hash_code_()
, back_(&impl_, sizeof(impl_), hash_code_)
{}
/// @b Complexity: O(1)
BOOST_STACKTRACE_FUNCTION stacktrace(const stacktrace& bt) BOOST_NOEXCEPT;
stacktrace(const stacktrace& st) BOOST_NOEXCEPT
: impl_()
, hash_code_(st.hash_code_)
, back_(st.back_, &impl_)
{}
/// @b Complexity: O(1)
BOOST_STACKTRACE_FUNCTION stacktrace& operator=(const stacktrace& bt) BOOST_NOEXCEPT;
stacktrace& operator=(const stacktrace& st) BOOST_NOEXCEPT {
back_.~backend();
new (&back_) boost::stacktrace::detail::backend(st.back_, &impl_);
return *this;
}
/// @b Complexity: O(N) for libunwind, O(1) for other backends.
BOOST_STACKTRACE_FUNCTION ~stacktrace() BOOST_NOEXCEPT;
~stacktrace() BOOST_NOEXCEPT {}
/// @returns Number of function names stored inside the class.
///
/// @b Complexity: O(1)
BOOST_STACKTRACE_FUNCTION std::size_t size() const BOOST_NOEXCEPT;
std::size_t size() const BOOST_NOEXCEPT {
return back_.size();
}
/// @param frame_no Zero based index of frame to return. 0
/// is the function index where stacktrace was constructed and
@@ -250,22 +197,22 @@ public:
/// @b Complexity: O(1)
const_iterator begin() const BOOST_NOEXCEPT { return const_iterator(this, 0); }
const_iterator begin() const BOOST_NOEXCEPT { return const_iterator(&back_, 0); }
/// @b Complexity: O(1)
const_iterator cbegin() const BOOST_NOEXCEPT { return const_iterator(this, 0); }
const_iterator cbegin() const BOOST_NOEXCEPT { return const_iterator(&back_, 0); }
/// @b Complexity: O(1)
const_iterator end() const BOOST_NOEXCEPT { return const_iterator(this, size()); }
const_iterator end() const BOOST_NOEXCEPT { return const_iterator(&back_, size()); }
/// @b Complexity: O(1)
const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(this, size()); }
const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(&back_, size()); }
/// @b Complexity: O(1)
const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(this, 0) ); }
const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, 0) ); }
/// @b Complexity: O(1)
const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(this, 0) ); }
const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, 0) ); }
/// @b Complexity: O(1)
const_reverse_iterator rend() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(this, size()) ); }
const_reverse_iterator rend() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, size()) ); }
/// @b Complexity: O(1)
const_reverse_iterator crend() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(this, size()) ); }
const_reverse_iterator crend() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, size()) ); }
/// @brief Allows to check that stack trace capturing was successful.
@@ -277,12 +224,16 @@ public:
/// @brief Compares stacktraces for less, order is platform dependant.
///
/// @b Complexity: Amortized O(1); worst case O(size())
BOOST_STACKTRACE_FUNCTION bool operator< (const stacktrace& rhs) const BOOST_NOEXCEPT;
bool operator< (const stacktrace& rhs) const BOOST_NOEXCEPT {
return hash_code_ < rhs.hash_code_ || (hash_code_ == rhs.hash_code_ && back_ < rhs.back_);
}
/// @brief Compares stacktraces for equality.
///
/// @b Complexity: Amortized O(1); worst case O(size())
BOOST_STACKTRACE_FUNCTION bool operator==(const stacktrace& rhs) const BOOST_NOEXCEPT;
bool operator==(const stacktrace& rhs) const BOOST_NOEXCEPT {
return hash_code_ == rhs.hash_code_ && back_ == rhs.back_;
}
/// @brief Returns hashed code of the stacktrace.
///
@@ -371,12 +322,4 @@ std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT
}} // namespace boost::stacktrace
/// @cond
#undef BOOST_STACKTRACE_FUNCTION
#ifndef BOOST_STACKTRACE_LINK
# include <boost/stacktrace/detail/stacktrace.ipp>
#endif
/// @endcond
#endif // BOOST_STACKTRACE_STACKTRACE_HPP

View File

@@ -0,0 +1,103 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKEND_HPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/core/noncopyable.hpp>
#include <string>
// 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
// Backend autodetection
#if !defined(BOOST_STACKTRACE_USE_NOOP) && !defined(BOOST_STACKTRACE_USE_WINDBG) && !defined(BOOST_STACKTRACE_USE_LIBUNWIND) \
&& !defined(BOOST_STACKTRACE_USE_BACKTRACE) &&!defined(BOOST_STACKTRACE_USE_HEADER)
#if defined(__has_include) && (!defined(__GNUC__) || __GNUC__ > 4 || BOOST_CLANG)
# if __has_include(<libunwind.h>)
# define BOOST_STACKTRACE_USE_LIBUNWIND
# elif __has_include(<execinfo.h>)
# define BOOST_STACKTRACE_USE_BACKTRACE
# elif __has_include("Dbgeng.h")
# define BOOST_STACKTRACE_USE_WINDBG
# endif
#else
# if defined(BOOST_WINDOWS)
# define BOOST_STACKTRACE_USE_WINDBG
# else
# define BOOST_STACKTRACE_USE_BACKTRACE
# endif
#endif
#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
#else
# define BOOST_STACKTRACE_FUNCTION BOOST_FORCEINLINE
#endif
namespace boost { namespace stacktrace { namespace detail {
struct backtrace_holder;
// Class that implements the actual backtracing
class backend: boost::noncopyable {
void* data_;
inline boost::stacktrace::detail::backtrace_holder& impl() BOOST_NOEXCEPT {
return *reinterpret_cast<boost::stacktrace::detail::backtrace_holder*>(data_);
}
inline const boost::stacktrace::detail::backtrace_holder& impl() const BOOST_NOEXCEPT {
return *reinterpret_cast<const boost::stacktrace::detail::backtrace_holder*>(data_);
}
public:
BOOST_STACKTRACE_FUNCTION backend(void* memory, std::size_t size, std::size_t& hash_code) BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION std::string get_name(std::size_t frame_no) const;
BOOST_STACKTRACE_FUNCTION const void* get_address(std::size_t frame_no) const BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION std::string get_source_file(std::size_t frame_no) const;
BOOST_STACKTRACE_FUNCTION std::size_t get_source_line(std::size_t frame_no) const BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION bool operator< (const backend& rhs) const BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION bool operator==(const backend& rhs) const BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION backend(const backend& b, void* memory) BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION ~backend() BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION std::size_t size() const BOOST_NOEXCEPT;
};
}}} // namespace boost::stacktrace::detail
/// @cond
#undef BOOST_STACKTRACE_FUNCTION
#ifndef BOOST_STACKTRACE_LINK
# include <boost/stacktrace/detail/backend.ipp>
#endif
/// @endcond
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_HPP

View File

@@ -0,0 +1,29 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKEND_IPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/detail/backend.hpp>
#if defined(BOOST_STACKTRACE_USE_NOOP)
# include <boost/stacktrace/detail/backend_noop.hpp>
#elif defined(BOOST_STACKTRACE_USE_WINDBG)
# include <boost/stacktrace/detail/backend_windows.hpp>
#elif defined(BOOST_STACKTRACE_USE_LIBUNWIND)
# include <boost/stacktrace/detail/backend_libunwind.hpp>
#elif defined(BOOST_STACKTRACE_USE_BACKTRACE)
# include <boost/stacktrace/detail/backend_linux.hpp>
#else
# error No suitable backtrace backend found
#endif
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_IPP

View File

@@ -0,0 +1,35 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKEND_COMMON_IPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_COMMON_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace stacktrace { namespace detail {
backend::backend(const backend& b, void* memory) BOOST_NOEXCEPT
: data_(memory)
{
new(data_) backtrace_holder(
b.impl()
);
}
backend::~backend() BOOST_NOEXCEPT {
reinterpret_cast<backtrace_holder*>(data_)->~backtrace_holder();
}
std::size_t backend::size() const BOOST_NOEXCEPT {
return impl().frames_count;
}
}}}
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_COMMON_IPP

View File

@@ -0,0 +1,180 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKEND_LIBUNWIND_HPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_LIBUNWIND_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/core/demangle.hpp>
#include <cstring>
#include <boost/functional/hash.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/make_shared.hpp>
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <algorithm>
#define UNW_LOCAL_ONLY
#include <libunwind.h>
namespace boost { namespace stacktrace { namespace detail {
struct bt_pair {
std::string name;
const void* addr;
};
inline bool operator< (const bt_pair& lhs, const bt_pair& rhs) BOOST_NOEXCEPT {
return lhs.addr < rhs.addr;
}
inline bool operator== (const bt_pair& lhs, const bt_pair& rhs) BOOST_NOEXCEPT {
return lhs.addr == rhs.addr;
}
struct backtrace_holder {
std::size_t frames_count;
boost::shared_ptr<bt_pair[]> frames;
};
inline std::string get_frame_impl(unw_cursor_t& cursor) {
std::string res;
unw_word_t offp;
char data[256];
const int ret = unw_get_proc_name(&cursor, data, sizeof(data) / sizeof(char), &offp);
if (ret == -UNW_ENOMEM) {
res.resize(sizeof(data) * 2);
do {
const int ret2 = unw_get_proc_name(&cursor, &res[0], res.size(), &offp);
if (ret2 == -UNW_ENOMEM) {
res.resize(res.size() * 2);
} else if (ret2 == 0) {
break;
} else {
res = data;
return res;
}
} while(1);
} else if (ret == 0) {
res = data;
} else {
return res;
}
boost::core::scoped_demangled_name demangled(res.data());
if (demangled.get()) {
res = demangled.get();
} else {
res.resize( std::strlen(res.data()) ); // Note: here res is \0 terminated, but size() not equal to strlen
}
res += " +";
res += to_hex_array(offp).data();
return res;
}
backend::backend(void* memory, std::size_t size, std::size_t& hash_code) BOOST_NOEXCEPT
: data_(memory)
{
new (data_) backtrace_holder();
impl().frames_count = 0;
hash_code = 0;
unw_context_t uc;
if (unw_getcontext(&uc) != 0) {
return;
}
{ // Counting frames_count
unw_cursor_t cursor;
if (unw_init_local(&cursor, &uc) != 0) {
return;
}
while (unw_step(&cursor) > 0) {
++ impl().frames_count;
}
}
unw_cursor_t cursor;
if (unw_init_local(&cursor, &uc) != 0) {
impl().frames_count = 0;
return;
}
BOOST_TRY {
impl().frames = boost::make_shared<boost::stacktrace::detail::bt_pair[]>(impl().frames_count);
std::size_t i = 0;
while (unw_step(&cursor) > 0){
impl().frames[i].name = get_frame_impl(cursor);
unw_proc_info_t inf;
const int res = unw_get_proc_info(&cursor, &inf);
(void)res;
impl().frames[i].addr = reinterpret_cast<void*>(inf.start_ip ? inf.start_ip : inf.gp);
boost::hash_combine(hash_code, impl().frames[i].name);
++ i;
}
} BOOST_CATCH(...) {}
BOOST_CATCH_END
}
std::string backend::get_name(std::size_t frame) const {
if (frame < impl().frames_count) {
return impl().frames[frame].name;
} else {
return std::string();
}
}
const void* backend::get_address(std::size_t frame) const BOOST_NOEXCEPT {
return impl().frames[frame].addr;
}
std::string backend::get_source_file(std::size_t /*frame*/) const {
return std::string();
}
std::size_t backend::get_source_line(std::size_t /*frame*/) const BOOST_NOEXCEPT {
return 0;
}
bool backend::operator< (const backend& rhs) const BOOST_NOEXCEPT {
if (impl().frames_count != rhs.impl().frames_count) {
return impl().frames_count < rhs.impl().frames_count;
} else if (impl().frames.get() == rhs.impl().frames.get()) {
return false;
}
return std::lexicographical_compare(
impl().frames.get(), impl().frames.get() + impl().frames_count,
rhs.impl().frames.get(), rhs.impl().frames.get() + rhs.impl().frames_count
);
}
bool backend::operator==(const backend& rhs) const BOOST_NOEXCEPT {
if (impl().frames_count != rhs.impl().frames_count) {
return false;
} else if (impl().frames.get() == rhs.impl().frames.get()) {
return true;
}
return std::equal(
impl().frames.get(), impl().frames.get() + impl().frames_count,
rhs.impl().frames.get()
);
}
}}} // namespace boost::stacktrace::detail
#include <boost/stacktrace/detail/backend_common.ipp>
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LIBUNWIND_HPP

View File

@@ -0,0 +1,117 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKEND_LINUX_HPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_LINUX_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/core/demangle.hpp>
#include <boost/functional/hash.hpp>
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <algorithm>
#include <dlfcn.h>
#include <execinfo.h>
namespace boost { namespace stacktrace { namespace detail {
struct backtrace_holder {
std::size_t frames_count;
void* buffer[1];
backtrace_holder() BOOST_NOEXCEPT {}
backtrace_holder(const backtrace_holder& d) BOOST_NOEXCEPT
: frames_count(d.frames_count)
{
std::copy(d.buffer, d.buffer + frames_count, buffer);
}
};
backend::backend(void* memory, std::size_t size, std::size_t& hash_code) BOOST_NOEXCEPT
: data_(memory)
{
new (data_) backtrace_holder();
impl().frames_count = 0;
hash_code = 0;
impl().frames_count = ::backtrace(impl().buffer, 1 + (size - sizeof(backtrace_holder)) / sizeof(void*));
if (impl().buffer[impl().frames_count - 1] == 0) {
-- impl().frames_count;
}
hash_code = boost::hash_range(impl().buffer, impl().buffer + impl().frames_count);
}
std::string backend::get_name(std::size_t frame) const {
std::string res;
if (frame >= impl().frames_count) {
return res;
}
Dl_info dli;
if (!!dladdr(impl().buffer[frame], &dli) && dli.dli_sname) {
boost::core::scoped_demangled_name demangled(dli.dli_sname);
if (demangled.get()) {
res = demangled.get();
} else {
res = dli.dli_sname;
}
} else {
res = "?? at ";
res += to_hex_array(impl().buffer[frame]).data();
}
return res;
}
const void* backend::get_address(std::size_t frame) const BOOST_NOEXCEPT {
return impl().buffer[frame];
}
std::string backend::get_source_file(std::size_t /*frame*/) const {
return std::string();
}
std::size_t backend::get_source_line(std::size_t /*frame*/) const BOOST_NOEXCEPT {
return 0;
}
bool backend::operator< (const backend& rhs) const BOOST_NOEXCEPT {
if (impl().frames_count != rhs.impl().frames_count) {
return impl().frames_count < rhs.impl().frames_count;
} else if (this == &rhs) {
return false;
}
return std::lexicographical_compare(
impl().buffer, impl().buffer + impl().frames_count,
rhs.impl().buffer, rhs.impl().buffer + rhs.impl().frames_count
);
}
bool backend::operator==(const backend& rhs) const BOOST_NOEXCEPT {
if (impl().frames_count != rhs.impl().frames_count) {
return false;
} else if (this == &rhs) {
return true;
}
return std::equal(
impl().buffer, impl().buffer + impl().frames_count,
rhs.impl().buffer
);
}
}}} // namespace boost::stacktrace::detail
#include <boost/stacktrace/detail/backend_common.ipp>
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LINUX_HPP

View File

@@ -0,0 +1,57 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKEND_NOOP_HPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_NOOP_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace stacktrace { namespace detail {
backend::backend(void* memory, std::size_t size, std::size_t& hash_code) BOOST_NOEXCEPT
: data_(memory)
{}
std::string backend::get_name(std::size_t /*frame*/) const {
return std::string();
}
const void* backend::get_address(std::size_t /*frame*/) const BOOST_NOEXCEPT {
return 0;
}
std::string backend::get_source_file(std::size_t /*frame*/) const {
return std::string();
}
std::size_t backend::get_source_line(std::size_t /*frame*/) const BOOST_NOEXCEPT {
return 0;
}
bool backend::operator< (const backend& /*rhs*/) const BOOST_NOEXCEPT {
return false;
}
bool backend::operator==(const backend& /*rhs*/) const BOOST_NOEXCEPT {
return true;
}
backend::backend(const backend& b, void* memory) BOOST_NOEXCEPT
: data_(memory)
{}
backend::~backend() BOOST_NOEXCEPT {}
std::size_t backend::size() const BOOST_NOEXCEPT {
return 0;
}
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LIBUNWIND_HPP

View File

@@ -0,0 +1,267 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKEND_WINDOWS_HPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_WINDOWS_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <boost/core/noncopyable.hpp>
#include <algorithm>
#include <windows.h>
#include "Dbgeng.h"
#include <boost/detail/winapi/get_current_process.hpp>
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "Dbgeng.lib")
namespace boost { namespace stacktrace { namespace detail {
template <class T>
class com_holder: boost::noncopyable {
T* holder_;
public:
com_holder() 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_;
}
void reset() const BOOST_NOEXCEPT {
if (holder_) {
holder_->Release();
}
}
~com_holder() BOOST_NOEXCEPT {
reset();
}
};
inline bool try_init_com(com_holder<IDebugSymbols>& idebug_) BOOST_NOEXCEPT {
if (idebug_.is_inited()) {
return true;
}
CoInitializeEx(0, COINIT_MULTITHREADED);
com_holder<IDebugClient> iclient;
DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr());
com_holder<IDebugControl> icontrol;
iclient->QueryInterface(__uuidof(IDebugControl), icontrol.to_void_ptr_ptr());
const bool res1 = (S_OK == iclient->AttachProcess(
0,
GetCurrentProcessId(),
DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)
);
if (!res1) {
return false;
}
const bool res2 = (S_OK == icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE));
if (!res2) {
return false;
}
const bool res = (S_OK == iclient->QueryInterface(__uuidof(IDebugSymbols), idebug_.to_void_ptr_ptr()));
if (!res) {
idebug_.reset();
return false;
}
return true;
}
struct backtrace_holder {
std::size_t frames_count;
void* buffer[1];
backtrace_holder() BOOST_NOEXCEPT {}
backtrace_holder(const backtrace_holder& d) BOOST_NOEXCEPT
: frames_count(d.frames_count)
{
std::copy(d.buffer, d.buffer + frames_count, buffer);
}
};
backend::backend(void* memory, std::size_t size, std::size_t& hash_code) BOOST_NOEXCEPT
: data_(memory)
{
new (data_) backtrace_holder();
impl().frames_count = 0;
hash_code = 0;
boost::detail::winapi::ULONG_ hc = 0;
impl().frames_count = CaptureStackBackTrace(0, 1 + (size - sizeof(backtrace_holder)) / sizeof(void*), impl().buffer, &hc);
boost::hash_combine(hash_code, hc);
}
std::string backend::get_name(std::size_t frame) const {
std::string result;
if (frame >= impl().frames_count) {
return result;
}
com_holder<IDebugSymbols> idebug_;
if (!try_init_com(idebug_)) {
return result;
}
const ULONG64 offset = reinterpret_cast<ULONG64>(impl().buffer[frame]);
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
));
} else if (res) {
result = name;
}
if (!res) {
result.clear();
}
return result;
}
const void* backend::get_address(std::size_t frame) const BOOST_NOEXCEPT {
return impl().buffer[frame];
}
std::string backend::get_source_file(std::size_t frame) const {
std::string result;
if (frame >= impl().frames_count) {
return result;
}
com_holder<IDebugSymbols> idebug_;
if (!try_init_com(idebug_)) {
return result;
}
const ULONG64 offset = reinterpret_cast<ULONG64>(impl().buffer[frame]);
char name[256];
name[0] = 0;
ULONG size = 0;
bool res = (S_OK == idebug_->GetLineByOffset(
offset,
0,
name,
sizeof(name),
&size,
0
));
if (!res && size != 0) {
result.resize(size);
res = (S_OK == idebug_->GetLineByOffset(
offset,
0,
&result[0],
static_cast<ULONG>(result.size()),
&size,
0
));
} else if (res) {
result = name;
}
if (!res) {
result.clear();
}
return result;
}
std::size_t backend::get_source_line(std::size_t frame) const BOOST_NOEXCEPT {
ULONG line_num = 0;
com_holder<IDebugSymbols> idebug_;
if (!try_init_com(idebug_)) {
return 0;
}
const bool is_ok = (S_OK == idebug_->GetLineByOffset(
reinterpret_cast<ULONG64>(impl().buffer[frame]),
&line_num,
0,
0,
0,
0
));
return (is_ok ? line_num : 0);
}
bool backend::operator< (const backend& rhs) const BOOST_NOEXCEPT {
if (impl().frames_count != rhs.impl().frames_count) {
return impl().frames_count < rhs.impl().frames_count;
} else if (this == &rhs) {
return false;
}
return std::lexicographical_compare(
impl().buffer, impl().buffer + impl().frames_count,
rhs.impl().buffer, rhs.impl().buffer + rhs.impl().frames_count
);
}
bool backend::operator==(const backend& rhs) const BOOST_NOEXCEPT {
if (impl().frames_count != rhs.impl().frames_count) {
return false;
} else if (this == &rhs) {
return true;
}
return std::equal(
impl().buffer, impl().buffer + impl().frames_count,
rhs.impl().buffer
);
}
}}} // namespace boost::stacktrace::detail
#include <boost/stacktrace/detail/backend_common.ipp>
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LINUX_HPP

View File

@@ -1,135 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKTRACE_HOLDER_LIBUNWIND_HPP
#define BOOST_STACKTRACE_DETAIL_BACKTRACE_HOLDER_LIBUNWIND_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/core/demangle.hpp>
#include <cstring>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/make_shared.hpp>
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <algorithm>
#define UNW_LOCAL_ONLY
#include <libunwind.h>
namespace boost { namespace stacktrace { namespace detail {
struct bt_pair {
std::string name;
const void* addr;
};
inline bool operator< (const bt_pair& lhs, const bt_pair& rhs) BOOST_NOEXCEPT {
return lhs.addr < rhs.addr;
}
inline bool operator== (const bt_pair& lhs, const bt_pair& rhs) BOOST_NOEXCEPT {
return lhs.addr == rhs.addr;
}
struct backtrace_holder {
std::size_t frames_count;
boost::shared_ptr<bt_pair[]> frames;
inline std::size_t size() const BOOST_NOEXCEPT {
return frames_count;
}
inline const void* get_address(std::size_t frame) const BOOST_NOEXCEPT {
return frames[frame].addr;
}
inline std::string get_source_file(std::size_t /*frame*/) const {
return std::string();
}
inline std::size_t get_source_line(std::size_t /*frame*/) const BOOST_NOEXCEPT {
return 0;
}
inline std::string get_frame(std::size_t frame) const {
if (frame < frames_count) {
return frames[frame].name;
} else {
return std::string();
}
}
static inline std::string get_frame_impl(unw_cursor_t& cursor) {
std::string res;
unw_word_t offp;
char data[256];
const int ret = unw_get_proc_name(&cursor, data, sizeof(data) / sizeof(char), &offp);
if (ret == -UNW_ENOMEM) {
res.resize(sizeof(data) * 2);
do {
const int ret2 = unw_get_proc_name(&cursor, &res[0], res.size(), &offp);
if (ret2 == -UNW_ENOMEM) {
res.resize(res.size() * 2);
} else if (ret2 == 0) {
break;
} else {
res = data;
return res;
}
} while(1);
} else if (ret == 0) {
res = data;
} else {
return res;
}
boost::core::scoped_demangled_name demangled(res.data());
if (demangled.get()) {
res = demangled.get();
} else {
res.resize( std::strlen(res.data()) ); // Note: here res is \0 terminated, but size() not equal to strlen
}
res += " +";
res += to_hex_array(offp).data();
return res;
}
inline bool operator< (const backtrace_holder& rhs) const BOOST_NOEXCEPT {
if (frames_count != rhs.frames_count) {
return frames_count < rhs.frames_count;
} else if (frames.get() == rhs.frames.get()) {
return false;
}
return std::lexicographical_compare(
frames.get(), frames.get() + frames_count,
rhs.frames.get(), rhs.frames.get() + rhs.frames_count
);
}
inline bool operator==(const backtrace_holder& rhs) const BOOST_NOEXCEPT {
if (frames_count != rhs.frames_count) {
return false;
} else if (frames.get() == rhs.frames.get()) {
return true;
}
return std::equal(
frames.get(), frames.get() + frames_count,
rhs.frames.get()
);
}
};
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_BACKTRACE_HOLDER_LIBUNWIND_HPP

View File

@@ -1,96 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKTRACE_HOLDER_LINUX_HPP
#define BOOST_STACKTRACE_DETAIL_BACKTRACE_HOLDER_LINUX_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/core/demangle.hpp>
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <algorithm>
#include <dlfcn.h>
#include <execinfo.h>
namespace boost { namespace stacktrace { namespace detail {
struct backtrace_holder {
std::size_t frames_count;
BOOST_STATIC_CONSTEXPR std::size_t max_size = 100u;
void* buffer[max_size];
inline std::size_t size() const BOOST_NOEXCEPT {
return frames_count;
}
inline const void* get_address(std::size_t frame) const BOOST_NOEXCEPT {
return buffer[frame];
}
inline std::string get_source_file(std::size_t /*frame*/) const {
return std::string();
}
inline std::size_t get_source_line(std::size_t /*frame*/) const BOOST_NOEXCEPT {
return 0;
}
inline std::string get_frame(std::size_t frame) const {
std::string res;
if (frame >= frames_count) {
return res;
}
Dl_info dli;
if (!!dladdr(buffer[frame], &dli) && dli.dli_sname) {
boost::core::scoped_demangled_name demangled(dli.dli_sname);
if (demangled.get()) {
res = demangled.get();
} else {
res = dli.dli_sname;
}
} else {
res = "?? at ";
res += to_hex_array(buffer[frame]).data();
}
return res;
}
inline bool operator< (const backtrace_holder& rhs) const BOOST_NOEXCEPT {
if (frames_count != rhs.frames_count) {
return frames_count < rhs.frames_count;
} else if (this == &rhs) {
return false;
}
return std::lexicographical_compare(
buffer, buffer + frames_count,
rhs.buffer, rhs.buffer + rhs.frames_count
);
}
inline bool operator==(const backtrace_holder& rhs) const BOOST_NOEXCEPT {
if (frames_count != rhs.frames_count) {
return false;
} else if (this == &rhs) {
return true;
}
return std::equal(
buffer, buffer + frames_count,
rhs.buffer
);
}
};
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_BACKTRACE_HOLDER_LINUX_HPP

View File

@@ -1,50 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKTRACE_HOLDER_NOOP_HPP
#define BOOST_STACKTRACE_DETAIL_BACKTRACE_HOLDER_NOOP_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace stacktrace { namespace detail {
struct backtrace_holder {
inline std::size_t size() const BOOST_NOEXCEPT {
return 0u;
}
inline const void* get_address(std::size_t /*frame*/) const BOOST_NOEXCEPT {
return 0;
}
inline std::string get_source_file(std::size_t /*frame*/) const {
return std::string();
}
inline std::size_t get_source_line(std::size_t /*frame*/) const BOOST_NOEXCEPT {
return 0;
}
inline std::string get_frame(std::size_t /*frame*/) const {
return std::string();
}
inline bool operator< (const backtrace_holder& /*rhs*/) const BOOST_NOEXCEPT {
return false;
}
inline bool operator==(const backtrace_holder& /*rhs*/) const BOOST_NOEXCEPT {
return true;
}
};
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_BACKTRACE_HOLDER_NOOP_HPP

View File

@@ -1,130 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKTRACE_HOLDER_WIN_DBGHELP_HPP
#define BOOST_STACKTRACE_DETAIL_BACKTRACE_HOLDER_WIN_DBGHELP_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <algorithm>
#include <windows.h>
#include "DbgHelp.h"
#include <WinBase.h>
#include <boost/detail/winapi/get_current_process.hpp>
#include <boost/detail/winapi/sym_from_addr.hpp>
#if !defined(BOOST_ALL_NO_LIB)
# define BOOST_LIB_NAME Dbghelp
# ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_DYN_LINK
# endif
# include <boost/config/auto_link.hpp>
#endif
namespace boost { namespace stacktrace { namespace detail {
struct symbol_info_with_stack {
BOOST_STATIC_CONSTEXPR std::size_t max_name_length = MAX_SYM_NAME * sizeof(char);
boost::detail::winapi::SYMBOL_INFO_ symbol;
char name_part[max_name_length];
};
struct symbol_initialization_structure {
boost::detail::winapi::HANDLE_ process;
inline symbol_initialization_structure() BOOST_NOEXCEPT
: process(boost::detail::winapi::GetCurrentProcess())
{
SymInitialize(process, 0, true);
}
inline ~symbol_initialization_structure() BOOST_NOEXCEPT {
SymCleanup(process);
}
};
struct backtrace_holder {
BOOST_STATIC_CONSTEXPR std::size_t max_size = 100u;
std::size_t frames_count;
void* buffer[max_size];
inline std::size_t size() const BOOST_NOEXCEPT {
return frames_count;
}
inline const void* get_address(std::size_t frame) const BOOST_NOEXCEPT {
return buffer[frame];
}
inline std::string get_source_file(std::size_t /*frame*/) const {
return std::string();
}
inline std::size_t get_source_line(std::size_t /*frame*/) const BOOST_NOEXCEPT {
return 0;
}
inline std::string get_frame(std::size_t frame) const {
std::string res;
static symbol_initialization_structure symproc;
if (frame >= frames_count) {
return res;
}
symbol_info_with_stack s;
s.symbol.MaxNameLen = symbol_info_with_stack::max_name_length;
s.symbol.SizeOfStruct = sizeof(boost::detail::winapi::SYMBOL_INFO_);
const bool sym_res = !!boost::detail::winapi::SymFromAddr(
symproc.process, reinterpret_cast<boost::detail::winapi::ULONGLONG_>(buffer[frame]), 0, &s.symbol
);
if (sym_res) {
res = s.symbol.Name;
} else {
res = "?? at ";
res += to_hex_array(buffer[frame]).data();
}
return res;
}
inline bool operator< (const backtrace_holder& rhs) const BOOST_NOEXCEPT {
if (frames_count != rhs.frames_count) {
return frames_count < rhs.frames_count;
} else if (this == &rhs) {
return false;
}
return std::lexicographical_compare(
buffer, buffer + frames_count,
rhs.buffer, rhs.buffer + rhs.frames_count
);
}
inline bool operator==(const backtrace_holder& rhs) const BOOST_NOEXCEPT {
if (frames_count != rhs.frames_count) {
return false;
} else if (this == &rhs) {
return true;
}
return std::equal(
buffer, buffer + frames_count,
rhs.buffer
);
}
};
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_BACKTRACE_HOLDER_WIN_DBGHELP_HPP

View File

@@ -1,250 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_BACKTRACE_HOLDER_WINDOWS_HPP
#define BOOST_STACKTRACE_DETAIL_BACKTRACE_HOLDER_WINDOWS_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <boost/core/noncopyable.hpp>
#include <algorithm>
#include <windows.h>
#include "Dbgeng.h"
#include <boost/detail/winapi/get_current_process.hpp>
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "Dbgeng.lib")
namespace boost { namespace stacktrace { namespace detail {
template <class T>
class com_holder: boost::noncopyable {
T* holder_;
public:
com_holder() 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_;
}
void reset() const BOOST_NOEXCEPT {
if (holder_) {
holder_->Release();
}
}
~com_holder() BOOST_NOEXCEPT {
reset();
}
};
struct backtrace_holder {
BOOST_STATIC_CONSTEXPR std::size_t max_size = 100u;
std::size_t frames_count;
void* buffer[max_size];
inline std::size_t size() const BOOST_NOEXCEPT {
return frames_count;
}
inline const void* get_address(std::size_t frame) const BOOST_NOEXCEPT {
return buffer[frame];
}
inline std::string get_source_file(std::size_t frame) const {
std::string result;
if (frame >= frames_count) {
return result;
}
com_holder<IDebugSymbols> idebug_;
if (!try_init_com(idebug_)) {
return result;
}
const ULONG64 offset = reinterpret_cast<ULONG64>(buffer[frame]);
char name[256];
name[0] = 0;
ULONG size = 0;
bool res = (S_OK == idebug_->GetLineByOffset(
offset,
0,
name,
sizeof(name),
&size,
0
));
if (!res && size != 0) {
result.resize(size);
res = (S_OK == idebug_->GetLineByOffset(
offset,
0,
&result[0],
static_cast<ULONG>(result.size()),
&size,
0
));
} else if (res) {
result = name;
}
if (!res) {
result.clear();
}
return result;
}
inline std::size_t get_source_line(std::size_t frame) const BOOST_NOEXCEPT {
ULONG line_num = 0;
com_holder<IDebugSymbols> idebug_;
if (!try_init_com(idebug_)) {
return 0;
}
const bool is_ok = (S_OK == idebug_->GetLineByOffset(
reinterpret_cast<ULONG64>(buffer[frame]),
&line_num,
0,
0,
0,
0
));
return (is_ok ? line_num : 0);
}
static bool try_init_com(com_holder<IDebugSymbols>& idebug_) BOOST_NOEXCEPT {
if (idebug_.is_inited()) {
return true;
}
CoInitializeEx(0, COINIT_MULTITHREADED);
com_holder<IDebugClient> iclient;
DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr());
com_holder<IDebugControl> icontrol;
iclient->QueryInterface(__uuidof(IDebugControl), icontrol.to_void_ptr_ptr());
const bool res1 = (S_OK == iclient->AttachProcess(
0,
GetCurrentProcessId(),
DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)
);
if (!res1) {
return false;
}
const bool res2 = (S_OK == icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE));
if (!res2) {
return false;
}
const bool res = (S_OK == iclient->QueryInterface(__uuidof(IDebugSymbols), idebug_.to_void_ptr_ptr()));
if (!res) {
idebug_.reset();
return false;
}
return true;
}
inline std::string get_frame(std::size_t frame) const {
std::string result;
if (frame >= frames_count) {
return result;
}
com_holder<IDebugSymbols> idebug_;
if (!try_init_com(idebug_)) {
return result;
}
const ULONG64 offset = reinterpret_cast<ULONG64>(buffer[frame]);
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
));
} else if (res) {
result = name;
}
if (!res) {
result.clear();
}
return result;
}
inline bool operator< (const backtrace_holder& rhs) const BOOST_NOEXCEPT {
if (frames_count != rhs.frames_count) {
return frames_count < rhs.frames_count;
} else if (this == &rhs) {
return false;
}
return std::lexicographical_compare(
buffer, buffer + frames_count,
rhs.buffer, rhs.buffer + rhs.frames_count
);
}
inline bool operator==(const backtrace_holder& rhs) const BOOST_NOEXCEPT {
if (frames_count != rhs.frames_count) {
return false;
} else if (this == &rhs) {
return true;
}
return std::equal(
buffer, buffer + frames_count,
rhs.buffer
);
}
};
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_BACKTRACE_HOLDER_WINDOWS_HPP

View File

@@ -1,41 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_STACKTRACE_HELPERS_HPP
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_HELPERS_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace stacktrace { namespace detail {
struct backtrace_holder;
template <class T>
inline boost::stacktrace::detail::backtrace_holder& to_bt(T& data) BOOST_NOEXCEPT {
return *reinterpret_cast<boost::stacktrace::detail::backtrace_holder*>(&data);
}
template <class T>
inline const boost::stacktrace::detail::backtrace_holder& to_bt(const T& data) BOOST_NOEXCEPT {
return *reinterpret_cast<const boost::stacktrace::detail::backtrace_holder*>(&data);
}
template <class T>
inline boost::stacktrace::detail::backtrace_holder& construct_bt_and_return(T& data) BOOST_NOEXCEPT {
new (&data) boost::stacktrace::detail::backtrace_holder();
return boost::stacktrace::detail::to_bt(data);
}
inline boost::stacktrace::detail::backtrace_holder& construct_bt_and_return(backtrace_holder& data) BOOST_NOEXCEPT {
return data;
}
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_HELPERS_HPP

View File

@@ -1,80 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_STACKTRACE_IPP
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace.hpp>
#if defined(BOOST_STACKTRACE_USE_NOOP)
# include <boost/stacktrace/detail/stacktrace_noop.hpp>
#elif defined(BOOST_STACKTRACE_USE_WINDBG)
# include <boost/stacktrace/detail/stacktrace_windows.hpp>
#elif defined(BOOST_STACKTRACE_USE_LIBUNWIND)
# include <boost/stacktrace/detail/stacktrace_libunwind.hpp>
#elif defined(BOOST_STACKTRACE_USE_BACKTRACE)
# include <boost/stacktrace/detail/stacktrace_linux.hpp>
#else
# error No suitable backtrace backend found
#endif
namespace boost { namespace stacktrace {
// stacktrace::stacktrace() is defined in each backend separately. This is
// requered to avoid `boost::stacktrace::detail::backtrace_holder` apearing in
// stack traces.
stacktrace::stacktrace(const stacktrace& bt) BOOST_NOEXCEPT
: impl_(bt.impl_)
, hash_code_(bt.hash_code_)
{}
stacktrace& stacktrace::operator=(const stacktrace& bt) BOOST_NOEXCEPT {
impl_ = bt.impl_;
hash_code_ = bt.hash_code_;
return *this;
}
stacktrace::~stacktrace() BOOST_NOEXCEPT {}
std::size_t stacktrace::size() const BOOST_NOEXCEPT {
return impl_.size();
}
std::string stacktrace::get_name(std::size_t frame) const {
return impl_.get_frame(frame);
}
const void* stacktrace::get_address(std::size_t frame) const BOOST_NOEXCEPT {
return impl_.get_address(frame);
}
std::string stacktrace::get_source_file(std::size_t frame) const {
return impl_.get_source_file(frame);
}
std::size_t stacktrace::get_source_line(std::size_t frame) const BOOST_NOEXCEPT {
return impl_.get_source_line(frame);
}
bool stacktrace::operator< (const stacktrace& rhs) const BOOST_NOEXCEPT {
return hash_code_ < rhs.hash_code_ || (hash_code_ == rhs.hash_code_ && impl_ < rhs.impl_);
}
bool stacktrace::operator==(const stacktrace& rhs) const BOOST_NOEXCEPT {
return hash_code_ == rhs.hash_code_ && impl_ == rhs.impl_;
}
}}
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_IPP

View File

@@ -1,68 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_STACKTRACE_LIBUNWIND_HPP
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_LIBUNWIND_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace.hpp>
#include <boost/stacktrace/detail/backtrace_holder_libunwind.hpp>
#include <boost/stacktrace/detail/helpers.hpp>
#include <boost/functional/hash.hpp>
namespace boost { namespace stacktrace {
stacktrace::stacktrace() BOOST_NOEXCEPT
: hash_code_(0)
{
boost::stacktrace::detail::backtrace_holder& bt = boost::stacktrace::detail::construct_bt_and_return(impl_);
bt.frames_count = 0;
unw_context_t uc;
if (unw_getcontext(&uc) != 0) {
return;
}
{ // Counting frames_count
unw_cursor_t cursor;
if (unw_init_local(&cursor, &uc) != 0) {
return;
}
while (unw_step(&cursor) > 0) {
++ bt.frames_count;
}
}
unw_cursor_t cursor;
if (unw_init_local(&cursor, &uc) != 0) {
bt.frames_count = 0;
return;
}
BOOST_TRY {
bt.frames = boost::make_shared<boost::stacktrace::detail::bt_pair[]>(bt.frames_count);
std::size_t i = 0;
while (unw_step(&cursor) > 0){
bt.frames[i].name = boost::stacktrace::detail::backtrace_holder::get_frame_impl(cursor);
unw_proc_info_t inf;
const int res = unw_get_proc_info(&cursor, &inf);
(void)res;
bt.frames[i].addr = reinterpret_cast<void*>(inf.start_ip ? inf.start_ip : inf.gp);
boost::hash_combine(hash_code_, bt.frames[i].name);
++ i;
}
} BOOST_CATCH(...) {}
BOOST_CATCH_END
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_LIBUNWIND_HPP

View File

@@ -1,37 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_STACKTRACE_LINUX_HPP
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_LINUX_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace.hpp>
#include <boost/stacktrace/detail/backtrace_holder_linux.hpp>
#include <boost/stacktrace/detail/helpers.hpp>
#include <boost/functional/hash.hpp>
namespace boost { namespace stacktrace {
stacktrace::stacktrace() BOOST_NOEXCEPT
: hash_code_(0)
{
boost::stacktrace::detail::backtrace_holder& bt = boost::stacktrace::detail::construct_bt_and_return(impl_);
bt.frames_count = ::backtrace(bt.buffer, boost::stacktrace::detail::backtrace_holder::max_size);
if (bt.buffer[bt.frames_count - 1] == 0) {
-- bt.frames_count;
}
hash_code_ = boost::hash_range(bt.buffer, bt.buffer + bt.frames_count);
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_LINUX_HPP

View File

@@ -1,29 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_STACKTRACE_NOOP_HPP
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_NOOP_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace.hpp>
#include <boost/stacktrace/detail/backtrace_holder_noop.hpp>
#include <boost/stacktrace/detail/helpers.hpp>
namespace boost { namespace stacktrace {
stacktrace::stacktrace() BOOST_NOEXCEPT
: hash_code_(0)
{
boost::stacktrace::detail::construct_bt_and_return(impl_);
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_NOOP_HPP

View File

@@ -1,34 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_STACKTRACE_WINDOWS_HPP
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_WINDOWS_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace.hpp>
#include <boost/stacktrace/detail/backtrace_holder_windows.hpp>
#include <boost/stacktrace/detail/helpers.hpp>
#include <boost/functional/hash.hpp>
namespace boost { namespace stacktrace {
stacktrace::stacktrace() BOOST_NOEXCEPT
: hash_code_(0)
{
boost::stacktrace::detail::backtrace_holder& bt = boost::stacktrace::detail::construct_bt_and_return(impl_);
boost::detail::winapi::ULONG_ hc = 0;
bt.frames_count = CaptureStackBackTrace(0, boost::stacktrace::detail::backtrace_holder::max_size, bt.buffer, &hc);
boost::hash_combine(hash_code_, hc);
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_WINDOWS_HPP

View File

@@ -7,4 +7,4 @@
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_BACKTRACE
#define BOOST_STACKTRACE_LINK
#include "stacktrace_src.ipp"
#include <boost/stacktrace/detail/backend.ipp>

View File

@@ -7,4 +7,4 @@
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_LIBUNWIND
#define BOOST_STACKTRACE_LINK
#include "stacktrace_src.ipp"
#include <boost/stacktrace/detail/backend.ipp>

View File

@@ -7,4 +7,4 @@
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_NOOP
#define BOOST_STACKTRACE_LINK
#include "stacktrace_src.ipp"
#include <boost/stacktrace/detail/backend.ipp>

View File

@@ -1,99 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// 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_SRC_STACKTRACE_IPP
#define BOOST_STACKTRACE_SRC_STACKTRACE_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace.hpp>
#include <boost/static_assert.hpp>
#if defined(BOOST_STACKTRACE_USE_HEADER)
# include BOOST_STACKTRACE_USE_HEADER
#elif defined(BOOST_STACKTRACE_USE_NOOP)
# include <boost/stacktrace/detail/backtrace_holder_noop.hpp>
# include <boost/stacktrace/detail/stacktrace_noop.hpp>
#elif defined(BOOST_STACKTRACE_USE_WINDBG)
# include <boost/stacktrace/detail/backtrace_holder_windows.hpp>
# include <boost/stacktrace/detail/stacktrace_windows.hpp>
#elif defined(BOOST_STACKTRACE_USE_LIBUNWIND)
# include <boost/stacktrace/detail/backtrace_holder_libunwind.hpp>
# include <boost/stacktrace/detail/stacktrace_libunwind.hpp>
#elif defined(BOOST_STACKTRACE_USE_BACKTRACE)
# include <boost/stacktrace/detail/backtrace_holder_linux.hpp>
# include <boost/stacktrace/detail/stacktrace_linux.hpp>
#else
# error No suitable backtrace backend found
#endif
#include <boost/stacktrace/detail/helpers.hpp>
namespace boost { namespace stacktrace {
// stacktrace::stacktrace() is defined in each backend separately. This is
// requered to avoid `boost::stacktrace::detail::backtrace_holder` apearing in
// stack traces.
stacktrace::stacktrace(const stacktrace& bt) BOOST_NOEXCEPT
: hash_code_(bt.hash_code_)
{
new (&impl_) boost::stacktrace::detail::backtrace_holder(
boost::stacktrace::detail::to_bt(bt.impl_)
);
}
stacktrace& stacktrace::operator=(const stacktrace& bt) BOOST_NOEXCEPT {
boost::stacktrace::detail::to_bt(impl_) = boost::stacktrace::detail::to_bt(bt.impl_);
hash_code_ = bt.hash_code_;
return *this;
}
stacktrace::~stacktrace() BOOST_NOEXCEPT {
BOOST_STATIC_ASSERT_MSG(sizeof(impl_) >= sizeof(boost::stacktrace::detail::backtrace_holder), "Too small storage for holding backtrace");
boost::stacktrace::detail::to_bt(impl_).~backtrace_holder();
}
std::size_t stacktrace::size() const BOOST_NOEXCEPT {
return boost::stacktrace::detail::to_bt(impl_).size();
}
std::string stacktrace::get_name(std::size_t frame) const {
return boost::stacktrace::detail::to_bt(impl_).get_frame(frame);
}
const void* stacktrace::get_address(std::size_t frame) const BOOST_NOEXCEPT {
return boost::stacktrace::detail::to_bt(impl_).get_address(frame);
}
std::string stacktrace::get_source_file(std::size_t frame) const {
return boost::stacktrace::detail::to_bt(impl_).get_source_file(frame);
}
std::size_t stacktrace::get_source_line(std::size_t frame) const BOOST_NOEXCEPT {
return boost::stacktrace::detail::to_bt(impl_).get_source_line(frame);
}
bool stacktrace::operator< (const stacktrace& rhs) const BOOST_NOEXCEPT {
return hash_code_ < rhs.hash_code_
|| (hash_code_ == rhs.hash_code_ && boost::stacktrace::detail::to_bt(impl_) < boost::stacktrace::detail::to_bt(rhs.impl_))
;
}
bool stacktrace::operator==(const stacktrace& rhs) const BOOST_NOEXCEPT {
return hash_code_ == rhs.hash_code_
&& boost::stacktrace::detail::to_bt(impl_) == boost::stacktrace::detail::to_bt(rhs.impl_)
;
}
}}
#endif // BOOST_STACKTRACE_SRC_STACKTRACE_IPP

View File

@@ -7,4 +7,4 @@
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_WINDBG
#define BOOST_STACKTRACE_LINK
#include "stacktrace_src.ipp"
#include <boost/stacktrace/detail/backend.ipp>