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