diff --git a/include/boost/detail/winapi/sym_from_addr.hpp b/include/boost/detail/winapi/sym_from_addr.hpp deleted file mode 100644 index d175de9..0000000 --- a/include/boost/detail/winapi/sym_from_addr.hpp +++ /dev/null @@ -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 - -#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 diff --git a/include/boost/stacktrace.hpp b/include/boost/stacktrace.hpp index e3bdb8d..98680a6 100644 --- a/include/boost/stacktrace.hpp +++ b/include/boost/stacktrace.hpp @@ -21,64 +21,7 @@ #include #include -/// @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() -# define BOOST_STACKTRACE_USE_LIBUNWIND -# elif __has_include() -# 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 -# elif defined(BOOST_STACKTRACE_USE_WINDBG) -# include -# elif defined(BOOST_STACKTRACE_USE_LIBUNWIND) -# include -# elif defined(BOOST_STACKTRACE_USE_BACKTRACE) -# include -# else -# error No suitable backtrace backend found -# endif -#endif -/// @endcond +#include 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::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& operator<<(std::basic_ostream -#endif -/// @endcond - #endif // BOOST_STACKTRACE_STACKTRACE_HPP diff --git a/include/boost/stacktrace/detail/backend.hpp b/include/boost/stacktrace/detail/backend.hpp new file mode 100644 index 0000000..bee340b --- /dev/null +++ b/include/boost/stacktrace/detail/backend.hpp @@ -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 +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +// 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() +# define BOOST_STACKTRACE_USE_LIBUNWIND +# elif __has_include() +# 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(data_); + } + + inline const boost::stacktrace::detail::backtrace_holder& impl() const BOOST_NOEXCEPT { + return *reinterpret_cast(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 +#endif +/// @endcond + +#endif // BOOST_STACKTRACE_DETAIL_BACKEND_HPP diff --git a/include/boost/stacktrace/detail/backend.ipp b/include/boost/stacktrace/detail/backend.ipp new file mode 100644 index 0000000..6f42564 --- /dev/null +++ b/include/boost/stacktrace/detail/backend.ipp @@ -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 +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#include + +#if defined(BOOST_STACKTRACE_USE_NOOP) +# include +#elif defined(BOOST_STACKTRACE_USE_WINDBG) +# include +#elif defined(BOOST_STACKTRACE_USE_LIBUNWIND) +# include +#elif defined(BOOST_STACKTRACE_USE_BACKTRACE) +# include +#else +# error No suitable backtrace backend found +#endif + +#endif // BOOST_STACKTRACE_DETAIL_BACKEND_IPP diff --git a/include/boost/stacktrace/detail/backend_common.ipp b/include/boost/stacktrace/detail/backend_common.ipp new file mode 100644 index 0000000..7e138c2 --- /dev/null +++ b/include/boost/stacktrace/detail/backend_common.ipp @@ -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 +#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(data_)->~backtrace_holder(); +} + +std::size_t backend::size() const BOOST_NOEXCEPT { + return impl().frames_count; +} + +}}} + +#endif // BOOST_STACKTRACE_DETAIL_BACKEND_COMMON_IPP diff --git a/include/boost/stacktrace/detail/backend_libunwind.hpp b/include/boost/stacktrace/detail/backend_libunwind.hpp new file mode 100644 index 0000000..af57c07 --- /dev/null +++ b/include/boost/stacktrace/detail/backend_libunwind.hpp @@ -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 +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define UNW_LOCAL_ONLY +#include + +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 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(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(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 + +#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LIBUNWIND_HPP diff --git a/include/boost/stacktrace/detail/backend_linux.hpp b/include/boost/stacktrace/detail/backend_linux.hpp new file mode 100644 index 0000000..8e11e06 --- /dev/null +++ b/include/boost/stacktrace/detail/backend_linux.hpp @@ -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 +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +#include +#include + +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 + +#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LINUX_HPP diff --git a/include/boost/stacktrace/detail/backend_noop.hpp b/include/boost/stacktrace/detail/backend_noop.hpp new file mode 100644 index 0000000..c0d636a --- /dev/null +++ b/include/boost/stacktrace/detail/backend_noop.hpp @@ -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 +#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 diff --git a/include/boost/stacktrace/detail/backend_windows.hpp b/include/boost/stacktrace/detail/backend_windows.hpp new file mode 100644 index 0000000..1c87b77 --- /dev/null +++ b/include/boost/stacktrace/detail/backend_windows.hpp @@ -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 +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#include +#include "Dbgeng.h" + +#include + +#pragma comment(lib, "ole32.lib") +#pragma comment(lib, "Dbgeng.lib") + +namespace boost { namespace stacktrace { namespace detail { + +template +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(&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& idebug_) BOOST_NOEXCEPT { + if (idebug_.is_inited()) { + return true; + } + + CoInitializeEx(0, COINIT_MULTITHREADED); + + com_holder iclient; + DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr()); + + com_holder 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 idebug_; + if (!try_init_com(idebug_)) { + return result; + } + const ULONG64 offset = reinterpret_cast(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(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 idebug_; + if (!try_init_com(idebug_)) { + return result; + } + const ULONG64 offset = reinterpret_cast(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(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 idebug_; + if (!try_init_com(idebug_)) { + return 0; + } + + const bool is_ok = (S_OK == idebug_->GetLineByOffset( + reinterpret_cast(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 + +#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LINUX_HPP diff --git a/include/boost/stacktrace/detail/backtrace_holder_libunwind.hpp b/include/boost/stacktrace/detail/backtrace_holder_libunwind.hpp deleted file mode 100644 index 097639f..0000000 --- a/include/boost/stacktrace/detail/backtrace_holder_libunwind.hpp +++ /dev/null @@ -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 -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -#include -#include -#include -#include -#include -#include - -#define UNW_LOCAL_ONLY -#include - -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 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 diff --git a/include/boost/stacktrace/detail/backtrace_holder_linux.hpp b/include/boost/stacktrace/detail/backtrace_holder_linux.hpp deleted file mode 100644 index f4c7b6b..0000000 --- a/include/boost/stacktrace/detail/backtrace_holder_linux.hpp +++ /dev/null @@ -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 -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -#include -#include -#include - -#include -#include - -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 diff --git a/include/boost/stacktrace/detail/backtrace_holder_noop.hpp b/include/boost/stacktrace/detail/backtrace_holder_noop.hpp deleted file mode 100644 index 18ab888..0000000 --- a/include/boost/stacktrace/detail/backtrace_holder_noop.hpp +++ /dev/null @@ -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 -#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 diff --git a/include/boost/stacktrace/detail/backtrace_holder_win_dbghelp.hpp b/include/boost/stacktrace/detail/backtrace_holder_win_dbghelp.hpp deleted file mode 100644 index 2195cba..0000000 --- a/include/boost/stacktrace/detail/backtrace_holder_win_dbghelp.hpp +++ /dev/null @@ -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 -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -#include -#include - -#include -#include "DbgHelp.h" -#include - -#include -#include - -#if !defined(BOOST_ALL_NO_LIB) -# define BOOST_LIB_NAME Dbghelp -# ifdef BOOST_STACKTRACE_DYN_LINK -# define BOOST_DYN_LINK -# endif -# include -#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(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 diff --git a/include/boost/stacktrace/detail/backtrace_holder_windows.hpp b/include/boost/stacktrace/detail/backtrace_holder_windows.hpp deleted file mode 100644 index 1f66716..0000000 --- a/include/boost/stacktrace/detail/backtrace_holder_windows.hpp +++ /dev/null @@ -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 -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -#include -#include -#include - -#include -#include "Dbgeng.h" - -#include - -#pragma comment(lib, "ole32.lib") -#pragma comment(lib, "Dbgeng.lib") - -namespace boost { namespace stacktrace { namespace detail { - -template -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(&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 idebug_; - if (!try_init_com(idebug_)) { - return result; - } - const ULONG64 offset = reinterpret_cast(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(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 idebug_; - if (!try_init_com(idebug_)) { - return 0; - } - - const bool is_ok = (S_OK == idebug_->GetLineByOffset( - reinterpret_cast(buffer[frame]), - &line_num, - 0, - 0, - 0, - 0 - )); - - return (is_ok ? line_num : 0); - } - - static bool try_init_com(com_holder& idebug_) BOOST_NOEXCEPT { - if (idebug_.is_inited()) { - return true; - } - - CoInitializeEx(0, COINIT_MULTITHREADED); - - com_holder iclient; - DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr()); - - com_holder 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 idebug_; - if (!try_init_com(idebug_)) { - return result; - } - const ULONG64 offset = reinterpret_cast(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(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 diff --git a/include/boost/stacktrace/detail/helpers.hpp b/include/boost/stacktrace/detail/helpers.hpp deleted file mode 100644 index 64b8a49..0000000 --- a/include/boost/stacktrace/detail/helpers.hpp +++ /dev/null @@ -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 -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -namespace boost { namespace stacktrace { namespace detail { - -struct backtrace_holder; - -template -inline boost::stacktrace::detail::backtrace_holder& to_bt(T& data) BOOST_NOEXCEPT { - return *reinterpret_cast(&data); -} - -template -inline const boost::stacktrace::detail::backtrace_holder& to_bt(const T& data) BOOST_NOEXCEPT { - return *reinterpret_cast(&data); -} - -template -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 diff --git a/include/boost/stacktrace/detail/stacktrace.ipp b/include/boost/stacktrace/detail/stacktrace.ipp deleted file mode 100644 index 9cdc249..0000000 --- a/include/boost/stacktrace/detail/stacktrace.ipp +++ /dev/null @@ -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 -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -#include - -#if defined(BOOST_STACKTRACE_USE_NOOP) -# include -#elif defined(BOOST_STACKTRACE_USE_WINDBG) -# include -#elif defined(BOOST_STACKTRACE_USE_LIBUNWIND) -# include -#elif defined(BOOST_STACKTRACE_USE_BACKTRACE) -# include -#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 diff --git a/include/boost/stacktrace/detail/stacktrace_libunwind.hpp b/include/boost/stacktrace/detail/stacktrace_libunwind.hpp deleted file mode 100644 index af53a7f..0000000 --- a/include/boost/stacktrace/detail/stacktrace_libunwind.hpp +++ /dev/null @@ -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 -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -#include -#include -#include - -#include - -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(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(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 diff --git a/include/boost/stacktrace/detail/stacktrace_linux.hpp b/include/boost/stacktrace/detail/stacktrace_linux.hpp deleted file mode 100644 index 0720d5d..0000000 --- a/include/boost/stacktrace/detail/stacktrace_linux.hpp +++ /dev/null @@ -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 -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -#include -#include -#include - -#include - -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 diff --git a/include/boost/stacktrace/detail/stacktrace_noop.hpp b/include/boost/stacktrace/detail/stacktrace_noop.hpp deleted file mode 100644 index 82c86c2..0000000 --- a/include/boost/stacktrace/detail/stacktrace_noop.hpp +++ /dev/null @@ -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 -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -#include -#include -#include - -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 diff --git a/include/boost/stacktrace/detail/stacktrace_windows.hpp b/include/boost/stacktrace/detail/stacktrace_windows.hpp deleted file mode 100644 index 2825042..0000000 --- a/include/boost/stacktrace/detail/stacktrace_windows.hpp +++ /dev/null @@ -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 -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -#include -#include -#include - -#include - -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 diff --git a/src/backtrace.cpp b/src/backtrace.cpp index 17a791a..4b6e018 100644 --- a/src/backtrace.cpp +++ b/src/backtrace.cpp @@ -7,4 +7,4 @@ #define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS #define BOOST_STACKTRACE_USE_BACKTRACE #define BOOST_STACKTRACE_LINK -#include "stacktrace_src.ipp" +#include diff --git a/src/libunwind.cpp b/src/libunwind.cpp index 6da4753..9f4aa4e 100644 --- a/src/libunwind.cpp +++ b/src/libunwind.cpp @@ -7,4 +7,4 @@ #define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS #define BOOST_STACKTRACE_USE_LIBUNWIND #define BOOST_STACKTRACE_LINK -#include "stacktrace_src.ipp" +#include diff --git a/src/noop.cpp b/src/noop.cpp index 6344e95..7be3af4 100644 --- a/src/noop.cpp +++ b/src/noop.cpp @@ -7,4 +7,4 @@ #define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS #define BOOST_STACKTRACE_USE_NOOP #define BOOST_STACKTRACE_LINK -#include "stacktrace_src.ipp" +#include diff --git a/src/stacktrace_src.ipp b/src/stacktrace_src.ipp deleted file mode 100644 index 896f9a1..0000000 --- a/src/stacktrace_src.ipp +++ /dev/null @@ -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 -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -#include -#include - - -#if defined(BOOST_STACKTRACE_USE_HEADER) -# include BOOST_STACKTRACE_USE_HEADER -#elif defined(BOOST_STACKTRACE_USE_NOOP) -# include -# include -#elif defined(BOOST_STACKTRACE_USE_WINDBG) -# include -# include -#elif defined(BOOST_STACKTRACE_USE_LIBUNWIND) -# include -# include -#elif defined(BOOST_STACKTRACE_USE_BACKTRACE) -# include -# include -#else -# error No suitable backtrace backend found -#endif - -#include - - -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 diff --git a/src/windbg.cpp b/src/windbg.cpp index 8b69466..304569c 100644 --- a/src/windbg.cpp +++ b/src/windbg.cpp @@ -7,4 +7,4 @@ #define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS #define BOOST_STACKTRACE_USE_WINDBG #define BOOST_STACKTRACE_LINK -#include "stacktrace_src.ipp" +#include