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