mirror of
https://github.com/boostorg/stacktrace.git
synced 2026-02-24 04:12:31 +00:00
Follow Niall comments and reimplement win debugging in thread safe manner
This commit is contained in:
122
include/boost/stacktrace/detail/backtrace_holder_win_dbghelp.hpp
Normal file
122
include/boost/stacktrace/detail/backtrace_holder_win_dbghelp.hpp
Normal file
@@ -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 <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_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
|
||||
@@ -13,17 +13,21 @@
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#include <windows.h>
|
||||
#include "DbgHelp.h"
|
||||
#include <WinBase.h>
|
||||
#include "Dbgeng.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
|
||||
# define BOOST_LIB_NAME ole32
|
||||
# ifdef BOOST_STACKTRACE_DYN_LINK
|
||||
# define BOOST_DYN_LINK
|
||||
# endif
|
||||
# include <boost/config/auto_link.hpp>
|
||||
# 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 T>
|
||||
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<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;
|
||||
|
||||
@@ -66,28 +82,84 @@ struct backtrace_holder {
|
||||
return buffer[frame];
|
||||
}
|
||||
|
||||
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 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<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();
|
||||
com_holder<IDebugSymbols> 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<PULONG>(&size),
|
||||
0
|
||||
));
|
||||
|
||||
if (!res && size != 0) {
|
||||
result.resize(reinterpret_cast<std::size_t>(size));
|
||||
res = (S_OK == idebug_->GetNameByOffset(
|
||||
offset,
|
||||
&result[0],
|
||||
result.size(),
|
||||
reinterpret_cast<PULONG>(&size),
|
||||
0
|
||||
));
|
||||
} else if (res) {
|
||||
result = name;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
result.clear();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool operator< (const backtrace_holder& rhs) const BOOST_NOEXCEPT {
|
||||
|
||||
Reference in New Issue
Block a user