File indexing completed on 2025-01-18 09:52:31
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP
0008 #define BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP
0009
0010 #include <boost/config.hpp>
0011 #ifdef BOOST_HAS_PRAGMA_ONCE
0012 # pragma once
0013 #endif
0014
0015 #include <boost/stacktrace/frame.hpp>
0016
0017 #include <boost/core/demangle.hpp>
0018 #include <boost/core/noncopyable.hpp>
0019 #include <boost/stacktrace/detail/to_dec_array.hpp>
0020 #include <boost/stacktrace/detail/to_hex_array.hpp>
0021 #include <windows.h>
0022 #include "dbgeng.h"
0023
0024 #ifdef BOOST_MSVC
0025 # pragma comment(lib, "ole32.lib")
0026 # pragma comment(lib, "Dbgeng.lib")
0027 #endif
0028
0029
0030 #ifdef __CRT_UUID_DECL
0031 #if !defined(__MINGW32__) || \
0032 (!defined(__clang__) && __GNUC__ < 12) || \
0033 (defined(__clang__) && __clang_major__ < 16)
0034 __CRT_UUID_DECL(IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8)
0035 __CRT_UUID_DECL(IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba)
0036 __CRT_UUID_DECL(IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50)
0037 #endif
0038 #elif defined(DEFINE_GUID) && !defined(BOOST_MSVC)
0039 DEFINE_GUID(IID_IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8);
0040 DEFINE_GUID(IID_IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba);
0041 DEFINE_GUID(IID_IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50);
0042 #endif
0043
0044
0045
0046
0047
0048
0049 namespace boost { namespace stacktrace { namespace detail {
0050
0051 template <class T>
0052 class com_holder: boost::noncopyable {
0053 T* holder_;
0054
0055 public:
0056 com_holder() noexcept
0057 : holder_(0)
0058 {}
0059
0060 T* operator->() const noexcept {
0061 return holder_;
0062 }
0063
0064 void** to_void_ptr_ptr() noexcept {
0065 return reinterpret_cast<void**>(&holder_);
0066 }
0067
0068 bool is_inited() const noexcept {
0069 return !!holder_;
0070 }
0071
0072 ~com_holder() noexcept {
0073 if (holder_) {
0074 holder_->Release();
0075 }
0076 }
0077 };
0078
0079
0080 inline std::string mingw_demangling_workaround(const std::string& s) {
0081 #ifdef BOOST_GCC
0082 if (s.empty()) {
0083 return s;
0084 }
0085
0086 if (s[0] != '_') {
0087 return boost::core::demangle(('_' + s).c_str());
0088 }
0089
0090 return boost::core::demangle(s.c_str());
0091 #else
0092 return s;
0093 #endif
0094 }
0095
0096 inline void trim_right_zeroes(std::string& s) {
0097
0098 while (!s.empty()) {
0099 const std::size_t last = static_cast<std::size_t>(s.size() - 1);
0100 if (s[last] != '\0') {
0101 break;
0102 }
0103 s.resize(last);
0104 }
0105 }
0106
0107 class debugging_symbols: boost::noncopyable {
0108 static void try_init_com(com_holder< ::IDebugSymbols>& idebug) noexcept {
0109 com_holder< ::IDebugClient> iclient;
0110 if (S_OK != ::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr())) {
0111 return;
0112 }
0113
0114 com_holder< ::IDebugControl> icontrol;
0115 const bool res0 = (S_OK == iclient->QueryInterface(
0116 __uuidof(IDebugControl),
0117 icontrol.to_void_ptr_ptr()
0118 ));
0119 if (!res0) {
0120 return;
0121 }
0122
0123 const bool res1 = (S_OK == iclient->AttachProcess(
0124 0,
0125 ::GetCurrentProcessId(),
0126 DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND
0127 ));
0128 if (!res1) {
0129 return;
0130 }
0131
0132 if (S_OK != icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)) {
0133 return;
0134 }
0135
0136
0137 iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr());
0138 }
0139
0140 #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
0141
0142 com_holder< ::IDebugSymbols> idebug_;
0143 public:
0144 debugging_symbols() noexcept
0145 {
0146 try_init_com(idebug_);
0147 }
0148
0149 #else
0150
0151 #ifdef BOOST_NO_CXX11_THREAD_LOCAL
0152 # error Your compiler does not support C++11 thread_local storage. It`s impossible to build with BOOST_STACKTRACE_USE_WINDBG_CACHED.
0153 #endif
0154
0155 static com_holder< ::IDebugSymbols>& get_thread_local_debug_inst() noexcept {
0156
0157
0158 static thread_local com_holder< ::IDebugSymbols> idebug;
0159
0160 if (!idebug.is_inited()) {
0161 try_init_com(idebug);
0162 }
0163
0164 return idebug;
0165 }
0166
0167 com_holder< ::IDebugSymbols>& idebug_;
0168 public:
0169 debugging_symbols() noexcept
0170 : idebug_( get_thread_local_debug_inst() )
0171 {}
0172
0173 #endif
0174
0175 bool is_inited() const noexcept {
0176 return idebug_.is_inited();
0177 }
0178
0179 std::string get_name_impl(const void* addr, std::string* module_name = 0) const {
0180 std::string result;
0181 if (!is_inited()) {
0182 return result;
0183 }
0184 const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
0185
0186 char name[256];
0187 name[0] = '\0';
0188 ULONG size = 0;
0189 bool res = (S_OK == idebug_->GetNameByOffset(
0190 offset,
0191 name,
0192 sizeof(name),
0193 &size,
0194 0
0195 ));
0196
0197 if (!res && size != 0) {
0198 result.resize(size);
0199 res = (S_OK == idebug_->GetNameByOffset(
0200 offset,
0201 &result[0],
0202 static_cast<ULONG>(result.size()),
0203 &size,
0204 0
0205 ));
0206
0207
0208
0209 result.resize(size - 1);
0210 } else if (res) {
0211 result.assign(name, size - 1);
0212 }
0213
0214 if (!res) {
0215 result.clear();
0216 return result;
0217 }
0218
0219 const std::size_t delimiter = result.find_first_of('!');
0220 if (module_name) {
0221 *module_name = result.substr(0, delimiter);
0222 }
0223
0224 if (delimiter == std::string::npos) {
0225
0226 result.clear();
0227 return result;
0228 }
0229
0230 result = mingw_demangling_workaround(
0231 result.substr(delimiter + 1)
0232 );
0233
0234 return result;
0235 }
0236
0237 std::size_t get_line_impl(const void* addr) const noexcept {
0238 ULONG result = 0;
0239 if (!is_inited()) {
0240 return result;
0241 }
0242
0243 const bool is_ok = (S_OK == idebug_->GetLineByOffset(
0244 reinterpret_cast<ULONG64>(addr),
0245 &result,
0246 0,
0247 0,
0248 0,
0249 0
0250 ));
0251
0252 return (is_ok ? result : 0);
0253 }
0254
0255 std::pair<std::string, std::size_t> get_source_file_line_impl(const void* addr) const {
0256 std::pair<std::string, std::size_t> result;
0257 if (!is_inited()) {
0258 return result;
0259 }
0260 const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
0261
0262 char name[256];
0263 name[0] = 0;
0264 ULONG size = 0;
0265 ULONG line_num = 0;
0266 bool res = (S_OK == idebug_->GetLineByOffset(
0267 offset,
0268 &line_num,
0269 name,
0270 sizeof(name),
0271 &size,
0272 0
0273 ));
0274
0275 if (res) {
0276 result.first = name;
0277 result.second = line_num;
0278 return result;
0279 }
0280
0281 if (!res && size == 0) {
0282 return result;
0283 }
0284
0285 result.first.resize(size);
0286 res = (S_OK == idebug_->GetLineByOffset(
0287 offset,
0288 &line_num,
0289 &result.first[0],
0290 static_cast<ULONG>(result.first.size()),
0291 &size,
0292 0
0293 ));
0294 trim_right_zeroes(result.first);
0295 result.second = line_num;
0296
0297 if (!res) {
0298 result.first.clear();
0299 result.second = 0;
0300 }
0301
0302 return result;
0303 }
0304
0305 void to_string_impl(const void* addr, std::string& res) const {
0306 if (!is_inited()) {
0307 return;
0308 }
0309
0310 std::string module_name;
0311 std::string name = this->get_name_impl(addr, &module_name);
0312 if (!name.empty()) {
0313 res += name;
0314 } else {
0315 res += to_hex_array(addr).data();
0316 }
0317
0318 std::pair<std::string, std::size_t> source_line = this->get_source_file_line_impl(addr);
0319 if (!source_line.first.empty() && source_line.second) {
0320 res += " at ";
0321 res += source_line.first;
0322 res += ':';
0323 res += boost::stacktrace::detail::to_dec_array(source_line.second).data();
0324 } else if (!module_name.empty()) {
0325 res += " in ";
0326 res += module_name;
0327 }
0328 }
0329 };
0330
0331 std::string to_string(const frame* frames, std::size_t size) {
0332 boost::stacktrace::detail::debugging_symbols idebug;
0333 if (!idebug.is_inited()) {
0334 return std::string();
0335 }
0336
0337 std::string res;
0338 res.reserve(64 * size);
0339 for (std::size_t i = 0; i < size; ++i) {
0340 if (i < 10) {
0341 res += ' ';
0342 }
0343 res += boost::stacktrace::detail::to_dec_array(i).data();
0344 res += '#';
0345 res += ' ';
0346 idebug.to_string_impl(frames[i].address(), res);
0347 res += '\n';
0348 }
0349
0350 return res;
0351 }
0352
0353 }
0354
0355 std::string frame::name() const {
0356 boost::stacktrace::detail::debugging_symbols idebug;
0357 return idebug.get_name_impl(addr_);
0358 }
0359
0360
0361 std::string frame::source_file() const {
0362 boost::stacktrace::detail::debugging_symbols idebug;
0363 return idebug.get_source_file_line_impl(addr_).first;
0364 }
0365
0366 std::size_t frame::source_line() const {
0367 boost::stacktrace::detail::debugging_symbols idebug;
0368 return idebug.get_line_impl(addr_);
0369 }
0370
0371 std::string to_string(const frame& f) {
0372 std::string res;
0373
0374 boost::stacktrace::detail::debugging_symbols idebug;
0375 idebug.to_string_impl(f.address(), res);
0376 return res;
0377 }
0378
0379 }}
0380
0381 #endif