github.com/searKing/golang/go@v1.2.117/os/signal/cgo/include/boost/stacktrace/detail/addr2line_impls.hpp (about) 1 // Copyright Antony Polukhin, 2016-2023. 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/addr_base.hpp> 16 #include <boost/stacktrace/detail/to_hex_array.hpp> 17 #include <boost/stacktrace/detail/to_dec_array.hpp> 18 #include <boost/stacktrace/detail/try_dec_convert.hpp> 19 #include <boost/core/demangle.hpp> 20 #include <cstdio> 21 22 #include <sys/types.h> 23 #include <sys/wait.h> 24 #include <signal.h> 25 26 27 namespace boost { namespace stacktrace { namespace detail { 28 29 30 #if defined(BOOST_STACKTRACE_ADDR2LINE_LOCATION) && !defined(BOOST_NO_CXX11_CONSTEXPR) 31 32 constexpr bool is_abs_path(const char* path) noexcept { 33 return *path != '\0' && ( 34 *path == ':' || *path == '/' || is_abs_path(path + 1) 35 ); 36 } 37 38 #endif 39 40 class addr2line_pipe { 41 ::FILE* p; 42 ::pid_t pid; 43 44 public: 45 explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) noexcept 46 : p(0) 47 , pid(0) 48 { 49 int pdes[2]; 50 #ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION 51 char prog_name[] = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION ); 52 #if !defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CXX11_STATIC_ASSERT) 53 static_assert( 54 boost::stacktrace::detail::is_abs_path( BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION ) ), 55 "BOOST_STACKTRACE_ADDR2LINE_LOCATION must be an absolute path" 56 ); 57 #endif 58 59 #else 60 char prog_name[] = "/usr/bin/addr2line"; 61 #endif 62 63 char* argp[] = { 64 prog_name, 65 const_cast<char*>(flag), 66 const_cast<char*>(exec_path), 67 const_cast<char*>(addr), 68 0 69 }; 70 71 if (::pipe(pdes) < 0) { 72 return; 73 } 74 75 pid = ::fork(); 76 switch (pid) { 77 case -1: 78 // Failed... 79 ::close(pdes[0]); 80 ::close(pdes[1]); 81 return; 82 83 case 0: 84 // We are the child. 85 ::close(STDERR_FILENO); 86 ::close(pdes[0]); 87 if (pdes[1] != STDOUT_FILENO) { 88 ::dup2(pdes[1], STDOUT_FILENO); 89 } 90 91 // Do not use `execlp()`, `execvp()`, and `execvpe()` here! 92 // `exec*p*` functions are vulnerable to PATH variable evaluation attacks. 93 ::execv(prog_name, argp); 94 ::_exit(127); 95 } 96 97 p = ::fdopen(pdes[0], "r"); 98 ::close(pdes[1]); 99 } 100 101 operator ::FILE*() const noexcept { 102 return p; 103 } 104 105 ~addr2line_pipe() noexcept { 106 if (p) { 107 ::fclose(p); 108 int pstat = 0; 109 ::kill(pid, SIGKILL); 110 ::waitpid(pid, &pstat, 0); 111 } 112 } 113 }; 114 115 inline std::string addr2line(const char* flag, const void* addr) { 116 std::string res; 117 118 boost::stacktrace::detail::location_from_symbol loc(addr); 119 if (!loc.empty()) { 120 res = loc.name(); 121 } else { 122 res.resize(16); 123 int rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1); 124 while (rlin_size == static_cast<int>(res.size() - 1)) { 125 res.resize(res.size() * 4); 126 rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1); 127 } 128 if (rlin_size == -1) { 129 res.clear(); 130 return res; 131 } 132 res.resize(rlin_size); 133 } 134 135 addr2line_pipe p(flag, res.c_str(), to_hex_array(addr).data()); 136 res.clear(); 137 138 if (!p) { 139 return res; 140 } 141 142 char data[32]; 143 while (!::feof(p)) { 144 if (::fgets(data, sizeof(data), p)) { 145 res += data; 146 } else { 147 break; 148 } 149 } 150 151 // Trimming 152 while (!res.empty() && (res[res.size() - 1] == '\n' || res[res.size() - 1] == '\r')) { 153 res.erase(res.size() - 1); 154 } 155 156 return res; 157 } 158 159 inline std::string source_location(const void* addr, bool position_independent) { 160 uintptr_t addr_base = 0; 161 if (position_independent) { 162 addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr); 163 } 164 const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base); 165 std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", reinterpret_cast<const void*>(offset)); 166 if (source_line.empty() || source_line[0] == '?') { 167 return ""; 168 } 169 170 return source_line; 171 } 172 173 struct to_string_using_addr2line { 174 std::string res; 175 void prepare_function_name(const void* addr) { 176 res = boost::stacktrace::frame(addr).name(); 177 } 178 179 bool prepare_source_location(const void* addr) { 180 // general idea in all addr2line uses: 181 // in each case: 182 // - try to resolve whole address as if it was a non-pie binary 183 // - if that didn't work, try to resolve just an offset from binary base address 184 // this is needed because: 185 // - in pie binaries just passing an address to addr2line won't work (it needs an offset in this case) 186 // - in non-pie binaries whole address is needed (offset won't work) 187 // - there is no easy way to test if binary is position independent (that I know of) 188 std::string source_line = boost::stacktrace::detail::source_location(addr, false); 189 if(source_line.empty()) { 190 source_line = boost::stacktrace::detail::source_location(addr, true); 191 } 192 193 if (!source_line.empty()) { 194 res += " at "; 195 res += source_line; 196 return true; 197 } 198 199 return false; 200 } 201 }; 202 203 template <class Base> class to_string_impl_base; 204 typedef to_string_impl_base<to_string_using_addr2line> to_string_impl; 205 206 inline std::string name(const void* addr, bool position_independent) { 207 uintptr_t addr_base = 0; 208 if(position_independent){ 209 addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr); 210 } 211 const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base); 212 std::string res = boost::stacktrace::detail::addr2line("-fe", offset); 213 res = res.substr(0, res.find_last_of('\n')); 214 res = boost::core::demangle(res.c_str()); 215 216 if (res == "??") { 217 res.clear(); 218 } 219 220 return res; 221 } 222 223 inline std::string name_impl(const void* addr) { 224 std::string res = boost::stacktrace::detail::name(addr, false); 225 if (res.empty()) { 226 res = boost::stacktrace::detail::name(addr, true); 227 } 228 229 return res; 230 } 231 232 inline std::string source_file(const void* addr, bool position_independent) { 233 std::string res; 234 uintptr_t addr_base = 0; 235 if(position_independent){ 236 addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr); 237 } 238 const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base); 239 res = boost::stacktrace::detail::addr2line("-e", offset); 240 res = res.substr(0, res.find_last_of(':')); 241 if (res == "??") { 242 res.clear(); 243 } 244 245 return res; 246 } 247 248 inline std::size_t source_line(const void* addr, bool position_independent) { 249 std::size_t line_num = 0; 250 uintptr_t addr_base = 0; 251 if(position_independent){ 252 addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr); 253 } 254 const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base); 255 std::string res = boost::stacktrace::detail::addr2line("-e", offset); 256 const std::size_t last = res.find_last_of(':'); 257 if (last == std::string::npos) { 258 return 0; 259 } 260 res = res.substr(last + 1); 261 262 if (!boost::stacktrace::detail::try_dec_convert(res.c_str(), line_num)) { 263 return 0; 264 } 265 266 return line_num; 267 } 268 269 } // namespace detail 270 271 272 std::string frame::source_file() const { 273 std::string res = boost::stacktrace::detail::source_file(addr_, false); 274 if (res.empty()) { 275 res = boost::stacktrace::detail::source_file(addr_, true); 276 } 277 278 return res; 279 } 280 281 std::size_t frame::source_line() const { 282 std::size_t line_num = boost::stacktrace::detail::source_line(addr_, false); 283 if (line_num == 0) { 284 line_num = boost::stacktrace::detail::source_line(addr_, true); 285 } 286 287 return line_num; 288 } 289 290 291 }} // namespace boost::stacktrace 292 293 #endif // BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP