Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 10:09:41

0001 // Copyright Antony Polukhin, 2016-2025.
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See
0004 // accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 #ifndef BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP
0008 #define BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP
0009 
0010 #include <boost/config.hpp>
0011 #ifdef BOOST_HAS_PRAGMA_ONCE
0012 #   pragma once
0013 #endif
0014 
0015 #include <boost/stacktrace/detail/addr_base.hpp>
0016 #include <boost/stacktrace/detail/to_hex_array.hpp>
0017 #include <boost/stacktrace/detail/to_dec_array.hpp>
0018 #include <boost/stacktrace/detail/try_dec_convert.hpp>
0019 #include <boost/core/demangle.hpp>
0020 #include <cstdio>
0021 #include <cstring>
0022 
0023 #include <sys/types.h>
0024 #include <sys/wait.h>
0025 #include <signal.h>
0026 
0027 
0028 namespace boost { namespace stacktrace { namespace detail {
0029 
0030 
0031 #if defined(BOOST_STACKTRACE_ADDR2LINE_LOCATION) && !defined(BOOST_NO_CXX11_CONSTEXPR)
0032 
0033 constexpr bool is_abs_path(const char* path) noexcept {
0034     return *path != '\0' && (
0035         *path == ':' || *path == '/' || is_abs_path(path + 1)
0036     );
0037 }
0038 
0039 #endif
0040 
0041 class addr2line_pipe {
0042     ::FILE* p;
0043     ::pid_t pid;
0044 
0045 public:
0046     explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) noexcept
0047         : p(0)
0048         , pid(0)
0049     {
0050         int pdes[2];
0051         #ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION
0052         char prog_name[] = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION );
0053         #if !defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CXX11_STATIC_ASSERT)
0054         static_assert(
0055             boost::stacktrace::detail::is_abs_path( BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION ) ),
0056             "BOOST_STACKTRACE_ADDR2LINE_LOCATION must be an absolute path"
0057         );
0058         #endif
0059 
0060         #else
0061         char prog_name[] = "/usr/bin/addr2line";
0062         #endif
0063 
0064         char* argp[] = {
0065             prog_name,
0066             const_cast<char*>(flag),
0067             const_cast<char*>(exec_path),
0068             const_cast<char*>(addr),
0069             0
0070         };
0071 
0072         if (::pipe(pdes) < 0) {
0073             return;
0074         }
0075 
0076         pid = ::fork();
0077         switch (pid) {
0078         case -1:
0079             // Failed...
0080             ::close(pdes[0]);
0081             ::close(pdes[1]);
0082             return;
0083 
0084         case 0:
0085             // We are the child.
0086             ::close(STDERR_FILENO);
0087             ::close(pdes[0]);
0088             if (pdes[1] != STDOUT_FILENO) {
0089                 ::dup2(pdes[1], STDOUT_FILENO);
0090             }
0091 
0092             // Do not use `execlp()`, `execvp()`, and `execvpe()` here!
0093             // `exec*p*` functions are vulnerable to PATH variable evaluation attacks.
0094             ::execv(prog_name, argp);
0095             ::_exit(127);
0096         }
0097 
0098         p = ::fdopen(pdes[0], "r");
0099         ::close(pdes[1]);
0100     }
0101 
0102     operator ::FILE*() const noexcept {
0103         return p;
0104     }
0105 
0106     ~addr2line_pipe() noexcept {
0107         if (p) {
0108             ::fclose(p);
0109             int pstat = 0;
0110             ::kill(pid, SIGKILL);
0111             ::waitpid(pid, &pstat, 0);
0112         }
0113     }
0114 };
0115 
0116 inline std::string addr2line(const char* flag, const void* addr) {
0117     std::string res;
0118 
0119     boost::stacktrace::detail::location_from_symbol loc(addr);
0120     // For programs started through $PATH loc.name() is not absolute and
0121     // addr2line will fail.
0122     if (!loc.empty() && std::strchr(loc.name(), '/') != nullptr) {
0123         res = loc.name();
0124     } else {
0125         res.resize(16);
0126         ssize_t rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
0127         while (rlin_size == static_cast<ssize_t>(res.size() - 1)) {
0128             res.resize(res.size() * 4);
0129             rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
0130         }
0131         if (rlin_size == -1) {
0132             res.clear();
0133             return res;
0134         }
0135         res.resize(static_cast<std::size_t>(rlin_size));
0136     }
0137 
0138     addr2line_pipe p(flag, res.c_str(), to_hex_array(addr).data());
0139     res.clear();
0140 
0141     if (!p) {
0142         return res;
0143     }
0144 
0145     char data[32];
0146     while (!::feof(p)) {
0147         if (::fgets(data, sizeof(data), p)) {
0148             res += data;
0149         } else {
0150             break;
0151         }
0152     }
0153 
0154     // Trimming
0155     while (!res.empty() && (res[res.size() - 1] == '\n' || res[res.size() - 1] == '\r')) {
0156         res.erase(res.size() - 1);
0157     }
0158 
0159     return res;
0160 }
0161 
0162 inline std::string source_location(const void* addr, bool position_independent) {
0163     uintptr_t addr_base = 0;
0164     if (position_independent) {
0165         addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
0166     }
0167     const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
0168     std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", reinterpret_cast<const void*>(offset));
0169     if (source_line.empty() || source_line[0] == '?') {
0170         return "";
0171     }
0172 
0173     return source_line;
0174 }
0175 
0176 struct to_string_using_addr2line {
0177     std::string res;
0178     void prepare_function_name(const void* addr) {
0179         res = boost::stacktrace::frame(addr).name();
0180     }
0181 
0182     bool prepare_source_location(const void* addr) {
0183         // general idea in all addr2line uses:
0184         // in each case:
0185         //  - try to resolve whole address as if it was a non-pie binary
0186         //  - if that didn't work, try to resolve just an offset from binary base address
0187         // this is needed because:
0188         //  - in pie binaries just passing an address to addr2line won't work (it needs an offset in this case)
0189         //  - in non-pie binaries whole address is needed (offset won't work)
0190         //  - there is no easy way to test if binary is position independent (that I know of)
0191         std::string source_line = boost::stacktrace::detail::source_location(addr, false);
0192         if(source_line.empty()) {
0193             source_line = boost::stacktrace::detail::source_location(addr, true);
0194         }
0195 
0196         if (!source_line.empty()) {
0197             res += " at ";
0198             res += source_line;
0199             return true;
0200         }
0201 
0202         return false;
0203     }
0204 };
0205 
0206 template <class Base> class to_string_impl_base;
0207 typedef to_string_impl_base<to_string_using_addr2line> to_string_impl;
0208 
0209 inline std::string name(const void* addr, bool position_independent) {
0210     uintptr_t addr_base = 0;
0211     if(position_independent){
0212         addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
0213     }
0214     const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
0215     std::string res = boost::stacktrace::detail::addr2line("-fe", offset);
0216     res = res.substr(0, res.find_last_of('\n'));
0217     res = boost::core::demangle(res.c_str());
0218 
0219     if (res == "??") {
0220         res.clear();
0221     }
0222 
0223     return res;
0224 }
0225 
0226 inline std::string name_impl(const void* addr) {
0227     std::string res = boost::stacktrace::detail::name(addr, false);
0228     if (res.empty()) {
0229         res = boost::stacktrace::detail::name(addr, true);
0230     }
0231 
0232     return res;
0233 }
0234 
0235 inline std::string source_file(const void* addr, bool position_independent) {
0236     std::string res;
0237     uintptr_t addr_base = 0;
0238     if(position_independent){
0239         addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
0240     }
0241     const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
0242     res = boost::stacktrace::detail::addr2line("-e", offset);
0243     res = res.substr(0, res.find_last_of(':'));
0244     if (res == "??") {
0245         res.clear();
0246     }
0247 
0248     return res;
0249 }
0250 
0251 inline std::size_t source_line(const void* addr, bool position_independent) {
0252     std::size_t line_num = 0;
0253     uintptr_t addr_base = 0;
0254     if(position_independent){
0255         addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
0256     }
0257     const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
0258     std::string res = boost::stacktrace::detail::addr2line("-e", offset);
0259     const std::size_t last = res.find_last_of(':');
0260     if (last == std::string::npos) {
0261         return 0;
0262     }
0263     res = res.substr(last + 1);
0264 
0265     if (!boost::stacktrace::detail::try_dec_convert(res.c_str(), line_num)) {
0266         return 0;
0267     }
0268 
0269     return line_num;
0270 }
0271 
0272 } // namespace detail
0273 
0274 
0275 std::string frame::source_file() const {
0276     std::string res = boost::stacktrace::detail::source_file(addr_, false);
0277     if (res.empty()) {
0278         res = boost::stacktrace::detail::source_file(addr_, true);
0279     }
0280 
0281     return res;
0282 }
0283 
0284 std::size_t frame::source_line() const {
0285     std::size_t line_num = boost::stacktrace::detail::source_line(addr_, false);
0286     if (line_num == 0) {
0287         line_num = boost::stacktrace::detail::source_line(addr_, true);
0288     }
0289 
0290     return line_num;
0291 }
0292 
0293 
0294 }} // namespace boost::stacktrace
0295 
0296 #endif // BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP