diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:24:46 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-09-13 11:25:39 +0900 |
commit | 4fadd968fa12130524c8380f33fcfe25d4de79e5 (patch) | |
tree | fd26a490cd15388d42fc6652b3c5c13012e7f93e /boost/stacktrace/detail | |
parent | b5c87084afaef42b2d058f68091be31988a6a874 (diff) | |
download | boost-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/detail')
-rw-r--r-- | boost/stacktrace/detail/addr2line_impls.hpp | 225 | ||||
-rw-r--r-- | boost/stacktrace/detail/collect_msvc.ipp | 33 | ||||
-rw-r--r-- | boost/stacktrace/detail/collect_noop.ipp | 25 | ||||
-rw-r--r-- | boost/stacktrace/detail/collect_unwind.ipp | 68 | ||||
-rw-r--r-- | boost/stacktrace/detail/frame_decl.hpp | 159 | ||||
-rw-r--r-- | boost/stacktrace/detail/frame_msvc.ipp | 392 | ||||
-rw-r--r-- | boost/stacktrace/detail/frame_noop.ipp | 44 | ||||
-rw-r--r-- | boost/stacktrace/detail/frame_unwind.ipp | 103 | ||||
-rw-r--r-- | boost/stacktrace/detail/libbacktrace_impls.hpp | 173 | ||||
-rw-r--r-- | boost/stacktrace/detail/location_from_symbol.hpp | 76 | ||||
-rw-r--r-- | boost/stacktrace/detail/pop_options.pp | 12 | ||||
-rw-r--r-- | boost/stacktrace/detail/push_options.pp | 31 | ||||
-rw-r--r-- | boost/stacktrace/detail/safe_dump_noop.ipp | 37 | ||||
-rw-r--r-- | boost/stacktrace/detail/safe_dump_posix.ipp | 58 | ||||
-rw-r--r-- | boost/stacktrace/detail/safe_dump_win.ipp | 60 | ||||
-rw-r--r-- | boost/stacktrace/detail/to_hex_array.hpp | 54 | ||||
-rw-r--r-- | boost/stacktrace/detail/unwind_base_impls.hpp | 50 | ||||
-rw-r--r-- | boost/stacktrace/detail/void_ptr_cast.hpp | 46 |
18 files changed, 1646 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 + |