github.com/searKing/golang/go@v1.2.117/runtime/cgosymbolizer/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 // MSVC-9 does not have back() and pop_back() functions in std::string 119 while (!s.empty()) { 120 const std::size_t last = static_cast<std::size_t>(s.size() - 1); 121 if (s[last] != '\0') { 122 break; 123 } 124 s.resize(last); 125 } 126 } 127 128 class debugging_symbols: boost::noncopyable { 129 static void try_init_com(com_holder< ::IDebugSymbols>& idebug, const com_global_initer& com) BOOST_NOEXCEPT { 130 com_holder< ::IDebugClient> iclient(com); 131 if (S_OK != ::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr())) { 132 return; 133 } 134 135 com_holder< ::IDebugControl> icontrol(com); 136 const bool res0 = (S_OK == iclient->QueryInterface( 137 __uuidof(IDebugControl), 138 icontrol.to_void_ptr_ptr() 139 )); 140 if (!res0) { 141 return; 142 } 143 144 const bool res1 = (S_OK == iclient->AttachProcess( 145 0, 146 ::GetCurrentProcessId(), 147 DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND 148 )); 149 if (!res1) { 150 return; 151 } 152 153 if (S_OK != icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)) { 154 return; 155 } 156 157 // No cheking: QueryInterface sets the output parameter to NULL in case of error. 158 iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr()); 159 } 160 161 #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED 162 163 boost::stacktrace::detail::com_global_initer com_; 164 com_holder< ::IDebugSymbols> idebug_; 165 public: 166 debugging_symbols() BOOST_NOEXCEPT 167 : com_() 168 , idebug_(com_) 169 { 170 try_init_com(idebug_, com_); 171 } 172 173 #else 174 175 #ifdef BOOST_NO_CXX11_THREAD_LOCAL 176 # error Your compiler does not support C++11 thread_local storage. It`s impossible to build with BOOST_STACKTRACE_USE_WINDBG_CACHED. 177 #endif 178 179 static com_holder< ::IDebugSymbols>& get_thread_local_debug_inst() BOOST_NOEXCEPT { 180 // [class.mfct]: A static local variable or local type in a member function always refers to the same entity, whether 181 // or not the member function is inline. 182 static thread_local boost::stacktrace::detail::com_global_initer com; 183 static thread_local com_holder< ::IDebugSymbols> idebug(com); 184 185 if (!idebug.is_inited()) { 186 try_init_com(idebug, com); 187 } 188 189 return idebug; 190 } 191 192 com_holder< ::IDebugSymbols>& idebug_; 193 public: 194 debugging_symbols() BOOST_NOEXCEPT 195 : idebug_( get_thread_local_debug_inst() ) 196 {} 197 198 #endif // #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED 199 200 bool is_inited() const BOOST_NOEXCEPT { 201 return idebug_.is_inited(); 202 } 203 204 std::string get_name_impl(const void* addr, std::string* module_name = 0) const { 205 std::string result; 206 if (!is_inited()) { 207 return result; 208 } 209 const ULONG64 offset = reinterpret_cast<ULONG64>(addr); 210 211 char name[256]; 212 name[0] = '\0'; 213 ULONG size = 0; 214 bool res = (S_OK == idebug_->GetNameByOffset( 215 offset, 216 name, 217 sizeof(name), 218 &size, 219 0 220 )); 221 222 if (!res && size != 0) { 223 result.resize(size); 224 res = (S_OK == idebug_->GetNameByOffset( 225 offset, 226 &result[0], 227 static_cast<ULONG>(result.size()), 228 &size, 229 0 230 )); 231 trim_right_zeroes(result); 232 } else if (res) { 233 result = name; 234 } 235 236 if (!res) { 237 result.clear(); 238 return result; 239 } 240 241 const std::size_t delimiter = result.find_first_of('!'); 242 if (module_name) { 243 *module_name = result.substr(0, delimiter); 244 } 245 246 if (delimiter == std::string::npos) { 247 // If 'delimiter' is equal to 'std::string::npos' then we have only module name. 248 result.clear(); 249 return result; 250 } 251 252 result = mingw_demangling_workaround( 253 result.substr(delimiter + 1) 254 ); 255 256 return result; 257 } 258 259 std::size_t get_line_impl(const void* addr) const BOOST_NOEXCEPT { 260 ULONG result = 0; 261 if (!is_inited()) { 262 return result; 263 } 264 265 const bool is_ok = (S_OK == idebug_->GetLineByOffset( 266 reinterpret_cast<ULONG64>(addr), 267 &result, 268 0, 269 0, 270 0, 271 0 272 )); 273 274 return (is_ok ? result : 0); 275 } 276 277 std::pair<std::string, std::size_t> get_source_file_line_impl(const void* addr) const { 278 std::pair<std::string, std::size_t> result; 279 if (!is_inited()) { 280 return result; 281 } 282 const ULONG64 offset = reinterpret_cast<ULONG64>(addr); 283 284 char name[256]; 285 name[0] = 0; 286 ULONG size = 0; 287 ULONG line_num = 0; 288 bool res = (S_OK == idebug_->GetLineByOffset( 289 offset, 290 &line_num, 291 name, 292 sizeof(name), 293 &size, 294 0 295 )); 296 297 if (res) { 298 result.first = name; 299 result.second = line_num; 300 return result; 301 } 302 303 if (!res && size == 0) { 304 return result; 305 } 306 307 result.first.resize(size); 308 res = (S_OK == idebug_->GetLineByOffset( 309 offset, 310 &line_num, 311 &result.first[0], 312 static_cast<ULONG>(result.first.size()), 313 &size, 314 0 315 )); 316 trim_right_zeroes(result.first); 317 result.second = line_num; 318 319 if (!res) { 320 result.first.clear(); 321 result.second = 0; 322 } 323 324 return result; 325 } 326 327 void to_string_impl(const void* addr, std::string& res) const { 328 if (!is_inited()) { 329 return; 330 } 331 332 std::string module_name; 333 std::string name = this->get_name_impl(addr, &module_name); 334 if (!name.empty()) { 335 res += name; 336 } else { 337 res += to_hex_array(addr).data(); 338 } 339 340 std::pair<std::string, std::size_t> source_line = this->get_source_file_line_impl(addr); 341 if (!source_line.first.empty() && source_line.second) { 342 res += " at "; 343 res += source_line.first; 344 res += ':'; 345 res += boost::stacktrace::detail::to_dec_array(source_line.second).data(); 346 } else if (!module_name.empty()) { 347 res += " in "; 348 res += module_name; 349 } 350 } 351 }; 352 353 std::string to_string(const frame* frames, std::size_t size) { 354 boost::stacktrace::detail::debugging_symbols idebug; 355 if (!idebug.is_inited()) { 356 return std::string(); 357 } 358 359 std::string res; 360 res.reserve(64 * size); 361 for (std::size_t i = 0; i < size; ++i) { 362 if (i < 10) { 363 res += ' '; 364 } 365 res += boost::stacktrace::detail::to_dec_array(i).data(); 366 res += '#'; 367 res += ' '; 368 idebug.to_string_impl(frames[i].address(), res); 369 res += '\n'; 370 } 371 372 return res; 373 } 374 375 } // namespace detail 376 377 std::string frame::name() const { 378 boost::stacktrace::detail::debugging_symbols idebug; 379 return idebug.get_name_impl(addr_); 380 } 381 382 383 std::string frame::source_file() const { 384 boost::stacktrace::detail::debugging_symbols idebug; 385 return idebug.get_source_file_line_impl(addr_).first; 386 } 387 388 std::size_t frame::source_line() const { 389 boost::stacktrace::detail::debugging_symbols idebug; 390 return idebug.get_line_impl(addr_); 391 } 392 393 std::string to_string(const frame& f) { 394 std::string res; 395 396 boost::stacktrace::detail::debugging_symbols idebug; 397 idebug.to_string_impl(f.address(), res); 398 return res; 399 } 400 401 }} // namespace boost::stacktrace 402 403 #endif // BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP