diff --git a/build/Jamfile.v2 b/build/Jamfile.v2
index f78d968..1aa3d19 100644
--- a/build/Jamfile.v2
+++ b/build/Jamfile.v2
@@ -6,7 +6,7 @@
#
project boost/stacktrace ;
-lib dl ;
+lib dl : : shared ;
lib unwind : : shared ;
lib Dbghelp ;
@@ -24,24 +24,23 @@ rule mp-run-simple ( sources + : args * : input-files * : requirements * : targe
alias $(target-name) : $(target-name).output ;
}
-mp-run-simple has_libunwind.cpp : : : : has_libunwind ;
-explicit has_libunwind ;
+mp-run-simple has_libunwind.cpp : : : : libunwind ;
+explicit libunwind ;
-mp-run-simple has_backtrace.cpp : : : : has_backtrace ;
-explicit has_backtrace ;
+mp-run-simple has_backtrace.cpp : : : : backtrace ;
+explicit backtrace ;
-mp-run-simple has_windbg.cpp : : : : has_windbg ;
-explicit has_windbg ;
+mp-run-simple has_windbg.cpp : : : : WinDbg ;
+explicit WinDbg ;
lib boost_stacktrace_libunwind
: # sources
- ../src/stacktrace.cpp
+ ../src/libunwind.cpp
: # requirements
all
- static
BOOST_STACKTRACE_USE_LIBUNWIND=1
unwind
- [ check-target-builds ../build//has_libunwind "has libunwind" : : no ]
+ [ check-target-builds ../build//libunwind : : no ]
: # default build
: # usage-requirements
shared:BOOST_TEST_DYN_LINK=1
@@ -51,12 +50,12 @@ boost-install boost_stacktrace_libunwind ;
lib boost_stacktrace_backtrace
: # sources
- ../src/stacktrace.cpp
+ ../src/backtrace.cpp
: # requirements
all
BOOST_STACKTRACE_USE_BACKTRACE=1
dl
- [ check-target-builds ../build//has_backtrace "has ::backtrace()" : : no ]
+ [ check-target-builds ../build//backtrace : : no ]
: # default build
: # usage-requirements
shared:BOOST_TEST_DYN_LINK=1
@@ -66,12 +65,12 @@ boost-install boost_stacktrace_backtrace ;
lib boost_stacktrace_windbg
: # sources
- ../src/stacktrace.cpp
+ ../src/windbg.cpp
: # requirements
all
Dbghelp
BOOST_STACKTRACE_USE_WINDBG=1
- [ check-target-builds ../build//has_windbg "has WinDbg" : : no ]
+ [ check-target-builds ../build//WinDbg : : no ]
: # default build
: # usage-requirements
shared:BOOST_TEST_DYN_LINK=1
diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2
new file mode 100644
index 0000000..e4110a9
--- /dev/null
+++ b/doc/Jamfile.v2
@@ -0,0 +1,34 @@
+# Copyright Antony Polukhin 2016.
+# Use, modification, and distribution are
+# subject to 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)
+
+using quickbook ;
+import boostbook : boostbook ;
+import doxygen ;
+
+doxygen autodoc
+ :
+ [ glob ../../../boost/stacktrace.hpp ]
+ :
+ EXTRACT_ALL=NO
+ HIDE_UNDOC_MEMBERS=YES
+ EXTRACT_PRIVATE=NO
+ ENABLE_PREPROCESSING=YES
+ EXPAND_ONLY_PREDEF=YES
+ MACRO_EXPANSION=YES
+ "PREDEFINED=\"stl_type_info=std::type_info\" \\
+ \"BOOST_STACKTRACE_FUNCTION\""
+ "boost.doxygen.reftitle=Boost.Stacktrace Header Reference"
+ ;
+
+xml stacktrace : stacktrace.qbk : autodoc ;
+boostbook standalone
+ :
+ stacktrace
+ :
+ boost.root=http://www.boost.org/doc/libs/1_61_0
+# boost.root=../../../..
+ pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
+ ;
+
diff --git a/doc/stacktrace.qbk b/doc/stacktrace.qbk
new file mode 100644
index 0000000..524a446
--- /dev/null
+++ b/doc/stacktrace.qbk
@@ -0,0 +1,28 @@
+[library Boost.Stacktrace
+ [quickbook 1.6]
+ [version 1.0]
+ [copyright 2016 Antony Polukhin]
+ [category Language Features Emulation]
+ [license
+ 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])
+ ]
+]
+
+[section Motivation]
+How to display the call sequence in C++? From what function was called the current function? What call sequence lead to an exception?
+
+Boost.Stacktrace library is a simple library that provides information about call sequence in human readable form.
+
+[warning This is not an official Boost library! It wasn't reviewed and can't be downloaded from www.boost.org. This library is available to the community to know real interest and get comments for refinement. The intention is to submit library to formal review, if community think that it is interesting!]
+
+[endsect]
+
+[section Getting Started]
+
+[endsect]
+
+
+[xinclude autodoc.xml]
+
diff --git a/example/getting_started.cpp b/example/getting_started.cpp
new file mode 100644
index 0000000..2dff3ea
--- /dev/null
+++ b/example/getting_started.cpp
@@ -0,0 +1,58 @@
+// 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
+struct events {
+ typedef boost::function callback_type;
+
+ static void from_keyboard(callback_type callback);
+ static void from_network(callback_type callback);
+};
+
+
+#include
+#include
+BOOST_NOINLINE void validate_positive(float f) {
+ if (f < 0.f) {
+ std::cerr << "Negative number " << f << " detected. Call stack:\n"
+ << boost::stacktrace::stacktrace() << '\n';
+ }
+}
+
+
+
+
+boost::function on_keyboard;
+boost::function on_network;
+
+BOOST_NOINLINE void keyboard_event() {
+ on_keyboard(-0.1f);
+}
+
+BOOST_NOINLINE void network_event() {
+ on_network(1.0f);
+}
+
+void events::from_keyboard(events::callback_type callback) {
+ on_keyboard = callback;
+}
+
+void events::from_network(events::callback_type callback) {
+ on_network = callback;
+}
+
+
+
+int main() {
+ events::from_keyboard(&validate_positive);
+ events::from_network(&validate_positive);
+
+ keyboard_event();
+ network_event();
+}
+
+
+
diff --git a/include/boost/stacktrace.hpp b/include/boost/stacktrace.hpp
index 004ced8..b5e8597 100644
--- a/include/boost/stacktrace.hpp
+++ b/include/boost/stacktrace.hpp
@@ -5,32 +5,49 @@
// http://www.boost.org/LICENSE_1_0.txt)
-#pragma once
-
#include
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
-#include
#include
#include
+#include
+
+/// @cond
+#if defined(BOOST_STACKTRACE_HEADER_ONLY)
+# define BOOST_STACKTRACE_FUNCTION inline
+#else
+# define BOOST_STACKTRACE_FUNCTION
+#endif
+/// @endcond
namespace boost { namespace stacktrace {
class stacktrace {
- typename boost::aligned_storage::type data_;
-
+ BOOST_STATIC_CONSTEXPR std::size_t max_implementation_size = sizeof(void*) * 110u;
+ boost::aligned_storage::type impl_;
public:
- BOOST_STATIC_CONSTEXPR std::size_t max_symbol_width = 256;
- typedef boost::array frame_t;
+ /// Stores the current function call sequence inside the class
+ BOOST_STACKTRACE_FUNCTION stacktrace() BOOST_NOEXCEPT;
- stacktrace() BOOST_NOEXCEPT;
- stacktrace(const stacktrace& bt) BOOST_NOEXCEPT;
- stacktrace& operator=(const stacktrace& bt) BOOST_NOEXCEPT;
- ~stacktrace() BOOST_NOEXCEPT;
+ BOOST_STACKTRACE_FUNCTION stacktrace(const stacktrace& bt) BOOST_NOEXCEPT;
+ BOOST_STACKTRACE_FUNCTION stacktrace& operator=(const stacktrace& bt) BOOST_NOEXCEPT;
+ BOOST_STACKTRACE_FUNCTION ~stacktrace() BOOST_NOEXCEPT;
- std::size_t size() const BOOST_NOEXCEPT;
- frame_t operator[](std::size_t frame) const BOOST_NOEXCEPT;
+ /// @returns Number of function names stored inside the class.
+ BOOST_STACKTRACE_FUNCTION std::size_t size() const BOOST_NOEXCEPT;
+
+ /// @param frame Zero based index of function to return. 0
+ /// is the function index where stacktrace was constructed and
+ /// index close to this->size() contains function `main()`.
+ /// @returns Function name in a human readable form.
+ /// @throws std::bad_alloc if not enough memory.
+ BOOST_STACKTRACE_FUNCTION std::string operator[](std::size_t frame) const;
};
+
+/// Outputs stacktrace in a human readable format to output stream.
template
std::basic_ostream& operator<<(std::basic_ostream& os, const stacktrace& bt) {
const std::streamsize w = os.width();
@@ -39,7 +56,14 @@ std::basic_ostream& operator<<(std::basic_ostream& operator<<(std::basic_ostream
+#endif
+/// @endcond
diff --git a/include/boost/stacktrace/detail/stacktrace.ipp b/include/boost/stacktrace/detail/stacktrace.ipp
index d6e00a6..ba5bd76 100644
--- a/include/boost/stacktrace/detail/stacktrace.ipp
+++ b/include/boost/stacktrace/detail/stacktrace.ipp
@@ -4,64 +4,67 @@
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
-#include
-#include
+#include
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+#include
#include
#if BOOST_OS_WINDOWS
# include
-//#elif defined(__has_include) && (!defined(__GNUC__) || __GNUC__ > 4)
-//# if __has_include()
-//# include
-//# endif
#elif defined(BOOST_STACKTRACE_USE_LIBUNWIND)
# include
#elif defined(BOOST_STACKTRACE_USE_BACKTRACE)
# include
+#elif defined(__has_include) && (!defined(__GNUC__) || __GNUC__ > 4)
+# if __has_include()
+# include
+# elif __has_include()
+# include
+# endif
#else
# error No suitable backtrace backend found
#endif
namespace boost { namespace stacktrace {
-using boost::stacktrace::detail::backtrace_holder;
-
template
-inline backtrace_holder& to_bt(T& data) BOOST_NOEXCEPT {
- return *reinterpret_cast(&data);
+inline boost::stacktrace::detail::backtrace_holder& to_bt(T& data) BOOST_NOEXCEPT {
+ return *reinterpret_cast(&data);
}
template
-inline const backtrace_holder& to_bt(const T& data) BOOST_NOEXCEPT {
- return *reinterpret_cast(&data);
+inline const boost::stacktrace::detail::backtrace_holder& to_bt(const T& data) BOOST_NOEXCEPT {
+ return *reinterpret_cast(&data);
}
stacktrace::stacktrace() BOOST_NOEXCEPT {
- new (&data_) backtrace_holder();
+ new (&impl_) boost::stacktrace::detail::backtrace_holder();
}
stacktrace::stacktrace(const stacktrace& bt) BOOST_NOEXCEPT {
- new (&data_) backtrace_holder(to_bt(bt.data_));
+ new (&impl_) boost::stacktrace::detail::backtrace_holder(to_bt(bt.impl_));
}
stacktrace& stacktrace::operator=(const stacktrace& bt) BOOST_NOEXCEPT {
- to_bt(data_) = to_bt(bt.data_);
+ to_bt(impl_) = to_bt(bt.impl_);
return *this;
}
stacktrace::~stacktrace() BOOST_NOEXCEPT {
- BOOST_STATIC_ASSERT_MSG(sizeof(data_) >= sizeof(backtrace_holder), "Too small storage for holding backtrace");
- to_bt(data_).~backtrace_holder();
+ BOOST_STATIC_ASSERT_MSG(sizeof(impl_) >= sizeof(boost::stacktrace::detail::backtrace_holder), "Too small storage for holding backtrace");
+ to_bt(impl_).~backtrace_holder();
}
std::size_t stacktrace::size() const BOOST_NOEXCEPT {
- return to_bt(data_).size();
+ return to_bt(impl_).size();
}
-stacktrace::frame_t stacktrace::operator[](std::size_t frame) const BOOST_NOEXCEPT {
- return to_bt(data_).get_frame(frame);
+std::string stacktrace::operator[](std::size_t frame) const BOOST_NOEXCEPT {
+ return to_bt(impl_).get_frame(frame);
}
diff --git a/include/boost/stacktrace/detail/stacktrace_helpers.hpp b/include/boost/stacktrace/detail/stacktrace_helpers.hpp
index cbfa5ad..29bf3ce 100644
--- a/include/boost/stacktrace/detail/stacktrace_helpers.hpp
+++ b/include/boost/stacktrace/detail/stacktrace_helpers.hpp
@@ -1,9 +1,20 @@
+// 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
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
+
#include
#include
#include
namespace boost { namespace stacktrace { namespace detail {
-
+/*
BOOST_STATIC_CONSTEXPR char to_hex_array[] = "0123456789ABCDEF";
template
@@ -28,6 +39,6 @@ inline boost::array to_hex(T addr) BOOST_NOEXCE
}
return ret;
-}
+}*/
}}} // namespace boost::stacktrace::detail
diff --git a/include/boost/stacktrace/detail/stacktrace_libunwind.hpp b/include/boost/stacktrace/detail/stacktrace_libunwind.hpp
index 8033ec7..9adc80b 100644
--- a/include/boost/stacktrace/detail/stacktrace_libunwind.hpp
+++ b/include/boost/stacktrace/detail/stacktrace_libunwind.hpp
@@ -4,77 +4,93 @@
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+#include
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
-#include
#include
#include
#include
+#include
+#include
#define UNW_LOCAL_ONLY
#include
namespace boost { namespace stacktrace { namespace detail {
-typedef boost::stacktrace::stacktrace::frame_t frame_t;
-
struct backtrace_holder {
- mutable unw_context_t uc;
+ BOOST_STATIC_CONSTEXPR std::size_t skip_frames = 1u;
+ std::vector frames;
backtrace_holder() BOOST_NOEXCEPT {
- BOOST_VERIFY(unw_getcontext(&uc) == 0);
+ unw_context_t uc;
+ if (unw_getcontext(&uc) != 0) {
+ return;
+ }
+
+ unw_cursor_t cursor;
+ if (unw_init_local(&cursor, &uc) != 0) {
+ return;
+ }
+
+ for (std::size_t i = 0; i < skip_frames; ++i) {
+ if (unw_step(&cursor) <= 0) {
+ return;
+ }
+ }
+
+ BOOST_TRY {
+ while (unw_step(&cursor) > 0){
+ frames.push_back(get_frame_impl(cursor));
+ }
+ } BOOST_CATCH(...) {}
+ BOOST_CATCH_END
}
std::size_t size() const BOOST_NOEXCEPT {
- std::size_t frames = 0;
- unw_cursor_t cursor;
- BOOST_VERIFY(unw_init_local(&cursor, &uc) >= 0);
- while (unw_step(&cursor) > 0) ++frames;
-
- return frames - 1;
+ return frames.size();
}
- frame_t get_frame(std::size_t frame) const BOOST_NOEXCEPT {
- frame_t name = {"??"};
- name.back() = '\0';
- unw_cursor_t cursor;
+ std::string get_frame(std::size_t frame) const {
+ return frames[frame];
+ }
+
+ static std::string get_frame_impl(unw_cursor_t& cursor) {
+ std::string res;
unw_word_t offp;
+ char data[128];
+ const int ret = unw_get_proc_name (&cursor, data, sizeof(data) / sizeof(char), &offp);
- const int ret_init = unw_init_local(&cursor, &uc);
- BOOST_VERIFY(ret_init == 0);
- if (ret_init == 0 && unw_step(&cursor) == 0) {
- return name;
- }
-
- while (frame) {
- if (unw_step(&cursor) == 0) {
- return name;
- }
-
- --frame;
- }
-
- const int ret = unw_get_proc_name (&cursor, name.data(), sizeof(name), &offp);
- if (ret == 0 && name[0]) {
- boost::core::scoped_demangled_name demangled(name.data());
- if (demangled.get()) {
- std::strncpy(name.data(), demangled.get(), name.size() - 1);
- }
-
- std::strncat(name.data(), " +", name.size() - 1);
- std::strncat(name.data(), to_hex(offp).data(), name.size() - 1);
+ if (ret == -UNW_ENOMEM) {
+ res.resize(sizeof(data) * 2);
+ do {
+ const int ret2 = unw_get_proc_name(&cursor, &res[0], res.size(), &offp);
+ if (ret2 == -UNW_ENOMEM) {
+ res.resize(res.size() * 2);
+ } else if (ret2 == 0) {
+ break;
+ } else {
+ res = data;
+ return res;
+ }
+ } while(1);
+ } else if (ret == 0) {
+ res = data;
} else {
- unw_proc_info_t pi;
- const int new_ret = unw_get_proc_info(&cursor, &pi);
- if (new_ret == 0 && pi.start_ip) {
- std::strncpy(name.data(), to_hex(pi.start_ip).data(), name.size() - 1);
- } else {
- std::strncpy(name.data(), "??", name.size() - 1);
- }
+ return res;
}
- return name;
+ boost::core::scoped_demangled_name demangled(res.data());
+ if (demangled.get()) {
+ res = demangled.get();
+ } else {
+ res.resize( std::strlen(res.data()) ); // Note: here res is \0 terminated, but size() not equal to strlen
+ }
+
+ return res;
}
};
}}} // namespace boost::stacktrace::detail
-
diff --git a/include/boost/stacktrace/detail/stacktrace_linux.hpp b/include/boost/stacktrace/detail/stacktrace_linux.hpp
index 5bfd974..75e1d50 100644
--- a/include/boost/stacktrace/detail/stacktrace_linux.hpp
+++ b/include/boost/stacktrace/detail/stacktrace_linux.hpp
@@ -4,6 +4,10 @@
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+#include
+#ifdef BOOST_HAS_PRAGMA_ONCE
+# pragma once
+#endif
#include
#include
@@ -11,48 +15,51 @@
#include
#include
-#include
-#include
namespace boost { namespace stacktrace { namespace detail {
-typedef boost::stacktrace::stacktrace::frame_t frame_t;
-
struct backtrace_holder {
std::size_t frames_count;
BOOST_STATIC_CONSTEXPR std::size_t max_size = 100u;
void* buffer[max_size];
- backtrace_holder() BOOST_NOEXCEPT {
+#ifdef BOOST_STACKTRACE_HEADER_ONLY
+ BOOST_STATIC_CONSTEXPR std::size_t skip_frames = 0u;
+#else
+ BOOST_STATIC_CONSTEXPR std::size_t skip_frames = 1u;
+#endif
+
+ inline backtrace_holder() BOOST_NOEXCEPT {
frames_count = ::backtrace(buffer, max_size);
}
- std::size_t size() const BOOST_NOEXCEPT {
- return frames_count;
+ inline std::size_t size() const BOOST_NOEXCEPT {
+ return frames_count > skip_frames ? frames_count - skip_frames : 1u;
}
- frame_t get_frame(std::size_t frame) const BOOST_NOEXCEPT {
- frame_t name = {"??"};
- name.back() = '\0';
+ inline std::string get_frame(std::size_t frame) const {
+ std::string res;
+ frame += skip_frames;
if (frame >= frames_count) {
- return name;
+ return res;
}
Dl_info dli;
- if (dladdr(buffer[frame], &dli) && dli.dli_sname) {
- boost::core::scoped_demangled_name demangled(dli.dli_sname);
- if (demangled.get()) {
- std::strncpy(name.data(), demangled.get(), name.size() - 1);
- } else {
- std::strncpy(name.data(), dli.dli_sname, name.size() - 1);
- }
- } else {
- std::strncpy(name.data(), to_hex(reinterpret_cast(buffer[frame])).data(), name.size() - 1);
+ if (!dladdr(buffer[frame], &dli)) {
+ return res;
}
- return name;
- }
+ if (dli.dli_sname) {
+ boost::core::scoped_demangled_name demangled(dli.dli_sname);
+ if (demangled.get()) {
+ res = demangled.get();
+ } else {
+ res = dli.dli_sname;
+ }
+ }
+ return res;
+ }
};
diff --git a/include/boost/stacktrace/detail/stacktrace_windows.hpp b/include/boost/stacktrace/detail/stacktrace_windows.hpp
index 0f57ff1..3961b39 100644
--- a/include/boost/stacktrace/detail/stacktrace_windows.hpp
+++ b/include/boost/stacktrace/detail/stacktrace_windows.hpp
@@ -7,7 +7,7 @@
#include
#include
-#include
+#include
#include
#include
@@ -16,11 +16,9 @@
namespace boost { namespace stacktrace { namespace detail {
-typedef boost::stacktrace::stacktrace::frame_t frame_t;
-
struct symbol_info_with_stack {
SYMBOL_INFO symbol;
- char name_part[frame_t::static_size - 1];
+ char name_part[MAX_SYM_NAME * sizeof(TCHAR)];
};
struct backtrace_holder {
@@ -30,41 +28,39 @@ struct backtrace_holder {
void* buffer[max_size];
HANDLE process;
- backtrace_holder() BOOST_NOEXCEPT
- : frames_count(1)
+ inline backtrace_holder() BOOST_NOEXCEPT
+ : frames_count(0)
, process(GetCurrentProcess())
{
- BOOST_VERIFY(process);
-
const bool inited = !!SymInitialize(process, 0, true);
- BOOST_VERIFY(inited);
if (inited) {
frames_count = CaptureStackBackTrace(0, max_size, buffer, 0);
+ } else {
+ process = 0;
}
}
- std::size_t size() const BOOST_NOEXCEPT {
+ inline std::size_t size() const BOOST_NOEXCEPT {
return frames_count;
}
- frame_t get_frame(std::size_t frame) const BOOST_NOEXCEPT {
- frame_t name = {"??"};
- name.back() = '\0';
+ inline std::string get_frame(std::size_t frame) const BOOST_NOEXCEPT {
+ std::string res;
- if (frame >= frames_count) {
- return name;
+ if (frame >= frames_count || !process) {
+ return res;
}
symbol_info_with_stack s;
- s.symbol.MaxNameLen = name.size() - 1;
+ s.symbol.MaxNameLen = f.name.size() - 1;
s.symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
- SymFromAddr(process, (DWORD64)(buffer[frame]), 0, &s.symbol);
- std::strncpy(name.data(), s.symbol.Name, name.size() - 1);
- std::strncat(name.data(), " ", name.size() - 1);
- std::strncat(name.data(), to_hex(s.symbol.Address).data(), name.size() - 1);
-
- return name;
+ SymFromAddr(process, reinterpret_cast(buffer[frame]), 0, &s.symbol);
+ BOOST_TRY {
+ res = s.symbol.Name;
+ } BOOST_CATCH(...) {}
+ BOOST_CATCH_END
+ return res;
}
};
diff --git a/src/backtrace.cpp b/src/backtrace.cpp
new file mode 100644
index 0000000..b44ae7e
--- /dev/null
+++ b/src/backtrace.cpp
@@ -0,0 +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
diff --git a/src/libunwind.cpp b/src/libunwind.cpp
new file mode 100644
index 0000000..b44ae7e
--- /dev/null
+++ b/src/libunwind.cpp
@@ -0,0 +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
diff --git a/src/windbg.cpp b/src/windbg.cpp
new file mode 100644
index 0000000..b44ae7e
--- /dev/null
+++ b/src/windbg.cpp
@@ -0,0 +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
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 5a83913..1d950db 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -5,23 +5,39 @@
# http://www.boost.org/LICENSE_1_0.txt)
#
-lib unwind ;
-lib dl ;
+lib dl : : shared ;
+lib unwind : : shared ;
+lib Dbghelp ;
project
: requirements
msvc:on
all
on
- debug
always_show_run_output
;
+lib test_unwind_lib : test_impl.cpp : shared : : /boost/stacktrace//boost_stacktrace_libunwind [ check-target-builds ../build//libunwind : : no ] ;
+lib test_backtrace_lib : test_impl.cpp : shared : : /boost/stacktrace//boost_stacktrace_backtrace [ check-target-builds ../build//backtrace : : no ] ;
+lib test_windbg_lib : test_impl.cpp : shared : : /boost/stacktrace//boost_stacktrace_windbg [ check-target-builds ../build//WinDbg : : no ] ;
+
+local HONLY_UNW = BOOST_STACKTRACE_HEADER_ONLY BOOST_STACKTRACE_USE_LIBUNWIND unwind [ check-target-builds ../build//libunwind : : no ] ;
+local HONLY_BT = BOOST_STACKTRACE_HEADER_ONLY BOOST_STACKTRACE_USE_BACKTRACE dl [ check-target-builds ../build//backtrace : : no ] ;
+local HONLY_WIND = BOOST_STACKTRACE_HEADER_ONLY BOOST_STACKTRACE_USE_WINDBG Dbghelp [ check-target-builds ../build//WinDbg : : no ] ;
+
test-suite stacktrace
:
- [ run test.cpp test_impl.cpp /boost/stacktrace//boost_stacktrace_libunwind : : : [ check-target-builds ../build//has_libunwind "has libunwind" : : no ] : test_libunwind ]
- [ run test.cpp test_impl.cpp /boost/stacktrace//boost_stacktrace_backtrace : : : [ check-target-builds ../build//has_backtrace "has ::backtrace()" : : no ] : test_backtrace ]
- [ run test.cpp test_impl.cpp /boost/stacktrace//boost_stacktrace_windbg : : : [ check-target-builds ../build//has_windbg "has WinDbg" : : no ] : test_windbg ]
+ [ run test.cpp test_impl.cpp : : : $(HONLY_UNW) : libunwind_ho ]
+ [ run test.cpp test_impl.cpp : : : $(HONLY_BT) : backtrace_ho ]
+ [ run test.cpp test_impl.cpp : : : $(HONLY_WIND) : windbg_ho ]
+
+ [ run test.cpp : : : .//test_unwind_lib [ check-target-builds ../build//libunwind : : no ] : libunwind_lib ]
+ [ run test.cpp : : : .//test_backtrace_lib [ check-target-builds ../build//backtrace : : no ] : backtrace_lib ]
+ [ run test.cpp : : : .//test_windbg_lib [ check-target-builds ../build//WinDbg : : no ] : windbg_lib ]
+
+ [ run ../example/getting_started.cpp : : : $(HONLY_UNW) : libunwind_getting_started ]
+ [ run ../example/getting_started.cpp : : : $(HONLY_BT) : backtrace_getting_started ]
+ [ run ../example/getting_started.cpp : : : $(HONLY_WIND) : windbg_getting_started ]
;
diff --git a/test/test.cpp b/test/test.cpp
index ca7bcff..d224e39 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -9,42 +9,21 @@
#include
#include
#include
+#include
-using namespace boost::stacktrace;
-typedef std::pair btp;
-void foo2(int i);
-
-void foo1(int i) {
- if (i) {
- foo2(i - 1);
- return;
- }
-
- btp ret;
- try {
- ret.first = stacktrace();
- throw std::logic_error("test");
- } catch (const std::logic_error& e) {
- ret.second = stacktrace();
- std::cout << e.what() << '\n';
- throw ret;
- }
-}
-
+using boost::stacktrace::stacktrace;
+BOOST_SYMBOL_IMPORT std::pair foo2(int i);
+BOOST_SYMBOL_IMPORT std::pair foo1(int i);
+BOOST_SYMBOL_IMPORT stacktrace return_from_nested_namespaces();
void test_nested() {
- btp res;
- try {
- foo2(15);
- } catch(btp const r) {
- res = r;
- }
+ std::pair res = foo2(15);
std::stringstream ss1, ss2;
ss1 << res.first;
ss2 << res.second;
- std::cout << ss1.str() << "\n\n" << ss2.str() << std::endl;
+ std::cout << "'" << ss1.str() << "'\n\n" << ss2.str() << std::endl;
assert(!ss1.str().empty());
assert(!ss2.str().empty());
@@ -58,9 +37,8 @@ void test_nested() {
assert(ss2.str().find("main") != std::string::npos);
}
-void test_from_nested_namespaces();
int main() {
- test_from_nested_namespaces();
+ std::cout << return_from_nested_namespaces();
test_nested();
}
diff --git a/test/test_impl.cpp b/test/test_impl.cpp
index 0f797bb..a83ab2f 100644
--- a/test/test_impl.cpp
+++ b/test/test_impl.cpp
@@ -7,15 +7,31 @@
#include
#include
-#include
-#include
using namespace boost::stacktrace;
-typedef std::pair btp;
-void foo1(int i);
+BOOST_SYMBOL_EXPORT std::pair foo1(int i);
+BOOST_SYMBOL_EXPORT std::pair foo2(int i);
-void foo2(int i) {
- foo1(i);
+std::pair foo1(int i) {
+ if (i) {
+ return foo2(i - 1);
+ }
+
+ std::pair ret;
+ try {
+ throw std::logic_error("test");
+ } catch (const std::logic_error& e) {
+ ret.second = stacktrace();
+ return ret;
+ }
+}
+
+std::pair foo2(int i) {
+ if (i) {
+ return foo1(--i);
+ } else {
+ return foo1(i);
+ }
}
@@ -29,16 +45,16 @@ namespace very_very_very_very_very_very_long_namespace {
namespace very_very_very_very_very_very_long_namespace {
namespace very_very_very_very_very_very_long_namespace {
namespace very_very_very_very_very_very_long_namespace {
- extern stacktrace get_backtrace_from_nested_namespaces() {
+ BOOST_SYMBOL_EXPORT stacktrace get_backtrace_from_nested_namespaces() {
return stacktrace();
}
}}}}}}}}}}
-using namespace very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace
- ::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace
- ::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace
- ::very_very_very_very_very_very_long_namespace;
+BOOST_SYMBOL_EXPORT stacktrace return_from_nested_namespaces() {
+ using very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace
+ ::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace
+ ::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace
+ ::very_very_very_very_very_very_long_namespace::get_backtrace_from_nested_namespaces;
-void test_from_nested_namespaces() {
- std::cout << get_backtrace_from_nested_namespaces() << "\n\n";
+ return get_backtrace_from_nested_namespaces();
}