summaryrefslogtreecommitdiff
path: root/boost/stacktrace
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2017-09-13 11:24:46 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2017-09-13 11:25:39 +0900
commit4fadd968fa12130524c8380f33fcfe25d4de79e5 (patch)
treefd26a490cd15388d42fc6652b3c5c13012e7f93e /boost/stacktrace
parentb5c87084afaef42b2d058f68091be31988a6a874 (diff)
downloadboost-4fadd968fa12130524c8380f33fcfe25d4de79e5.tar.gz
boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.tar.bz2
boost-4fadd968fa12130524c8380f33fcfe25d4de79e5.zip
Imported Upstream version 1.65.0upstream/1.65.0
Change-Id: Icf8400b375482cb11bcf77440a6934ba360d6ba4 Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'boost/stacktrace')
-rw-r--r--boost/stacktrace/detail/addr2line_impls.hpp225
-rw-r--r--boost/stacktrace/detail/collect_msvc.ipp33
-rw-r--r--boost/stacktrace/detail/collect_noop.ipp25
-rw-r--r--boost/stacktrace/detail/collect_unwind.ipp68
-rw-r--r--boost/stacktrace/detail/frame_decl.hpp159
-rw-r--r--boost/stacktrace/detail/frame_msvc.ipp392
-rw-r--r--boost/stacktrace/detail/frame_noop.ipp44
-rw-r--r--boost/stacktrace/detail/frame_unwind.ipp103
-rw-r--r--boost/stacktrace/detail/libbacktrace_impls.hpp173
-rw-r--r--boost/stacktrace/detail/location_from_symbol.hpp76
-rw-r--r--boost/stacktrace/detail/pop_options.pp12
-rw-r--r--boost/stacktrace/detail/push_options.pp31
-rw-r--r--boost/stacktrace/detail/safe_dump_noop.ipp37
-rw-r--r--boost/stacktrace/detail/safe_dump_posix.ipp58
-rw-r--r--boost/stacktrace/detail/safe_dump_win.ipp60
-rw-r--r--boost/stacktrace/detail/to_hex_array.hpp54
-rw-r--r--boost/stacktrace/detail/unwind_base_impls.hpp50
-rw-r--r--boost/stacktrace/detail/void_ptr_cast.hpp46
-rw-r--r--boost/stacktrace/frame.hpp67
-rw-r--r--boost/stacktrace/safe_dump_to.hpp218
-rw-r--r--boost/stacktrace/stacktrace.hpp414
-rw-r--r--boost/stacktrace/stacktrace_fwd.hpp28
22 files changed, 2373 insertions, 0 deletions
diff --git a/boost/stacktrace/detail/addr2line_impls.hpp b/boost/stacktrace/detail/addr2line_impls.hpp
new file mode 100644
index 0000000000..e314fe9f31
--- /dev/null
+++ b/boost/stacktrace/detail/addr2line_impls.hpp
@@ -0,0 +1,225 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP
+#define BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/detail/to_hex_array.hpp>
+#include <boost/core/demangle.hpp>
+#include <boost/lexical_cast.hpp>
+#include <cstdio>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+
+namespace boost { namespace stacktrace { namespace detail {
+
+
+#if defined(BOOST_STACKTRACE_ADDR2LINE_LOCATION) && !defined(BOOST_NO_CXX11_CONSTEXPR)
+
+constexpr bool is_abs_path(const char* path) BOOST_NOEXCEPT {
+ return *path != '\0' && (
+ *path == ':' || *path == '/' || is_abs_path(path + 1)
+ );
+}
+
+#endif
+
+class addr2line_pipe {
+ ::FILE* p;
+ ::pid_t pid;
+
+public:
+ explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) BOOST_NOEXCEPT
+ : p(0)
+ , pid(0)
+ {
+ int pdes[2];
+ #ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION
+ char prog_name[] = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION );
+ #if !defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CXX11_STATIC_ASSERT)
+ static_assert(
+ boost::stacktrace::detail::is_abs_path( BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION ) ),
+ "BOOST_STACKTRACE_ADDR2LINE_LOCATION must be an absolute path"
+ );
+ #endif
+
+ #else
+ char prog_name[] = "/usr/bin/addr2line";
+ #endif
+
+ char* argp[] = {
+ prog_name,
+ const_cast<char*>(flag),
+ const_cast<char*>(exec_path),
+ const_cast<char*>(addr),
+ 0
+ };
+
+ if (::pipe(pdes) < 0) {
+ return;
+ }
+
+ pid = ::fork();
+ switch (pid) {
+ case -1:
+ // Failed...
+ ::close(pdes[0]);
+ ::close(pdes[1]);
+ return;
+
+ case 0:
+ // We are the child.
+ ::close(STDERR_FILENO);
+ ::close(pdes[0]);
+ if (pdes[1] != STDOUT_FILENO) {
+ ::dup2(pdes[1], STDOUT_FILENO);
+ }
+
+ // Do not use `execlp()`, `execvp()`, and `execvpe()` here!
+ // `exec*p*` functions are vulnerable to PATH variable evaluation attacks.
+ ::execv(prog_name, argp);
+ ::_exit(127);
+ }
+
+ p = ::fdopen(pdes[0], "r");
+ ::close(pdes[1]);
+ }
+
+ operator ::FILE*() const BOOST_NOEXCEPT {
+ return p;
+ }
+
+ ~addr2line_pipe() BOOST_NOEXCEPT {
+ if (p) {
+ ::fclose(p);
+ int pstat = 0;
+ ::kill(pid, SIGKILL);
+ ::waitpid(pid, &pstat, 0);
+ }
+ }
+};
+
+inline std::string addr2line(const char* flag, const void* addr) {
+ std::string res;
+
+ boost::stacktrace::detail::location_from_symbol loc(addr);
+ if (!loc.empty()) {
+ res = loc.name();
+ } else {
+ res.resize(16);
+ int rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
+ while (rlin_size == static_cast<int>(res.size() - 1)) {
+ res.resize(res.size() * 4);
+ rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
+ }
+ if (rlin_size == -1) {
+ res.clear();
+ return res;
+ }
+ res.resize(rlin_size);
+ }
+
+ addr2line_pipe p(flag, res.c_str(), to_hex_array(addr).data());
+ res.clear();
+
+ if (!p) {
+ return res;
+ }
+
+ char data[32];
+ while (!::feof(p)) {
+ if (::fgets(data, sizeof(data), p)) {
+ res += data;
+ } else {
+ break;
+ }
+ }
+
+ // Trimming
+ while (!res.empty() && (res[res.size() - 1] == '\n' || res[res.size() - 1] == '\r')) {
+ res.erase(res.size() - 1);
+ }
+
+ return res;
+}
+
+
+struct to_string_using_addr2line {
+ std::string res;
+ void prepare_function_name(const void* addr) {
+ res = boost::stacktrace::frame(addr).name();
+ }
+
+ bool prepare_source_location(const void* addr) {
+ //return addr2line("-Cfipe", addr); // Does not seem to work in all cases
+ std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", addr);
+ if (!source_line.empty() && source_line[0] != '?') {
+ res += " at ";
+ res += source_line;
+ return true;
+ }
+
+ return false;
+ }
+};
+
+template <class Base> class to_string_impl_base;
+typedef to_string_impl_base<to_string_using_addr2line> to_string_impl;
+
+inline std::string name_impl(const void* addr) {
+ std::string res = boost::stacktrace::detail::addr2line("-fe", addr);
+ res = res.substr(0, res.find_last_of('\n'));
+ res = boost::core::demangle(res.c_str());
+
+ if (res == "??") {
+ res.clear();
+ }
+
+ return res;
+}
+
+} // namespace detail
+
+std::string frame::source_file() const {
+ std::string res;
+ res = boost::stacktrace::detail::addr2line("-e", addr_);
+ res = res.substr(0, res.find_last_of(':'));
+ if (res == "??") {
+ res.clear();
+ }
+
+ return res;
+}
+
+
+std::size_t frame::source_line() const {
+ std::size_t line_num = 0;
+ std::string res = boost::stacktrace::detail::addr2line("-e", addr_);
+ const std::size_t last = res.find_last_of(':');
+ if (last == std::string::npos) {
+ return 0;
+ }
+ res = res.substr(last + 1);
+
+ if (!boost::conversion::try_lexical_convert(res, line_num)) {
+ return 0;
+ }
+
+ return line_num;
+}
+
+
+}} // namespace boost::stacktrace
+
+#endif // BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP
diff --git a/boost/stacktrace/detail/collect_msvc.ipp b/boost/stacktrace/detail/collect_msvc.ipp
new file mode 100644
index 0000000000..d75df558f3
--- /dev/null
+++ b/boost/stacktrace/detail/collect_msvc.ipp
@@ -0,0 +1,33 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_COLLECT_MSVC_IPP
+#define BOOST_STACKTRACE_DETAIL_COLLECT_MSVC_IPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/safe_dump_to.hpp>
+
+#include <boost/detail/winapi/stack_backtrace.hpp>
+
+namespace boost { namespace stacktrace { namespace detail {
+
+std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT {
+ return boost::detail::winapi::RtlCaptureStackBackTrace(
+ static_cast<boost::detail::winapi::ULONG_>(skip),
+ static_cast<boost::detail::winapi::ULONG_>(max_frames_count),
+ const_cast<boost::detail::winapi::PVOID_*>(out_frames),
+ 0
+ );
+}
+
+
+}}} // namespace boost::stacktrace
+
+#endif // BOOST_STACKTRACE_DETAIL_COLLECT_MSVC_IPP
diff --git a/boost/stacktrace/detail/collect_noop.ipp b/boost/stacktrace/detail/collect_noop.ipp
new file mode 100644
index 0000000000..bcfae4c400
--- /dev/null
+++ b/boost/stacktrace/detail/collect_noop.ipp
@@ -0,0 +1,25 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_COLLECT_NOOP_IPP
+#define BOOST_STACKTRACE_DETAIL_COLLECT_NOOP_IPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/safe_dump_to.hpp>
+
+namespace boost { namespace stacktrace { namespace detail {
+
+std::size_t this_thread_frames::collect(native_frame_ptr_t* /*out_frames*/, std::size_t /*max_frames_count*/, std::size_t /*skip*/) BOOST_NOEXCEPT {
+ return 0;
+}
+
+}}} // namespace boost::stacktrace::detail
+
+#endif // BOOST_STACKTRACE_DETAIL_COLLECT_NOOP_IPP
diff --git a/boost/stacktrace/detail/collect_unwind.ipp b/boost/stacktrace/detail/collect_unwind.ipp
new file mode 100644
index 0000000000..3ee4e8f61e
--- /dev/null
+++ b/boost/stacktrace/detail/collect_unwind.ipp
@@ -0,0 +1,68 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_COLLECT_UNWIND_IPP
+#define BOOST_STACKTRACE_DETAIL_COLLECT_UNWIND_IPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/safe_dump_to.hpp>
+
+#include <unwind.h>
+#include <cstdio>
+
+namespace boost { namespace stacktrace { namespace detail {
+
+struct unwind_state {
+ std::size_t frames_to_skip;
+ native_frame_ptr_t* current;
+ native_frame_ptr_t* end;
+};
+
+inline _Unwind_Reason_Code unwind_callback(::_Unwind_Context* context, void* arg) {
+ // Note: do not write `::_Unwind_GetIP` because it is a macro on some platforms.
+ // Use `_Unwind_GetIP` instead!
+ unwind_state* const state = static_cast<unwind_state*>(arg);
+ if (state->frames_to_skip) {
+ --state->frames_to_skip;
+ return _Unwind_GetIP(context) ? ::_URC_NO_REASON : ::_URC_END_OF_STACK;
+ }
+
+ *state->current = reinterpret_cast<native_frame_ptr_t>(
+ _Unwind_GetIP(context)
+ );
+
+ ++state->current;
+ if (!*(state->current - 1) || state->current == state->end) {
+ return ::_URC_END_OF_STACK;
+ }
+ return ::_URC_NO_REASON;
+}
+
+std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT {
+ std::size_t frames_count = 0;
+ if (!max_frames_count) {
+ return frames_count;
+ }
+
+ boost::stacktrace::detail::unwind_state state = { skip + 1, out_frames, out_frames + max_frames_count };
+ ::_Unwind_Backtrace(&boost::stacktrace::detail::unwind_callback, &state);
+ frames_count = state.current - out_frames;
+
+ if (frames_count && out_frames[frames_count - 1] == 0) {
+ -- frames_count;
+ }
+
+ return frames_count;
+}
+
+
+}}} // namespace boost::stacktrace::detail
+
+#endif // BOOST_STACKTRACE_DETAIL_COLLECT_UNWIND_IPP
diff --git a/boost/stacktrace/detail/frame_decl.hpp b/boost/stacktrace/detail/frame_decl.hpp
new file mode 100644
index 0000000000..10b912113f
--- /dev/null
+++ b/boost/stacktrace/detail/frame_decl.hpp
@@ -0,0 +1,159 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_FRAME_DECL_HPP
+#define BOOST_STACKTRACE_DETAIL_FRAME_DECL_HPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iosfwd>
+#include <string>
+
+#include <boost/core/explicit_operator_bool.hpp>
+
+#include <boost/stacktrace/safe_dump_to.hpp> // boost::stacktrace::detail::native_frame_ptr_t
+#include <boost/stacktrace/detail/void_ptr_cast.hpp>
+
+#include <boost/stacktrace/detail/push_options.pp>
+
+/// @file boost/stacktrace/detail/frame_decl.hpp
+/// Use <boost/stacktrace/frame.hpp> header instead of this one!
+
+namespace boost { namespace stacktrace {
+
+/// @class boost::stacktrace::frame boost/stacktrace/detail/frame_decl.hpp <boost/stacktrace/frame.hpp>
+/// @brief Class that stores frame/function address and can get information about it at runtime.
+class frame {
+public:
+ typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
+
+private:
+ /// @cond
+ native_frame_ptr_t addr_;
+ /// @endcond
+
+public:
+ /// @brief Constructs frame that references NULL address.
+ /// Calls to source_file() and source_line() will return empty string.
+ /// Calls to source_line() will return 0.
+ ///
+ /// @b Complexity: O(1).
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ /// @throws Nothing.
+ BOOST_CONSTEXPR frame() BOOST_NOEXCEPT
+ : addr_(0)
+ {}
+
+#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
+ /// @brief Copy constructs frame.
+ ///
+ /// @b Complexity: O(1).
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ /// @throws Nothing.
+ constexpr frame(const frame&) = default;
+
+ /// @brief Copy assigns frame.
+ ///
+ /// @b Complexity: O(1).
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ /// @throws Nothing.
+ constexpr frame& operator=(const frame&) = default;
+#endif
+
+ /// @brief Constructs frame that references addr and could later generate information about that address using platform specific features.
+ ///
+ /// @b Complexity: O(1).
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ /// @throws Nothing.
+ BOOST_CONSTEXPR explicit frame(native_frame_ptr_t addr) BOOST_NOEXCEPT
+ : addr_(addr)
+ {}
+
+ /// @brief Constructs frame that references function_addr and could later generate information about that function using platform specific features.
+ ///
+ /// @b Complexity: O(1).
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ /// @throws Nothing.
+ template <class T>
+ explicit frame(T* function_addr) BOOST_NOEXCEPT
+ : addr_(boost::stacktrace::detail::void_ptr_cast<native_frame_ptr_t>(function_addr))
+ {}
+
+ /// @returns Name of the frame (function name in a human readable form).
+ ///
+ /// @b Complexity: unknown (lots of platform specific work).
+ ///
+ /// @b Async-Handler-Safety: Unsafe.
+ /// @throws std::bad_alloc if not enough memory to construct resulting string.
+ BOOST_STACKTRACE_FUNCTION std::string name() const;
+
+ /// @returns Address of the frame function.
+ ///
+ /// @b Complexity: O(1).
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ /// @throws Nothing.
+ BOOST_CONSTEXPR native_frame_ptr_t address() const BOOST_NOEXCEPT {
+ return addr_;
+ }
+
+ /// @returns Path to the source file, were the function of the frame is defined. Returns empty string
+ /// if this->source_line() == 0.
+ /// @throws std::bad_alloc if not enough memory to construct resulting string.
+ ///
+ /// @b Complexity: unknown (lots of platform specific work).
+ ///
+ /// @b Async-Handler-Safety: Unsafe.
+ BOOST_STACKTRACE_FUNCTION std::string source_file() const;
+
+ /// @returns Code line in the source file, were the function of the frame is defined.
+ /// @throws std::bad_alloc if not enough memory to construct string for internal needs.
+ ///
+ /// @b Complexity: unknown (lots of platform specific work).
+ ///
+ /// @b Async-Handler-Safety: Unsafe.
+ BOOST_STACKTRACE_FUNCTION std::size_t source_line() const;
+
+ /// @brief Checks that frame is not references NULL address.
+ /// @returns `true` if `this->address() != 0`
+ ///
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ BOOST_EXPLICIT_OPERATOR_BOOL()
+
+ /// @brief Checks that frame references NULL address.
+ /// @returns `true` if `this->address() == 0`
+ ///
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT { return !address(); }
+
+ /// @cond
+ BOOST_CONSTEXPR bool operator!() const BOOST_NOEXCEPT { return !address(); }
+ /// @endcond
+};
+
+
+namespace detail {
+ BOOST_STACKTRACE_FUNCTION std::string to_string(const frame* frames, std::size_t size);
+} // namespace detail
+
+}} // namespace boost::stacktrace
+
+
+#include <boost/stacktrace/detail/pop_options.pp>
+
+#endif // BOOST_STACKTRACE_DETAIL_FRAME_DECL_HPP
diff --git a/boost/stacktrace/detail/frame_msvc.ipp b/boost/stacktrace/detail/frame_msvc.ipp
new file mode 100644
index 0000000000..6719598b33
--- /dev/null
+++ b/boost/stacktrace/detail/frame_msvc.ipp
@@ -0,0 +1,392 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP
+#define BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/frame.hpp>
+
+#include <boost/core/demangle.hpp>
+#include <boost/core/noncopyable.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/stacktrace/detail/to_hex_array.hpp>
+#include <windows.h>
+#include "dbgeng.h"
+
+#include <boost/detail/winapi/get_current_process.hpp>
+
+#ifdef BOOST_MSVC
+# pragma comment(lib, "ole32.lib")
+# pragma comment(lib, "Dbgeng.lib")
+#endif
+
+
+#ifdef __CRT_UUID_DECL // for __MINGW32__
+ __CRT_UUID_DECL(IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8)
+ __CRT_UUID_DECL(IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba)
+ __CRT_UUID_DECL(IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50)
+#elif defined(DEFINE_GUID) && !defined(BOOST_MSVC)
+ DEFINE_GUID(IID_IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8);
+ DEFINE_GUID(IID_IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba);
+ DEFINE_GUID(IID_IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50);
+#endif
+
+
+
+// Testing. Remove later
+//# define __uuidof(x) ::IID_ ## x
+
+namespace boost { namespace stacktrace { namespace detail {
+
+class com_global_initer: boost::noncopyable {
+ bool ok_;
+
+public:
+ com_global_initer() BOOST_NOEXCEPT
+ : ok_(false)
+ {
+ // COINIT_MULTITHREADED means that we must serialize access to the objects manually.
+ // This is the fastest way to work. If user calls CoInitializeEx before us - we
+ // can end up with other mode (which is OK for us).
+ //
+ // If we call CoInitializeEx befire user - user may end up with different mode, which is a problem.
+ // So we need to call that initialization function as late as possible.
+ const boost::detail::winapi::DWORD_ res = ::CoInitializeEx(0, COINIT_MULTITHREADED);
+ ok_ = (res == S_OK || res == S_FALSE);
+ }
+
+ ~com_global_initer() BOOST_NOEXCEPT {
+ if (ok_) {
+ ::CoUninitialize();
+ }
+ }
+};
+
+
+template <class T>
+class com_holder: boost::noncopyable {
+ T* holder_;
+
+public:
+ com_holder(const com_global_initer&) BOOST_NOEXCEPT
+ : holder_(0)
+ {}
+
+ T* operator->() const BOOST_NOEXCEPT {
+ return holder_;
+ }
+
+ void** to_void_ptr_ptr() BOOST_NOEXCEPT {
+ return reinterpret_cast<void**>(&holder_);
+ }
+
+ bool is_inited() const BOOST_NOEXCEPT {
+ return !!holder_;
+ }
+
+ ~com_holder() BOOST_NOEXCEPT {
+ if (holder_) {
+ holder_->Release();
+ }
+ }
+};
+
+
+static std::string minwg_demangling_workaround(const std::string& s) {
+#ifdef BOOST_GCC
+ if (s.empty()) {
+ return s;
+ }
+
+ if (s[0] != '_') {
+ return boost::core::demangle(('_' + s).c_str());
+ }
+
+ return boost::core::demangle(s.c_str());
+#else
+ return s;
+#endif
+}
+
+class debugging_symbols: boost::noncopyable {
+ static void try_init_com(com_holder< ::IDebugSymbols>& idebug, const com_global_initer& com) BOOST_NOEXCEPT {
+ com_holder< ::IDebugClient> iclient(com);
+ if (S_OK != ::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr())) {
+ return;
+ }
+
+ com_holder< ::IDebugControl> icontrol(com);
+ const bool res0 = (S_OK == iclient->QueryInterface(
+ __uuidof(IDebugControl),
+ icontrol.to_void_ptr_ptr()
+ ));
+ if (!res0) {
+ return;
+ }
+
+ const bool res1 = (S_OK == iclient->AttachProcess(
+ 0,
+ ::GetCurrentProcessId(),
+ DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND
+ ));
+ if (!res1) {
+ return;
+ }
+
+ if (S_OK != icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)) {
+ return;
+ }
+
+ // No cheking: QueryInterface sets the output parameter to NULL in case of error.
+ iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr());
+ }
+
+#ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
+
+ boost::stacktrace::detail::com_global_initer com_;
+ com_holder< ::IDebugSymbols> idebug_;
+public:
+ debugging_symbols() BOOST_NOEXCEPT
+ : com_()
+ , idebug_(com_)
+ {
+ try_init_com(idebug_, com_);
+ }
+
+#else
+
+#ifdef BOOST_NO_CXX11_THREAD_LOCAL
+# error Your compiler does not support C++11 thread_local storage. It's impossible to build with BOOST_STACKTRACE_USE_WINDBG_CACHED.
+#endif
+
+ static com_holder< ::IDebugSymbols>& get_thread_local_debug_inst() BOOST_NOEXCEPT {
+ // [class.mfct]: A static local variable or local type in a member function always refers to the same entity, whether
+ // or not the member function is inline.
+ static thread_local boost::stacktrace::detail::com_global_initer com;
+ static thread_local com_holder< ::IDebugSymbols> idebug(com);
+
+ if (!idebug.is_inited()) {
+ try_init_com(idebug, com);
+ }
+
+ return idebug;
+ }
+
+ com_holder< ::IDebugSymbols>& idebug_;
+public:
+ debugging_symbols() BOOST_NOEXCEPT
+ : idebug_( get_thread_local_debug_inst() )
+ {}
+
+#endif // #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
+
+ bool is_inited() const BOOST_NOEXCEPT {
+ return idebug_.is_inited();
+ }
+
+ std::string get_name_impl(const void* addr, std::string* module_name = 0) const {
+ std::string result;
+ if (!is_inited()) {
+ return result;
+ }
+ const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
+
+ char name[256];
+ name[0] = '\0';
+ ULONG size = 0;
+ bool res = (S_OK == idebug_->GetNameByOffset(
+ offset,
+ name,
+ sizeof(name),
+ &size,
+ 0
+ ));
+
+ if (!res && size != 0) {
+ result.resize(size);
+ res = (S_OK == idebug_->GetNameByOffset(
+ offset,
+ &result[0],
+ static_cast<ULONG>(result.size()),
+ &size,
+ 0
+ ));
+ } else if (res) {
+ result = name;
+ }
+
+ if (!res) {
+ result.clear();
+ return result;
+ }
+
+ const std::size_t delimiter = result.find_first_of('!');
+ if (module_name) {
+ *module_name = result.substr(0, delimiter);
+ }
+
+ if (delimiter == std::string::npos) {
+ // If 'delimiter' is equal to 'std::string::npos' then we have only module name.
+ result.clear();
+ return result;
+ }
+
+ result = minwg_demangling_workaround(
+ result.substr(delimiter + 1)
+ );
+
+ return result;
+ }
+
+ std::size_t get_line_impl(const void* addr) const BOOST_NOEXCEPT {
+ ULONG result = 0;
+ if (!is_inited()) {
+ return result;
+ }
+
+ const bool is_ok = (S_OK == idebug_->GetLineByOffset(
+ reinterpret_cast<ULONG64>(addr),
+ &result,
+ 0,
+ 0,
+ 0,
+ 0
+ ));
+
+ return (is_ok ? result : 0);
+ }
+
+ std::pair<std::string, std::size_t> get_source_file_line_impl(const void* addr) const {
+ std::pair<std::string, std::size_t> result;
+ if (!is_inited()) {
+ return result;
+ }
+ const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
+
+ char name[256];
+ name[0] = 0;
+ ULONG size = 0;
+ ULONG line_num = 0;
+ bool res = (S_OK == idebug_->GetLineByOffset(
+ offset,
+ &line_num,
+ name,
+ sizeof(name),
+ &size,
+ 0
+ ));
+
+ if (res) {
+ result.first = name;
+ result.second = line_num;
+ return result;
+ }
+
+ if (!res && size == 0) {
+ return result;
+ }
+
+ result.first.resize(size);
+ res = (S_OK == idebug_->GetLineByOffset(
+ offset,
+ &line_num,
+ &result.first[0],
+ static_cast<ULONG>(result.first.size()),
+ &size,
+ 0
+ ));
+ result.second = line_num;
+
+ if (!res) {
+ result.first.clear();
+ result.second = 0;
+ }
+
+ return result;
+ }
+
+ void to_string_impl(const void* addr, std::string& res) const {
+ if (!is_inited()) {
+ return;
+ }
+
+ std::string module_name;
+ std::string name = this->get_name_impl(addr, &module_name);
+ if (!name.empty()) {
+ res += name;
+ } else {
+ res += to_hex_array(addr).data();
+ }
+
+ std::pair<std::string, std::size_t> source_line = this->get_source_file_line_impl(addr);
+ if (!source_line.first.empty() && source_line.second) {
+ res += " at ";
+ res += source_line.first;
+ res += ':';
+ res += boost::lexical_cast<boost::array<char, 40> >(source_line.second).data();
+ } else if (!module_name.empty()) {
+ res += " in ";
+ res += module_name;
+ }
+ }
+};
+
+std::string to_string(const frame* frames, std::size_t size) {
+ boost::stacktrace::detail::debugging_symbols idebug;
+ if (!idebug.is_inited()) {
+ return std::string();
+ }
+
+ std::string res;
+ res.reserve(64 * size);
+ for (std::size_t i = 0; i < size; ++i) {
+ if (i < 10) {
+ res += ' ';
+ }
+ res += boost::lexical_cast<boost::array<char, 40> >(i).data();
+ res += '#';
+ res += ' ';
+ idebug.to_string_impl(frames[i].address(), res);
+ res += '\n';
+ }
+
+ return res;
+}
+
+} // namespace detail
+
+std::string frame::name() const {
+ boost::stacktrace::detail::debugging_symbols idebug;
+ return idebug.get_name_impl(addr_);
+}
+
+
+std::string frame::source_file() const {
+ boost::stacktrace::detail::debugging_symbols idebug;
+ return idebug.get_source_file_line_impl(addr_).first;
+}
+
+std::size_t frame::source_line() const {
+ boost::stacktrace::detail::debugging_symbols idebug;
+ return idebug.get_line_impl(addr_);
+}
+
+std::string to_string(const frame& f) {
+ std::string res;
+
+ boost::stacktrace::detail::debugging_symbols idebug;
+ idebug.to_string_impl(f.address(), res);
+ return res;
+}
+
+}} // namespace boost::stacktrace
+
+#endif // BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP
diff --git a/boost/stacktrace/detail/frame_noop.ipp b/boost/stacktrace/detail/frame_noop.ipp
new file mode 100644
index 0000000000..b9b1b98800
--- /dev/null
+++ b/boost/stacktrace/detail/frame_noop.ipp
@@ -0,0 +1,44 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_FRAME_NOOP_IPP
+#define BOOST_STACKTRACE_DETAIL_FRAME_NOOP_IPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/frame.hpp>
+
+namespace boost { namespace stacktrace { namespace detail {
+
+std::string to_string(const frame* /*frames*/, std::size_t /*count*/) {
+ return std::string();
+}
+
+} // namespace detail
+
+std::string frame::name() const {
+ return std::string();
+}
+
+std::string frame::source_file() const {
+ return std::string();
+}
+
+std::size_t frame::source_line() const {
+ return 0;
+}
+
+std::string to_string(const frame& /*f*/) {
+ return std::string();
+}
+
+
+}} // namespace boost::stacktrace
+
+#endif // BOOST_STACKTRACE_DETAIL_FRAME_NOOP_IPP
diff --git a/boost/stacktrace/detail/frame_unwind.ipp b/boost/stacktrace/detail/frame_unwind.ipp
new file mode 100644
index 0000000000..d4e7973968
--- /dev/null
+++ b/boost/stacktrace/detail/frame_unwind.ipp
@@ -0,0 +1,103 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_FRAME_UNWIND_IPP
+#define BOOST_STACKTRACE_DETAIL_FRAME_UNWIND_IPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/frame.hpp>
+
+#include <boost/stacktrace/detail/to_hex_array.hpp>
+#include <boost/stacktrace/detail/location_from_symbol.hpp>
+#include <boost/core/demangle.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <cstdio>
+
+#ifdef BOOST_STACKTRACE_USE_BACKTRACE
+# include <boost/stacktrace/detail/libbacktrace_impls.hpp>
+#elif defined(BOOST_STACKTRACE_USE_ADDR2LINE)
+# include <boost/stacktrace/detail/addr2line_impls.hpp>
+#else
+# include <boost/stacktrace/detail/unwind_base_impls.hpp>
+#endif
+
+namespace boost { namespace stacktrace { namespace detail {
+
+template <class Base>
+class to_string_impl_base: private Base {
+public:
+ std::string operator()(boost::stacktrace::detail::native_frame_ptr_t addr) {
+ Base::res.clear();
+ Base::prepare_function_name(addr);
+ if (!Base::res.empty()) {
+ Base::res = boost::core::demangle(Base::res.c_str());
+ } else {
+ Base::res = to_hex_array(addr).data();
+ }
+
+ if (Base::prepare_source_location(addr)) {
+ return Base::res;
+ }
+
+ boost::stacktrace::detail::location_from_symbol loc(addr);
+ if (!loc.empty()) {
+ Base::res += " in ";
+ Base::res += loc.name();
+ }
+
+ return Base::res;
+ }
+};
+
+std::string to_string(const frame* frames, std::size_t size) {
+ std::string res;
+ res.reserve(64 * size);
+
+ to_string_impl impl;
+
+ for (std::size_t i = 0; i < size; ++i) {
+ if (i < 10) {
+ res += ' ';
+ }
+ res += boost::lexical_cast<boost::array<char, 40> >(i).data();
+ res += '#';
+ res += ' ';
+ res += impl(frames[i].address());
+ res += '\n';
+ }
+
+ return res;
+}
+
+
+} // namespace detail
+
+
+std::string frame::name() const {
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+ ::Dl_info dli;
+ const bool dl_ok = !!::dladdr(addr_, &dli);
+ if (dl_ok && dli.dli_sname) {
+ return boost::core::demangle(dli.dli_sname);
+ }
+#endif
+ return boost::stacktrace::detail::name_impl(addr_);
+}
+
+std::string to_string(const frame& f) {
+ boost::stacktrace::detail::to_string_impl impl;
+ return impl(f.address());
+}
+
+
+}} // namespace boost::stacktrace
+
+#endif // BOOST_STACKTRACE_DETAIL_FRAME_UNWIND_IPP
diff --git a/boost/stacktrace/detail/libbacktrace_impls.hpp b/boost/stacktrace/detail/libbacktrace_impls.hpp
new file mode 100644
index 0000000000..a0c2d2a5aa
--- /dev/null
+++ b/boost/stacktrace/detail/libbacktrace_impls.hpp
@@ -0,0 +1,173 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP
+#define BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/detail/to_hex_array.hpp>
+#include <boost/core/demangle.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <backtrace.h>
+
+namespace boost { namespace stacktrace { namespace detail {
+
+
+struct pc_data {
+ std::string* function;
+ std::string* filename;
+ std::size_t line;
+};
+
+inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *filename, int lineno, const char *function) {
+ pc_data& d = *static_cast<pc_data*>(data);
+ if (d.filename && filename) {
+ *d.filename = filename;
+ }
+ if (d.function && function) {
+ *d.function = function;
+ }
+ d.line = lineno;
+ return 0;
+}
+
+inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) BOOST_NOEXCEPT {
+ // Do nothing, just return.
+}
+
+
+extern inline ::backtrace_state* construct_state() BOOST_NOEXCEPT {
+ return ::backtrace_create_state(
+ 0, 0 /*thread-safe*/, boost::stacktrace::detail::libbacktrace_error_callback, 0
+ );
+
+ // TODO: this does not seem to work well when this function is in .so:
+ // Not async-signal-safe, so this method is not called from async-safe functions.
+ //
+ // This function is not async signal safe because:
+ // * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
+ // * No guarantees on `backtrace_create_state` function.
+
+ // [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
+
+ /*
+ static ::backtrace_state* state = ::backtrace_create_state(
+ 0, 1 , boost::stacktrace::detail::libbacktrace_error_callback, 0
+ );
+
+ return state;
+ */
+}
+
+struct to_string_using_backtrace {
+ std::string res;
+ ::backtrace_state* state;
+ std::string filename;
+ std::size_t line;
+
+ void prepare_function_name(const void* addr) {
+ boost::stacktrace::detail::pc_data data = {&res, &filename, 0};
+ if (state) {
+ ::backtrace_pcinfo(
+ state,
+ reinterpret_cast<uintptr_t>(addr),
+ boost::stacktrace::detail::libbacktrace_full_callback,
+ boost::stacktrace::detail::libbacktrace_error_callback,
+ &data
+ );
+ }
+ line = data.line;
+ }
+
+ bool prepare_source_location(const void* /*addr*/) {
+ if (filename.empty() || !line) {
+ return false;
+ }
+
+ res += " at ";
+ res += filename;
+ res += ':';
+ res += boost::lexical_cast<boost::array<char, 40> >(line).data();
+ return true;
+ }
+
+ to_string_using_backtrace() BOOST_NOEXCEPT {
+ state = boost::stacktrace::detail::construct_state();
+ }
+};
+
+template <class Base> class to_string_impl_base;
+typedef to_string_impl_base<to_string_using_backtrace> to_string_impl;
+
+inline std::string name_impl(const void* addr) {
+ std::string res;
+
+ ::backtrace_state* state = boost::stacktrace::detail::construct_state();
+
+ boost::stacktrace::detail::pc_data data = {&res, 0, 0};
+ if (state) {
+ ::backtrace_pcinfo(
+ state,
+ reinterpret_cast<uintptr_t>(addr),
+ boost::stacktrace::detail::libbacktrace_full_callback,
+ boost::stacktrace::detail::libbacktrace_error_callback,
+ &data
+ );
+ }
+ if (!res.empty()) {
+ res = boost::core::demangle(res.c_str());
+ }
+
+ return res;
+}
+
+} // namespace detail
+
+std::string frame::source_file() const {
+ std::string res;
+
+ ::backtrace_state* state = boost::stacktrace::detail::construct_state();
+
+ boost::stacktrace::detail::pc_data data = {0, &res, 0};
+ if (state) {
+ ::backtrace_pcinfo(
+ state,
+ reinterpret_cast<uintptr_t>(addr_),
+ boost::stacktrace::detail::libbacktrace_full_callback,
+ boost::stacktrace::detail::libbacktrace_error_callback,
+ &data
+ );
+ }
+
+ return res;
+}
+
+std::size_t frame::source_line() const {
+ ::backtrace_state* state = boost::stacktrace::detail::construct_state();
+
+ boost::stacktrace::detail::pc_data data = {0, 0, 0};
+ if (state) {
+ ::backtrace_pcinfo(
+ state,
+ reinterpret_cast<uintptr_t>(addr_),
+ boost::stacktrace::detail::libbacktrace_full_callback,
+ boost::stacktrace::detail::libbacktrace_error_callback,
+ &data
+ );
+ }
+
+ return data.line;
+}
+
+
+}} // namespace boost::stacktrace
+
+#endif // BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP
diff --git a/boost/stacktrace/detail/location_from_symbol.hpp b/boost/stacktrace/detail/location_from_symbol.hpp
new file mode 100644
index 0000000000..d20b0d6707
--- /dev/null
+++ b/boost/stacktrace/detail/location_from_symbol.hpp
@@ -0,0 +1,76 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
+#define BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+# include <dlfcn.h>
+#else
+# include <boost/detail/winapi/dll.hpp>
+#endif
+
+namespace boost { namespace stacktrace { namespace detail {
+
+class location_from_symbol {
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+ ::Dl_info dli_;
+
+public:
+ explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT
+ : dli_()
+ {
+ if (!::dladdr(addr, &dli_)) {
+ dli_.dli_fname = 0;
+ }
+ }
+
+ bool empty() const BOOST_NOEXCEPT {
+ return !dli_.dli_fname;
+ }
+
+ const char* name() const BOOST_NOEXCEPT {
+ return dli_.dli_fname;
+ }
+#else
+ BOOST_STATIC_CONSTEXPR boost::detail::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
+
+ char file_name_[DEFAULT_PATH_SIZE_];
+
+public:
+ explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT {
+ file_name_[0] = '\0';
+
+ boost::detail::winapi::MEMORY_BASIC_INFORMATION_ mbi;
+ if (!boost::detail::winapi::VirtualQuery(addr, &mbi, sizeof(mbi))) {
+ return;
+ }
+
+ boost::detail::winapi::HMODULE_ handle = reinterpret_cast<boost::detail::winapi::HMODULE_>(mbi.AllocationBase);
+ if (!boost::detail::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
+ file_name_[0] = '\0';
+ return;
+ }
+ }
+
+ bool empty() const BOOST_NOEXCEPT {
+ return file_name_[0] == '\0';
+ }
+
+ const char* name() const BOOST_NOEXCEPT {
+ return file_name_;
+ }
+#endif
+};
+
+}}} // namespace boost::stacktrace::detail
+
+#endif // BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
diff --git a/boost/stacktrace/detail/pop_options.pp b/boost/stacktrace/detail/pop_options.pp
new file mode 100644
index 0000000000..8995b00ada
--- /dev/null
+++ b/boost/stacktrace/detail/pop_options.pp
@@ -0,0 +1,12 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// No include guards! Intentionally.
+
+#ifdef BOOST_STACKTRACE_FUNCTION
+# undef BOOST_STACKTRACE_FUNCTION
+#endif
+
diff --git a/boost/stacktrace/detail/push_options.pp b/boost/stacktrace/detail/push_options.pp
new file mode 100644
index 0000000000..3adb626121
--- /dev/null
+++ b/boost/stacktrace/detail/push_options.pp
@@ -0,0 +1,31 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// No include guards! Intentionally.
+
+// Link or header only
+#if !defined(BOOST_STACKTRACE_LINK) && defined(BOOST_STACKTRACE_DYN_LINK)
+# define BOOST_STACKTRACE_LINK
+#endif
+
+#if defined(BOOST_STACKTRACE_LINK) && !defined(BOOST_STACKTRACE_DYN_LINK) && defined(BOOST_ALL_DYN_LINK)
+# define BOOST_STACKTRACE_DYN_LINK
+#endif
+
+#ifdef BOOST_STACKTRACE_LINK
+# if defined(BOOST_STACKTRACE_DYN_LINK)
+# ifdef BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
+# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_EXPORT
+# else
+# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_IMPORT
+# endif
+# else
+# define BOOST_STACKTRACE_FUNCTION
+# endif
+#elif !defined(BOOST_STACKTRACE_DOXYGEN_INVOKED)
+# define BOOST_STACKTRACE_FUNCTION inline
+#endif
+
diff --git a/boost/stacktrace/detail/safe_dump_noop.ipp b/boost/stacktrace/detail/safe_dump_noop.ipp
new file mode 100644
index 0000000000..78fdc3a8ae
--- /dev/null
+++ b/boost/stacktrace/detail/safe_dump_noop.ipp
@@ -0,0 +1,37 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_SAFE_DUMP_NOOP_IPP
+#define BOOST_STACKTRACE_DETAIL_SAFE_DUMP_NOOP_IPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/safe_dump_to.hpp>
+
+namespace boost { namespace stacktrace { namespace detail {
+
+
+#if defined(BOOST_WINDOWS)
+std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
+ return 0;
+}
+#else
+std::size_t dump(int /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
+ return 0;
+}
+#endif
+
+
+std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
+ return 0;
+}
+
+}}} // namespace boost::stacktrace::detail
+
+#endif // BOOST_STACKTRACE_DETAIL_SAFE_DUMP_NOOP_IPP
diff --git a/boost/stacktrace/detail/safe_dump_posix.ipp b/boost/stacktrace/detail/safe_dump_posix.ipp
new file mode 100644
index 0000000000..37eef5ac7c
--- /dev/null
+++ b/boost/stacktrace/detail/safe_dump_posix.ipp
@@ -0,0 +1,58 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_SAFE_DUMP_POSIX_IPP
+#define BOOST_STACKTRACE_DETAIL_SAFE_DUMP_POSIX_IPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/safe_dump_to.hpp>
+
+#include <unistd.h> // ::write
+#include <fcntl.h> // ::open
+
+
+namespace boost { namespace stacktrace { namespace detail {
+
+std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
+ // We do not retry, because this function must be typically called from signal handler so it's:
+ // * to scary to continue in case of EINTR
+ // * EAGAIN or EWOULDBLOCK may occur only in case of O_NONBLOCK is set for fd,
+ // so it seems that user does not want to block
+ if (::write(fd, frames, sizeof(native_frame_ptr_t) * frames_count) == -1) {
+ return 0;
+ }
+
+ return frames_count;
+}
+
+std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
+ const int fd = ::open(
+ file,
+ O_CREAT | O_WRONLY | O_TRUNC,
+#if defined(S_IWUSR) && defined(S_IRUSR) // Workarounds for some Android OSes
+ S_IWUSR | S_IRUSR
+#elif defined(S_IWRITE) && defined(S_IREAD)
+ S_IWRITE | S_IREAD
+#else
+ 0
+#endif
+ );
+ if (fd == -1) {
+ return 0;
+ }
+
+ const std::size_t size = boost::stacktrace::detail::dump(fd, frames, frames_count);
+ ::close(fd);
+ return size;
+}
+
+}}} // namespace boost::stacktrace::detail
+
+#endif // BOOST_STACKTRACE_DETAIL_SAFE_DUMP_POSIX_IPP
diff --git a/boost/stacktrace/detail/safe_dump_win.ipp b/boost/stacktrace/detail/safe_dump_win.ipp
new file mode 100644
index 0000000000..26f0516c01
--- /dev/null
+++ b/boost/stacktrace/detail/safe_dump_win.ipp
@@ -0,0 +1,60 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_SAFE_DUMP_WIN_IPP
+#define BOOST_STACKTRACE_DETAIL_SAFE_DUMP_WIN_IPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/safe_dump_to.hpp>
+
+#include <boost/core/noncopyable.hpp>
+
+#include <boost/detail/winapi/get_current_process.hpp>
+#include <boost/detail/winapi/file_management.hpp>
+#include <boost/detail/winapi/handles.hpp>
+#include <boost/detail/winapi/access_rights.hpp>
+
+namespace boost { namespace stacktrace { namespace detail {
+
+std::size_t dump(void* fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
+ boost::detail::winapi::DWORD_ written;
+ const boost::detail::winapi::DWORD_ bytes_to_write = static_cast<boost::detail::winapi::DWORD_>(
+ sizeof(native_frame_ptr_t) * frames_count
+ );
+ if (!boost::detail::winapi::WriteFile(fd, frames, bytes_to_write, &written, 0)) {
+ return 0;
+ }
+
+ return frames_count;
+}
+
+std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
+ void* const fd = boost::detail::winapi::CreateFileA(
+ file,
+ boost::detail::winapi::GENERIC_WRITE_,
+ 0,
+ 0,
+ boost::detail::winapi::CREATE_ALWAYS_,
+ boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
+ 0
+ );
+
+ if (fd == boost::detail::winapi::invalid_handle_value) {
+ return 0;
+ }
+
+ const std::size_t size = boost::stacktrace::detail::dump(fd, frames, frames_count);
+ boost::detail::winapi::CloseHandle(fd);
+ return size;
+}
+
+}}} // namespace boost::stacktrace::detail
+
+#endif // BOOST_STACKTRACE_DETAIL_SAFE_DUMP_WIN_IPP
diff --git a/boost/stacktrace/detail/to_hex_array.hpp b/boost/stacktrace/detail/to_hex_array.hpp
new file mode 100644
index 0000000000..dd55ded8b6
--- /dev/null
+++ b/boost/stacktrace/detail/to_hex_array.hpp
@@ -0,0 +1,54 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_TO_HEX_ARRAY_HPP
+#define BOOST_STACKTRACE_DETAIL_TO_HEX_ARRAY_HPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/array.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_pointer.hpp>
+#include <boost/type_traits/make_unsigned.hpp>
+
+namespace boost { namespace stacktrace { namespace detail {
+
+BOOST_STATIC_CONSTEXPR char to_hex_array_bytes[] = "0123456789ABCDEF";
+
+template <class T>
+inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(T addr) BOOST_NOEXCEPT {
+ boost::array<char, 2 + sizeof(void*) * 2 + 1> ret = {"0x"};
+ ret.back() = '\0';
+ BOOST_STATIC_ASSERT_MSG(!boost::is_pointer<T>::value, "");
+
+ const std::size_t s = sizeof(T);
+
+ char* out = ret.data() + s * 2 + 1;
+
+ for (std::size_t i = 0; i < s; ++i) {
+ const unsigned char tmp_addr = (addr & 0xFFu);
+ *out = to_hex_array_bytes[tmp_addr & 0xF];
+ -- out;
+ *out = to_hex_array_bytes[tmp_addr >> 4];
+ -- out;
+ addr >>= 8;
+ }
+
+ return ret;
+}
+
+inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(const void* addr) BOOST_NOEXCEPT {
+ return to_hex_array(
+ reinterpret_cast< boost::make_unsigned<std::ptrdiff_t>::type >(addr)
+ );
+}
+
+}}} // namespace boost::stacktrace::detail
+
+#endif // BOOST_STACKTRACE_DETAIL_TO_HEX_ARRAY_HPP
diff --git a/boost/stacktrace/detail/unwind_base_impls.hpp b/boost/stacktrace/detail/unwind_base_impls.hpp
new file mode 100644
index 0000000000..18a2378d25
--- /dev/null
+++ b/boost/stacktrace/detail/unwind_base_impls.hpp
@@ -0,0 +1,50 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_UNWIND_BASE_IMPLS_HPP
+#define BOOST_STACKTRACE_DETAIL_UNWIND_BASE_IMPLS_HPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/frame.hpp>
+
+namespace boost { namespace stacktrace { namespace detail {
+
+struct to_string_using_nothing {
+ std::string res;
+
+ void prepare_function_name(const void* addr) {
+ res = boost::stacktrace::frame(addr).name();
+ }
+
+ bool prepare_source_location(const void* /*addr*/) const BOOST_NOEXCEPT {
+ return false;
+ }
+};
+
+template <class Base> class to_string_impl_base;
+typedef to_string_impl_base<to_string_using_nothing> to_string_impl;
+
+inline std::string name_impl(const void* /*addr*/) {
+ return std::string();
+}
+
+} // namespace detail
+
+std::string frame::source_file() const {
+ return std::string();
+}
+
+std::size_t frame::source_line() const {
+ return 0;
+}
+
+}} // namespace boost::stacktrace
+
+#endif // BOOST_STACKTRACE_DETAIL_UNWIND_BASE_IMPLS_HPP
diff --git a/boost/stacktrace/detail/void_ptr_cast.hpp b/boost/stacktrace/detail/void_ptr_cast.hpp
new file mode 100644
index 0000000000..f956f4789f
--- /dev/null
+++ b/boost/stacktrace/detail/void_ptr_cast.hpp
@@ -0,0 +1,46 @@
+// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
+// Copyright 2015-2017 Antony Polukhin.
+//
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt
+// or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_DETAIL_VOID_PTR_CAST_HPP
+#define BOOST_STACKTRACE_DETAIL_VOID_PTR_CAST_HPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_pointer.hpp>
+
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ * 100 + __GNUC_MINOR__ > 301)
+# pragma GCC system_header
+#endif
+
+namespace boost { namespace stacktrace { namespace detail {
+
+// GCC warns when reinterpret_cast between function pointer and object pointer occur.
+// This functionsuppress the warnings and ensures that such casts are safe.
+template <class To, class From>
+To void_ptr_cast(From* v) BOOST_NOEXCEPT {
+ BOOST_STATIC_ASSERT_MSG(
+ boost::is_pointer<To>::value,
+ "`void_ptr_cast` function must be used only for casting to or from void pointers."
+ );
+
+ BOOST_STATIC_ASSERT_MSG(
+ sizeof(From*) == sizeof(To),
+ "Pointer to function and pointer to object differ in size on your platform."
+ );
+
+ return reinterpret_cast<To>(v);
+}
+
+
+}}} // boost::stacktrace::detail
+
+#endif // BOOST_STACKTRACE_DETAIL_VOID_PTR_CAST_HPP
+
diff --git a/boost/stacktrace/frame.hpp b/boost/stacktrace/frame.hpp
new file mode 100644
index 0000000000..4ad3c507f3
--- /dev/null
+++ b/boost/stacktrace/frame.hpp
@@ -0,0 +1,67 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_FRAME_HPP
+#define BOOST_STACKTRACE_FRAME_HPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iosfwd>
+#include <string>
+
+#include <boost/core/explicit_operator_bool.hpp>
+
+#include <boost/stacktrace/safe_dump_to.hpp> // boost::stacktrace::detail::native_frame_ptr_t
+
+#include <boost/stacktrace/detail/frame_decl.hpp>
+#include <boost/stacktrace/detail/push_options.pp>
+
+namespace boost { namespace stacktrace {
+
+/// Comparison operators that provide platform dependant ordering and have O(1) complexity; are Async-Handler-Safe.
+BOOST_CONSTEXPR inline bool operator< (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() < rhs.address(); }
+BOOST_CONSTEXPR inline bool operator> (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return rhs < lhs; }
+BOOST_CONSTEXPR inline bool operator<=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); }
+BOOST_CONSTEXPR inline bool operator>=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); }
+BOOST_CONSTEXPR inline bool operator==(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() == rhs.address(); }
+BOOST_CONSTEXPR inline bool operator!=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); }
+
+/// Fast hashing support, O(1) complexity; Async-Handler-Safe.
+inline std::size_t hash_value(const frame& f) BOOST_NOEXCEPT {
+ return reinterpret_cast<std::size_t>(f.address());
+}
+
+/// Outputs stacktrace::frame in a human readable format to string; unsafe to use in async handlers.
+BOOST_STACKTRACE_FUNCTION std::string to_string(const frame& f);
+
+/// Outputs stacktrace::frame in a human readable format to output stream; unsafe to use in async handlers.
+template <class CharT, class TraitsT>
+std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const frame& f) {
+ return os << boost::stacktrace::to_string(f);
+}
+
+}} // namespace boost::stacktrace
+
+/// @cond
+
+#include <boost/stacktrace/detail/pop_options.pp>
+
+#ifndef BOOST_STACKTRACE_LINK
+# if defined(BOOST_STACKTRACE_USE_NOOP)
+# include <boost/stacktrace/detail/frame_noop.ipp>
+# elif defined(BOOST_MSVC) || defined(BOOST_STACKTRACE_USE_WINDBG) || defined(BOOST_STACKTRACE_USE_WINDBG_CACHED)
+# include <boost/stacktrace/detail/frame_msvc.ipp>
+# else
+# include <boost/stacktrace/detail/frame_unwind.ipp>
+# endif
+#endif
+/// @endcond
+
+
+#endif // BOOST_STACKTRACE_FRAME_HPP
diff --git a/boost/stacktrace/safe_dump_to.hpp b/boost/stacktrace/safe_dump_to.hpp
new file mode 100644
index 0000000000..79981dabea
--- /dev/null
+++ b/boost/stacktrace/safe_dump_to.hpp
@@ -0,0 +1,218 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_SAFE_DUMP_TO_HPP
+#define BOOST_STACKTRACE_SAFE_DUMP_TO_HPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/stacktrace/detail/push_options.pp>
+
+#ifdef BOOST_INTEL
+# pragma warning(push)
+# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
+#endif
+
+/// @file safe_dump_to.hpp This header contains low-level async-signal-safe functions for dumping call stacks. Dumps are binary serialized arrays of `void*`,
+/// so you could read them by using 'od -tx8 -An stacktrace_dump_failename' Linux command or using boost::stacktrace::stacktrace::from_dump functions.
+
+namespace boost { namespace stacktrace {
+
+/// @cond
+namespace detail {
+
+ typedef const void* native_frame_ptr_t; // TODO: change to `typedef void(*native_frame_ptr_t)();`
+ enum helper{ max_frames_dump = 128 };
+
+ BOOST_STACKTRACE_FUNCTION std::size_t from_dump(const char* filename, native_frame_ptr_t* out_frames);
+ BOOST_STACKTRACE_FUNCTION std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
+#if defined(BOOST_WINDOWS)
+ BOOST_STACKTRACE_FUNCTION std::size_t dump(void* fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
+#else
+ // POSIX
+ BOOST_STACKTRACE_FUNCTION std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
+#endif
+
+
+struct this_thread_frames { // struct is required to avoid warning about usage of inline+BOOST_NOINLINE
+ BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT;
+
+ BOOST_NOINLINE static std::size_t safe_dump_to_impl(void* memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
+ typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
+
+ if (size < sizeof(native_frame_ptr_t)) {
+ return 0;
+ }
+
+ native_frame_ptr_t* mem = static_cast<native_frame_ptr_t*>(memory);
+ const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(mem, size / sizeof(native_frame_ptr_t) - 1, skip + 1);
+ mem[frames_count] = 0;
+ return frames_count + 1;
+ }
+
+ template <class T>
+ BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) BOOST_NOEXCEPT {
+ typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
+
+ native_frame_ptr_t buffer[boost::stacktrace::detail::max_frames_dump + 1];
+ if (max_depth > boost::stacktrace::detail::max_frames_dump) {
+ max_depth = boost::stacktrace::detail::max_frames_dump;
+ }
+
+ const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, max_depth, skip + 1);
+ buffer[frames_count] = 0;
+ return boost::stacktrace::detail::dump(file, buffer, frames_count + 1);
+ }
+};
+
+} // namespace detail
+/// @endcond
+
+/// @brief Stores current function call sequence into the memory.
+///
+/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
+///
+/// @b Async-Handler-Safety: Safe.
+///
+/// @returns Stored call sequence depth including terminating zero frame.
+///
+/// @param memory Preallocated buffer to store current function call sequence into.
+///
+/// @param size Size of the preallocated buffer.
+BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST_NOEXCEPT {
+ return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, 0);
+}
+
+/// @brief Stores current function call sequence into the memory.
+///
+/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
+///
+/// @b Async-Handler-Safety: Safe.
+///
+/// @returns Stored call sequence depth including terminating zero frame.
+///
+/// @param skip How many top calls to skip and do not store.
+///
+/// @param memory Preallocated buffer to store current function call sequence into.
+///
+/// @param size Size of the preallocated buffer.
+BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, void* memory, std::size_t size) BOOST_NOEXCEPT {
+ return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, skip);
+}
+
+
+/// @brief Opens a file and rewrites its content with current function call sequence.
+///
+/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
+///
+/// @b Async-Handler-Safety: Safe.
+///
+/// @returns Stored call sequence depth including terminating zero frame.
+///
+/// @param file File to store current function call sequence.
+BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
+ return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, 0, boost::stacktrace::detail::max_frames_dump);
+}
+
+/// @brief Opens a file and rewrites its content with current function call sequence.
+///
+/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
+///
+/// @b Async-Handler-Safety: Safe.
+///
+/// @returns Stored call sequence depth including terminating zero frame.
+///
+/// @param skip How many top calls to skip and do not store.
+///
+/// @param max_depth Max call sequence depth to collect.
+///
+/// @param file File to store current function call sequence.
+BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, const char* file) BOOST_NOEXCEPT {
+ return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, skip, max_depth);
+}
+
+#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
+
+/// @brief Writes into the provided file descriptor the current function call sequence.
+///
+/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
+///
+/// @b Async-Handler-Safety: Safe.
+///
+/// @returns Stored call sequence depth including terminating zero frame.
+///
+/// @param file File to store current function call sequence.
+BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) BOOST_NOEXCEPT;
+
+/// @brief Writes into the provided file descriptor the current function call sequence.
+///
+/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
+///
+/// @b Async-Handler-Safety: Safe.
+///
+/// @returns Stored call sequence depth including terminating zero frame.
+///
+/// @param skip How many top calls to skip and do not store.
+///
+/// @param max_depth Max call sequence depth to collect.
+///
+/// @param file File to store current function call sequence.
+BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, platform_specific_descriptor fd) BOOST_NOEXCEPT;
+
+#elif defined(BOOST_WINDOWS)
+
+BOOST_FORCEINLINE std::size_t safe_dump_to(void* fd) BOOST_NOEXCEPT {
+ return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
+}
+
+BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, void* fd) BOOST_NOEXCEPT {
+ return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
+}
+
+#else
+
+// POSIX
+BOOST_FORCEINLINE std::size_t safe_dump_to(int fd) BOOST_NOEXCEPT {
+ return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
+}
+
+BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, int fd) BOOST_NOEXCEPT {
+ return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
+}
+
+#endif
+
+
+}} // namespace boost::stacktrace
+
+#ifdef BOOST_INTEL
+# pragma warning(pop)
+#endif
+
+#include <boost/stacktrace/detail/pop_options.pp>
+
+#if !defined(BOOST_STACKTRACE_LINK) || defined(BOOST_STACKTRACE_INTERNAL_BUILD_LIBS)
+# if defined(BOOST_STACKTRACE_USE_NOOP)
+# include <boost/stacktrace/detail/safe_dump_noop.ipp>
+# include <boost/stacktrace/detail/collect_noop.ipp>
+# else
+# if defined(BOOST_WINDOWS)
+# include <boost/stacktrace/detail/safe_dump_win.ipp>
+# else
+# include <boost/stacktrace/detail/safe_dump_posix.ipp>
+# endif
+# if defined(BOOST_WINDOWS) && !defined(BOOST_GCC)
+# include <boost/stacktrace/detail/collect_msvc.ipp>
+# else
+# include <boost/stacktrace/detail/collect_unwind.ipp>
+# endif
+# endif
+#endif
+
+#endif // BOOST_STACKTRACE_SAFE_DUMP_TO_HPP
diff --git a/boost/stacktrace/stacktrace.hpp b/boost/stacktrace/stacktrace.hpp
new file mode 100644
index 0000000000..3c72488767
--- /dev/null
+++ b/boost/stacktrace/stacktrace.hpp
@@ -0,0 +1,414 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_STACKTRACE_HPP
+#define BOOST_STACKTRACE_STACKTRACE_HPP
+
+#include <boost/config.hpp>
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <boost/core/explicit_operator_bool.hpp>
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
+# include <type_traits>
+#endif
+
+#include <boost/stacktrace/stacktrace_fwd.hpp>
+#include <boost/stacktrace/safe_dump_to.hpp>
+#include <boost/stacktrace/detail/frame_decl.hpp>
+
+#ifdef BOOST_INTEL
+# pragma warning(push)
+# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
+#endif
+
+/// @cond
+namespace boost {
+ // Forward declaration
+ template <class It> std::size_t hash_range(It, It);
+}
+/// @endcond
+
+namespace boost { namespace stacktrace {
+
+/// Class that on construction copies minimal information about call stack into its internals and provides access to that information.
+/// @tparam Allocator Allocator to use during stack capture.
+template <class Allocator>
+class basic_stacktrace {
+ std::vector<boost::stacktrace::frame, Allocator> impl_;
+ typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
+
+ /// @cond
+ void fill(native_frame_ptr_t* begin, std::size_t size) {
+ if (!size) {
+ return;
+ }
+
+ impl_.reserve(static_cast<std::size_t>(size));
+ for (std::size_t i = 0; i < size; ++i) {
+ if (!begin[i]) {
+ return;
+ }
+ impl_.push_back(
+ frame(begin[i])
+ );
+ }
+ }
+
+ static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) BOOST_NOEXCEPT {
+ const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0);
+ return (ret > 1024 ? 1024 : ret); // Dealing with suspiciously big sizes
+ }
+
+ BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) {
+ BOOST_CONSTEXPR_OR_CONST std::size_t buffer_size = 128;
+ if (!max_depth) {
+ return;
+ }
+
+ try {
+ { // Fast path without additional allocations
+ native_frame_ptr_t buffer[buffer_size];
+ const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size, frames_to_skip + 1);
+ if (buffer_size > frames_count || frames_count >= max_depth) {
+ const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
+ fill(buffer, size);
+ return;
+ }
+ }
+
+ // Failed to fit in `buffer_size`. Allocating memory:
+ typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t;
+ std::vector<native_frame_ptr_t, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
+ do {
+ const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(&buf[0], buf.size(), frames_to_skip + 1);
+ if (buf.size() > frames_count || frames_count >= max_depth) {
+ const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
+ fill(&buf[0], size);
+ return;
+ }
+
+ buf.resize(buf.size() * 2);
+ } while (buf.size() < buf.max_size()); // close to `true`, but suppresses `C4127: conditional expression is constant`.
+ } catch (...) {
+ // ignore exception
+ }
+ }
+ /// @endcond
+
+public:
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::value_type value_type;
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::allocator_type allocator_type;
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer pointer;
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer const_pointer;
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference reference;
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference const_reference;
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::size_type size_type;
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::difference_type difference_type;
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator iterator;
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator const_iterator;
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator reverse_iterator;
+ typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator const_reverse_iterator;
+
+ /// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
+ ///
+ /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
+ ///
+ /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
+ BOOST_FORCEINLINE basic_stacktrace() BOOST_NOEXCEPT
+ : impl_()
+ {
+ init(0 , static_cast<std::size_t>(-1));
+ }
+
+ /// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
+ ///
+ /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
+ ///
+ /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
+ ///
+ /// @param a Allocator that would be passed to underlying storeage.
+ BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) BOOST_NOEXCEPT
+ : impl_(a)
+ {
+ init(0 , static_cast<std::size_t>(-1));
+ }
+
+ /// @brief Stores [skip, skip + max_depth) of the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
+ ///
+ /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
+ ///
+ /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
+ ///
+ /// @param skip How many top calls to skip and do not store in *this.
+ ///
+ /// @param max_depth Max call sequence depth to collect.
+ ///
+ /// @param a Allocator that would be passed to underlying storeage.
+ ///
+ /// @throws Nothing. Note that default construction of allocator may throw, however it is
+ /// performed outside the constructor and exception in `allocator_type()` would not result in calling `std::terminate`.
+ BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) BOOST_NOEXCEPT
+ : impl_(a)
+ {
+ init(skip , max_depth);
+ }
+
+ /// @b Complexity: O(st.size())
+ ///
+ /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
+ basic_stacktrace(const basic_stacktrace& st)
+ : impl_(st.impl_)
+ {}
+
+ /// @b Complexity: O(st.size())
+ ///
+ /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
+ basic_stacktrace& operator=(const basic_stacktrace& st) {
+ impl_ = st.impl_;
+ return *this;
+ }
+
+#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe if Allocator::deallocate is async signal safe.
+ ~basic_stacktrace() BOOST_NOEXCEPT = default;
+#endif
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
+ basic_stacktrace(basic_stacktrace&& st) BOOST_NOEXCEPT
+ : impl_(std::move(st.impl_))
+ {}
+
+ /// @b Complexity: O(st.size())
+ ///
+ /// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
+ basic_stacktrace& operator=(basic_stacktrace&& st)
+#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
+ BOOST_NOEXCEPT_IF(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
+#else
+ BOOST_NOEXCEPT
+#endif
+ {
+ impl_ = std::move(st.impl_);
+ return *this;
+ }
+#endif
+
+ /// @returns Number of function names stored inside the class.
+ ///
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ size_type size() const BOOST_NOEXCEPT {
+ return impl_.size();
+ }
+
+ /// @param frame_no Zero based index of frame to return. 0
+ /// is the function index where stacktrace was constructed and
+ /// index close to this->size() contains function `main()`.
+ /// @returns frame that references the actual frame info, stored inside *this.
+ ///
+ /// @b Complexity: O(1).
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ const_reference operator[](std::size_t frame_no) const BOOST_NOEXCEPT {
+ return impl_[frame_no];
+ }
+
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ const_iterator begin() const BOOST_NOEXCEPT { return impl_.begin(); }
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ const_iterator cbegin() const BOOST_NOEXCEPT { return impl_.begin(); }
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ const_iterator end() const BOOST_NOEXCEPT { return impl_.end(); }
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ const_iterator cend() const BOOST_NOEXCEPT { return impl_.end(); }
+
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ const_reverse_iterator rend() const BOOST_NOEXCEPT { return impl_.rend(); }
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ const_reverse_iterator crend() const BOOST_NOEXCEPT { return impl_.rend(); }
+
+
+ /// @brief Allows to check that stack trace capturing was successful.
+ /// @returns `true` if `this->size() != 0`
+ ///
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
+
+ /// @brief Allows to check that stack trace failed.
+ /// @returns `true` if `this->size() == 0`
+ ///
+ /// @b Complexity: O(1)
+ ///
+ /// @b Async-Handler-Safety: Safe.
+ bool empty() const BOOST_NOEXCEPT { return !size(); }
+
+ /// @cond
+ bool operator!() const BOOST_NOEXCEPT { return !size(); }
+ /// @endcond
+
+ const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const BOOST_NOEXCEPT {
+ return impl_;
+ }
+
+ /// Constructs stacktrace from basic_istreamable that references the dumped stacktrace. Terminating zero frame is discarded.
+ ///
+ /// @b Complexity: O(N)
+ template <class Char, class Trait>
+ static basic_stacktrace from_dump(std::basic_istream<Char, Trait>& in, const allocator_type& a = allocator_type()) {
+ typedef typename std::basic_istream<Char, Trait>::pos_type pos_type;
+ basic_stacktrace ret(0, 0, a);
+
+ // reserving space
+ const pos_type pos = in.tellg();
+ in.seekg(0, in.end);
+ const std::size_t frames_count = frames_count_from_buffer_size(static_cast<std::size_t>(in.tellg()));
+ in.seekg(pos);
+
+ if (!frames_count) {
+ return ret;
+ }
+
+ native_frame_ptr_t ptr = 0;
+ ret.impl_.reserve(frames_count);
+ while (in.read(reinterpret_cast<Char*>(&ptr), sizeof(ptr))) {
+ if (!ptr) {
+ break;
+ }
+
+ ret.impl_.push_back(frame(ptr));
+ }
+
+ return ret;
+ }
+
+ /// Constructs stacktrace from raw memory dump. Terminating zero frame is discarded.
+ ///
+ /// @b Complexity: O(size) in worst case
+ static basic_stacktrace from_dump(const void* begin, std::size_t buffer_size_in_bytes, const allocator_type& a = allocator_type()) {
+ basic_stacktrace ret(0, 0, a);
+ const native_frame_ptr_t* first = static_cast<const native_frame_ptr_t*>(begin);
+ const std::size_t frames_count = frames_count_from_buffer_size(buffer_size_in_bytes);
+ if (!frames_count) {
+ return ret;
+ }
+
+ const native_frame_ptr_t* const last = first + frames_count;
+ ret.impl_.reserve(frames_count);
+ for (; first != last; ++first) {
+ if (!*first) {
+ break;
+ }
+
+ ret.impl_.push_back(frame(*first));
+ }
+
+ return ret;
+ }
+};
+
+/// @brief Compares stacktraces for less, order is platform dependent.
+///
+/// @b Complexity: Amortized O(1); worst case O(size())
+///
+/// @b Async-Handler-Safety: Safe.
+template <class Allocator1, class Allocator2>
+bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
+ return lhs.size() < rhs.size() || (lhs.size() == rhs.size() && lhs.as_vector() < rhs.as_vector());
+}
+
+/// @brief Compares stacktraces for equality.
+///
+/// @b Complexity: Amortized O(1); worst case O(size())
+///
+/// @b Async-Handler-Safety: Safe.
+template <class Allocator1, class Allocator2>
+bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
+ return lhs.as_vector() == rhs.as_vector();
+}
+
+
+/// Comparison operators that provide platform dependant ordering and have amortized O(1) complexity; O(size()) worst case complexity; are Async-Handler-Safe.
+template <class Allocator1, class Allocator2>
+bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
+ return rhs < lhs;
+}
+
+template <class Allocator1, class Allocator2>
+bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
+ return !(lhs > rhs);
+}
+
+template <class Allocator1, class Allocator2>
+bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
+ return !(lhs < rhs);
+}
+
+template <class Allocator1, class Allocator2>
+bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
+ return !(lhs == rhs);
+}
+
+/// Fast hashing support, O(st.size()) complexity; Async-Handler-Safe.
+template <class Allocator>
+std::size_t hash_value(const basic_stacktrace<Allocator>& st) BOOST_NOEXCEPT {
+ return boost::hash_range(st.as_vector().begin(), st.as_vector().end());
+}
+
+/// Outputs stacktrace in a human readable format to output stream; unsafe to use in async handlers.
+template <class CharT, class TraitsT, class Allocator>
+std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) {
+ if (bt) {
+ os << boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size());
+ }
+
+ return os;
+}
+
+/// This is the typedef to use unless you'd like to provide a specific allocator to boost::stacktrace::basic_stacktrace.
+typedef basic_stacktrace<> stacktrace;
+
+}} // namespace boost::stacktrace
+
+#ifdef BOOST_INTEL
+# pragma warning(pop)
+#endif
+
+#endif // BOOST_STACKTRACE_STACKTRACE_HPP
diff --git a/boost/stacktrace/stacktrace_fwd.hpp b/boost/stacktrace/stacktrace_fwd.hpp
new file mode 100644
index 0000000000..ec131564c0
--- /dev/null
+++ b/boost/stacktrace/stacktrace_fwd.hpp
@@ -0,0 +1,28 @@
+// Copyright Antony Polukhin, 2016-2017.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_STACKTRACE_STACKTRACE_FWD_HPP
+#define BOOST_STACKTRACE_STACKTRACE_FWD_HPP
+
+#include <cstddef>
+#include <memory>
+
+/// @file stacktrace_fwd.hpp This header contains only forward declarations of
+/// boost::stacktrace::frame, boost::stacktrace::basic_stacktrace, boost::stacktrace::stacktrace
+/// and does not include any other Boost headers.
+
+/// @cond
+namespace boost { namespace stacktrace {
+
+class frame;
+template <class Allocator = std::allocator<frame> > class basic_stacktrace;
+typedef basic_stacktrace<> stacktrace;
+
+}} // namespace boost::stacktrace
+/// @endcond
+
+
+#endif // BOOST_STACKTRACE_STACKTRACE_FWD_HPP