Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:52:30

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