Big refactoring: no more backends, only macro to enable additional functionality

This commit is contained in:
Antony Polukhin
2017-01-13 22:33:37 +03:00
parent bd616a7249
commit 1c5274f9fa
15 changed files with 109 additions and 270 deletions

View File

@@ -1,86 +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_CONST_ITERATOR_HPP
#define BOOST_STACKTRACE_CONST_ITERATOR_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/iterator/iterator_facade.hpp>
#include <boost/assert.hpp>
#include <boost/stacktrace/frame.hpp>
namespace boost { namespace stacktrace {
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
/// Random access iterator over frames that returns boost::stacktrace::frame on dereference
class const_iterator: implementation_details {};
#else
// Forward declarations
template <std::size_t> class basic_stacktrace;
class const_iterator: public boost::iterator_facade<
const_iterator,
frame,
boost::random_access_traversal_tag,
frame>
{
typedef boost::iterator_facade<
const_iterator,
frame,
boost::random_access_traversal_tag,
frame
> base_t;
const boost::stacktrace::detail::backend* impl_;
std::size_t frame_no_;
const_iterator(const boost::stacktrace::detail::backend* impl, std::size_t frame_no) BOOST_NOEXCEPT
: impl_(impl)
, frame_no_(frame_no)
{}
template <std::size_t> friend class basic_stacktrace;
friend class ::boost::iterators::iterator_core_access;
frame dereference() const BOOST_NOEXCEPT {
return frame(impl_->get_address(frame_no_));
}
bool equal(const const_iterator& it) const BOOST_NOEXCEPT {
return impl_ == it.impl_ && frame_no_ == it.frame_no_;
}
void increment() BOOST_NOEXCEPT {
++frame_no_;
}
void decrement() BOOST_NOEXCEPT {
--frame_no_;
}
void advance(std::size_t n) BOOST_NOEXCEPT {
frame_no_ += n;
}
base_t::difference_type distance_to(const const_iterator& it) const {
BOOST_ASSERT(impl_ == it.impl_);
return it.frame_no_ - frame_no_;
}
};
#endif // #ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_CONST_ITERATOR_HPP

View File

@@ -1,25 +0,0 @@
// Copyright Antony Polukhin, 2016-2017.
//
// 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/frame.hpp>
#if defined(BOOST_STACKTRACE_USE_NOOP)
# include <boost/stacktrace/detail/backend_noop.hpp>
#elif defined(BOOST_MSVC)
# include <boost/stacktrace/detail/backend_msvc.hpp>
#else
# include <boost/stacktrace/detail/backend_unwind.hpp>
#endif
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_IPP

View File

@@ -1,49 +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_BACKEND_COMMON_IPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_COMMON_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <algorithm>
namespace boost { namespace stacktrace { namespace detail {
bool backend::operator< (const backend& rhs) const BOOST_NOEXCEPT {
if (frames_count_ != rhs.frames_count_) {
return frames_count_ < rhs.frames_count_;
} else if (hash_code_ != rhs.hash_code_) {
return hash_code_ < rhs.hash_code_;
} else if (data_ == rhs.data_) {
return false;
}
return std::lexicographical_compare(
data_, data_ + frames_count_,
rhs.data_, rhs.data_ + rhs.frames_count_
);
}
bool backend::operator==(const backend& rhs) const BOOST_NOEXCEPT {
if (hash_code_ != rhs.hash_code_ || frames_count_ != rhs.frames_count_) {
return false;
} else if (data_ == rhs.data_) {
return true;
}
return std::equal(
data_, data_ + frames_count_,
rhs.data_
);
}
}}}
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_COMMON_IPP

View File

@@ -4,14 +4,16 @@
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_STACKTRACE_DETAIL_BACKEND_MSVC_HPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_MSVC_HPP
#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/noncopyable.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/stacktrace/detail/to_hex_array.hpp>
@@ -95,17 +97,6 @@ inline bool try_init_com(com_holder<::IDebugSymbols>& idebug, const com_global_i
return true;
}
std::size_t backend::collect(void** memory, std::size_t size) BOOST_NOEXCEPT {
return ::CaptureStackBackTrace(
0,
static_cast<boost::detail::winapi::ULONG_>(size),
memory,
0
);
}
inline std::string get_name_impl(const com_holder<IDebugSymbols>& idebug, const void* addr, std::string* module_name = 0) {
std::string result;
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
@@ -222,19 +213,7 @@ inline void to_string_impl(const com_holder<IDebugSymbols>& idebug, const void*
}
}
std::string backend::to_string(const void* addr) {
boost::stacktrace::detail::com_global_initer com_guard;
boost::stacktrace::detail::com_holder<IDebugSymbols> idebug(com_guard);
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
return std::string();
}
std::string res;
to_string_impl(idebug, addr, res);
return res;
}
std::string backend::to_string(const frame* frames, std::size_t size) {
std::string to_string(const frame* frames, std::size_t size) {
boost::stacktrace::detail::com_global_initer com_guard;
boost::stacktrace::detail::com_holder<IDebugSymbols> idebug(com_guard);
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
@@ -259,7 +238,6 @@ std::string backend::to_string(const frame* frames, std::size_t size) {
} // namespace detail
std::string frame::name() const {
boost::stacktrace::detail::com_global_initer com_guard;
boost::stacktrace::detail::com_holder<IDebugSymbols> idebug(com_guard);
@@ -301,6 +279,28 @@ std::size_t frame::source_line() const {
return (is_ok ? line_num : 0);
}
std::string to_string(const frame& f) {
boost::stacktrace::detail::com_global_initer com_guard;
boost::stacktrace::detail::com_holder<IDebugSymbols> idebug(com_guard);
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
return std::string();
}
std::string res;
boost::stacktrace::detail::to_string_impl(idebug, f.address(), res);
return res;
}
std::size_t this_thread_frames::collect(void** memory, std::size_t size) BOOST_NOEXCEPT {
return ::CaptureStackBackTrace(
0,
static_cast<boost::detail::winapi::ULONG_>(size),
memory,
0
);
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_MSVC_HPP
#endif // BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP

View File

@@ -4,26 +4,19 @@
// 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
#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::size_t backend::collect(void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
return 0;
}
std::string backend::to_string(const void* /*addr*/) {
return std::string();
}
std::string backend::to_string(const frame* /*frames*/, std::size_t /*count*/) {
std::string to_string(const frame* /*frames*/, std::size_t /*count*/) {
return std::string();
}
@@ -41,6 +34,14 @@ std::size_t frame::source_line() const {
return 0;
}
std::string to_string(const frame& /*f*/) {
return std::string();
}
std::size_t this_thread_frames::collect(void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
return 0;
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LIBUNWIND_HPP
#endif // BOOST_STACKTRACE_DETAIL_FRAME_NOOP_IPP

View File

@@ -1,17 +1,19 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2017.
//
// 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_UNWIND_HPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_UNWIND_HPP
#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/try_demangle.hpp>
#include <boost/lexical_cast.hpp>
@@ -50,23 +52,6 @@ inline _Unwind_Reason_Code unwind_callback(::_Unwind_Context* context, void* arg
return ::_URC_NO_REASON;
}
std::size_t backend::collect(void** memory, std::size_t size) BOOST_NOEXCEPT {
std::size_t frames_count = 0;
if (!size) {
return frames_count;
}
unwind_state state = { memory, memory + size };
::_Unwind_Backtrace(&unwind_callback, &state);
frames_count = state.current - memory;
if (memory[frames_count - 1] == 0) {
-- frames_count;
}
return frames_count;
}
template <class Base>
class to_string_impl_base: private Base {
public:
@@ -91,12 +76,7 @@ public:
}
};
std::string backend::to_string(const void* addr) {
to_string_impl impl;
return impl(addr);
}
std::string backend::to_string(const frame* frames, std::size_t size) {
std::string to_string(const frame* frames, std::size_t size) {
std::string res;
res.reserve(64 * size);
@@ -116,9 +96,9 @@ std::string backend::to_string(const frame* frames, std::size_t size) {
return res;
}
} // namespace detail
std::string frame::name() const {
::Dl_info dli;
const bool dl_ok = !!::dladdr(addr_, &dli);
@@ -129,6 +109,29 @@ std::string frame::name() const {
return boost::stacktrace::detail::name_impl(addr_);
}
std::string to_string(const frame& f) {
boost::stacktrace::detail::to_string_impl impl;
return impl(f.address());
}
std::size_t this_thread_frames::collect(void** memory, std::size_t size) BOOST_NOEXCEPT {
std::size_t frames_count = 0;
if (!size) {
return frames_count;
}
boost::stacktrace::detail::unwind_state state = { memory, memory + size };
::_Unwind_Backtrace(&boost::stacktrace::detail::unwind_callback, &state);
frames_count = state.current - memory;
if (memory[frames_count - 1] == 0) {
-- frames_count;
}
return frames_count;
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_UNWIND_HPP
#endif // BOOST_STACKTRACE_DETAIL_FRAME_UNWIND_IPP

View File

@@ -40,21 +40,13 @@
# define BOOST_STACKTRACE_FUNCTION inline
#endif
namespace boost { namespace stacktrace {
class frame;
namespace detail {
// Class that implements the actual backtracing
class backend {
public:
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(void** memory, std::size_t size) BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION static std::string to_string(const void* addr);
BOOST_STACKTRACE_FUNCTION static std::string to_string(const frame* frames, std::size_t size);
};
BOOST_STACKTRACE_FUNCTION std::string to_string(const frame* frames, std::size_t size);
} // namespace detail
/// Non-owning class that references the frame information stored inside the boost::stacktrace::stacktrace class.
@@ -165,19 +157,33 @@ 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::detail::backend::to_string(f.address());
return os << boost::stacktrace::to_string(f);
}
struct this_thread_frames {
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(void** memory, std::size_t size) BOOST_NOEXCEPT;
};
}} // namespace boost::stacktrace
/// @cond
#undef BOOST_STACKTRACE_FUNCTION
#ifndef BOOST_STACKTRACE_LINK
# include <boost/stacktrace/detail/backend.ipp>
# if defined(BOOST_STACKTRACE_USE_NOOP)
# include <boost/stacktrace/detail/frame_noop.ipp>
# elif defined(BOOST_MSVC)
# include <boost/stacktrace/detail/frame_msvc.ipp>
# else
# include <boost/stacktrace/detail/frame_unwind.ipp>
# endif
#endif
/// @endcond

View File

@@ -67,7 +67,7 @@ public:
/// @brief Stores the current function call sequence inside the class.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) for noop backend.
/// @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.
///
@@ -90,7 +90,7 @@ public:
try {
{ // Fast path without additional allocations
void* buffer[buffer_size];
const std::size_t frames_count = boost::stacktrace::detail::backend::collect(buffer, buffer_size);
const std::size_t frames_count = boost::stacktrace::this_thread_frames::collect(buffer, buffer_size);
if (buffer_size > frames_count || frames_count >= max_depth) {
const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
fill(buffer, size);
@@ -102,7 +102,7 @@ public:
typedef typename Allocator::template rebind<void*>::other allocator_void_t;
boost::container::vector<void*, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
do {
const std::size_t frames_count = boost::stacktrace::detail::backend::collect(buf.data(), buf.size());
const std::size_t frames_count = boost::stacktrace::this_thread_frames::collect(buf.data(), buf.size());
if (buf.size() > frames_count || frames_count >= max_depth) {
const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
fill(buf.data(), size);
@@ -164,7 +164,7 @@ public:
/// index close to this->size() contains function `main()`.
/// @returns frame that references the actual frame info, stored inside *this.
///
/// @b Complexity: Amortized O(1), O(1) for noop backend.
/// @b Complexity: Amortized O(1), O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe.
const_reference operator[](std::size_t frame_no) const BOOST_NOEXCEPT {
@@ -283,7 +283,7 @@ std::size_t hash_value(const basic_stacktrace<Allocator>& st) BOOST_NOEXCEPT {
/// Outputs stacktrace in a human readable format to output stream; 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::detail::backend::to_string(bt.as_vector().data(), bt.size());
return os << boost::stacktrace::detail::to_string(bt.as_vector().data(), bt.size());
}
typedef basic_stacktrace<> stacktrace;

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2017.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -11,18 +11,9 @@
#include <memory>
/// @file stacktrace_fwd.hpp This header contains only forward declarations of
/// boost::stacktrace::frame, boost::stacktrace::const_iterator, boost::stacktrace::basic_stacktrace
/// boost::stacktrace::frame, boost::stacktrace::basic_stacktrace
/// and does not include any other Boost headers.
#ifndef BOOST_STACKTRACE_DEFAULT_MAX_DEPTH
/// You may define this macro to some positive integer to limit the max stack frames count for the boost::stacktrace::stacktrace class.
/// This macro does not affect the boost::stacktrace::basic_stacktrace.
///
/// @b Default: 100
#define BOOST_STACKTRACE_DEFAULT_MAX_DEPTH 100
#endif
namespace boost { namespace stacktrace {
class frame;

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2017.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -7,4 +7,4 @@
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_ADDR2LINE
#define BOOST_STACKTRACE_LINK
#include <boost/stacktrace/detail/backend.ipp>
#include <boost/stacktrace/detail/frame_unwind.ipp>

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2017.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -7,4 +7,4 @@
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_BACKTRACE
#define BOOST_STACKTRACE_LINK
#include <boost/stacktrace/detail/backend.ipp>
#include <boost/stacktrace/detail/frame_unwind.ipp>

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2017.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -6,4 +6,4 @@
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_LINK
#include <boost/stacktrace/detail/backend.ipp>
#include <boost/stacktrace/detail/frame_unwind.ipp>

View File

@@ -1,10 +1,9 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2017.
//
// 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)
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_NOOP
#define BOOST_STACKTRACE_LINK
#include <boost/stacktrace/detail/backend.ipp>
#include <boost/stacktrace/detail/frame_noop.ipp>

View File

@@ -1,10 +1,9 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2017.
//
// 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)
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_WINDBG
#define BOOST_STACKTRACE_LINK
#include <boost/stacktrace/detail/backend.ipp>
#include <boost/stacktrace/detail/frame_msvc.ipp>

View File

@@ -62,7 +62,7 @@ test-suite stacktrace_tests
[ run test.cpp test_impl.cpp : : : $(WIND_DEPS) : windbg_ho ]
[ run test.cpp test_impl.cpp : : : $(BASIC_DEPS) : basic_ho ]
# Test with shared linked backends
# Test with shared linked implementations
[ run test.cpp : : : <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) : backtrace_lib ]
[ run test.cpp : : : <library>.//test_impl_lib_addr2line $(LINKSHARED_UNWD) : addr2line_lib ]
[ run test.cpp : : : <library>.//test_impl_lib_windbg $(LINKSHARED_WIND) : windbg_lib ]