Skip to content

Commit 2d6c03e

Browse files
committed
Fixed libunwind backend, added docs, fixed tests and compilation, changed return type of stacktrace::operator[]
1 parent 13d8ee4 commit 2d6c03e

16 files changed

Lines changed: 401 additions & 184 deletions

build/Jamfile.v2

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#
77
project boost/stacktrace ;
88

9-
lib dl ;
9+
lib dl : : <link>shared ;
1010
lib unwind : : <link>shared ;
1111
lib Dbghelp ;
1212

@@ -24,24 +24,23 @@ rule mp-run-simple ( sources + : args * : input-files * : requirements * : targe
2424
alias $(target-name) : $(target-name).output ;
2525
}
2626

27-
mp-run-simple has_libunwind.cpp : : : : has_libunwind ;
28-
explicit has_libunwind ;
27+
mp-run-simple has_libunwind.cpp : : : : libunwind ;
28+
explicit libunwind ;
2929

30-
mp-run-simple has_backtrace.cpp : : : : has_backtrace ;
31-
explicit has_backtrace ;
30+
mp-run-simple has_backtrace.cpp : : : : backtrace ;
31+
explicit backtrace ;
3232

33-
mp-run-simple has_windbg.cpp : : : : has_windbg ;
34-
explicit has_windbg ;
33+
mp-run-simple has_windbg.cpp : : : : WinDbg ;
34+
explicit WinDbg ;
3535

3636
lib boost_stacktrace_libunwind
3737
: # sources
38-
../src/stacktrace.cpp
38+
../src/libunwind.cpp
3939
: # requirements
4040
<warnings>all
41-
<link>static
4241
<define>BOOST_STACKTRACE_USE_LIBUNWIND=1
4342
<library>unwind
44-
[ check-target-builds ../build//has_libunwind "has libunwind" : : <build>no ]
43+
[ check-target-builds ../build//libunwind : : <build>no ]
4544
: # default build
4645
: # usage-requirements
4746
<link>shared:<define>BOOST_TEST_DYN_LINK=1
@@ -51,12 +50,12 @@ boost-install boost_stacktrace_libunwind ;
5150

5251
lib boost_stacktrace_backtrace
5352
: # sources
54-
../src/stacktrace.cpp
53+
../src/backtrace.cpp
5554
: # requirements
5655
<warnings>all
5756
<define>BOOST_STACKTRACE_USE_BACKTRACE=1
5857
<library>dl
59-
[ check-target-builds ../build//has_backtrace "has ::backtrace()" : : <build>no ]
58+
[ check-target-builds ../build//backtrace : : <build>no ]
6059
: # default build
6160
: # usage-requirements
6261
<link>shared:<define>BOOST_TEST_DYN_LINK=1
@@ -66,12 +65,12 @@ boost-install boost_stacktrace_backtrace ;
6665

6766
lib boost_stacktrace_windbg
6867
: # sources
69-
../src/stacktrace.cpp
68+
../src/windbg.cpp
7069
: # requirements
7170
<warnings>all
7271
<library>Dbghelp
7372
<define>BOOST_STACKTRACE_USE_WINDBG=1
74-
[ check-target-builds ../build//has_windbg "has WinDbg" : : <build>no ]
73+
[ check-target-builds ../build//WinDbg : : <build>no ]
7574
: # default build
7675
: # usage-requirements
7776
<link>shared:<define>BOOST_TEST_DYN_LINK=1

doc/Jamfile.v2

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright Antony Polukhin 2016.
2+
# Use, modification, and distribution are
3+
# subject to the Boost Software License, Version 1.0. (See accompanying
4+
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
using quickbook ;
7+
import boostbook : boostbook ;
8+
import doxygen ;
9+
10+
doxygen autodoc
11+
:
12+
[ glob ../../../boost/stacktrace.hpp ]
13+
:
14+
<doxygen:param>EXTRACT_ALL=NO
15+
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
16+
<doxygen:param>EXTRACT_PRIVATE=NO
17+
<doxygen:param>ENABLE_PREPROCESSING=YES
18+
<doxygen:param>EXPAND_ONLY_PREDEF=YES
19+
<doxygen:param>MACRO_EXPANSION=YES
20+
<doxygen:param>"PREDEFINED=\"stl_type_info=std::type_info\" \\
21+
\"BOOST_STACKTRACE_FUNCTION\""
22+
<xsl:param>"boost.doxygen.reftitle=Boost.Stacktrace Header Reference"
23+
;
24+
25+
xml stacktrace : stacktrace.qbk : <dependency>autodoc ;
26+
boostbook standalone
27+
:
28+
stacktrace
29+
:
30+
<xsl:param>boost.root=http://www.boost.org/doc/libs/1_61_0
31+
# <xsl:param>boost.root=../../../..
32+
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
33+
;
34+

doc/stacktrace.qbk

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[library Boost.Stacktrace
2+
[quickbook 1.6]
3+
[version 1.0]
4+
[copyright 2016 Antony Polukhin]
5+
[category Language Features Emulation]
6+
[license
7+
Distributed under the Boost Software License, Version 1.0.
8+
(See accompanying file LICENSE_1_0.txt or copy at
9+
[@http://www.boost.org/LICENSE_1_0.txt])
10+
]
11+
]
12+
13+
[section Motivation]
14+
How to display the call sequence in C++? From what function was called the current function? What call sequence lead to an exception?
15+
16+
Boost.Stacktrace library is a simple library that provides information about call sequence in human readable form.
17+
18+
[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!]
19+
20+
[endsect]
21+
22+
[section Getting Started]
23+
24+
[endsect]
25+
26+
27+
[xinclude autodoc.xml]
28+

example/getting_started.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright Antony Polukhin, 2016.
2+
//
3+
// Distributed under the Boost Software License, Version 1.0. (See
4+
// accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#include <boost/function.hpp>
8+
struct events {
9+
typedef boost::function<void (float)> callback_type;
10+
11+
static void from_keyboard(callback_type callback);
12+
static void from_network(callback_type callback);
13+
};
14+
15+
16+
#include <boost/stacktrace.hpp>
17+
#include <iostream>
18+
BOOST_NOINLINE void validate_positive(float f) {
19+
if (f < 0.f) {
20+
std::cerr << "Negative number " << f << " detected. Call stack:\n"
21+
<< boost::stacktrace::stacktrace() << '\n';
22+
}
23+
}
24+
25+
26+
27+
28+
boost::function<void (float)> on_keyboard;
29+
boost::function<void (float)> on_network;
30+
31+
BOOST_NOINLINE void keyboard_event() {
32+
on_keyboard(-0.1f);
33+
}
34+
35+
BOOST_NOINLINE void network_event() {
36+
on_network(1.0f);
37+
}
38+
39+
void events::from_keyboard(events::callback_type callback) {
40+
on_keyboard = callback;
41+
}
42+
43+
void events::from_network(events::callback_type callback) {
44+
on_network = callback;
45+
}
46+
47+
48+
49+
int main() {
50+
events::from_keyboard(&validate_positive);
51+
events::from_network(&validate_positive);
52+
53+
keyboard_event();
54+
network_event();
55+
}
56+
57+
58+

include/boost/stacktrace.hpp

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,49 @@
55
// http://www.boost.org/LICENSE_1_0.txt)
66

77

8-
#pragma once
9-
108
#include <boost/config.hpp>
9+
#ifdef BOOST_HAS_PRAGMA_ONCE
10+
# pragma once
11+
#endif
1112

12-
#include <boost/array.hpp>
1313
#include <boost/aligned_storage.hpp>
1414
#include <iosfwd>
15+
#include <string>
16+
17+
/// @cond
18+
#if defined(BOOST_STACKTRACE_HEADER_ONLY)
19+
# define BOOST_STACKTRACE_FUNCTION inline
20+
#else
21+
# define BOOST_STACKTRACE_FUNCTION
22+
#endif
23+
/// @endcond
1524

1625
namespace boost { namespace stacktrace {
1726

1827
class stacktrace {
19-
typename boost::aligned_storage<sizeof(void*) * 250>::type data_;
20-
28+
BOOST_STATIC_CONSTEXPR std::size_t max_implementation_size = sizeof(void*) * 110u;
29+
boost::aligned_storage<max_implementation_size>::type impl_;
2130
public:
22-
BOOST_STATIC_CONSTEXPR std::size_t max_symbol_width = 256;
23-
typedef boost::array<char, max_symbol_width> frame_t;
31+
/// Stores the current function call sequence inside the class
32+
BOOST_STACKTRACE_FUNCTION stacktrace() BOOST_NOEXCEPT;
2433

25-
stacktrace() BOOST_NOEXCEPT;
26-
stacktrace(const stacktrace& bt) BOOST_NOEXCEPT;
27-
stacktrace& operator=(const stacktrace& bt) BOOST_NOEXCEPT;
28-
~stacktrace() BOOST_NOEXCEPT;
34+
BOOST_STACKTRACE_FUNCTION stacktrace(const stacktrace& bt) BOOST_NOEXCEPT;
35+
BOOST_STACKTRACE_FUNCTION stacktrace& operator=(const stacktrace& bt) BOOST_NOEXCEPT;
36+
BOOST_STACKTRACE_FUNCTION ~stacktrace() BOOST_NOEXCEPT;
2937

30-
std::size_t size() const BOOST_NOEXCEPT;
31-
frame_t operator[](std::size_t frame) const BOOST_NOEXCEPT;
38+
/// @returns Number of function names stored inside the class.
39+
BOOST_STACKTRACE_FUNCTION std::size_t size() const BOOST_NOEXCEPT;
40+
41+
/// @param frame Zero based index of function to return. 0
42+
/// is the function index where stacktrace was constructed and
43+
/// index close to this->size() contains function `main()`.
44+
/// @returns Function name in a human readable form.
45+
/// @throws std::bad_alloc if not enough memory.
46+
BOOST_STACKTRACE_FUNCTION std::string operator[](std::size_t frame) const;
3247
};
3348

49+
50+
/// Outputs stacktrace in a human readable format to output stream.
3451
template <class CharT, class TraitsT>
3552
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const stacktrace& bt) {
3653
const std::streamsize w = os.width();
@@ -39,11 +56,25 @@ std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT
3956
os.width(2);
4057
os << i;
4158
os.width(w);
42-
os << "# " << bt[i].data() << '\n';
59+
const std::string f = bt[i];
60+
os << "# ";
61+
if (f.empty()) {
62+
os << "??";
63+
} else {
64+
os << f;
65+
}
66+
os << '\n';
4367
}
4468

4569
return os;
4670
}
4771

4872
}} // namespace boost::stacktrace
4973

74+
/// @cond
75+
#undef BOOST_STACKTRACE_FUNCTION
76+
77+
#if defined(BOOST_STACKTRACE_HEADER_ONLY)
78+
# include <boost/stacktrace/detail/stacktrace.ipp>
79+
#endif
80+
/// @endcond

include/boost/stacktrace/detail/stacktrace.ipp

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,64 +4,67 @@
44
// accompanying file LICENSE_1_0.txt or copy at
55
// http://www.boost.org/LICENSE_1_0.txt)
66

7-
#include <boost/stacktrace.hpp>
8-
#include <boost/static_assert.hpp>
7+
#include <boost/config.hpp>
8+
#ifdef BOOST_HAS_PRAGMA_ONCE
9+
# pragma once
10+
#endif
911

12+
#include <boost/static_assert.hpp>
1013
#include <boost/predef/os/windows.h>
1114

1215
#if BOOST_OS_WINDOWS
1316
# include <boost/stacktrace/detail/stacktrace_windows.hpp>
14-
//#elif defined(__has_include) && (!defined(__GNUC__) || __GNUC__ > 4)
15-
//# if __has_include(<libunwind.h>)
16-
//# include <boost/stacktrace/detail/stacktrace_libunwind.hpp>
17-
//# endif
1817
#elif defined(BOOST_STACKTRACE_USE_LIBUNWIND)
1918
# include <boost/stacktrace/detail/stacktrace_libunwind.hpp>
2019
#elif defined(BOOST_STACKTRACE_USE_BACKTRACE)
2120
# include <boost/stacktrace/detail/stacktrace_linux.hpp>
21+
#elif defined(__has_include) && (!defined(__GNUC__) || __GNUC__ > 4)
22+
# if __has_include(<libunwind.h>)
23+
# include <boost/stacktrace/detail/stacktrace_libunwind.hpp>
24+
# elif __has_include(<execinfo.h>)
25+
# include <boost/stacktrace/detail/stacktrace_linux.hpp>
26+
# endif
2227
#else
2328
# error No suitable backtrace backend found
2429
#endif
2530

2631
namespace boost { namespace stacktrace {
2732

28-
using boost::stacktrace::detail::backtrace_holder;
29-
3033
template <class T>
31-
inline backtrace_holder& to_bt(T& data) BOOST_NOEXCEPT {
32-
return *reinterpret_cast<backtrace_holder*>(&data);
34+
inline boost::stacktrace::detail::backtrace_holder& to_bt(T& data) BOOST_NOEXCEPT {
35+
return *reinterpret_cast<boost::stacktrace::detail::backtrace_holder*>(&data);
3336
}
3437

3538
template <class T>
36-
inline const backtrace_holder& to_bt(const T& data) BOOST_NOEXCEPT {
37-
return *reinterpret_cast<const backtrace_holder*>(&data);
39+
inline const boost::stacktrace::detail::backtrace_holder& to_bt(const T& data) BOOST_NOEXCEPT {
40+
return *reinterpret_cast<const boost::stacktrace::detail::backtrace_holder*>(&data);
3841
}
3942

4043

4144
stacktrace::stacktrace() BOOST_NOEXCEPT {
42-
new (&data_) backtrace_holder();
45+
new (&impl_) boost::stacktrace::detail::backtrace_holder();
4346
}
4447

4548
stacktrace::stacktrace(const stacktrace& bt) BOOST_NOEXCEPT {
46-
new (&data_) backtrace_holder(to_bt(bt.data_));
49+
new (&impl_) boost::stacktrace::detail::backtrace_holder(to_bt(bt.impl_));
4750
}
4851

4952
stacktrace& stacktrace::operator=(const stacktrace& bt) BOOST_NOEXCEPT {
50-
to_bt(data_) = to_bt(bt.data_);
53+
to_bt(impl_) = to_bt(bt.impl_);
5154
return *this;
5255
}
5356

5457
stacktrace::~stacktrace() BOOST_NOEXCEPT {
55-
BOOST_STATIC_ASSERT_MSG(sizeof(data_) >= sizeof(backtrace_holder), "Too small storage for holding backtrace");
56-
to_bt(data_).~backtrace_holder();
58+
BOOST_STATIC_ASSERT_MSG(sizeof(impl_) >= sizeof(boost::stacktrace::detail::backtrace_holder), "Too small storage for holding backtrace");
59+
to_bt(impl_).~backtrace_holder();
5760
}
5861

5962
std::size_t stacktrace::size() const BOOST_NOEXCEPT {
60-
return to_bt(data_).size();
63+
return to_bt(impl_).size();
6164
}
6265

63-
stacktrace::frame_t stacktrace::operator[](std::size_t frame) const BOOST_NOEXCEPT {
64-
return to_bt(data_).get_frame(frame);
66+
std::string stacktrace::operator[](std::size_t frame) const BOOST_NOEXCEPT {
67+
return to_bt(impl_).get_frame(frame);
6568
}
6669

6770

0 commit comments

Comments
 (0)