github.com/searKing/golang/go@v1.2.117/runtime/cgosymbolizer/include/boost/stacktrace/detail/addr2line_impls.hpp (about)

     1  // Copyright Antony Polukhin, 2016-2020.
     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/to_hex_array.hpp>
    16  #include <boost/stacktrace/detail/to_dec_array.hpp>
    17  #include <boost/stacktrace/detail/try_dec_convert.hpp>
    18  #include <boost/core/demangle.hpp>
    19  #include <cstdio>
    20  
    21  #include <sys/types.h>
    22  #include <sys/wait.h>
    23  #include <signal.h>
    24  
    25  
    26  namespace boost { namespace stacktrace { namespace detail {
    27  
    28  
    29  #if defined(BOOST_STACKTRACE_ADDR2LINE_LOCATION) && !defined(BOOST_NO_CXX11_CONSTEXPR)
    30  
    31  constexpr bool is_abs_path(const char* path) BOOST_NOEXCEPT {
    32      return *path != '\0' && (
    33          *path == ':' || *path == '/' || is_abs_path(path + 1)
    34      );
    35  }
    36  
    37  #endif
    38  
    39  class addr2line_pipe {
    40      ::FILE* p;
    41      ::pid_t pid;
    42  
    43  public:
    44      explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) BOOST_NOEXCEPT
    45          : p(0)
    46          , pid(0)
    47      {
    48          int pdes[2];
    49          #ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION
    50          char prog_name[] = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION );
    51          #if !defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CXX11_STATIC_ASSERT)
    52          static_assert(
    53              boost::stacktrace::detail::is_abs_path( BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION ) ),
    54              "BOOST_STACKTRACE_ADDR2LINE_LOCATION must be an absolute path"
    55          );
    56          #endif
    57  
    58          #else
    59          char prog_name[] = "/usr/bin/addr2line";
    60          #endif
    61  
    62          char* argp[] = {
    63              prog_name,
    64              const_cast<char*>(flag),
    65              const_cast<char*>(exec_path),
    66              const_cast<char*>(addr),
    67              0
    68          };
    69  
    70          if (::pipe(pdes) < 0) {
    71              return;
    72          }
    73  
    74          pid = ::fork();
    75          switch (pid) {
    76          case -1:
    77              // Failed...
    78              ::close(pdes[0]);
    79              ::close(pdes[1]);
    80              return;
    81  
    82          case 0:
    83              // We are the child.
    84              ::close(STDERR_FILENO);
    85              ::close(pdes[0]);
    86              if (pdes[1] != STDOUT_FILENO) {
    87                  ::dup2(pdes[1], STDOUT_FILENO);
    88              }
    89  
    90              // Do not use `execlp()`, `execvp()`, and `execvpe()` here!
    91              // `exec*p*` functions are vulnerable to PATH variable evaluation attacks.
    92              ::execv(prog_name, argp);
    93              ::_exit(127);
    94          }
    95  
    96          p = ::fdopen(pdes[0], "r");
    97          ::close(pdes[1]);
    98      }
    99  
   100      operator ::FILE*() const BOOST_NOEXCEPT {
   101          return p;
   102      }
   103  
   104      ~addr2line_pipe() BOOST_NOEXCEPT {
   105          if (p) {
   106              ::fclose(p);
   107              int pstat = 0;
   108              ::kill(pid, SIGKILL);
   109              ::waitpid(pid, &pstat, 0);
   110          }
   111      }
   112  };
   113  
   114  inline std::string addr2line(const char* flag, const void* addr) {
   115      std::string res;
   116  
   117      boost::stacktrace::detail::location_from_symbol loc(addr);
   118      if (!loc.empty()) {
   119          res = loc.name();
   120      } else {
   121          res.resize(16);
   122          int rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
   123          while (rlin_size == static_cast<int>(res.size() - 1)) {
   124              res.resize(res.size() * 4);
   125              rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
   126          }
   127          if (rlin_size == -1) {
   128              res.clear();
   129              return res;
   130          }
   131          res.resize(rlin_size);
   132      }
   133  
   134      addr2line_pipe p(flag, res.c_str(), to_hex_array(addr).data());
   135      res.clear();
   136  
   137      if (!p) {
   138          return res;
   139      }
   140  
   141      char data[32];
   142      while (!::feof(p)) {
   143          if (::fgets(data, sizeof(data), p)) {
   144              res += data;
   145          } else {
   146              break;
   147          }
   148      }
   149  
   150      // Trimming
   151      while (!res.empty() && (res[res.size() - 1] == '\n' || res[res.size() - 1] == '\r')) {
   152          res.erase(res.size() - 1);
   153      }
   154  
   155      return res;
   156  }
   157  
   158  
   159  struct to_string_using_addr2line {
   160      std::string res;
   161      void prepare_function_name(const void* addr) {
   162          res = boost::stacktrace::frame(addr).name();
   163      }
   164  
   165      bool prepare_source_location(const void* addr) {
   166          //return addr2line("-Cfipe", addr); // Does not seem to work in all cases
   167          std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", addr);
   168          if (!source_line.empty() && source_line[0] != '?') {
   169              res += " at ";
   170              res += source_line;
   171              return true;
   172          }
   173  
   174          return false;
   175      }
   176  };
   177  
   178  template <class Base> class to_string_impl_base;
   179  typedef to_string_impl_base<to_string_using_addr2line> to_string_impl;
   180  
   181  inline std::string name_impl(const void* addr) {
   182      std::string res = boost::stacktrace::detail::addr2line("-fe", addr);
   183      res = res.substr(0, res.find_last_of('\n'));
   184      res = boost::core::demangle(res.c_str());
   185  
   186      if (res == "??") {
   187          res.clear();
   188      }
   189  
   190      return res;
   191  }
   192  
   193  } // namespace detail
   194  
   195  std::string frame::source_file() const {
   196      std::string res;
   197      res = boost::stacktrace::detail::addr2line("-e", addr_);
   198      res = res.substr(0, res.find_last_of(':'));
   199      if (res == "??") {
   200          res.clear();
   201      }
   202  
   203      return res;
   204  }
   205  
   206  
   207  std::size_t frame::source_line() const {
   208      std::size_t line_num = 0;
   209      std::string res = boost::stacktrace::detail::addr2line("-e", addr_);
   210      const std::size_t last = res.find_last_of(':');
   211      if (last == std::string::npos) {
   212          return 0;
   213      }
   214      res = res.substr(last + 1);
   215  
   216      if (!boost::stacktrace::detail::try_dec_convert(res.c_str(), line_num)) {
   217          return 0;
   218      }
   219  
   220      return line_num;
   221  }
   222  
   223  
   224  }} // namespace boost::stacktrace
   225  
   226  #endif // BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP