File indexing completed on 2025-01-18 09:52:30
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
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
0079 ::close(pdes[0]);
0080 ::close(pdes[1]);
0081 return;
0082
0083 case 0:
0084
0085 ::close(STDERR_FILENO);
0086 ::close(pdes[0]);
0087 if (pdes[1] != STDOUT_FILENO) {
0088 ::dup2(pdes[1], STDOUT_FILENO);
0089 }
0090
0091
0092
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
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
0181
0182
0183
0184
0185
0186
0187
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 }
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 }}
0292
0293 #endif