github.com/searKing/golang/go@v1.2.117/os/signal/cgo/include/boost/stacktrace/detail/frame_msvc.ipp (about) 1 // Copyright Antony Polukhin, 2016-2023. 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See 4 // accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 #ifndef BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP 8 #define BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP 9 10 #include <boost/config.hpp> 11 #ifdef BOOST_HAS_PRAGMA_ONCE 12 # pragma once 13 #endif 14 15 #include <boost/stacktrace/frame.hpp> 16 17 #include <boost/core/demangle.hpp> 18 #include <boost/core/noncopyable.hpp> 19 #include <boost/stacktrace/detail/to_dec_array.hpp> 20 #include <boost/stacktrace/detail/to_hex_array.hpp> 21 #include <windows.h> 22 #include "dbgeng.h" 23 24 #ifdef BOOST_MSVC 25 # pragma comment(lib, "ole32.lib") 26 # pragma comment(lib, "Dbgeng.lib") 27 #endif 28 29 30 #ifdef __CRT_UUID_DECL // for __MINGW32__ 31 #if !defined(__MINGW32__) || \ 32 (!defined(__clang__) && __GNUC__ < 12) || \ 33 (defined(__clang__) && __clang_major__ < 16) 34 __CRT_UUID_DECL(IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8) 35 __CRT_UUID_DECL(IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba) 36 __CRT_UUID_DECL(IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50) 37 #endif 38 #elif defined(DEFINE_GUID) && !defined(BOOST_MSVC) 39 DEFINE_GUID(IID_IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8); 40 DEFINE_GUID(IID_IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba); 41 DEFINE_GUID(IID_IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50); 42 #endif 43 44 45 46 // Testing. Remove later 47 //# define __uuidof(x) ::IID_ ## x 48 49 namespace boost { namespace stacktrace { namespace detail { 50 51 template <class T> 52 class com_holder: boost::noncopyable { 53 T* holder_; 54 55 public: 56 com_holder() noexcept 57 : holder_(0) 58 {} 59 60 T* operator->() const noexcept { 61 return holder_; 62 } 63 64 void** to_void_ptr_ptr() noexcept { 65 return reinterpret_cast<void**>(&holder_); 66 } 67 68 bool is_inited() const noexcept { 69 return !!holder_; 70 } 71 72 ~com_holder() noexcept { 73 if (holder_) { 74 holder_->Release(); 75 } 76 } 77 }; 78 79 80 inline std::string mingw_demangling_workaround(const std::string& s) { 81 #ifdef BOOST_GCC 82 if (s.empty()) { 83 return s; 84 } 85 86 if (s[0] != '_') { 87 return boost::core::demangle(('_' + s).c_str()); 88 } 89 90 return boost::core::demangle(s.c_str()); 91 #else 92 return s; 93 #endif 94 } 95 96 inline void trim_right_zeroes(std::string& s) { 97 // MSVC-9 does not have back() and pop_back() functions in std::string 98 while (!s.empty()) { 99 const std::size_t last = static_cast<std::size_t>(s.size() - 1); 100 if (s[last] != '\0') { 101 break; 102 } 103 s.resize(last); 104 } 105 } 106 107 class debugging_symbols: boost::noncopyable { 108 static void try_init_com(com_holder< ::IDebugSymbols>& idebug) noexcept { 109 com_holder< ::IDebugClient> iclient; 110 if (S_OK != ::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr())) { 111 return; 112 } 113 114 com_holder< ::IDebugControl> icontrol; 115 const bool res0 = (S_OK == iclient->QueryInterface( 116 __uuidof(IDebugControl), 117 icontrol.to_void_ptr_ptr() 118 )); 119 if (!res0) { 120 return; 121 } 122 123 const bool res1 = (S_OK == iclient->AttachProcess( 124 0, 125 ::GetCurrentProcessId(), 126 DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND 127 )); 128 if (!res1) { 129 return; 130 } 131 132 if (S_OK != icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)) { 133 return; 134 } 135 136 // No checking: QueryInterface sets the output parameter to NULL in case of error. 137 iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr()); 138 } 139 140 #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED 141 142 com_holder< ::IDebugSymbols> idebug_; 143 public: 144 debugging_symbols() noexcept 145 { 146 try_init_com(idebug_); 147 } 148 149 #else 150 151 #ifdef BOOST_NO_CXX11_THREAD_LOCAL 152 # error Your compiler does not support C++11 thread_local storage. It`s impossible to build with BOOST_STACKTRACE_USE_WINDBG_CACHED. 153 #endif 154 155 static com_holder< ::IDebugSymbols>& get_thread_local_debug_inst() noexcept { 156 // [class.mfct]: A static local variable or local type in a member function always refers to the same entity, whether 157 // or not the member function is inline. 158 static thread_local com_holder< ::IDebugSymbols> idebug; 159 160 if (!idebug.is_inited()) { 161 try_init_com(idebug); 162 } 163 164 return idebug; 165 } 166 167 com_holder< ::IDebugSymbols>& idebug_; 168 public: 169 debugging_symbols() noexcept 170 : idebug_( get_thread_local_debug_inst() ) 171 {} 172 173 #endif // #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED 174 175 bool is_inited() const noexcept { 176 return idebug_.is_inited(); 177 } 178 179 std::string get_name_impl(const void* addr, std::string* module_name = 0) const { 180 std::string result; 181 if (!is_inited()) { 182 return result; 183 } 184 const ULONG64 offset = reinterpret_cast<ULONG64>(addr); 185 186 char name[256]; 187 name[0] = '\0'; 188 ULONG size = 0; 189 bool res = (S_OK == idebug_->GetNameByOffset( 190 offset, 191 name, 192 sizeof(name), 193 &size, 194 0 195 )); 196 197 if (!res && size != 0) { 198 result.resize(size); 199 res = (S_OK == idebug_->GetNameByOffset( 200 offset, 201 &result[0], 202 static_cast<ULONG>(result.size()), 203 &size, 204 0 205 )); 206 207 // According to https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/dbgeng/nf-dbgeng-idebugsymbols-getnamebyoffset 208 // "This size includes the space for the '\0' terminating character." 209 result.resize(size - 1); 210 } else if (res) { 211 result.assign(name, size - 1); 212 } 213 214 if (!res) { 215 result.clear(); 216 return result; 217 } 218 219 const std::size_t delimiter = result.find_first_of('!'); 220 if (module_name) { 221 *module_name = result.substr(0, delimiter); 222 } 223 224 if (delimiter == std::string::npos) { 225 // If 'delimiter' is equal to 'std::string::npos' then we have only module name. 226 result.clear(); 227 return result; 228 } 229 230 result = mingw_demangling_workaround( 231 result.substr(delimiter + 1) 232 ); 233 234 return result; 235 } 236 237 std::size_t get_line_impl(const void* addr) const noexcept { 238 ULONG result = 0; 239 if (!is_inited()) { 240 return result; 241 } 242 243 const bool is_ok = (S_OK == idebug_->GetLineByOffset( 244 reinterpret_cast<ULONG64>(addr), 245 &result, 246 0, 247 0, 248 0, 249 0 250 )); 251 252 return (is_ok ? result : 0); 253 } 254 255 std::pair<std::string, std::size_t> get_source_file_line_impl(const void* addr) const { 256 std::pair<std::string, std::size_t> result; 257 if (!is_inited()) { 258 return result; 259 } 260 const ULONG64 offset = reinterpret_cast<ULONG64>(addr); 261 262 char name[256]; 263 name[0] = 0; 264 ULONG size = 0; 265 ULONG line_num = 0; 266 bool res = (S_OK == idebug_->GetLineByOffset( 267 offset, 268 &line_num, 269 name, 270 sizeof(name), 271 &size, 272 0 273 )); 274 275 if (res) { 276 result.first = name; 277 result.second = line_num; 278 return result; 279 } 280 281 if (!res && size == 0) { 282 return result; 283 } 284 285 result.first.resize(size); 286 res = (S_OK == idebug_->GetLineByOffset( 287 offset, 288 &line_num, 289 &result.first[0], 290 static_cast<ULONG>(result.first.size()), 291 &size, 292 0 293 )); 294 trim_right_zeroes(result.first); 295 result.second = line_num; 296 297 if (!res) { 298 result.first.clear(); 299 result.second = 0; 300 } 301 302 return result; 303 } 304 305 void to_string_impl(const void* addr, std::string& res) const { 306 if (!is_inited()) { 307 return; 308 } 309 310 std::string module_name; 311 std::string name = this->get_name_impl(addr, &module_name); 312 if (!name.empty()) { 313 res += name; 314 } else { 315 res += to_hex_array(addr).data(); 316 } 317 318 std::pair<std::string, std::size_t> source_line = this->get_source_file_line_impl(addr); 319 if (!source_line.first.empty() && source_line.second) { 320 res += " at "; 321 res += source_line.first; 322 res += ':'; 323 res += boost::stacktrace::detail::to_dec_array(source_line.second).data(); 324 } else if (!module_name.empty()) { 325 res += " in "; 326 res += module_name; 327 } 328 } 329 }; 330 331 std::string to_string(const frame* frames, std::size_t size) { 332 boost::stacktrace::detail::debugging_symbols idebug; 333 if (!idebug.is_inited()) { 334 return std::string(); 335 } 336 337 std::string res; 338 res.reserve(64 * size); 339 for (std::size_t i = 0; i < size; ++i) { 340 if (i < 10) { 341 res += ' '; 342 } 343 res += boost::stacktrace::detail::to_dec_array(i).data(); 344 res += '#'; 345 res += ' '; 346 idebug.to_string_impl(frames[i].address(), res); 347 res += '\n'; 348 } 349 350 return res; 351 } 352 353 } // namespace detail 354 355 std::string frame::name() const { 356 boost::stacktrace::detail::debugging_symbols idebug; 357 return idebug.get_name_impl(addr_); 358 } 359 360 361 std::string frame::source_file() const { 362 boost::stacktrace::detail::debugging_symbols idebug; 363 return idebug.get_source_file_line_impl(addr_).first; 364 } 365 366 std::size_t frame::source_line() const { 367 boost::stacktrace::detail::debugging_symbols idebug; 368 return idebug.get_line_impl(addr_); 369 } 370 371 std::string to_string(const frame& f) { 372 std::string res; 373 374 boost::stacktrace::detail::debugging_symbols idebug; 375 idebug.to_string_impl(f.address(), res); 376 return res; 377 } 378 379 }} // namespace boost::stacktrace 380 381 #endif // BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP