diff --git a/include/boost/stacktrace/detail/backtrace_holder_win_dbghelp.hpp b/include/boost/stacktrace/detail/backtrace_holder_win_dbghelp.hpp new file mode 100644 index 0000000..31266f2 --- /dev/null +++ b/include/boost/stacktrace/detail/backtrace_holder_win_dbghelp.hpp @@ -0,0 +1,122 @@ +// 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_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 index a607493..3a14639 100644 --- a/include/boost/stacktrace/detail/backtrace_holder_windows.hpp +++ b/include/boost/stacktrace/detail/backtrace_holder_windows.hpp @@ -13,17 +13,21 @@ #endif #include +#include #include #include -#include "DbgHelp.h" -#include +#include "Dbgeng.h" #include -#include #if !defined(BOOST_ALL_NO_LIB) -# define BOOST_LIB_NAME Dbghelp +# define BOOST_LIB_NAME ole32 +# ifdef BOOST_STACKTRACE_DYN_LINK +# define BOOST_DYN_LINK +# endif +# include +# define BOOST_LIB_NAME Dbgeng # ifdef BOOST_STACKTRACE_DYN_LINK # define BOOST_DYN_LINK # endif @@ -31,27 +35,39 @@ #endif namespace boost { namespace stacktrace { namespace detail { +template +class com_holder: boost::noncopyable { + T* holder_; -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]; -}; +public: + com_holder() BOOST_NOEXCEPT + : holder_(0) + {} -struct symbol_initialization_structure { - boost::detail::winapi::HANDLE_ process; - - inline symbol_initialization_structure() BOOST_NOEXCEPT - : process(boost::detail::winapi::GetCurrentProcess()) - { - SymInitialize(process, 0, true); + T* operator->() const BOOST_NOEXCEPT { + return holder_; } - inline ~symbol_initialization_structure() BOOST_NOEXCEPT { - SymCleanup(process); + 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; @@ -66,28 +82,84 @@ struct backtrace_holder { return buffer[frame]; } + 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 res; - - static symbol_initialization_structure symproc; - + std::string result; 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(); + com_holder idebug_; + if (!try_init_com(idebug_)) { + return result; } - return res; + ULONG64 offset = buffer[frame]); + + char name[256]; + name[0] = 0; + PULONG size = 0; + bool res = (S_OK == idebug_->GetNameByOffset( + offset, + name, + sizeof(name), + reinterpret_cast(&size), + 0 + )); + + if (!res && size != 0) { + result.resize(reinterpret_cast(size)); + res = (S_OK == idebug_->GetNameByOffset( + offset, + &result[0], + result.size(), + reinterpret_cast(&size), + 0 + )); + } else if (res) { + result = name; + } + + if (!res) { + result.clear(); + } + + return result; } inline bool operator< (const backtrace_holder& rhs) const BOOST_NOEXCEPT {