Follow Niall comments and reimplement win debugging in thread safe manner

This commit is contained in:
Antony Polukhin
2016-11-15 21:30:12 +03:00
parent e793933aa4
commit 115c5db0a3
2 changed files with 228 additions and 34 deletions

View 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

View File

@@ -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 {