]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/stacktrace/detail/frame_msvc.ipp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / stacktrace / detail / frame_msvc.ipp
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_FRAME_MSVC_IPP
8 #define BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP
9
10 #include <boost/config.hpp>
11 #ifdef BOOST_HAS_PRAGMA_ONCE
12 # pragma once
13 #endif
14
15 #include <boost/stacktrace/frame.hpp>
16
17 #include <boost/core/demangle.hpp>
18 #include <boost/core/noncopyable.hpp>
19 #include <boost/lexical_cast.hpp>
20 #include <boost/stacktrace/detail/to_hex_array.hpp>
21 #include <windows.h>
22 #include "dbgeng.h"
23
24 #include <boost/detail/winapi/get_current_process.hpp>
25
26 #ifdef BOOST_MSVC
27 # pragma comment(lib, "ole32.lib")
28 # pragma comment(lib, "Dbgeng.lib")
29 #endif
30
31
32 #ifdef __CRT_UUID_DECL // for __MINGW32__
33 __CRT_UUID_DECL(IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8)
34 __CRT_UUID_DECL(IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba)
35 __CRT_UUID_DECL(IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50)
36 #elif defined(DEFINE_GUID) && !defined(BOOST_MSVC)
37 DEFINE_GUID(IID_IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8);
38 DEFINE_GUID(IID_IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba);
39 DEFINE_GUID(IID_IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50);
40 #endif
41
42
43
44 // Testing. Remove later
45 //# define __uuidof(x) ::IID_ ## x
46
47 namespace boost { namespace stacktrace { namespace detail {
48
49 class com_global_initer: boost::noncopyable {
50 bool ok_;
51
52 public:
53 com_global_initer() BOOST_NOEXCEPT
54 : ok_(false)
55 {
56 // COINIT_MULTITHREADED means that we must serialize access to the objects manually.
57 // This is the fastest way to work. If user calls CoInitializeEx before us - we
58 // can end up with other mode (which is OK for us).
59 //
60 // If we call CoInitializeEx befire user - user may end up with different mode, which is a problem.
61 // So we need to call that initialization function as late as possible.
62 const boost::detail::winapi::DWORD_ res = ::CoInitializeEx(0, COINIT_MULTITHREADED);
63 ok_ = (res == S_OK || res == S_FALSE);
64 }
65
66 ~com_global_initer() BOOST_NOEXCEPT {
67 if (ok_) {
68 ::CoUninitialize();
69 }
70 }
71 };
72
73
74 template <class T>
75 class com_holder: boost::noncopyable {
76 T* holder_;
77
78 public:
79 com_holder(const com_global_initer&) BOOST_NOEXCEPT
80 : holder_(0)
81 {}
82
83 T* operator->() const BOOST_NOEXCEPT {
84 return holder_;
85 }
86
87 void** to_void_ptr_ptr() BOOST_NOEXCEPT {
88 return reinterpret_cast<void**>(&holder_);
89 }
90
91 bool is_inited() const BOOST_NOEXCEPT {
92 return !!holder_;
93 }
94
95 ~com_holder() BOOST_NOEXCEPT {
96 if (holder_) {
97 holder_->Release();
98 }
99 }
100 };
101
102
103 static std::string minwg_demangling_workaround(const std::string& s) {
104 #ifdef BOOST_GCC
105 if (s.empty()) {
106 return s;
107 }
108
109 if (s[0] != '_') {
110 return boost::core::demangle(('_' + s).c_str());
111 }
112
113 return boost::core::demangle(s.c_str());
114 #else
115 return s;
116 #endif
117 }
118
119 class debugging_symbols: boost::noncopyable {
120 static void try_init_com(com_holder< ::IDebugSymbols>& idebug, const com_global_initer& com) BOOST_NOEXCEPT {
121 com_holder< ::IDebugClient> iclient(com);
122 if (S_OK != ::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr())) {
123 return;
124 }
125
126 com_holder< ::IDebugControl> icontrol(com);
127 const bool res0 = (S_OK == iclient->QueryInterface(
128 __uuidof(IDebugControl),
129 icontrol.to_void_ptr_ptr()
130 ));
131 if (!res0) {
132 return;
133 }
134
135 const bool res1 = (S_OK == iclient->AttachProcess(
136 0,
137 ::GetCurrentProcessId(),
138 DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND
139 ));
140 if (!res1) {
141 return;
142 }
143
144 if (S_OK != icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)) {
145 return;
146 }
147
148 // No cheking: QueryInterface sets the output parameter to NULL in case of error.
149 iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr());
150 }
151
152 #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
153
154 boost::stacktrace::detail::com_global_initer com_;
155 com_holder< ::IDebugSymbols> idebug_;
156 public:
157 debugging_symbols() BOOST_NOEXCEPT
158 : com_()
159 , idebug_(com_)
160 {
161 try_init_com(idebug_, com_);
162 }
163
164 #else
165
166 #ifdef BOOST_NO_CXX11_THREAD_LOCAL
167 # error Your compiler does not support C++11 thread_local storage. It`s impossible to build with BOOST_STACKTRACE_USE_WINDBG_CACHED.
168 #endif
169
170 static com_holder< ::IDebugSymbols>& get_thread_local_debug_inst() BOOST_NOEXCEPT {
171 // [class.mfct]: A static local variable or local type in a member function always refers to the same entity, whether
172 // or not the member function is inline.
173 static thread_local boost::stacktrace::detail::com_global_initer com;
174 static thread_local com_holder< ::IDebugSymbols> idebug(com);
175
176 if (!idebug.is_inited()) {
177 try_init_com(idebug, com);
178 }
179
180 return idebug;
181 }
182
183 com_holder< ::IDebugSymbols>& idebug_;
184 public:
185 debugging_symbols() BOOST_NOEXCEPT
186 : idebug_( get_thread_local_debug_inst() )
187 {}
188
189 #endif // #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
190
191 bool is_inited() const BOOST_NOEXCEPT {
192 return idebug_.is_inited();
193 }
194
195 std::string get_name_impl(const void* addr, std::string* module_name = 0) const {
196 std::string result;
197 if (!is_inited()) {
198 return result;
199 }
200 const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
201
202 char name[256];
203 name[0] = '\0';
204 ULONG size = 0;
205 bool res = (S_OK == idebug_->GetNameByOffset(
206 offset,
207 name,
208 sizeof(name),
209 &size,
210 0
211 ));
212
213 if (!res && size != 0) {
214 result.resize(size);
215 res = (S_OK == idebug_->GetNameByOffset(
216 offset,
217 &result[0],
218 static_cast<ULONG>(result.size()),
219 &size,
220 0
221 ));
222 } else if (res) {
223 result = name;
224 }
225
226 if (!res) {
227 result.clear();
228 return result;
229 }
230
231 const std::size_t delimiter = result.find_first_of('!');
232 if (module_name) {
233 *module_name = result.substr(0, delimiter);
234 }
235
236 if (delimiter == std::string::npos) {
237 // If 'delimiter' is equal to 'std::string::npos' then we have only module name.
238 result.clear();
239 return result;
240 }
241
242 result = minwg_demangling_workaround(
243 result.substr(delimiter + 1)
244 );
245
246 return result;
247 }
248
249 std::size_t get_line_impl(const void* addr) const BOOST_NOEXCEPT {
250 ULONG result = 0;
251 if (!is_inited()) {
252 return result;
253 }
254
255 const bool is_ok = (S_OK == idebug_->GetLineByOffset(
256 reinterpret_cast<ULONG64>(addr),
257 &result,
258 0,
259 0,
260 0,
261 0
262 ));
263
264 return (is_ok ? result : 0);
265 }
266
267 std::pair<std::string, std::size_t> get_source_file_line_impl(const void* addr) const {
268 std::pair<std::string, std::size_t> result;
269 if (!is_inited()) {
270 return result;
271 }
272 const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
273
274 char name[256];
275 name[0] = 0;
276 ULONG size = 0;
277 ULONG line_num = 0;
278 bool res = (S_OK == idebug_->GetLineByOffset(
279 offset,
280 &line_num,
281 name,
282 sizeof(name),
283 &size,
284 0
285 ));
286
287 if (res) {
288 result.first = name;
289 result.second = line_num;
290 return result;
291 }
292
293 if (!res && size == 0) {
294 return result;
295 }
296
297 result.first.resize(size);
298 res = (S_OK == idebug_->GetLineByOffset(
299 offset,
300 &line_num,
301 &result.first[0],
302 static_cast<ULONG>(result.first.size()),
303 &size,
304 0
305 ));
306 result.second = line_num;
307
308 if (!res) {
309 result.first.clear();
310 result.second = 0;
311 }
312
313 return result;
314 }
315
316 void to_string_impl(const void* addr, std::string& res) const {
317 if (!is_inited()) {
318 return;
319 }
320
321 std::string module_name;
322 std::string name = this->get_name_impl(addr, &module_name);
323 if (!name.empty()) {
324 res += name;
325 } else {
326 res += to_hex_array(addr).data();
327 }
328
329 std::pair<std::string, std::size_t> source_line = this->get_source_file_line_impl(addr);
330 if (!source_line.first.empty() && source_line.second) {
331 res += " at ";
332 res += source_line.first;
333 res += ':';
334 res += boost::lexical_cast<boost::array<char, 40> >(source_line.second).data();
335 } else if (!module_name.empty()) {
336 res += " in ";
337 res += module_name;
338 }
339 }
340 };
341
342 std::string to_string(const frame* frames, std::size_t size) {
343 boost::stacktrace::detail::debugging_symbols idebug;
344 if (!idebug.is_inited()) {
345 return std::string();
346 }
347
348 std::string res;
349 res.reserve(64 * size);
350 for (std::size_t i = 0; i < size; ++i) {
351 if (i < 10) {
352 res += ' ';
353 }
354 res += boost::lexical_cast<boost::array<char, 40> >(i).data();
355 res += '#';
356 res += ' ';
357 idebug.to_string_impl(frames[i].address(), res);
358 res += '\n';
359 }
360
361 return res;
362 }
363
364 } // namespace detail
365
366 std::string frame::name() const {
367 boost::stacktrace::detail::debugging_symbols idebug;
368 return idebug.get_name_impl(addr_);
369 }
370
371
372 std::string frame::source_file() const {
373 boost::stacktrace::detail::debugging_symbols idebug;
374 return idebug.get_source_file_line_impl(addr_).first;
375 }
376
377 std::size_t frame::source_line() const {
378 boost::stacktrace::detail::debugging_symbols idebug;
379 return idebug.get_line_impl(addr_);
380 }
381
382 std::string to_string(const frame& f) {
383 std::string res;
384
385 boost::stacktrace::detail::debugging_symbols idebug;
386 idebug.to_string_impl(f.address(), res);
387 return res;
388 }
389
390 }} // namespace boost::stacktrace
391
392 #endif // BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP