]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/stacktrace/detail/addr2line_impls.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / stacktrace / detail / addr2line_impls.hpp
1 // Copyright Antony Polukhin, 2016-2017.
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/to_hex_array.hpp>
16 #include <boost/core/demangle.hpp>
17 #include <boost/lexical_cast.hpp>
18 #include <cstdio>
19
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 #include <signal.h>
23
24
25 namespace boost { namespace stacktrace { namespace detail {
26
27
28 #if defined(BOOST_STACKTRACE_ADDR2LINE_LOCATION) && !defined(BOOST_NO_CXX11_CONSTEXPR)
29
30 constexpr bool is_abs_path(const char* path) BOOST_NOEXCEPT {
31 return *path != '\0' && (
32 *path == ':' || *path == '/' || is_abs_path(path + 1)
33 );
34 }
35
36 #endif
37
38 class addr2line_pipe {
39 ::FILE* p;
40 ::pid_t pid;
41
42 public:
43 explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) BOOST_NOEXCEPT
44 : p(0)
45 , pid(0)
46 {
47 int pdes[2];
48 #ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION
49 char prog_name[] = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION );
50 #if !defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CXX11_STATIC_ASSERT)
51 static_assert(
52 boost::stacktrace::detail::is_abs_path( BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION ) ),
53 "BOOST_STACKTRACE_ADDR2LINE_LOCATION must be an absolute path"
54 );
55 #endif
56
57 #else
58 char prog_name[] = "/usr/bin/addr2line";
59 #endif
60
61 char* argp[] = {
62 prog_name,
63 const_cast<char*>(flag),
64 const_cast<char*>(exec_path),
65 const_cast<char*>(addr),
66 0
67 };
68
69 if (::pipe(pdes) < 0) {
70 return;
71 }
72
73 pid = ::fork();
74 switch (pid) {
75 case -1:
76 // Failed...
77 ::close(pdes[0]);
78 ::close(pdes[1]);
79 return;
80
81 case 0:
82 // We are the child.
83 ::close(STDERR_FILENO);
84 ::close(pdes[0]);
85 if (pdes[1] != STDOUT_FILENO) {
86 ::dup2(pdes[1], STDOUT_FILENO);
87 }
88
89 // Do not use `execlp()`, `execvp()`, and `execvpe()` here!
90 // `exec*p*` functions are vulnerable to PATH variable evaluation attacks.
91 ::execv(prog_name, argp);
92 ::_exit(127);
93 }
94
95 p = ::fdopen(pdes[0], "r");
96 ::close(pdes[1]);
97 }
98
99 operator ::FILE*() const BOOST_NOEXCEPT {
100 return p;
101 }
102
103 ~addr2line_pipe() BOOST_NOEXCEPT {
104 if (p) {
105 ::fclose(p);
106 int pstat = 0;
107 ::kill(pid, SIGKILL);
108 ::waitpid(pid, &pstat, 0);
109 }
110 }
111 };
112
113 inline std::string addr2line(const char* flag, const void* addr) {
114 std::string res;
115
116 boost::stacktrace::detail::location_from_symbol loc(addr);
117 if (!loc.empty()) {
118 res = loc.name();
119 } else {
120 res.resize(16);
121 int rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
122 while (rlin_size == static_cast<int>(res.size() - 1)) {
123 res.resize(res.size() * 4);
124 rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
125 }
126 if (rlin_size == -1) {
127 res.clear();
128 return res;
129 }
130 res.resize(rlin_size);
131 }
132
133 addr2line_pipe p(flag, res.c_str(), to_hex_array(addr).data());
134 res.clear();
135
136 if (!p) {
137 return res;
138 }
139
140 char data[32];
141 while (!::feof(p)) {
142 if (::fgets(data, sizeof(data), p)) {
143 res += data;
144 } else {
145 break;
146 }
147 }
148
149 // Trimming
150 while (!res.empty() && (res[res.size() - 1] == '\n' || res[res.size() - 1] == '\r')) {
151 res.erase(res.size() - 1);
152 }
153
154 return res;
155 }
156
157
158 struct to_string_using_addr2line {
159 std::string res;
160 void prepare_function_name(const void* addr) {
161 res = boost::stacktrace::frame(addr).name();
162 }
163
164 bool prepare_source_location(const void* addr) {
165 //return addr2line("-Cfipe", addr); // Does not seem to work in all cases
166 std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", addr);
167 if (!source_line.empty() && source_line[0] != '?') {
168 res += " at ";
169 res += source_line;
170 return true;
171 }
172
173 return false;
174 }
175 };
176
177 template <class Base> class to_string_impl_base;
178 typedef to_string_impl_base<to_string_using_addr2line> to_string_impl;
179
180 inline std::string name_impl(const void* addr) {
181 std::string res = boost::stacktrace::detail::addr2line("-fe", addr);
182 res = res.substr(0, res.find_last_of('\n'));
183 res = boost::core::demangle(res.c_str());
184
185 if (res == "??") {
186 res.clear();
187 }
188
189 return res;
190 }
191
192 } // namespace detail
193
194 std::string frame::source_file() const {
195 std::string res;
196 res = boost::stacktrace::detail::addr2line("-e", addr_);
197 res = res.substr(0, res.find_last_of(':'));
198 if (res == "??") {
199 res.clear();
200 }
201
202 return res;
203 }
204
205
206 std::size_t frame::source_line() const {
207 std::size_t line_num = 0;
208 std::string res = boost::stacktrace::detail::addr2line("-e", addr_);
209 const std::size_t last = res.find_last_of(':');
210 if (last == std::string::npos) {
211 return 0;
212 }
213 res = res.substr(last + 1);
214
215 if (!boost::conversion::try_lexical_convert(res, line_num)) {
216 return 0;
217 }
218
219 return line_num;
220 }
221
222
223 }} // namespace boost::stacktrace
224
225 #endif // BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP