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