From fd513391ca8f188aefde53fb5a5d7cea4ae6c973 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 30 Nov 2016 10:47:58 +0300 Subject: [PATCH] Async signal safe backend implmented and notes about async-safety were added to the docs. --- build/Jamfile.v2 | 19 +++++++ build/has_backtrace.cpp | 5 ++ build/has_unwind.cpp | 11 ++++ doc/stacktrace.qbk | 12 ++--- example/getting_started.cpp | 2 +- include/boost/stacktrace/const_iterator.hpp | 12 +++-- include/boost/stacktrace/detail/backend.hpp | 13 ++--- include/boost/stacktrace/detail/backend.ipp | 2 +- .../boost/stacktrace/detail/backend_linux.hpp | 39 +++++++++++++- include/boost/stacktrace/frame.hpp | 26 ++++++--- include/boost/stacktrace/stacktrace.hpp | 53 +++++++++++++++---- src/unwind.cpp | 10 ++++ test/Jamfile.v2 | 8 +++ test/test.cpp | 5 +- 14 files changed, 182 insertions(+), 35 deletions(-) create mode 100644 build/has_unwind.cpp create mode 100644 src/unwind.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 0b6c3d2..403a58b 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -12,6 +12,7 @@ project ; lib dl : : shared ; +lib gcc_s : : shared ; lib Dbghelp ; actions mp_simple_run_action @@ -31,6 +32,9 @@ rule mp-run-simple ( sources + : args * : input-files * : requirements * : targe mp-run-simple has_backtrace.cpp : : : : backtrace ; explicit backtrace ; +mp-run-simple has_unwind.cpp : : : : unwind ; +explicit unwind ; + mp-run-simple has_windbg.cpp : : : : WinDbg ; explicit WinDbg ; @@ -62,6 +66,21 @@ lib boost_stacktrace_backtrace boost-install boost_stacktrace_backtrace ; +lib boost_stacktrace_unwind + : # sources + ../src/unwind.cpp + : # requirements + all + linux:dl + shared:BOOST_STACKTRACE_DYN_LINK=1 + [ check-target-builds ../build//unwind : : no ] + : # default build + : # usage-requirements + #shared:BOOST_STACKTRACE_DYN_LINK=1 + ; + +boost-install boost_stacktrace_unwind ; + lib boost_stacktrace_windbg : # sources ../src/windbg.cpp diff --git a/build/has_backtrace.cpp b/build/has_backtrace.cpp index 4a43522..0389e7f 100644 --- a/build/has_backtrace.cpp +++ b/build/has_backtrace.cpp @@ -1,3 +1,8 @@ +// Copyright Antony Polukhin, 2016. +// +// 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) #include #include diff --git a/build/has_unwind.cpp b/build/has_unwind.cpp new file mode 100644 index 0000000..e14843c --- /dev/null +++ b/build/has_unwind.cpp @@ -0,0 +1,11 @@ +// Copyright Antony Polukhin, 2016. +// +// 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) + +#include + +int main() { + +} diff --git a/doc/stacktrace.qbk b/doc/stacktrace.qbk index 1f9283d..e213033 100644 --- a/doc/stacktrace.qbk +++ b/doc/stacktrace.qbk @@ -247,11 +247,11 @@ By default Boost.Stacktrace is a header-only library and it attempts to detect t You can define the following macros to explicitly specify backend that you're willing to use in header-only mode (those macros have no effect if defined *BOOST_STACKTRACE_LINK* or *BOOST_STACKTRACE_DYN_LINK*): [table:configbackend Header only backend specifications - [[Macro name] [Effect] [Platforms] [Uses debug information [footnote This will provide more readable backtraces if the binary is built with debug information.]] [Uses dynamic exports information [footnote This will provide readable function names in backtrace for functions that are exported by the binary.]] [Construction speed] [Async signal safe[footnote Absolutely safe to use that backend in async signal handler.]]] - [[*BOOST_STACKTRACE_USE_LIBUNWIND*] [Use libunwind tracing backend. This is the best known backend for POSIX systems that requires linking with libunwind library.] [POSIX] [yes] [yes] [slow] [no]] - [[*BOOST_STACKTRACE_USE_WINDBG*] [Use Windows specific tracing backend that uses DbgHelp. This is the best and only known backend for Windows platform that requires linking with DbgHelp library.] [Windows] [yes] [yes] [fast] [no]] - [[*BOOST_STACKTRACE_USE_BACKTRACE*] [Use tracing backend that calls POSIX function backtrace. This is a fallback backend for POSIX platforms that requires linking with libdl library.] [POSIX] [no] [yes] [fast] [no]] - [[*BOOST_STACKTRACE_USE_NOOP*] [Use noop tracing backend that does nothing. Use this backend if you wish to disable backtracing, `stacktrace::size()` with that backend always return 0. ] [POSIX and Windows] [no] [no] [noop] [yes]] + [[Macro name] [Effect] [Platforms] [Uses debug information [footnote This will provide more readable backtraces if the binary is built with debug information.]] [Uses dynamic exports information [footnote This will provide readable function names in backtrace for functions that are exported by the binary.]] [Async signal safe[footnote Absolutely safe to construct instances of [classref boost::stacktrace::stacktrace] in async signal handlers using that backend.]]] + [[*BOOST_STACKTRACE_USE_UNWIND*] [Use unwind tracing backend. This is the best known backend for POSIX systems that requires LSB Core Specification 4.1 from OS. Requires linking with libdl library.] [POSIX] [yes] [yes] [Constructors]] + [[*BOOST_STACKTRACE_USE_WINDBG*] [Use Windows specific tracing backend that uses DbgHelp. This is the best and only known backend for Windows platform that requires linking with DbgHelp library.] [Windows] [yes] [yes] [???]] + [[*BOOST_STACKTRACE_USE_BACKTRACE*] [Use tracing backend that calls POSIX function `backtrace`. Requires linking with libdl library.] [POSIX] [no] [yes] [no]] + [[*BOOST_STACKTRACE_USE_NOOP*] [Use noop tracing backend that does nothing. Use this backend if you wish to disable backtracing, `stacktrace::size()` with that backend always return 0. ] [POSIX and Windows] [no] [no] [all functions]] ] @@ -264,7 +264,7 @@ You may use the following macros to improve build times or to be able to switch If one of the link macros is defined, you have to manually link your binary with one of the libraries that has the backend implementation: -* boost_stacktrace_libunwind +* boost_stacktrace_unwind * boost_stacktrace_windbg * boost_stacktrace_backtrace * boost_stacktrace_noop diff --git a/example/getting_started.cpp b/example/getting_started.cpp index 6b26b1f..14b6688 100644 --- a/example/getting_started.cpp +++ b/example/getting_started.cpp @@ -99,7 +99,7 @@ void my_terminate_handler() { void my_signal_handler(int signum) { boost::stacktrace::stacktrace bt; if (bt) { - std::cerr << "Signal " << signum << ", backtrace:\n" << boost::stacktrace::stacktrace() << '\n'; // ``[footnote Strictly speaking this code is not async-signal-safe, but we have SIGSEGV already it could hardly become worse. [link boost_stacktrace.build_macros_and_backends Section "Build, Macros and Backends"] describes async-signal-safe backends, so if you will use the noop backend code becomes absolutely valid as that backens always returns 0 frames and `operator<<` will be never called. ]`` + std::cerr << "Signal " << signum << ", backtrace:\n" << boost::stacktrace::stacktrace() << '\n'; // ``[footnote Strictly speaking this code is not async-signal-safe, because it uses std::cerr. [link boost_stacktrace.build_macros_and_backends Section "Build, Macros and Backends"] describes async-signal-safe backends, so if you will use the noop backend code becomes absolutely valid as that backens always returns 0 frames and `operator<<` will be never called. ]`` } std::abort(); } diff --git a/include/boost/stacktrace/const_iterator.hpp b/include/boost/stacktrace/const_iterator.hpp index 919d7b0..4771fc1 100644 --- a/include/boost/stacktrace/const_iterator.hpp +++ b/include/boost/stacktrace/const_iterator.hpp @@ -20,17 +20,22 @@ namespace boost { namespace stacktrace { + +#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED +/// Random access iterator over frames that returns boost::stacktrace::frame on dereference +class const_iterator: implementation_details {}; + +#else + // Forward declarations class stacktrace; -/// Random access iterator over frames that returns `frame` on dereference. class const_iterator: public boost::iterator_facade< const_iterator, frame, boost::random_access_traversal_tag, frame> { -/// @cond typedef boost::iterator_facade< const_iterator, frame, @@ -73,9 +78,10 @@ class const_iterator: public boost::iterator_facade< BOOST_ASSERT(impl_ == it.impl_); return it.frame_no_ - frame_no_; } -/// @endcond }; +#endif // #ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED + }} // namespace boost::stacktrace #endif // BOOST_STACKTRACE_CONST_ITERATOR_HPP diff --git a/include/boost/stacktrace/detail/backend.hpp b/include/boost/stacktrace/detail/backend.hpp index 438cd3d..91f56cd 100644 --- a/include/boost/stacktrace/detail/backend.hpp +++ b/include/boost/stacktrace/detail/backend.hpp @@ -25,20 +25,21 @@ #endif // Backend autodetection -#if !defined(BOOST_STACKTRACE_USE_NOOP) && !defined(BOOST_STACKTRACE_USE_WINDBG) && !defined(BOOST_STACKTRACE_USE_LIBUNWIND) \ - && !defined(BOOST_STACKTRACE_USE_BACKTRACE) &&!defined(BOOST_STACKTRACE_USE_HEADER) +#if !defined(BOOST_STACKTRACE_USE_NOOP) && !defined(BOOST_STACKTRACE_USE_WINDBG) && !defined(BOOST_STACKTRACE_USE_UNWIND) \ + && !defined(BOOST_STACKTRACE_USE_BACKTRACE) && !defined(BOOST_STACKTRACE_USE_HEADER) #if defined(__has_include) && (!defined(__GNUC__) || __GNUC__ > 4 || BOOST_CLANG) -# if __has_include() -# define BOOST_STACKTRACE_USE_BACKTRACE -# elif __has_include("Dbgeng.h") +# if __has_include("Dbgeng.h") # define BOOST_STACKTRACE_USE_WINDBG +# else +# define BOOST_STACKTRACE_USE_UNWIND # endif #else # if defined(BOOST_WINDOWS) # define BOOST_STACKTRACE_USE_WINDBG # else -# define BOOST_STACKTRACE_USE_BACKTRACE +# define BOOST_STACKTRACE_USE_UNWIND +//# define BOOST_STACKTRACE_USE_BACKTRACE # endif #endif diff --git a/include/boost/stacktrace/detail/backend.ipp b/include/boost/stacktrace/detail/backend.ipp index 1b7fda2..a78a898 100644 --- a/include/boost/stacktrace/detail/backend.ipp +++ b/include/boost/stacktrace/detail/backend.ipp @@ -18,7 +18,7 @@ # include #elif defined(BOOST_STACKTRACE_USE_WINDBG) # include -#elif defined(BOOST_STACKTRACE_USE_BACKTRACE) +#elif defined(BOOST_STACKTRACE_USE_BACKTRACE) || defined(BOOST_STACKTRACE_USE_UNWIND) # include #else # error No suitable backtrace backend found diff --git a/include/boost/stacktrace/detail/backend_linux.hpp b/include/boost/stacktrace/detail/backend_linux.hpp index a394ea7..f846d0b 100644 --- a/include/boost/stacktrace/detail/backend_linux.hpp +++ b/include/boost/stacktrace/detail/backend_linux.hpp @@ -18,6 +18,10 @@ #include #include +#if defined(BOOST_STACKTRACE_USE_UNWIND) +#include +#endif + #include #include #include @@ -163,6 +167,32 @@ static inline std::string try_demangle(const char* mangled) { return res; } + + + +#if defined(BOOST_STACKTRACE_USE_UNWIND) +struct unwind_state { + void** current; + void** end; +}; + +inline _Unwind_Reason_Code unwind_callback(struct _Unwind_Context* context, void* arg) { + unwind_state* state = static_cast(arg); + *state->current = reinterpret_cast( + _Unwind_GetIP(context) + ); + + ++state->current; + if (!*(state->current - 1) || state->current == state->end) { + return _URC_END_OF_STACK; + } + return _URC_NO_REASON; +} +#endif + + + + backend::backend(void* memory, std::size_t size, std::size_t& hash_code) BOOST_NOEXCEPT : data_(static_cast(memory)) { @@ -170,11 +200,18 @@ backend::backend(void* memory, std::size_t size, std::size_t& hash_code) BOOST_N data_->frames_count = 0; hash_code = 0; - // TODO: Not async signal safe. Use _Unwind_Backtrace, _Unwind_GetIP +#if defined(BOOST_STACKTRACE_USE_UNWIND) + unwind_state state = { data_->buffer, data_->buffer + data_->frames_count }; + _Unwind_Backtrace(&unwind_callback, &state); + data_->frames_count = state.current - data_->buffer; +#elif defined(BOOST_STACKTRACE_USE_BACKTRACE) data_->frames_count = ::backtrace(data_->buffer, (size - sizeof(backtrace_holder)) / sizeof(void*)); if (data_->buffer[data_->frames_count - 1] == 0) { -- data_->frames_count; } +#else +# error No stacktrace backend defined. Define BOOST_STACKTRACE_USE_UNWIND or BOOST_STACKTRACE_USE_BACKTRACE +#endif hash_code = boost::hash_range(data_->buffer, data_->buffer + data_->frames_count); } diff --git a/include/boost/stacktrace/frame.hpp b/include/boost/stacktrace/frame.hpp index 25e22b5..88791a1 100644 --- a/include/boost/stacktrace/frame.hpp +++ b/include/boost/stacktrace/frame.hpp @@ -35,33 +35,43 @@ public: frame() = delete; /// @brief Copy constructs frame. - /// @throws Nothing. /// /// @b Complexity: O(1). + /// + /// @b Async-Handler-Safety: Safe. + /// @throws Nothing. frame(const frame&) = default; /// @brief Copy assigns frame. - /// @throws Nothing. /// /// @b Complexity: O(1). + /// + /// @b Async-Handler-Safety: Safe. + /// @throws Nothing. frame& operator=(const frame&) = default; #endif /// @brief Constructs frame that can extract information from addr at runtime. - /// @throws Nothing. /// /// @b Complexity: O(1). + /// + /// @b Async-Handler-Safety: Safe. + /// @throws Nothing. explicit frame(const void* addr) BOOST_NOEXCEPT : addr_(addr) {} /// @returns Name of the frame (function name in a human readable form). + /// + /// @b Async-Handler-Safety: Unsafe. /// @throws std::bad_alloc if not enough memory to construct resulting string. std::string name() const { return boost::stacktrace::detail::backend::get_name(address()); } /// @returns Address of the frame function. + /// + /// @b Async-Handler-Safety: Safe. /// @throws Nothing. const void* address() const BOOST_NOEXCEPT { return addr_; @@ -70,18 +80,22 @@ public: /// @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 Async-Handler-Safety: Unsafe. std::string source_file() const { return boost::stacktrace::detail::backend::get_source_file(address()); } /// @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 Async-Handler-Safety: Unsafe. std::size_t source_line() const { return boost::stacktrace::detail::backend::get_source_line(address()); } }; -/// Comparison operators that provide platform dependant ordering and have O(1) complexity. +/// Comparison operators that provide platform dependant ordering and have O(1) complexity; are Async-Handler-Safe. inline bool operator< (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() < rhs.address(); } inline bool operator> (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return rhs < lhs; } inline bool operator<=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); } @@ -89,12 +103,12 @@ inline bool operator>=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { retu inline bool operator==(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() == rhs.address(); } inline bool operator!=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); } -/// Hashing support, O(1) complexity. +/// Hashing support, O(1) complexity; Async-Handler-Safe. inline std::size_t hash_value(const frame& f) BOOST_NOEXCEPT { return reinterpret_cast(f.address()); } -/// Outputs stacktrace::frame in a human readable format to output stream. +/// Outputs stacktrace::frame in a human readable format to output stream; unsafe to use in async handlers. template std::basic_ostream& operator<<(std::basic_ostream& os, const frame& f) { os << f.name(); diff --git a/include/boost/stacktrace/stacktrace.hpp b/include/boost/stacktrace/stacktrace.hpp index 5b96b3e..b4f550d 100644 --- a/include/boost/stacktrace/stacktrace.hpp +++ b/include/boost/stacktrace/stacktrace.hpp @@ -36,29 +36,34 @@ class stacktrace { public: typedef frame reference; - /// @brief Random access iterator that returns frame. typedef boost::stacktrace::const_iterator iterator; - typedef iterator const_iterator; + typedef boost::stacktrace::const_iterator const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; /// @brief Stores the current function call sequence inside the class. /// - /// @b Complexity: O(N) where N is call seaquence length, O(1) for noop backend. + /// @b Complexity: O(N) where N is call sequence length, O(1) for noop backend. + /// + /// @b Async-Handler-Safety: Depends on backend, see "Build, Macros and Backends" section. BOOST_FORCEINLINE stacktrace() BOOST_NOEXCEPT : impl_() , hash_code_() , back_(&impl_, sizeof(impl_), hash_code_) {} - /// @b Complexity: O(1) + /// @b Complexity: O(st.size()) + /// + /// @b Async-Handler-Safety: Safe. stacktrace(const stacktrace& st) BOOST_NOEXCEPT : impl_() , hash_code_(st.hash_code_) , back_(st.back_, &impl_) {} - /// @b Complexity: O(1) + /// @b Complexity: O(st.size()) + /// + /// @b Async-Handler-Safety: Safe. stacktrace& operator=(const stacktrace& st) BOOST_NOEXCEPT { hash_code_ = st.hash_code_; back_ = back_; @@ -66,12 +71,16 @@ public: return *this; } - /// @b Complexity: O(N) for libunwind, O(1) for other backends. + /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. ~stacktrace() BOOST_NOEXCEPT {} /// @returns Number of function names stored inside the class. /// /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. std::size_t size() const BOOST_NOEXCEPT { return back_.size(); } @@ -82,27 +91,45 @@ public: /// @returns frame that references the actual frame info, stored inside *this. /// /// @b Complexity: Amortized O(1), O(1) for noop backend. + /// + /// @b Async-Handler-Safety: Safe. frame operator[](std::size_t frame_no) const BOOST_NOEXCEPT { return *(cbegin() + frame_no); } /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. const_iterator begin() const BOOST_NOEXCEPT { return const_iterator(&back_, 0); } /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. const_iterator cbegin() const BOOST_NOEXCEPT { return const_iterator(&back_, 0); } /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. const_iterator end() const BOOST_NOEXCEPT { return const_iterator(&back_, size()); } /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(&back_, size()); } /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, 0) ); } /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, 0) ); } /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. const_reverse_iterator rend() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, size()) ); } /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. const_reverse_iterator crend() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, size()) ); } @@ -110,11 +137,15 @@ public: /// @returns `true` if `this->size() != 0` /// /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT() /// @brief Compares stacktraces for less, order is platform dependant. /// /// @b Complexity: Amortized O(1); worst case O(size()) + /// + /// @b Async-Handler-Safety: Safe. bool operator< (const stacktrace& rhs) const BOOST_NOEXCEPT { return hash_code_ < rhs.hash_code_ || (hash_code_ == rhs.hash_code_ && back_ < rhs.back_); } @@ -122,6 +153,8 @@ public: /// @brief Compares stacktraces for equality. /// /// @b Complexity: Amortized O(1); worst case O(size()) + /// + /// @b Async-Handler-Safety: Safe. bool operator==(const stacktrace& rhs) const BOOST_NOEXCEPT { return hash_code_ == rhs.hash_code_ && back_ == rhs.back_; } @@ -129,6 +162,8 @@ public: /// @brief Returns hashed code of the stacktrace. /// /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe. std::size_t hash_code() const BOOST_NOEXCEPT { return hash_code_; } /// @cond @@ -137,18 +172,18 @@ public: }; -/// Comparison operators that provide platform dependant ordering and have amortized O(1) complexity; O(size()) worst case complexity. +/// Comparison operators that provide platform dependant ordering and have amortized O(1) complexity; O(size()) worst case complexity; are Async-Handler-Safe. inline bool operator> (const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return rhs < lhs; } inline bool operator<=(const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); } inline bool operator>=(const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); } inline bool operator!=(const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); } -/// Hashing support, O(1) complexity. +/// Hashing support, O(1) complexity; Async-Handler-Safe. inline std::size_t hash_value(const stacktrace& st) BOOST_NOEXCEPT { return st.hash_code(); } -/// Outputs stacktrace in a human readable format to output stream. +/// Outputs stacktrace in a human readable format to output stream; unsafe to use in async handlers. template std::basic_ostream& operator<<(std::basic_ostream& os, const stacktrace& bt) { const std::streamsize w = os.width(); diff --git a/src/unwind.cpp b/src/unwind.cpp new file mode 100644 index 0000000..0ef19da --- /dev/null +++ b/src/unwind.cpp @@ -0,0 +1,10 @@ +// Copyright Antony Polukhin, 2016. +// +// 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) + +#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS +#define BOOST_STACKTRACE_USE_UNWIND +#define BOOST_STACKTRACE_LINK +#include diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index dd94e2d..c819ede 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -6,6 +6,7 @@ # lib dl : : shared ; +lib gcc_s ; lib Dbghelp ; project @@ -19,15 +20,18 @@ project local BT_DEPS = linux:dl [ check-target-builds ../build//backtrace : : no ] ; +local UNWD_DEPS = linux:dl [ check-target-builds ../build//unwind : : no ] ; local WIND_DEPS = Dbghelp [ check-target-builds ../build//WinDbg : : no ] ; local NOOP_DEPS = ; local AUTO_DEPS = linux:dl [ check-target-builds ../build//WinDbg : Dbghelp ] ; local LINKSHARED_BT = shared BOOST_STACKTRACE_DYN_LINK /boost/stacktrace//boost_stacktrace_backtrace $(BT_DEPS) ; +local LINKSHARED_UNWD = shared BOOST_STACKTRACE_DYN_LINK /boost/stacktrace//boost_stacktrace_unwind $(UNWD_DEPS) ; local LINKSHARED_WIND = shared BOOST_STACKTRACE_DYN_LINK /boost/stacktrace//boost_stacktrace_windbg $(WIND_DEPS) ; local LINKSHARED_NOOP = shared BOOST_STACKTRACE_DYN_LINK /boost/stacktrace//boost_stacktrace_noop $(NOOP_DEPS) ; lib test_impl_lib_backtrace : test_impl.cpp : $(LINKSHARED_BT) ; +lib test_impl_lib_unwind : test_impl.cpp : $(LINKSHARED_UNWD) ; lib test_impl_lib_windbg : test_impl.cpp : $(LINKSHARED_WIND) ; lib test_impl_lib_noop : test_impl.cpp : $(LINKSHARED_NOOP) ; @@ -35,22 +39,26 @@ test-suite stacktrace_tests : # Header only tests [ run test.cpp test_impl.cpp : : : BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : backtrace_ho ] + [ run test.cpp test_impl.cpp : : : BOOST_STACKTRACE_USE_UNWIND $(UNWD_DEPS) : unwind_ho ] [ run test.cpp test_impl.cpp : : : BOOST_STACKTRACE_USE_WINDBG $(WIND_DEPS) : windbg_ho ] [ run test_noop.cpp test_impl.cpp : : : BOOST_STACKTRACE_USE_NOOP $(NOOP_DEPS) : noop_ho ] [ run test.cpp test_impl.cpp : : : $(AUTO_DEPS) : autodetect_ho ] # Test with shared linked backends [ run test.cpp : : : .//test_impl_lib_backtrace $(LINKSHARED_BT) : backtrace_lib ] + [ run test.cpp : : : .//test_impl_lib_unwind $(LINKSHARED_UNWD) : unwind_lib ] [ run test.cpp : : : .//test_impl_lib_windbg $(LINKSHARED_WIND) : windbg_lib ] [ run test_noop.cpp : : : .//test_impl_lib_noop $(LINKSHARED_NOOP) : noop_lib ] # Making sure that the examples work [ run ../example/getting_started.cpp : : : BOOST_ENABLE_ASSERT_DEBUG_HANDLER $(LINKSHARED_BT) : backtrace_getting_started ] + [ run ../example/getting_started.cpp : : : BOOST_ENABLE_ASSERT_DEBUG_HANDLER $(LINKSHARED_UNWD) : unwind_getting_started ] [ run ../example/getting_started.cpp : : : BOOST_ENABLE_ASSERT_DEBUG_HANDLER $(LINKSHARED_WIND) : windbg_getting_started ] [ run ../example/getting_started.cpp : : : BOOST_ENABLE_ASSERT_DEBUG_HANDLER $(LINKSHARED_NOOP) : noop_getting_started ] [ run ../example/getting_started.cpp : : : BOOST_ENABLE_ASSERT_DEBUG_HANDLER $(AUTO_DEPS) : autodetect_getting_started ] [ run ../example/throwing_st.cpp : : : $(LINKSHARED_BT) : backtrace_throwing_st ] + [ run ../example/throwing_st.cpp : : : $(LINKSHARED_UNWD) : unwind_throwing_st ] [ run ../example/throwing_st.cpp : : : $(LINKSHARED_WIND) : windbg_throwing_st ] [ run ../example/throwing_st.cpp : : : $(LINKSHARED_NOOP) : noop_throwing_st ] [ run ../example/throwing_st.cpp : : : $(AUTO_DEPS) : autodetect_throwing_st ] diff --git a/test/test.cpp b/test/test.cpp index a7afc3a..b1a25a7 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -30,8 +30,9 @@ void test_deeply_nested_namespaces() { std::cout << ss.str() << '\n'; BOOST_TEST(ss.str().find("main") != std::string::npos); -#if defined(BOOST_STACKTRACE_DYN_LINK) || !defined(BOOST_STACKTRACE_USE_BACKTRACE) - BOOST_TEST(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos); +#if defined(BOOST_STACKTRACE_DYN_LINK) + BOOST_TEST(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos + || ss.str().find("return_from_nested_namespaces") != std::string::npos); #endif stacktrace ns1 = return_from_nested_namespaces();