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