github.com/searKing/golang/go@v1.2.117/os/signal/cgo/include/boost/stacktrace/detail/addr2line_impls.hpp (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_ADDR2LINE_IMPLS_HPP
     8  #define BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP
     9  
    10  #include <boost/config.hpp>
    11  #ifdef BOOST_HAS_PRAGMA_ONCE
    12  #   pragma once
    13  #endif
    14  
    15  #include <boost/stacktrace/detail/addr_base.hpp>
    16  #include <boost/stacktrace/detail/to_hex_array.hpp>
    17  #include <boost/stacktrace/detail/to_dec_array.hpp>
    18  #include <boost/stacktrace/detail/try_dec_convert.hpp>
    19  #include <boost/core/demangle.hpp>
    20  #include <cstdio>
    21  
    22  #include <sys/types.h>
    23  #include <sys/wait.h>
    24  #include <signal.h>
    25  
    26  
    27  namespace boost { namespace stacktrace { namespace detail {
    28  
    29  
    30  #if defined(BOOST_STACKTRACE_ADDR2LINE_LOCATION) && !defined(BOOST_NO_CXX11_CONSTEXPR)
    31  
    32  constexpr bool is_abs_path(const char* path) noexcept {
    33      return *path != '\0' && (
    34          *path == ':' || *path == '/' || is_abs_path(path + 1)
    35      );
    36  }
    37  
    38  #endif
    39  
    40  class addr2line_pipe {
    41      ::FILE* p;
    42      ::pid_t pid;
    43  
    44  public:
    45      explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) noexcept
    46          : p(0)
    47          , pid(0)
    48      {
    49          int pdes[2];
    50          #ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION
    51          char prog_name[] = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION );
    52          #if !defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CXX11_STATIC_ASSERT)
    53          static_assert(
    54              boost::stacktrace::detail::is_abs_path( BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION ) ),
    55              "BOOST_STACKTRACE_ADDR2LINE_LOCATION must be an absolute path"
    56          );
    57          #endif
    58  
    59          #else
    60          char prog_name[] = "/usr/bin/addr2line";
    61          #endif
    62  
    63          char* argp[] = {
    64              prog_name,
    65              const_cast<char*>(flag),
    66              const_cast<char*>(exec_path),
    67              const_cast<char*>(addr),
    68              0
    69          };
    70  
    71          if (::pipe(pdes) < 0) {
    72              return;
    73          }
    74  
    75          pid = ::fork();
    76          switch (pid) {
    77          case -1:
    78              // Failed...
    79              ::close(pdes[0]);
    80              ::close(pdes[1]);
    81              return;
    82  
    83          case 0:
    84              // We are the child.
    85              ::close(STDERR_FILENO);
    86              ::close(pdes[0]);
    87              if (pdes[1] != STDOUT_FILENO) {
    88                  ::dup2(pdes[1], STDOUT_FILENO);
    89              }
    90  
    91              // Do not use `execlp()`, `execvp()`, and `execvpe()` here!
    92              // `exec*p*` functions are vulnerable to PATH variable evaluation attacks.
    93              ::execv(prog_name, argp);
    94              ::_exit(127);
    95          }
    96  
    97          p = ::fdopen(pdes[0], "r");
    98          ::close(pdes[1]);
    99      }
   100  
   101      operator ::FILE*() const noexcept {
   102          return p;
   103      }
   104  
   105      ~addr2line_pipe() noexcept {
   106          if (p) {
   107              ::fclose(p);
   108              int pstat = 0;
   109              ::kill(pid, SIGKILL);
   110              ::waitpid(pid, &pstat, 0);
   111          }
   112      }
   113  };
   114  
   115  inline std::string addr2line(const char* flag, const void* addr) {
   116      std::string res;
   117  
   118      boost::stacktrace::detail::location_from_symbol loc(addr);
   119      if (!loc.empty()) {
   120          res = loc.name();
   121      } else {
   122          res.resize(16);
   123          int rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
   124          while (rlin_size == static_cast<int>(res.size() - 1)) {
   125              res.resize(res.size() * 4);
   126              rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
   127          }
   128          if (rlin_size == -1) {
   129              res.clear();
   130              return res;
   131          }
   132          res.resize(rlin_size);
   133      }
   134  
   135      addr2line_pipe p(flag, res.c_str(), to_hex_array(addr).data());
   136      res.clear();
   137  
   138      if (!p) {
   139          return res;
   140      }
   141  
   142      char data[32];
   143      while (!::feof(p)) {
   144          if (::fgets(data, sizeof(data), p)) {
   145              res += data;
   146          } else {
   147              break;
   148          }
   149      }
   150  
   151      // Trimming
   152      while (!res.empty() && (res[res.size() - 1] == '\n' || res[res.size() - 1] == '\r')) {
   153          res.erase(res.size() - 1);
   154      }
   155  
   156      return res;
   157  }
   158  
   159  inline std::string source_location(const void* addr, bool position_independent) {
   160      uintptr_t addr_base = 0;
   161      if (position_independent) {
   162          addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
   163      }
   164      const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
   165      std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", reinterpret_cast<const void*>(offset));
   166      if (source_line.empty() || source_line[0] == '?') {
   167          return "";
   168      }
   169  
   170      return source_line;
   171  }
   172  
   173  struct to_string_using_addr2line {
   174      std::string res;
   175      void prepare_function_name(const void* addr) {
   176          res = boost::stacktrace::frame(addr).name();
   177      }
   178  
   179      bool prepare_source_location(const void* addr) {
   180          // general idea in all addr2line uses:
   181          // in each case:
   182          //  - try to resolve whole address as if it was a non-pie binary
   183          //  - if that didn't work, try to resolve just an offset from binary base address
   184          // this is needed because:
   185          //  - in pie binaries just passing an address to addr2line won't work (it needs an offset in this case)
   186          //  - in non-pie binaries whole address is needed (offset won't work)
   187          //  - there is no easy way to test if binary is position independent (that I know of)
   188          std::string source_line = boost::stacktrace::detail::source_location(addr, false);
   189          if(source_line.empty()) {
   190              source_line = boost::stacktrace::detail::source_location(addr, true);
   191          }
   192  
   193          if (!source_line.empty()) {
   194              res += " at ";
   195              res += source_line;
   196              return true;
   197          }
   198  
   199          return false;
   200      }
   201  };
   202  
   203  template <class Base> class to_string_impl_base;
   204  typedef to_string_impl_base<to_string_using_addr2line> to_string_impl;
   205  
   206  inline std::string name(const void* addr, bool position_independent) {
   207      uintptr_t addr_base = 0;
   208      if(position_independent){
   209          addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
   210      }
   211      const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
   212      std::string res = boost::stacktrace::detail::addr2line("-fe", offset);
   213      res = res.substr(0, res.find_last_of('\n'));
   214      res = boost::core::demangle(res.c_str());
   215  
   216      if (res == "??") {
   217          res.clear();
   218      }
   219  
   220      return res;
   221  }
   222  
   223  inline std::string name_impl(const void* addr) {
   224      std::string res = boost::stacktrace::detail::name(addr, false);
   225      if (res.empty()) {
   226          res = boost::stacktrace::detail::name(addr, true);
   227      }
   228  
   229      return res;
   230  }
   231  
   232  inline std::string source_file(const void* addr, bool position_independent) {
   233      std::string res;
   234      uintptr_t addr_base = 0;
   235      if(position_independent){
   236          addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
   237      }
   238      const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
   239      res = boost::stacktrace::detail::addr2line("-e", offset);
   240      res = res.substr(0, res.find_last_of(':'));
   241      if (res == "??") {
   242          res.clear();
   243      }
   244  
   245      return res;
   246  }
   247  
   248  inline std::size_t source_line(const void* addr, bool position_independent) {
   249      std::size_t line_num = 0;
   250      uintptr_t addr_base = 0;
   251      if(position_independent){
   252          addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
   253      }
   254      const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
   255      std::string res = boost::stacktrace::detail::addr2line("-e", offset);
   256      const std::size_t last = res.find_last_of(':');
   257      if (last == std::string::npos) {
   258          return 0;
   259      }
   260      res = res.substr(last + 1);
   261  
   262      if (!boost::stacktrace::detail::try_dec_convert(res.c_str(), line_num)) {
   263          return 0;
   264      }
   265  
   266      return line_num;
   267  }
   268  
   269  } // namespace detail
   270  
   271  
   272  std::string frame::source_file() const {
   273      std::string res = boost::stacktrace::detail::source_file(addr_, false);
   274      if (res.empty()) {
   275          res = boost::stacktrace::detail::source_file(addr_, true);
   276      }
   277  
   278      return res;
   279  }
   280  
   281  std::size_t frame::source_line() const {
   282      std::size_t line_num = boost::stacktrace::detail::source_line(addr_, false);
   283      if (line_num == 0) {
   284          line_num = boost::stacktrace::detail::source_line(addr_, true);
   285      }
   286  
   287      return line_num;
   288  }
   289  
   290  
   291  }} // namespace boost::stacktrace
   292  
   293  #endif // BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP