File indexing completed on 2025-12-16 10:09:41
0001
0002
0003
0004
0005
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
0080 ::close(pdes[0]);
0081 ::close(pdes[1]);
0082 return;
0083
0084 case 0:
0085
0086 ::close(STDERR_FILENO);
0087 ::close(pdes[0]);
0088 if (pdes[1] != STDOUT_FILENO) {
0089 ::dup2(pdes[1], STDOUT_FILENO);
0090 }
0091
0092
0093
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
0121
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
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
0184
0185
0186
0187
0188
0189
0190
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 }
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 }}
0295
0296 #endif