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