[DEV] add v1.66.0

This commit is contained in:
2018-01-12 21:47:58 +01:00
parent 87059bb1af
commit a97e9ae7d4
49032 changed files with 7668950 additions and 0 deletions

15
libs/stacktrace/README.md Normal file
View File

@@ -0,0 +1,15 @@
### Stacktrace
Library for storing and printing backtraces.
[Documentation and examples.](http://boostorg.github.io/stacktrace/index.html)
### Test results
@ | Build | Tests coverage | More info
----------------|-------------- | -------------- |-----------
Develop branch: | [![Build Status](https://travis-ci.org/boostorg/stacktrace.svg?branch=develop)](https://travis-ci.org/boostorg/stacktrace) [![Build status](https://ci.appveyor.com/api/projects/status/l3aak4j8k39rx08t/branch/develop?svg=true)](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/develop) | [![Coverage Status](https://coveralls.io/repos/github/boostorg/stacktrace/badge.svg?branch=develop)](https://coveralls.io/github/boostorg/stacktrace?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/stacktrace.html)
Master branch: | [![Build Status](https://travis-ci.org/boostorg/stacktrace.svg?branch=master)](https://travis-ci.org/boostorg/stacktrace) [![Build status](https://ci.appveyor.com/api/projects/status/l3aak4j8k39rx08t/branch/master?svg=true)](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/master) | [![Coverage Status](https://coveralls.io/repos/github/boostorg/stacktrace/badge.svg?branch=master)](https://coveralls.io/github/boostorg/stacktrace?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/stacktrace.html)
### License
Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).

View File

@@ -0,0 +1,142 @@
# Copyright (C) 2016-2017, Antony Polukhin.
#
# Use, modification and distribution is 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)
#
project
: source-location .
: requirements
<target-os>linux:<cxxflags>"-fvisibility=hidden"
;
lib dl ;
lib gcc_s ;
lib Dbgeng ;
lib ole32 ;
local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ;
lib backtrace
:
: <search>$(LIBBACKTRACE_PATH)/lib <link>static
:
: <include>$(LIBBACKTRACE_PATH)/include
;
actions mp_simple_run_action
{
$(>) > $(<)
}
rule mp-run-simple ( sources + : args * : input-files * : requirements * : target-name )
{
exe $(target-name)_exe : $(sources) : $(requirements) ;
explicit $(target-name)_exe ;
make $(target-name).output : $(target-name)_exe : @mp_simple_run_action ;
explicit $(target-name).output ;
alias $(target-name) : $(target-name).output ;
}
mp-run-simple has_backtrace.cpp : : : <library>backtrace : libbacktrace ;
explicit libbacktrace ;
mp-run-simple has_addr2line.cpp : : : : addr2line ;
explicit addr2line ;
mp-run-simple has_windbg.cpp : : : <library>Dbgeng <library>ole32 : WinDbg ;
explicit WinDbg ;
mp-run-simple has_windbg_cached.cpp : : : <library>Dbgeng <library>ole32 : WinDbgCached ;
explicit WinDbgCached ;
lib boost_stacktrace_noop
: # sources
../src/noop.cpp
: # requirements
<warnings>all
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
: # default build
: # usage-requirements
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_noop ;
lib boost_stacktrace_backtrace
: # sources
../src/backtrace.cpp
: # requirements
<warnings>all
<target-os>linux:<library>dl
<library>backtrace
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
[ check-target-builds ../build//libbacktrace : : <build>no ]
: # default build
: # usage-requirements
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_backtrace ;
lib boost_stacktrace_addr2line
: # sources
../src/addr2line.cpp
: # requirements
<warnings>all
<target-os>linux:<library>dl
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
[ check-target-builds ../build//addr2line : : <build>no ]
: # default build
: # usage-requirements
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_addr2line ;
lib boost_stacktrace_basic
: # sources
../src/basic.cpp
: # requirements
<warnings>all
<target-os>linux:<library>dl
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
[ check-target-builds ../build//WinDbg : <build>no ]
: # default build
: # usage-requirements
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_basic ;
lib boost_stacktrace_windbg
: # sources
../src/windbg.cpp
: # requirements
<warnings>all
<library>Dbgeng <library>ole32
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
[ check-target-builds ../build//WinDbg : : <build>no ]
: # default build
: # usage-requirements
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_windbg ;
lib boost_stacktrace_windbg_cached
: # sources
../src/windbg_cached.cpp
: # requirements
<warnings>all
<library>Dbgeng <library>ole32
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
[ check-target-builds ../build//WinDbgCached : : <build>no ]
: # default build
: # usage-requirements
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_windbg_cached ;

View File

@@ -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)
#include <cstdlib>
#include <string>
#include <boost/config.hpp>
#include <unwind.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
#ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION
std::string s = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION );
s += " -h";
#else
std::string s = "/usr/bin/addr2line -h";
#endif
return std::system(s.c_str());
}

View File

@@ -0,0 +1,15 @@
// 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)
#include <backtrace.h>
#include <unwind.h>
int main() {
backtrace_state* state = backtrace_create_state(
0, 1, 0, 0
);
(void)state;
}

View File

@@ -0,0 +1,13 @@
// 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)
#include <cstring>
#include <windows.h>
#include "dbgeng.h"
int main() {
::CoInitializeEx(0, COINIT_MULTITHREADED);
}

View File

@@ -0,0 +1,28 @@
// Copyright Antony Polukhin, 2016-2017.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#include <string>
#include <cstring>
#include <windows.h>
#include "dbgeng.h"
#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
int foo() {
static thread_local std::string i = std::string();
return i.size();
}
int main() {
::CoInitializeEx(0, COINIT_MULTITHREADED);
return foo();
}

View File

@@ -0,0 +1,56 @@
# Copyright Antony Polukhin 2016-2017.
# 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 ]
[ glob ../../../boost/stacktrace/*.hpp ]
[ glob ../../../boost/stacktrace/detail/frame_decl.hpp ]
:
<doxygen:param>EXTRACT_ALL=NO
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
<doxygen:param>EXTRACT_PRIVATE=NO
<doxygen:param>ENABLE_PREPROCESSING=YES
<doxygen:param>EXPAND_ONLY_PREDEF=YES
<doxygen:param>MACRO_EXPANSION=YES
<doxygen:param>SEARCH_INCLUDES=YES
<doxygen:param>SHORT_NAMES=NO
<doxygen:param>INCLUDE_PATH=../../../
<doxygen:param>"PREDEFINED=\"stl_type_info=std::type_info\" \\
\"BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()=explicit operator bool() const noexcept;\" \\
\"BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()=explicit constexpr operator bool() const noexcept;\" \\
\"BOOST_STATIC_CONSTEXPR=static constexpr\" \\
\"BOOST_FORCEINLINE=inline\" \\
\"BOOST_STACKTRACE_FUNCTION=inline\" \\
\"BOOST_CONSTEXPR=constexpr\" \\
\"BOOST_STACKTRACE_DOXYGEN_INVOKED\""
<xsl:param>"boost.doxygen.reftitle=Reference"
<xsl:param>"boost.doxygen.refid=stacktrace.reference"
;
xml stacktrace : stacktrace.qbk : <dependency>autodoc ;
boostbook standalone
:
stacktrace
:
<xsl:param>boost.root=http://www.boost.org/doc/libs/1_63_0
# <xsl:param>boost.root=../../../..
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
;
###############################################################################
alias boostdoc
: stacktrace
:
:
: ;
explicit boostdoc ;
alias boostrelease ;
explicit boostrelease ;

View File

@@ -0,0 +1,245 @@
<?xml version="1.0" standalone="yes"?>
<library-reference id="stacktrace.reference"><title>Reference</title><header name="boost/stacktrace.hpp">
</header>
<header name="boost/stacktrace/stacktrace.hpp">
<namespace name="boost">
<namespace name="stacktrace">
<class name="basic_stacktrace"><template>
<template-type-parameter name="Allocator"><purpose><para>Allocator to use during stack capture. </para></purpose></template-type-parameter>
</template><description><para>Class that on construction copies minimal information about call stack into its internals and provides access to that information.
</para></description><typedef name="value_type"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::value_type</type></typedef>
<typedef name="allocator_type"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::allocator_type</type></typedef>
<typedef name="pointer"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::const_pointer</type></typedef>
<typedef name="const_pointer"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::const_pointer</type></typedef>
<typedef name="reference"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::const_reference</type></typedef>
<typedef name="const_reference"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::const_reference</type></typedef>
<typedef name="size_type"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::size_type</type></typedef>
<typedef name="difference_type"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::difference_type</type></typedef>
<typedef name="iterator"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::const_iterator</type></typedef>
<typedef name="const_iterator"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::const_iterator</type></typedef>
<typedef name="reverse_iterator"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::const_reverse_iterator</type></typedef>
<typedef name="const_reverse_iterator"><type>std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt;::const_reverse_iterator</type></typedef>
<method-group name="public member functions">
<method name="size" cv="const noexcept"><type>size_type</type><description><para>
<emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description><returns><para>Number of function names stored inside the class.</para></returns></method>
<method name="operator[]" cv="const noexcept"><type>const_reference</type><parameter name="frame_no"><paramtype>std::size_t</paramtype><description><para>Zero based index of frame to return. 0 is the function index where stacktrace was constructed and index close to this-&gt;size() contains function <computeroutput>main()</computeroutput>. </para></description></parameter><description><para>
<emphasis role="bold">Complexity:</emphasis> O(1).</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description><returns><para>frame that references the actual frame info, stored inside *this.</para></returns></method>
<method name="begin" cv="const noexcept"><type>const_iterator</type><description><para><emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description></method>
<method name="cbegin" cv="const noexcept"><type>const_iterator</type><description><para><emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description></method>
<method name="end" cv="const noexcept"><type>const_iterator</type><description><para><emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description></method>
<method name="cend" cv="const noexcept"><type>const_iterator</type><description><para><emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description></method>
<method name="rbegin" cv="const noexcept"><type>const_reverse_iterator</type><description><para><emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description></method>
<method name="crbegin" cv="const noexcept"><type>const_reverse_iterator</type><description><para><emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description></method>
<method name="rend" cv="const noexcept"><type>const_reverse_iterator</type><description><para><emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description></method>
<method name="crend" cv="const noexcept"><type>const_reverse_iterator</type><description><para><emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description></method>
<method name="conversion-operator" cv="const noexcept" specifiers="explicit"><type>bool</type><purpose>Allows to check that stack trace capturing was successful. </purpose><description><para>
<emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description><returns><para><computeroutput>true</computeroutput> if <computeroutput>this-&gt;size() != 0</computeroutput></para></returns></method>
<method name="empty" cv="const noexcept"><type>bool</type><purpose>Allows to check that stack trace failed. </purpose><description><para>
<emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description><returns><para><computeroutput>true</computeroutput> if <computeroutput>this-&gt;size() == 0</computeroutput></para></returns></method>
<method name="as_vector" cv="const noexcept"><type>const std::vector&lt; <classname>boost::stacktrace::frame</classname>, Allocator &gt; &amp;</type></method>
</method-group>
<constructor cv="noexcept"><purpose>Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe. </para></description></constructor>
<constructor specifiers="explicit" cv="noexcept"><parameter name="a"><paramtype>const allocator_type &amp;</paramtype><description><para>Allocator that would be passed to underlying storeage. </para></description></parameter><purpose>Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.</para><para>
</para></description></constructor>
<constructor cv="noexcept"><parameter name="skip"><paramtype>std::size_t</paramtype><description><para>How many top calls to skip and do not store in *this.</para></description></parameter><parameter name="max_depth"><paramtype>std::size_t</paramtype><description><para>Max call sequence depth to collect.</para></description></parameter><parameter name="a"><paramtype>const allocator_type &amp;</paramtype><default>allocator_type()</default><description><para>Allocator that would be passed to underlying storeage.</para></description></parameter><purpose>Stores [skip, skip + max_depth) of the current function call sequence inside *this without any decoding or any other heavy platform specific operations. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.</para><para>
</para></description><throws><simpara><classname>Nothing.</classname> Note that default construction of allocator may throw, however it is performed outside the constructor and exception in <computeroutput>allocator_type()</computeroutput> would not result in calling <computeroutput>std::terminate</computeroutput>. </simpara></throws></constructor>
<constructor><parameter name="st"><paramtype>const <classname>basic_stacktrace</classname> &amp;</paramtype></parameter><description><para><emphasis role="bold">Complexity:</emphasis> O(st.size())</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe. </para></description></constructor>
<copy-assignment><type><classname>basic_stacktrace</classname> &amp;</type><parameter name="st"><paramtype>const <classname>basic_stacktrace</classname> &amp;</paramtype></parameter><description><para><emphasis role="bold">Complexity:</emphasis> O(st.size())</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe. </para></description></copy-assignment>
<destructor><description><para><emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe if Allocator::deallocate is async signal safe. </para></description></destructor>
<constructor cv="noexcept"><parameter name="st"><paramtype><classname>basic_stacktrace</classname> &amp;&amp;</paramtype></parameter><description><para><emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe if Allocator construction and copying are async signal safe. </para></description></constructor>
<copy-assignment><type><classname>basic_stacktrace</classname> &amp;</type><parameter name="st"><paramtype><classname>basic_stacktrace</classname> &amp;&amp;</paramtype></parameter><description><para><emphasis role="bold">Complexity:</emphasis> O(st.size())</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe if Allocator construction and copying are async signal safe. </para></description></copy-assignment>
<method-group name="public static functions">
<method name="from_dump" specifiers="static"><type><classname>basic_stacktrace</classname></type><template>
<template-type-parameter name="Char"/>
<template-type-parameter name="Trait"/>
</template><parameter name="in"><paramtype>std::basic_istream&lt; Char, Trait &gt; &amp;</paramtype></parameter><parameter name="a"><paramtype>const allocator_type &amp;</paramtype><default>allocator_type()</default></parameter><description><para>Constructs stacktrace from basic_istreamable that references the dumped stacktrace. Terminating zero frame is discarded.</para><para><emphasis role="bold">Complexity:</emphasis> O(N) </para></description></method>
<method name="from_dump" specifiers="static"><type><classname>basic_stacktrace</classname></type><parameter name="begin"><paramtype>const void *</paramtype></parameter><parameter name="buffer_size_in_bytes"><paramtype>std::size_t</paramtype></parameter><parameter name="a"><paramtype>const allocator_type &amp;</paramtype><default>allocator_type()</default></parameter><description><para>Constructs stacktrace from raw memory dump. Terminating zero frame is discarded.</para><para><emphasis role="bold">Complexity:</emphasis> O(size) in worst case </para></description></method>
</method-group>
</class><typedef name="stacktrace"><purpose>This is the typedef to use unless you'd like to provide a specific allocator to <classname alt="boost::stacktrace::basic_stacktrace">boost::stacktrace::basic_stacktrace</classname>. </purpose><type><classname>basic_stacktrace</classname></type></typedef>
<function name="operator&lt;"><type>bool</type><template>
<template-type-parameter name="Allocator1"/>
<template-type-parameter name="Allocator2"/>
</template><parameter name="lhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator1 &gt; &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator2 &gt; &amp;</paramtype></parameter><purpose>Compares stacktraces for less, order is platform dependent. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> Amortized O(1); worst case O(size())</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description></function>
<function name="operator=="><type>bool</type><template>
<template-type-parameter name="Allocator1"/>
<template-type-parameter name="Allocator2"/>
</template><parameter name="lhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator1 &gt; &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator2 &gt; &amp;</paramtype></parameter><purpose>Compares stacktraces for equality. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> Amortized O(1); worst case O(size())</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description></function>
<function name="operator&gt;"><type>bool</type><template>
<template-type-parameter name="Allocator1"/>
<template-type-parameter name="Allocator2"/>
</template><parameter name="lhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator1 &gt; &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator2 &gt; &amp;</paramtype></parameter><purpose>Comparison operators that provide platform dependant ordering and have amortized O(1) complexity; O(size()) worst case complexity; are Async-Handler-Safe. </purpose></function>
<function name="operator&lt;="><type>bool</type><template>
<template-type-parameter name="Allocator1"/>
<template-type-parameter name="Allocator2"/>
</template><parameter name="lhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator1 &gt; &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator2 &gt; &amp;</paramtype></parameter></function>
<function name="operator&gt;="><type>bool</type><template>
<template-type-parameter name="Allocator1"/>
<template-type-parameter name="Allocator2"/>
</template><parameter name="lhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator1 &gt; &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator2 &gt; &amp;</paramtype></parameter></function>
<function name="operator!="><type>bool</type><template>
<template-type-parameter name="Allocator1"/>
<template-type-parameter name="Allocator2"/>
</template><parameter name="lhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator1 &gt; &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator2 &gt; &amp;</paramtype></parameter></function>
<function name="hash_value"><type>std::size_t</type><template>
<template-type-parameter name="Allocator"/>
</template><parameter name="st"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator &gt; &amp;</paramtype></parameter><purpose>Fast hashing support, O(st.size()) complexity; Async-Handler-Safe. </purpose></function>
<function name="operator&lt;&lt;"><type>std::basic_ostream&lt; CharT, TraitsT &gt; &amp;</type><template>
<template-type-parameter name="CharT"/>
<template-type-parameter name="TraitsT"/>
<template-type-parameter name="Allocator"/>
</template><parameter name="os"><paramtype>std::basic_ostream&lt; CharT, TraitsT &gt; &amp;</paramtype></parameter><parameter name="bt"><paramtype>const <classname>basic_stacktrace</classname>&lt; Allocator &gt; &amp;</paramtype></parameter><purpose>Outputs stacktrace in a human readable format to output stream; unsafe to use in async handlers. </purpose></function>
</namespace>
</namespace>
</header>
<header name="boost/stacktrace/detail/frame_decl.hpp">
<para>Use &lt;boost/stacktrace/frame.hpp&gt; header instead of this one! </para><namespace name="boost">
<namespace name="stacktrace">
<class name="frame"><purpose>Class that stores frame/function address and can get information about it at runtime. </purpose><typedef name="native_frame_ptr_t"><type><emphasis>unspecified</emphasis></type></typedef>
<method-group name="public member functions">
<method name="name" cv="const"><type>std::string</type><description><para>
<emphasis role="bold">Complexity:</emphasis> unknown (lots of platform specific work).</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Unsafe.
</para></description><returns><para>Name of the frame (function name in a human readable form).</para></returns><throws><simpara><classname>std::bad_alloc</classname> if not enough memory to construct resulting string. </simpara></throws></method>
<method name="address" cv="const noexcept"><type>constexpr native_frame_ptr_t</type><description><para>
<emphasis role="bold">Complexity:</emphasis> O(1).</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.
</para></description><returns><para>Address of the frame function.</para></returns><throws><simpara><classname>Nothing.</classname> </simpara></throws></method>
<method name="source_file" cv="const"><type>std::string</type><description><para>
<emphasis role="bold">Complexity:</emphasis> unknown (lots of platform specific work).</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Unsafe. </para></description><returns><para>Path to the source file, were the function of the frame is defined. Returns empty string if this-&gt;source_line() == 0. </para></returns><throws><simpara><classname>std::bad_alloc</classname> if not enough memory to construct resulting string.</simpara></throws></method>
<method name="source_line" cv="const"><type>std::size_t</type><description><para>
<emphasis role="bold">Complexity:</emphasis> unknown (lots of platform specific work).</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Unsafe. </para></description><returns><para>Code line in the source file, were the function of the frame is defined. </para></returns><throws><simpara><classname>std::bad_alloc</classname> if not enough memory to construct string for internal needs.</simpara></throws></method>
<method name="empty" cv="const noexcept"><type>constexpr bool</type><purpose>Checks that frame is not references NULL address. </purpose><description><para>
<emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. Checks that frame references NULL address.
<emphasis role="bold">Complexity:</emphasis> O(1)</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe. </para></description><returns><para><computeroutput>true</computeroutput> if <computeroutput>this-&gt;address() != 0</computeroutput></para></returns><returns><para><computeroutput>true</computeroutput> if <computeroutput>this-&gt;address() == 0</computeroutput></para></returns></method>
</method-group>
<constructor cv="noexcept"><purpose>Constructs frame that references NULL address. Calls to source_file() and source_line() will return empty string. Calls to source_line() will return 0. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(1).</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.
</para></description><throws><simpara><classname>Nothing.</classname> </simpara></throws></constructor>
<constructor cv="= default"><parameter name=""><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><purpose>Copy constructs frame. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(1).</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.
</para></description><throws><simpara><classname>Nothing.</classname> </simpara></throws></constructor>
<copy-assignment cv="= default"><type>constexpr <classname>frame</classname> &amp;</type><parameter name=""><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><purpose>Copy assigns frame. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(1).</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.
</para></description><throws><simpara><classname>Nothing.</classname> </simpara></throws></copy-assignment>
<constructor specifiers="explicit" cv="noexcept"><parameter name="addr"><paramtype>native_frame_ptr_t</paramtype></parameter><purpose>Constructs frame that references addr and could later generate information about that address using platform specific features. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(1).</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.
</para></description><throws><simpara><classname>Nothing.</classname> </simpara></throws></constructor>
<constructor specifiers="explicit" cv="noexcept"><template>
<template-type-parameter name="T"/>
</template><parameter name="function_addr"><paramtype>T *</paramtype></parameter><purpose>Constructs frame that references function_addr and could later generate information about that function using platform specific features. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(1).</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.
</para></description><throws><simpara><classname>Nothing.</classname> </simpara></throws></constructor>
</class>
</namespace>
</namespace>
</header>
<header name="boost/stacktrace/frame.hpp">
<namespace name="boost">
<namespace name="stacktrace">
<function name="operator&lt;"><type>constexpr bool</type><parameter name="lhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><purpose>Comparison operators that provide platform dependant ordering and have O(1) complexity; are Async-Handler-Safe. </purpose></function>
<function name="operator&gt;"><type>constexpr bool</type><parameter name="lhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter></function>
<function name="operator&lt;="><type>constexpr bool</type><parameter name="lhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter></function>
<function name="operator&gt;="><type>constexpr bool</type><parameter name="lhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter></function>
<function name="operator=="><type>constexpr bool</type><parameter name="lhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter></function>
<function name="operator!="><type>constexpr bool</type><parameter name="lhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><parameter name="rhs"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter></function>
<function name="hash_value"><type>std::size_t</type><parameter name="f"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><purpose>Fast hashing support, O(1) complexity; Async-Handler-Safe. </purpose></function>
<function name="to_string"><type>std::string</type><parameter name="f"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><purpose>Outputs <classname alt="boost::stacktrace::frame">stacktrace::frame</classname> in a human readable format to string; unsafe to use in async handlers. </purpose></function>
<function name="operator&lt;&lt;"><type>std::basic_ostream&lt; CharT, TraitsT &gt; &amp;</type><template>
<template-type-parameter name="CharT"/>
<template-type-parameter name="TraitsT"/>
</template><parameter name="os"><paramtype>std::basic_ostream&lt; CharT, TraitsT &gt; &amp;</paramtype></parameter><parameter name="f"><paramtype>const <classname>frame</classname> &amp;</paramtype></parameter><purpose>Outputs <classname alt="boost::stacktrace::frame">stacktrace::frame</classname> in a human readable format to output stream; unsafe to use in async handlers. </purpose></function>
</namespace>
</namespace>
</header>
<header name="boost/stacktrace/safe_dump_to.hpp">
<para>This header contains low-level async-signal-safe functions for dumping call stacks. Dumps are binary serialized arrays of <computeroutput>void*</computeroutput>, so you could read them by using 'od -tx8 -An stacktrace_dump_failename' Linux command or using boost::stacktrace::stacktrace::from_dump functions. </para><namespace name="boost">
<namespace name="stacktrace">
<function name="safe_dump_to"><type>std::size_t</type><parameter name="memory"><paramtype>void *</paramtype><description><para>Preallocated buffer to store current function call sequence into.</para></description></parameter><parameter name="size"><paramtype>std::size_t</paramtype><description><para>Size of the preallocated buffer. </para></description></parameter><purpose>Stores current function call sequence into the memory. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.</para><para>
</para></description><returns><para>Stored call sequence depth including terminating zero frame.</para></returns></function>
<function name="safe_dump_to"><type>std::size_t</type><parameter name="skip"><paramtype>std::size_t</paramtype><description><para>How many top calls to skip and do not store.</para></description></parameter><parameter name="memory"><paramtype>void *</paramtype><description><para>Preallocated buffer to store current function call sequence into.</para></description></parameter><parameter name="size"><paramtype>std::size_t</paramtype><description><para>Size of the preallocated buffer. </para></description></parameter><purpose>Stores current function call sequence into the memory. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.</para><para>
</para></description><returns><para>Stored call sequence depth including terminating zero frame.</para></returns></function>
<function name="safe_dump_to"><type>std::size_t</type><parameter name="file"><paramtype>const char *</paramtype><description><para>File to store current function call sequence. </para></description></parameter><purpose>Opens a file and rewrites its content with current function call sequence. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.</para><para>
</para></description><returns><para>Stored call sequence depth including terminating zero frame.</para></returns></function>
<function name="safe_dump_to"><type>std::size_t</type><parameter name="skip"><paramtype>std::size_t</paramtype><description><para>How many top calls to skip and do not store.</para></description></parameter><parameter name="max_depth"><paramtype>std::size_t</paramtype><description><para>Max call sequence depth to collect.</para></description></parameter><parameter name="file"><paramtype>const char *</paramtype><description><para>File to store current function call sequence. </para></description></parameter><purpose>Opens a file and rewrites its content with current function call sequence. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.</para><para>
</para></description><returns><para>Stored call sequence depth including terminating zero frame.</para></returns></function>
<function name="safe_dump_to"><type>std::size_t</type><parameter name="fd"><paramtype>platform_specific_descriptor</paramtype></parameter><purpose>Writes into the provided file descriptor the current function call sequence. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.</para><para>
</para></description><returns><para>Stored call sequence depth including terminating zero frame.</para></returns></function>
<function name="safe_dump_to"><type>std::size_t</type><parameter name="skip"><paramtype>std::size_t</paramtype><description><para>How many top calls to skip and do not store.</para></description></parameter><parameter name="max_depth"><paramtype>std::size_t</paramtype><description><para>Max call sequence depth to collect.</para></description></parameter><parameter name="fd"><paramtype>platform_specific_descriptor</paramtype></parameter><purpose>Writes into the provided file descriptor the current function call sequence. </purpose><description><para><emphasis role="bold">Complexity:</emphasis> O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.</para><para><emphasis role="bold">Async-Handler-Safety</emphasis>: Safe.</para><para>
</para></description><returns><para>Stored call sequence depth including terminating zero frame.</para></returns></function>
</namespace>
</namespace>
</header>
<header name="boost/stacktrace/stacktrace_fwd.hpp">
<para>This header contains only forward declarations of <classname alt="boost::stacktrace::frame">boost::stacktrace::frame</classname>, <classname alt="boost::stacktrace::basic_stacktrace">boost::stacktrace::basic_stacktrace</classname>, boost::stacktrace::stacktrace and does not include any other Boost headers. </para></header>
</library-reference>

View File

@@ -0,0 +1,345 @@
[library Boost.Stacktrace
[quickbook 1.6]
[version 1.0]
[id stacktrace]
[copyright 2016-2017 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 can one display the call sequence in C++? What function called the current function? What call sequence led to an exception?
Boost.Stacktrace library is a simple C++03 library that provides information about call sequence in a human-readable form.
[endsect]
[section Getting Started]
[import ../example/assert_handler.cpp]
[import ../example/terminate_handler.cpp]
[import ../example/throwing_st.cpp]
[import ../example/trace_addresses.cpp]
[import ../example/debug_function.cpp]
[import ../example/user_config.hpp]
[section How to print current call stack]
[classref boost::stacktrace::stacktrace] contains methods for working with call-stack/backtraces/stacktraces. Here's a small example:
```
#include <boost/stacktrace.hpp>
// ... somewhere inside the `bar(int)` function that is called recursively:
std::cout << boost::stacktrace::stacktrace();
```
In that example:
* `boost::stacktrace::` is the namespace that has all the classes and functions to work with stacktraces
* [classref boost::stacktrace::stacktrace stacktrace()] is the default constructor call; constructor stores the current function call sequence inside the stacktrace class.
Code from above will output something like this:
```
0# bar(int) at /path/to/source/file.cpp:70
1# bar(int) at /path/to/source/file.cpp:70
2# bar(int) at /path/to/source/file.cpp:70
3# bar(int) at /path/to/source/file.cpp:70
4# main at /path/to/main.cpp:93
5# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
6# _start
```
[note By default the Stacktrace library is very conservative in methods to decode stacktrace. If your output does not look as fancy as in example from above, see [link stacktrace.configuration_and_build section "Configuration and Build"] for allowing advanced features of the library. ]
[endsect]
[section Handle terminates, aborts and Segmentation Faults]
Segmentation Faults and `std::terminate` calls sometimes happen in programs. Programmers usually wish to get as much information as possible on such incidents, so having a stacktrace will significantly improve debugging and fixing.
`std::terminate` calls `std::abort`, so we need to capture stack traces on Segmentation Faults and Abort signals.
[warning Writing a signal handler requires high attention! Only a few system calls allowed in signal handlers, so there's no cross platform way to print a stacktrace without a risk of deadlocking. The only way to deal with the problem - [*dump raw stacktrace into file/socket and parse it on program restart].]
Let's write a handler to safely dump stacktrace:
[getting_started_terminate_handlers]
Registering our handler:
[getting_started_setup_handlers]
At program start we check for a file with stacktrace and if it exist - we're writing it in human readable format:
[getting_started_on_program_restart]
Now we'll get the following output on `std::terminate` call after the program restarts:
```
Previous run crashed:
0# 0x00007F2EC0A6A8EF
1# my_signal_handler(int) at ../example/terminate_handler.cpp:37
2# 0x00007F2EBFD84CB0
3# 0x00007F2EBFD84C37
4# 0x00007F2EBFD88028
5# 0x00007F2EC0395BBD
6# 0x00007F2EC0393B96
7# 0x00007F2EC0393BE1
8# bar(int) at ../example/terminate_handler.cpp:18
9# foo(int) at ../example/terminate_handler.cpp:22
10# bar(int) at ../example/terminate_handler.cpp:14
11# foo(int) at ../example/terminate_handler.cpp:22
12# main at ../example/terminate_handler.cpp:84
13# 0x00007F2EBFD6FF45
14# 0x0000000000402209
```
[note Function names from shared libraries may not be decoded due to address space layout randomization. Still better than nothing.]
[endsect]
[section Better asserts]
Pretty often assertions provide not enough information to locate the problem. For example you can see the following message on out-of-range access:
```
../../../boost/array.hpp:123: T& boost::array<T, N>::operator[](boost::array<T, N>::size_type) [with T = int; long unsigned int N = 5ul]: Assertion '(i < N)&&("out of range")' failed.
Aborted (core dumped)
```
That's not enough to locate the problem without debugger. There may be thousand code lines in real world examples and hundred places where that assertion could happen. Let's try to improve the assertions, and make them more informative:
[getting_started_assert_handlers]
We've defined the `BOOST_ENABLE_ASSERT_DEBUG_HANDLER` macro for the whole project. Now all the `BOOST_ASSERT` and `BOOST_ASSERT_MSG` will call our functions `assertion_failed` and `assertion_failed_msg` in case of failure. In `assertion_failed_msg` we output information that was provided by the assertion macro and [classref boost::stacktrace::stacktrace]:
```
Expression 'i < N' is false in function 'T& boost::array<T, N>::operator[](boost::array<T, N>::size_type) [with T = int; long unsigned int N = 5ul; boost::array<T, N>::reference = int&; boost::array<T, N>::size_type = long unsigned int]': out of range.
Backtrace:
0# boost::assertion_failed_msg(char const*, char const*, char const*, char const*, long) at ../example/assert_handler.cpp:39
1# boost::array<int, 5ul>::operator[](unsigned long) at ../../../boost/array.hpp:124
2# bar(int) at ../example/assert_handler.cpp:17
3# foo(int) at ../example/assert_handler.cpp:25
4# bar(int) at ../example/assert_handler.cpp:17
5# foo(int) at ../example/assert_handler.cpp:25
6# main at ../example/assert_handler.cpp:54
7# 0x00007F991FD69F45 in /lib/x86_64-linux-gnu/libc.so.6
8# 0x0000000000401139
```
Now we do know the steps that led to the assertion and can find the error without debugger.
[endsect]
[section Exceptions with stacktrace]
You can provide more information along with exception by embedding stacktraces into the exception. There are many ways to do that, here's how to doe that using Boost.Exception:
* Declare a `boost::error_info` typedef that holds the stacktrace:
[getting_started_class_traced]
* Write a helper class for throwing any exception with stacktrace:
[getting_started_class_with_trace]
* Use `throw_with_trace(E);` instead of just `throw E;`:
[getting_started_throwing_with_trace]
* Process exceptions:
[getting_started_catching_trace]
Code from above will output:
```
'i' must not be greater than zero in oops()
0# void throw_with_trace<std::logic_error>(std::logic_error const&) at ../example/throwing_st.cpp:22
1# oops(int) at ../example/throwing_st.cpp:38
2# bar(int) at ../example/throwing_st.cpp:54
3# foo(int) at ../example/throwing_st.cpp:59
4# bar(int) at ../example/throwing_st.cpp:49
5# foo(int) at ../example/throwing_st.cpp:59
6# main at ../example/throwing_st.cpp:76
7# 0x00007FAC113BEF45 in /lib/x86_64-linux-gnu/libc.so.6
8# 0x0000000000402ED9
```
[endsect]
[section Enabling and disabling stacktraces]
At some point arises a requirement to easily enable/disable stacktraces for a whole project. That could be easily achieved.
Just define *BOOST_STACKTRACE_LINK* for a whole project. Now you can enable/disable stacktraces by just linking with different libraries:
* link with `boost_stacktrace_noop` to disable backtracing
* link with other `boost_stacktrace_*` libraries
See [link stacktrace.configuration_and_build section "Configuration and Build"] for more info.
[endsect]
[section Saving stacktraces by specified format]
[classref boost::stacktrace::stacktrace] provides access to individual [classref boost::stacktrace::frame frames] of the stacktrace,
so that you could save stacktrace information in your own format. Consider the example, that saves only function addresses of each frame:
[getting_started_trace_addresses]
Code from above will output:
```
0x7fbcfd17f6b5,0x400d4a,0x400d61,0x400d61,0x400d61,0x400d61,0x400d77,0x400cbf,0x400dc0,0x7fbcfc82d830,0x400a79,
```
[endsect]
[section Getting function information from pointer]
[classref boost::stacktrace::frame] provides information about functions. You may construct that class from function pointer and get the function name at runtime:
[getting_started_debug_function]
Code from above will output:
```
my_signal_handler(int) at boost/libs/stacktrace/example/debug_function.cpp:21
```
[endsect]
[section Global control over stacktrace output format]
You may override the behavior of default stacktrace output operator by defining the macro from Boost.Config [macroref BOOST_USER_CONFIG] to point to a file like following:
[getting_started_user_config]
Implementation of `do_stream_st` may be the following:
[getting_started_user_config_impl]
Code from above will output:
```
Terminate called:
0# bar(int)
1# foo(int)
2# bar(int)
3# foo(int)
```
[endsect]
[/
[section Store stacktraces into shared memory]
There's a way to serialize stacktrace in async safe manner and share that serialized representation with another process. Here's another example with signal handlers.
This example is very close to the [link stacktrace.getting_started.handle_terminates_aborts_and_seg "Handle terminates, aborts and Segmentation Faults"], but this time we are dumping stacktrace into shared memory:
[getting_started_terminate_handlers_shmem]
After registering signal handlers and catching a signal, we may print stacktrace dumps on program restart:
[getting_started_on_program_restart_shmem]
The program output will be the following:
```
Previous run crashed and left trace in shared memory:
0# 0x00007FD51C7218EF
1# my_signal_handler2(int) at ../example/terminate_handler.cpp:68
2# 0x00007FD51B833CB0
3# 0x00007FD51B833C37
4# 0x00007FD51B837028
5# 0x00007FD51BE44BBD
6# 0x00007FD51BE42B96
7# 0x00007FD51BE42BE1
8# bar(int) at ../example/terminate_handler.cpp:18
9# foo(int) at ../example/terminate_handler.cpp:22
10# bar(int) at ../example/terminate_handler.cpp:14
11# foo(int) at ../example/terminate_handler.cpp:22
12# run_3(char const**) at ../example/terminate_handler.cpp:152
13# main at ../example/terminate_handler.cpp:207
14# 0x00007FD51B81EF45
15# 0x0000000000402999
```
[endsect]
]
[endsect]
[section Configuration and Build]
By default Boost.Stacktrace is a header-only library, but you may change that and use the following macros to improve build times or to be able to tune library without recompiling your project:
[table:linkmacro Link macros
[[Macro name] [Effect]]
[[*BOOST_STACKTRACE_LINK*] [Disable header-only build and require linking with shared or static library that contains the tracing implementation. If *BOOST_ALL_DYN_LINK* is defined, then link with shared library.]]
[[*BOOST_STACKTRACE_DYN_LINK*] [Disable header-only build and require linking with shared library that contains tracing implementation.]]
]
In header only mode library could be tuned by macro. If one of the link macro from above is defined, you have to manually link with one of the libraries:
[table:libconfig Config
[[Macro name or default] [Library] [Effect] [Platforms] [Uses debug information [footnote This will provide more readable backtraces with *source code locations* 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. Compiling with `-rdynamic` flag, without `-fisibility=hidden` or marking functions as exported produce a better stacktraces.]] ]
[[['default for MSVC, Intel on Windows, MinGW-w64] / *BOOST_STACKTRACE_USE_WINDBG*] [*boost_stacktrace_windbg*] [ Uses COM to show debug info. May require linking with *ole32* and *dbgeng*. ] [MSVC, MinGW-w64, Intel on Windows] [yes] [no]]
[[['default for other platforms]] [*boost_stacktrace_basic*] [Uses compiler intrinsics to collect stacktrace and if possible `::dladdr` to show information about the symbol. Requires linking with *libdl* library on POSIX platforms.] [Any compiler on POSIX or MinGW] [no] [yes]]
[[*BOOST_STACKTRACE_USE_WINDBG_CACHED*] [*boost_stacktrace_windbg_cached*] [ Uses COM to show debug info and caches COM instances in TLS for better performance. Useful only for cases when traces are gathered very often. [footnote This may affect other components of your program that use COM, because this mode calls the `CoInitializeEx(0, COINIT_MULTITHREADED)` on first use and does not call `::CoUninitialize();` until the current thread is destroyed. ] May require linking with *ole32* and *dbgeng*. ] [MSVC, Intel on Windows] [yes] [no]]
[[*BOOST_STACKTRACE_USE_BACKTRACE*] [*boost_stacktrace_backtrace*] [Requires linking with *libdl* on POSIX and *libbacktrace* libraries. *libbacktrace* is probably already installed in your system, or built into your compiler.
Otherwise (if you are a *MinGW*/*MinGW-w64* user for example) it can be downloaded [@https://github.com/ianlancetaylor/libbacktrace from here] or [@https://github.com/gcc-mirror/gcc/tree/master/libbacktrace from here]. ] [Any compiler on POSIX, or MinGW, or MinGW-w64] [yes] [yes]]
[[*BOOST_STACKTRACE_USE_ADDR2LINE*] [*boost_stacktrace_addr2line*] [Use *addr2line* program to retrieve stacktrace. Requires linking with *libdl* library and `::fork` system call. Macro *BOOST_STACKTRACE_ADDR2LINE_LOCATION* must be defined to the absolute path to the addr2line executable if it is not located in /usr/bin/addr2line. ] [Any compiler on POSIX] [yes] [yes]]
[[*BOOST_STACKTRACE_USE_NOOP*] [*boost_stacktrace_noop*] [Use this if you wish to disable backtracing. `stacktrace::size()` with that macro always returns 0. ] [All] [no] [no]]
]
[*Examples:]
* if you wish to switch to more powerful implementation on Clang/MinGW and *BOOST_STACKTRACE_LINK* is defined, you just need link with "*-lboost_stacktrace_backtrace -ldl -lbacktrace*" or "*-lboost_stacktrace_addr2line -ldl*"
* if you wish to disable backtracing and you use the library in header only mode, you just need to define *BOOST_STACKTRACE_USE_NOOP* for the whole project
* if you wish to disable backtracing and *BOOST_STACKTRACE_LINK* is defined, you just need link with *-lboost_stacktrace_noop*
[section MinGW and MinGW-w64 specific notes]
MinGW-w64 and MinGW (without -w64) users have to install libbacktrace for getting better stacktraces. Follow the instruction:
Let's assume that you've installed MinGW into C:\MinGW and downloaded [@https://github.com/ianlancetaylor/libbacktrace libbacktrace sources] into C:\libbacktrace-master
* Configure & build libbacktrace from console:
* C:\MinGW\msys\1.0\bin\sh.exe
* cd /c/libbacktrace-master
* ./configure CC=/c/MinGW/bin/gcc.exe CXX=/c/MinGW/bin/g++.exe
* make
* ./libtool --mode=install /usr/bin/install -c libbacktrace.la '/c/libbacktrace-master'
* Add info to the project-config.jam in the Boost folder:
* using gcc : 6 : "C:\\MinGW\\bin\\g++.exe" : <compileflags>-I"C:\\libbacktrace-master\\" <linkflags>-L"C:\\libbacktrace-master\\" ;
* Now you can use a header only version by defining *BOOST_STACKTRACE_USE_BACKTRACE* for your project or build the stacktrace library from Boost folder:
* b2.exe toolset=gcc-6 --with-stacktrace
[endsect]
[endsect]
[section Acknowledgements]
In order of helping and advising:
* Great thanks to Bjorn Reese for highlighting the async-signal-safety issues.
* Great thanks to Nat Goodspeed for requesting [classref boost::stacktrace::frame] like class.
* Great thanks to Niall Douglas for making an initial review, helping with some platforms and giving great hints on library design.
* Great thanks to all the library reviewers.
[endsect]
[xinclude autodoc.xml]

View File

@@ -0,0 +1,57 @@
// 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)
#define BOOST_ENABLE_ASSERT_HANDLER
#include <cstdlib> // std::exit
#include <boost/array.hpp>
BOOST_NOINLINE void foo(int i);
BOOST_NOINLINE void bar(int i);
BOOST_NOINLINE void bar(int i) {
boost::array<int, 5> a = {{101, 100, 123, 23, 32}};
if (i >= 0) {
foo(a[i]);
} else {
std::exit(1);
}
}
BOOST_NOINLINE void foo(int i) {
bar(--i);
}
namespace std { inline void ignore_abort(){ std::exit(0); } }
#define abort ignore_abort
//[getting_started_assert_handlers
// BOOST_ENABLE_ASSERT_DEBUG_HANDLER is defined for the whole project
#include <stdexcept> // std::logic_error
#include <iostream> // std::cerr
#include <boost/stacktrace.hpp>
namespace boost {
inline void assertion_failed_msg(char const* expr, char const* msg, char const* function, char const* /*file*/, long /*line*/) {
std::cerr << "Expression '" << expr << "' is false in function '" << function << "': " << (msg ? msg : "<...>") << ".\n"
<< "Backtrace:\n" << boost::stacktrace::stacktrace() << '\n';
std::abort();
}
inline void assertion_failed(char const* expr, char const* function, char const* file, long line) {
::boost::assertion_failed_msg(expr, 0 /*nullptr*/, function, file, line);
}
} // namespace boost
//]
int main() {
foo(5);
return 2;
}

View File

@@ -0,0 +1,35 @@
// 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)
//[getting_started_debug_function
#include <signal.h> // ::signal
#include <boost/stacktrace/frame.hpp>
#include <iostream> // std::cerr
#include <cstdlib> // std::exit
void print_signal_handler_and_exit() {
typedef void(*function_t)(int);
function_t old_signal_function = ::signal(SIGSEGV, SIG_DFL);
boost::stacktrace::frame f(old_signal_function);
std::cout << f << std::endl;
std::exit(0);
}
//]
void my_signal_handler(int /*signum*/) {
std::exit(1);
}
int main() {
::signal(SIGSEGV, &my_signal_handler);
print_signal_handler_and_exit();
return 2;
}

View File

@@ -0,0 +1,319 @@
// 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)
#include <boost/array.hpp>
BOOST_NOINLINE void foo(int i);
BOOST_NOINLINE void bar(int i);
BOOST_NOINLINE void bar(int i) {
boost::array<int, 5> a = {{-1, -231, -123, -23, -32}};
if (i >= 0) {
foo(a[i]);
} else {
std::terminate();
}
}
BOOST_NOINLINE void foo(int i) {
bar(--i);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//[getting_started_terminate_handlers
#include <signal.h> // ::signal, ::raise
#include <boost/stacktrace.hpp>
void my_signal_handler(int signum) {
::signal(signum, SIG_DFL);
boost::stacktrace::safe_dump_to("./backtrace.dump");
::raise(SIGABRT);
}
//]
void setup_handlers() {
//[getting_started_setup_handlers
::signal(SIGSEGV, &my_signal_handler);
::signal(SIGABRT, &my_signal_handler);
//]
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOST_CONSTEXPR_OR_CONST std::size_t shared_memory_size = 4096 * 8;
//[getting_started_terminate_handlers_shmem
#include <boost/stacktrace.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
boost::interprocess::shared_memory_object g_shm; // inited at program start
boost::interprocess::mapped_region g_region; // inited at program start
void my_signal_handler2(int signum) {
::signal(signum, SIG_DFL);
void** f = static_cast<void**>(g_region.get_address());
*f = reinterpret_cast<void*>(1); // Setting flag that shared memory now constains stacktrace.
boost::stacktrace::safe_dump_to(f + 1, g_region.get_size() - sizeof(void*));
::raise(SIGABRT);
}
//]
#include <iostream> // std::cerr
#include <fstream> // std::ifstream
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
inline void copy_and_run(const char* exec_name, char param, bool not_null) {
std::cout << "Running with param " << param << std::endl;
boost::filesystem::path command = exec_name;
command = command.parent_path() / (command.stem().string() + param + command.extension().string());
boost::filesystem::copy_file(exec_name, command, boost::filesystem::copy_option::overwrite_if_exists);
boost::filesystem::path command_args = command;
command_args += ' ';
command_args += param;
const int ret = std::system(command_args.string().c_str());
std::cout << "End Running with param " << param << "; ret code is " << ret << std::endl;
boost::system::error_code ignore;
boost::filesystem::remove(command, ignore);
if (not_null && !ret) {
std::exit(97);
} else if (!not_null && ret) {
std::exit(ret);
}
}
int run_1(const char* /*argv*/[]) {
setup_handlers();
foo(5);
return 11;
}
int run_2(const char* argv[]) {
if (!boost::filesystem::exists("./backtrace.dump")) {
if (std::string(argv[0]).find("noop") == std::string::npos) {
return 21;
}
boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(std::cin);
if (st) {
return 22;
}
return 0;
}
//[getting_started_on_program_restart
if (boost::filesystem::exists("./backtrace.dump")) {
// there is a backtrace
std::ifstream ifs("./backtrace.dump");
boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(ifs);
std::cout << "Previous run crashed:\n" << st << std::endl; /*<-*/
if (!st) {
return 23;
} /*->*/
// cleaning up
ifs.close();
boost::filesystem::remove("./backtrace.dump");
}
//]
return 0;
}
int run_3(const char* /*argv*/[]) {
using namespace boost::interprocess;
{
shared_memory_object shm_obj(open_or_create, "shared_memory", read_write);
shm_obj.swap(g_shm);
}
g_shm.truncate(shared_memory_size);
{
mapped_region m(g_shm, read_write, 0, shared_memory_size);
m.swap(g_region);
}
void** f = static_cast<void**>(g_region.get_address());
*f = 0;
::signal(SIGSEGV, &my_signal_handler2);
::signal(SIGABRT, &my_signal_handler2);
foo(5);
return 31;
}
int run_4(const char* argv[]) {
using namespace boost::interprocess;
{
shared_memory_object shm_obj(open_only, "shared_memory", read_write);
shm_obj.swap(g_shm);
}
{
mapped_region m(g_shm, read_write, 0, shared_memory_size);
m.swap(g_region);
}
//[getting_started_on_program_restart_shmem
void** f = static_cast<void**>(g_region.get_address());
if (*f) { // Checking if memory constains stacktrace.
boost::stacktrace::stacktrace st
= boost::stacktrace::stacktrace::from_dump(f + 1, g_region.get_size() - sizeof(bool));
std::cout << "Previous run crashed and left trace in shared memory:\n" << st << std::endl;
*f = 0; /*<-*/
shared_memory_object::remove("shared_memory");
if (std::string(argv[0]).find("noop") == std::string::npos) {
if (!st) {
return 43;
}
} else {
if (st) {
return 44;
}
}
} else {
return 42; /*->*/
}
//]
return 0;
}
#include <sstream>
int test_inplace() {
const bool is_noop = !boost::stacktrace::stacktrace();
{
// This is very dependent on compiler and link flags. No sane way to make it work, because:
// * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled.
// * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length.
const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to("./backtrace2.dump");
boost::stacktrace::stacktrace ss2;
std::ifstream ifs("./backtrace2.dump");
boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(ifs);
ifs.close();
boost::filesystem::remove("./backtrace2.dump");
if (ss1.size() + 1 != frames_ss1 || ss2.size() != ss1.size()) {
std::cerr << "51: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n';
} else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) {
std::cerr << "52: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
}
}
{
// This is very dependent on compiler and link flags. No sane way to make it work, because:
// * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled.
// * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length.
void* data[1024];
const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to(data, sizeof(data));
boost::stacktrace::stacktrace ss2;
boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(data, sizeof(data));
if (ss1.size() + 1 != frames_ss1 || ss1.size() != ss2.size()) {
std::cerr << "53: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n';
} else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) {
std::cerr << "54: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
}
}
{
void* data[1024];
boost::stacktrace::safe_dump_to(1024, data, sizeof(data));
if (boost::stacktrace::stacktrace::from_dump(data, sizeof(data))) {
std::cerr << "Stacktrace not empty!\n";
return 55;
}
}
{
void* data[1024];
boost::stacktrace::safe_dump_to(1, data, sizeof(data));
if (!is_noop && !boost::stacktrace::stacktrace::from_dump(data, sizeof(data))) {
std::cerr << "Stacktrace empty!\n";
return 56;
}
const std::size_t size_1_skipped = boost::stacktrace::stacktrace::from_dump(data, sizeof(data)).size();
boost::stacktrace::safe_dump_to(0, data, sizeof(data));
const std::size_t size_0_skipped = boost::stacktrace::stacktrace::from_dump(data, sizeof(data)).size();
if (!is_noop && (size_1_skipped + 1 != size_0_skipped)) {
std::cerr << "failed to skip 1 frame!\n";
return 57;
}
}
{
boost::stacktrace::safe_dump_to(0, 1, "./backtrace3.dump");
std::ifstream ifs("./backtrace3.dump");
boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(ifs);
ifs.close();
boost::stacktrace::safe_dump_to(1, 1, "./backtrace3.dump");
ifs.open("./backtrace3.dump");
boost::stacktrace::stacktrace ss2 = boost::stacktrace::stacktrace::from_dump(ifs);
ifs.close();
boost::filesystem::remove("./backtrace3.dump");
if (ss1.size() != ss2.size()) {
std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
return 58;
}
if (!is_noop && ss1.size() != 1) {
std::cerr << "Stacktraces does not have size 1:\n" << ss1 << '\n';
return 59;
}
if (ss1 && ss1[0].address() == ss2[0].address()) {
std::cerr << "Stacktraces must differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
return 60;
}
}
return 0;
}
int main(int argc, const char* argv[]) {
if (argc < 2) {
// We are copying files to make sure that stacktrace printing works independently from executable name
copy_and_run(argv[0], '1', true);
copy_and_run(argv[0], '2', false);
#ifndef BOOST_WINDOWS
// There are some issues with async-safety of shared mmory writes on Windows.
copy_and_run(argv[0], '3', true);
copy_and_run(argv[0], '4', false);
#endif
return test_inplace();
}
switch (argv[1][0]) {
case '1': return run_1(argv);
case '2': return run_2(argv);
case '3': return run_3(argv);
case '4': return run_4(argv);
}
return 404;
}

View File

@@ -0,0 +1,78 @@
// 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)
#include <boost/config.hpp>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//[getting_started_class_traced
#include <boost/stacktrace.hpp>
#include <boost/exception/all.hpp>
typedef boost::error_info<struct tag_stacktrace, boost::stacktrace::stacktrace> traced;
//]
//[getting_started_class_with_trace
template <class E>
void throw_with_trace(const E& e) {
throw boost::enable_error_info(e)
<< traced(boost::stacktrace::stacktrace());
}
//]
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOST_NOINLINE void oops(int i);
BOOST_NOINLINE void foo(int i);
BOOST_NOINLINE void bar(int i);
#include <stdexcept>
BOOST_NOINLINE void oops(int i) {
//[getting_started_throwing_with_trace
if (i >= 4)
throw_with_trace(std::out_of_range("'i' must be less than 4 in oops()"));
if (i <= 0)
throw_with_trace(std::logic_error("'i' must not be greater than zero in oops()"));
//]
foo(i);
std::exit(1);
}
#include <boost/array.hpp>
BOOST_NOINLINE void bar(int i) {
boost::array<int, 5> a = {{0, 0, 0, 0, 0}};
if (i < 5) {
if (i >= 0) {
foo(a[i]);
} else {
oops(i);
}
}
std::exit(2);
}
BOOST_NOINLINE void foo(int i) {
bar(--i);
}
#include <iostream>
int main() {
//[getting_started_catching_trace
try {
foo(5); // testing assert handler
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
const boost::stacktrace::stacktrace* st = boost::get_error_info<traced>(e);
if (st) {
std::cerr << *st << '\n'; /*<-*/ std::exit(0); /*->*/
} /*<-*/ std::exit(3); /*->*/
}
//]
return 5;
}

View File

@@ -0,0 +1,63 @@
// 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)
#include <boost/config.hpp>
#ifdef BOOST_NO_CXX11_RANGE_BASED_FOR
#include <boost/stacktrace.hpp>
#include <iostream> // std::cout
namespace bs = boost::stacktrace;
void dump_compact(const bs::stacktrace& st) {
for (unsigned i = 0; i < st.size(); ++i) {
bs::frame frame = st[i];
std::cout << frame.address() << ',';
}
std::cout << std::endl;
}
#else
//[getting_started_trace_addresses
#include <boost/stacktrace.hpp>
#include <iostream> // std::cout
namespace bs = boost::stacktrace;
void dump_compact(const bs::stacktrace& st) {
for (bs::frame frame: st) {
std::cout << frame.address() << ',';
}
std::cout << std::endl;
}
//]
#endif
BOOST_NOINLINE boost::stacktrace::stacktrace rec1(int i);
BOOST_NOINLINE boost::stacktrace::stacktrace rec2(int i);
BOOST_NOINLINE boost::stacktrace::stacktrace rec1(int i) {
if (i < 5) {
if (!i) return boost::stacktrace::stacktrace();
return rec2(--i);
}
return rec2(i - 2);
}
BOOST_NOINLINE boost::stacktrace::stacktrace rec2(int i) {
if (i < 5) {
if (!i) return boost::stacktrace::stacktrace();
return rec2(--i);
}
return rec2(i - 2);
}
int main() {
dump_compact(rec1(8));
}

View File

@@ -0,0 +1,38 @@
// 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)
#define BOOST_USER_CONFIG <libs/stacktrace/example/user_config.hpp>
#include <boost/array.hpp>
#include <exception> // std::set_terminate, std::abort
#include <boost/stacktrace.hpp>
#include <iostream> // std::cerr
BOOST_NOINLINE void foo(int i);
BOOST_NOINLINE void bar(int i);
BOOST_NOINLINE void bar(int i) {
boost::array<int, 5> a = {{-1, -231, -123, -23, -32}};
if (i >= 0) {
foo(a[i]);
} else {
std::cerr << "Terminate called:\n" << boost::stacktrace::stacktrace() << '\n';
std::exit(0);
}
}
BOOST_NOINLINE void foo(int i) {
bar(--i);
}
int main() {
foo(5);
return 2;
}

View File

@@ -0,0 +1,55 @@
// 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)
//[getting_started_user_config
#ifndef USER_CONFIG_HPP
#define USER_CONFIG_HPP
#include <boost/stacktrace/stacktrace_fwd.hpp>
#include <iosfwd>
namespace boost { namespace stacktrace {
template <class CharT, class TraitsT, class Allocator>
std::basic_ostream<CharT, TraitsT>& do_stream_st(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt);
template <class CharT, class TraitsT>
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const stacktrace& bt) {
return do_stream_st(os, bt);
}
}} // namespace boost::stacktrace
#endif // USER_CONFIG_HPP
//]
#ifndef USER_CONFIG2_HPP
#define USER_CONFIG2_HPP
//[getting_started_user_config_impl
namespace boost { namespace stacktrace {
template <class CharT, class TraitsT, class Allocator>
std::basic_ostream<CharT, TraitsT>& do_stream_st(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) {
const std::streamsize w = os.width();
const std::size_t frames = bt.size();
for (std::size_t i = 0; i < frames; ++i) {
os.width(2);
os << i;
os.width(w);
os << "# ";
os << bt[i].name();
os << '\n';
}
return os;
}
}} // namespace boost::stacktrace
//]
#endif // USER_CONFIG2_HPP

View File

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<!--
Copyright (c) 2014-2017 Antony Polukhin
antoshkka at gmail dot com
Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://boost.org/LICENSE_1_0.txt)
-->
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=../../doc/html/stacktrace.html">
<title>Boost.Stacktrace</title>
<style>
body {
background: #fff;
color: #000;
}
a {
color: #00f;
text-decoration: none;
}
</style>
</head>
<body>
<p>
Automatic redirection failed, please go to
<a href="../../doc/html/stacktrace.html">../../doc/html/stacktrace.html</a>
</p>
<p>
&copy; 2014-2017 Antony Polukhin
</p>
</body>
</html>

View File

@@ -0,0 +1,14 @@
{
"key": "stacktrace",
"name": "Stacktrace",
"authors": [
"Antony Polukhin"
],
"maintainers": [
"Antony Polukhin <antoshkka -at- gmail.com>"
],
"description": "Gather, store, copy and print backtraces.",
"category": [
"System", "Correctness"
]
}

View File

@@ -0,0 +1,16 @@
// 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)
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_ADDR2LINE
#define BOOST_STACKTRACE_LINK
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <boost/stacktrace/detail/frame_unwind.ipp>
#include <boost/stacktrace/safe_dump_to.hpp>

View File

@@ -0,0 +1,16 @@
// 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)
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_BACKTRACE
#define BOOST_STACKTRACE_LINK
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <boost/stacktrace/detail/frame_unwind.ipp>
#include <boost/stacktrace/safe_dump_to.hpp>

View File

@@ -0,0 +1,15 @@
// 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)
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_LINK
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <boost/stacktrace/detail/frame_unwind.ipp>
#include <boost/stacktrace/safe_dump_to.hpp>

View File

@@ -0,0 +1,11 @@
// 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)
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_LINK
#define BOOST_STACKTRACE_USE_NOOP
#include <boost/stacktrace/detail/frame_noop.ipp>
#include <boost/stacktrace/detail/safe_dump_noop.ipp>

View File

@@ -0,0 +1,10 @@
// 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)
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_LINK
#include <boost/stacktrace/detail/frame_msvc.ipp>
#include <boost/stacktrace/safe_dump_to.hpp>

View File

@@ -0,0 +1,11 @@
// 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)
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_LINK
#define BOOST_STACKTRACE_USE_WINDBG_CACHED
#include <boost/stacktrace/detail/frame_msvc.ipp>
#include <boost/stacktrace/safe_dump_to.hpp>

View File

@@ -0,0 +1,190 @@
# Copyright (C) 2016-2017, Antony Polukhin.
#
# Use, modification and distribution is 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)
#
lib dl : : <link>shared ;
lib gcc_s ;
lib rt ;
lib Dbgeng ;
lib ole32 ;
local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ;
lib backtrace
:
: <search>$(LIBBACKTRACE_PATH)/lib <link>static
:
: <include>$(LIBBACKTRACE_PATH)/include
;
project
: requirements
<toolset>msvc:<asynch-exceptions>on
<toolset>intel:<cxxflags>-wd2196
<warnings>all
<test-info>always_show_run_output
;
local RDYNAMIC = <target-os>freebsd:<linkflags>"-rdynamic" <target-os>solaris:<linkflags>"-Bdynamic" <target-os>aix:<linkflags>"-rdynamic"
<target-os>qnxnto,<toolset>qcc:<linkflags>"-Bdynamic" <target-os>qnxnto,<toolset>gcc:<linkflags>"-rdynamic"
<target-os>android:<linkflags>"-rdynamic" <target-os>linux:<linkflags>"-rdynamic" <target-os>darwin,<toolset>gcc:<linkflags>"-dynamic"
<target-os>darwin,<toolset>clang:<linkflags>"-rdynamic" <target-os>iphone:<linkflags>"-rdynamic" ;
local HIDE_SYMBS = <target-os>linux:<cxxflags>"-fvisibility=hidden" ;
local BT_DEPS = $(HIDE_SYMBS) <target-os>linux:<library>dl <library>backtrace [ check-target-builds ../build//libbacktrace : : <build>no ] ;
local AD2L_DEPS = $(HIDE_SYMBS) <target-os>linux:<library>dl [ check-target-builds ../build//addr2line : : <build>no ] ;
local WIND_DEPS = $(HIDE_SYMBS) <library>Dbgeng <library>ole32 [ check-target-builds ../build//WinDbg : : <build>no ] ;
local WICA_DEPS = $(HIDE_SYMBS) <library>Dbgeng <library>ole32 [ check-target-builds ../build//WinDbgCached : : <build>no ] ;
local NOOP_DEPS = $(HIDE_SYMBS) ;
local BASIC_DEPS = $(RDYNAMIC) <target-os>linux:<library>dl [ check-target-builds ../build//WinDbg : <build>no ] ;
local LINKSHARED_BT = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_backtrace $(BT_DEPS) ;
local LINKSHARED_AD2L = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_addr2line $(AD2L_DEPS) ;
local LINKSHARED_WIND = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_windbg $(WIND_DEPS) ;
local LINKSHARED_WIND_CACHED = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_windbg_cached $(WICA_DEPS) ;
local LINKSHARED_NOOP = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_noop $(NOOP_DEPS) ;
local LINKSHARED_BASIC = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_basic $(BASIC_DEPS) ;
# Libs with debug symbols
lib test_impl_lib_backtrace : test_impl.cpp : <debug-symbols>on $(LINKSHARED_BT) ;
lib test_impl_lib_addr2line : test_impl.cpp : <debug-symbols>on $(LINKSHARED_AD2L) ;
lib test_impl_lib_windbg : test_impl.cpp : <debug-symbols>on $(LINKSHARED_WIND) ;
lib test_impl_lib_windbg_cached : test_impl.cpp : <debug-symbols>on $(LINKSHARED_WIND_CACHED) ;
lib test_impl_lib_noop : test_impl.cpp : <debug-symbols>on $(LINKSHARED_NOOP) ;
obj test_impl_nohide-obj : test_impl.cpp : <debug-symbols>on $(LINKSHARED_BASIC) ;
lib test_impl_lib_basic : test_impl_nohide-obj : <debug-symbols>on $(LINKSHARED_BASIC) ;
# Libs without debug symbols
lib test_impl_lib_backtrace_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_BT) ;
lib test_impl_lib_addr2line_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_AD2L) ;
lib test_impl_lib_windbg_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_WIND) ;
lib test_impl_lib_windbg_cached_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_WIND_CACHED) ;
lib test_impl_lib_noop_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_NOOP) ;
obj test_impl_nohide_no_dbg-obj : test_impl.cpp : <debug-symbols>off $(LINKSHARED_BASIC) ;
lib test_impl_lib_basic_no_dbg : test_impl_nohide_no_dbg-obj : <debug-symbols>off $(LINKSHARED_BASIC) ;
test-suite stacktrace_tests
:
# Header only tests with debug symbols
[ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : backtrace_ho ]
[ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_ADDR2LINE $(AD2L_DEPS) : addr2line_ho ]
[ run test_noop.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_NOOP $(NOOP_DEPS) : noop_ho ]
[ run test.cpp test_impl.cpp : : : <debug-symbols>on $(WIND_DEPS) : windbg_ho ]
[ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_WINDBG_CACHED $(WICA_DEPS) : windbg_cached_ho ]
[ run test.cpp test_impl.cpp : : : <debug-symbols>on $(BASIC_DEPS) : basic_ho ]
# Test with shared linked implementations with debug symbols
[ run test.cpp : : : <debug-symbols>on <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) : backtrace_lib ]
[ run test.cpp : : : <debug-symbols>on <library>.//test_impl_lib_addr2line $(LINKSHARED_AD2L) : addr2line_lib ]
[ run test.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg $(LINKSHARED_WIND) : windbg_lib ]
[ run test.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg_cached $(LINKSHARED_WIND_CACHED) : windbg_cached_lib ]
[ run test_noop.cpp : : : <debug-symbols>on <library>.//test_impl_lib_noop $(LINKSHARED_NOOP) : noop_lib ]
[ run test.cpp : : : <debug-symbols>on <library>.//test_impl_lib_basic $(LINKSHARED_BASIC) : basic_lib ]
# Thread safety with debug symbols
[ run thread_safety_checking.cpp
: : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_backtrace $(LINKSHARED_BT)
: backtrace_lib_threaded ]
[ run thread_safety_checking.cpp
: : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg $(LINKSHARED_WIND)
: windbg_lib_threaded ]
[ run thread_safety_checking.cpp
: : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg_cached $(LINKSHARED_WIND_CACHED)
: windbg_cached_lib_threaded ]
[ run thread_safety_checking.cpp
: : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_basic $(LINKSHARED_BASIC)
: basic_lib_threaded ]
[ run thread_safety_checking.cpp
: : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg
$(LINKSHARED_WIND) <define>BOOST_STACKTRACE_TEST_COM_PREINIT_MT
: windbg_lib_threaded_com_mt ]
[ run thread_safety_checking.cpp
: : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg_cached
$(LINKSHARED_WIND_CACHED) <define>BOOST_STACKTRACE_TEST_COM_PREINIT_ST
: windbg_cached_lib_threaded_com_st ]
##### Tests with disabled debug symbols #####
# Header only tests without debug symbols
[ run test.cpp test_impl.cpp : : : <debug-symbols>off <define>BOOST_STACKTRACE_USE_BACKTRACE <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(BT_DEPS) : backtrace_ho_no_dbg ]
[ run test_noop.cpp test_impl.cpp : : : <debug-symbols>off <define>BOOST_STACKTRACE_USE_NOOP $(NOOP_DEPS) : noop_ho_no_dbg ]
[ run test.cpp test_impl.cpp : : : <debug-symbols>off <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(WIND_DEPS) : windbg_ho_no_dbg ]
[ run test.cpp test_impl.cpp : : : <debug-symbols>off <define>BOOST_STACKTRACE_USE_WINDBG_CACHED <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(WICA_DEPS) : windbg_cached_ho_no_dbg ]
[ run test.cpp test_impl.cpp : : : <debug-symbols>off $(BASIC_DEPS) : basic_ho_no_dbg ]
[ run test.cpp test_impl.cpp
: : : <debug-symbols>off <define>BOOST_STACKTRACE_USE_ADDR2LINE <define>BOOST_STACKTRACE_ADDR2LINE_LOCATION="/usr/bin/addr2line" $(AD2L_DEPS)
: addr2line_ho_no_dbg ]
# Test with shared linked implementations without debug symbols
[ run test.cpp : : : <debug-symbols>off <library>.//test_impl_lib_backtrace_no_dbg $(LINKSHARED_BT) <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL : backtrace_lib_no_dbg ]
[ run test.cpp : : : <debug-symbols>off <library>.//test_impl_lib_addr2line_no_dbg $(LINKSHARED_AD2L) : addr2line_lib_no_dbg ]
[ run test.cpp : : : <debug-symbols>off <library>.//test_impl_lib_windbg_no_dbg $(LINKSHARED_WIND) <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL : windbg_lib_no_dbg ]
[ run test.cpp : : : <debug-symbols>off <library>.//test_impl_lib_windbg_cached_no_dbg $(LINKSHARED_WIND_CACHED) <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL : windbg_cached_lib_no_dbg ]
[ run test_noop.cpp : : : <debug-symbols>off <library>.//test_impl_lib_noop_no_dbg $(LINKSHARED_NOOP) : noop_lib_no_dbg ]
[ run test.cpp : : : <debug-symbols>off <library>.//test_impl_lib_basic_no_dbg $(LINKSHARED_BASIC) : basic_lib_no_dbg ]
# Thread safety without debug symbols
[ run thread_safety_checking.cpp
: : : <debug-symbols>off <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_backtrace_no_dbg $(LINKSHARED_BT)
: backtrace_lib_no_dbg_threaded ]
[ run thread_safety_checking.cpp
: : : <debug-symbols>off <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg_no_dbg $(LINKSHARED_WIND)
: windbg_lib_no_dbg_threaded ]
[ run thread_safety_checking.cpp
: : : <debug-symbols>off <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg_cached_no_dbg $(LINKSHARED_WIND_CACHED)
: windbg_cached_lib_no_dbg_threaded ]
[ run thread_safety_checking.cpp
: : : <debug-symbols>off <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_basic_no_dbg $(LINKSHARED_BASIC)
: basic_lib_no_dbg_threaded ]
[ run thread_safety_checking.cpp
: : : <debug-symbols>off <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg
$(LINKSHARED_WIND) <define>BOOST_STACKTRACE_TEST_COM_PREINIT_MT
: windbg_lib_threaded_com_mt ]
[ run thread_safety_checking.cpp
: : : <debug-symbols>off <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg_cached
$(LINKSHARED_WIND_CACHED) <define>BOOST_STACKTRACE_TEST_COM_PREINIT_ST
: windbg_cached_lib_threaded_com_st ]
[ run test_void_ptr_cast.cpp ]
;
# Assuring that examples compile and run. Adding sources from `examples` directory to the `type_index` test suite.
for local p in [ glob ../example/*.cpp ]
{
local target_name = $(p[1]:B) ;
local additional_dependency = ;
if $(target_name) = "terminate_handler"
{
additional_dependency = <library>/boost/filesystem//boost_filesystem <library>/boost/system//boost_system <target-os>linux:<library>rt ;
}
stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_BT) $(additional_dependency) : backtrace_$(p2[1]:B) ] ;
stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_AD2L) $(additional_dependency) : addr2line_$(p[1]:B) ] ;
stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_WIND) $(additional_dependency) : windbg_$(p[1]:B) ] ;
stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_WIND_CACHED) $(additional_dependency) : windbg_cached_$(p[1]:B) ] ;
stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_NOOP) $(additional_dependency) : noop_$(p[1]:B) ] ;
stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_BASIC) $(additional_dependency) : basic_$(p[1]:B) ] ;
##### Tests with disabled debug symbols #####
stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_BT) $(additional_dependency) : backtrace_$(p[1]:B)_no_dbg ] ;
stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_AD2L) $(additional_dependency) : addr2line_$(p[1]:B)_no_dbg ] ;
stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_WIND) $(additional_dependency) : windbg_$(p[1]:B)_no_dbg ] ;
stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_WIND_CACHED) $(additional_dependency) : windbg_cached_$(p[1]:B)_no_dbg ] ;
stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_NOOP) $(additional_dependency) : noop_$(p[1]:B)_no_dbg ] ;
stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_BASIC) $(additional_dependency) : basic_$(p[1]:B)_no_dbg ] ;
}

View File

@@ -0,0 +1,285 @@
// 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)
#include <boost/stacktrace/stacktrace_fwd.hpp>
#include <boost/stacktrace.hpp>
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <boost/core/lightweight_test.hpp>
#include <boost/functional/hash.hpp>
using boost::stacktrace::stacktrace;
using boost::stacktrace::frame;
#ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_ST_API BOOST_SYMBOL_IMPORT
#else
# define BOOST_ST_API
#endif
#if (defined(BOOST_GCC) && defined(BOOST_WINDOWS) && !defined(BOOST_STACKTRACE_USE_BACKTRACE) && !defined(BOOST_STACKTRACE_USE_ADDR2LINE)) \
|| defined(BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL)
# define BOOST_STACKTRACE_SYMNAME 0
#else
# define BOOST_STACKTRACE_SYMNAME 1
#endif
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
BOOST_ST_API std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1);
BOOST_ST_API stacktrace return_from_nested_namespaces();
BOOST_ST_API boost::stacktrace::stacktrace bar1();
BOOST_ST_API boost::stacktrace::stacktrace bar2();
BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo1(int i) {
if (i) {
return foo2(i - 1, foo1);
}
std::pair<stacktrace, stacktrace> ret;
try {
throw std::logic_error("test");
} catch (const std::logic_error& /*e*/) {
ret.second = stacktrace();
return ret;
}
}
void test_deeply_nested_namespaces() {
std::stringstream ss;
ss << return_from_nested_namespaces();
std::cout << ss.str() << '\n';
#if BOOST_STACKTRACE_SYMNAME
BOOST_TEST(ss.str().find("main") != std::string::npos);
BOOST_TEST(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos
|| ss.str().find("1# return_from_nested_namespaces") != std::string::npos); // GCC with -O1 has strange inlining, so this line is true while the prev one is false.
BOOST_TEST(ss.str().find("return_from_nested_namespaces") != std::string::npos);
#endif
stacktrace ns1 = return_from_nested_namespaces();
BOOST_TEST(ns1 != return_from_nested_namespaces()); // Different addresses in test_deeply_nested_namespaces() function
}
// Template parameter Depth is to produce different functions on each Depth. This simplifies debugging when one of the tests catches error
template <std::size_t Depth>
void test_nested() {
std::pair<stacktrace, stacktrace> res = foo2(Depth, foo1);
std::stringstream ss1, ss2;
ss1 << res.first;
ss2 << res.second;
std::cout << "'" << ss1.str() << "'\n\n" << ss2.str() << std::endl;
BOOST_TEST(!ss1.str().empty());
BOOST_TEST(!ss2.str().empty());
BOOST_TEST(ss1.str().find(" 0# ") != std::string::npos);
BOOST_TEST(ss2.str().find(" 0# ") != std::string::npos);
BOOST_TEST(ss1.str().find(" 1# ") != std::string::npos);
BOOST_TEST(ss2.str().find(" 1# ") != std::string::npos);
BOOST_TEST(ss1.str().find(" in ") != std::string::npos);
BOOST_TEST(ss2.str().find(" in ") != std::string::npos);
#if BOOST_STACKTRACE_SYMNAME
BOOST_TEST(ss1.str().find("main") != std::string::npos);
BOOST_TEST(ss2.str().find("main") != std::string::npos);
BOOST_TEST(ss1.str().find("foo2") != std::string::npos);
BOOST_TEST(ss2.str().find("foo2") != std::string::npos);
BOOST_TEST(ss1.str().find("foo1") != std::string::npos);
BOOST_TEST(ss2.str().find("foo1") != std::string::npos);
#endif
//BOOST_TEST(false);
}
template <class Bt>
void test_comparisons_base(Bt nst, Bt st) {
Bt cst(st);
st = st;
cst = cst;
BOOST_TEST(nst);
BOOST_TEST(st);
#if !defined(BOOST_MSVC) && !defined(BOOST_STACKTRACE_USE_WINDBG)
// This is very dependent on compiler and link flags. No sane way to make it work, because
// BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled.
BOOST_TEST(nst[0] != st[0]);
#endif
BOOST_TEST(nst != st);
BOOST_TEST(st != nst);
BOOST_TEST(st == st);
BOOST_TEST(nst == nst);
BOOST_TEST(nst != cst);
BOOST_TEST(cst != nst);
BOOST_TEST(cst == st);
BOOST_TEST(cst == cst);
BOOST_TEST(nst < st || nst > st);
BOOST_TEST(st < nst || nst < st);
BOOST_TEST(st <= st);
BOOST_TEST(nst <= nst);
BOOST_TEST(st >= st);
BOOST_TEST(nst >= nst);
BOOST_TEST(nst < cst || cst < nst);
BOOST_TEST(nst > cst || cst > nst);
BOOST_TEST(hash_value(nst) == hash_value(nst));
BOOST_TEST(hash_value(cst) == hash_value(st));
BOOST_TEST(hash_value(nst) != hash_value(cst));
BOOST_TEST(hash_value(st) != hash_value(nst));
}
void test_comparisons() {
stacktrace nst = return_from_nested_namespaces();
stacktrace st;
test_comparisons_base(nst, st);
}
void test_iterators() {
stacktrace st;
BOOST_TEST(st.begin() == st.begin());
BOOST_TEST(st.cbegin() == st.cbegin());
BOOST_TEST(st.crbegin() == st.crbegin());
BOOST_TEST(st.rbegin() == st.rbegin());
BOOST_TEST(st.begin() + 1 == st.begin() + 1);
BOOST_TEST(st.cbegin() + 1 == st.cbegin() + 1);
BOOST_TEST(st.crbegin() + 1 == st.crbegin() + 1);
BOOST_TEST(st.rbegin() + 1 == st.rbegin() + 1);
BOOST_TEST(st.end() == st.end());
BOOST_TEST(st.cend() == st.cend());
BOOST_TEST(st.crend() == st.crend());
BOOST_TEST(st.rend() == st.rend());
BOOST_TEST(st.end() > st.begin());
BOOST_TEST(st.end() > st.cbegin());
BOOST_TEST(st.cend() > st.cbegin());
BOOST_TEST(st.cend() > st.begin());
BOOST_TEST(st.size() == static_cast<std::size_t>(st.end() - st.begin()));
BOOST_TEST(st.size() == static_cast<std::size_t>(st.end() - st.cbegin()));
BOOST_TEST(st.size() == static_cast<std::size_t>(st.cend() - st.cbegin()));
BOOST_TEST(st.size() == static_cast<std::size_t>(st.cend() - st.begin()));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.rbegin(), st.rend())));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.crbegin(), st.rend())));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.crbegin(), st.crend())));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.rbegin(), st.crend())));
boost::stacktrace::stacktrace::iterator it = st.begin();
++ it;
BOOST_TEST(it == st.begin() + 1);
}
void test_frame() {
stacktrace nst = return_from_nested_namespaces();
stacktrace st;
const std::size_t min_size = (nst.size() < st.size() ? nst.size() : st.size());
BOOST_TEST(min_size > 2);
for (std::size_t i = 0; i < min_size; ++i) {
BOOST_TEST(st[i] == st[i]);
BOOST_TEST(st[i].source_file() == st[i].source_file());
BOOST_TEST(st[i].source_line() == st[i].source_line());
BOOST_TEST(st[i] <= st[i]);
BOOST_TEST(st[i] >= st[i]);
frame fv = nst[i];
BOOST_TEST(fv);
if (i > 1 && i < min_size - 3) { // Begin ...and end of the trace may match, skipping
BOOST_TEST(st[i] != fv);
#if !(defined(BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL) && defined(BOOST_MSVC))
// MSVC can not get function name withhout debug symbols even if it is exported
BOOST_TEST(st[i].name() != fv.name());
BOOST_TEST(st[i] != fv);
BOOST_TEST(st[i] < fv || st[i] > fv);
BOOST_TEST(hash_value(st[i]) != hash_value(fv));
#endif
if (st[i].source_line()) {
BOOST_TEST(st[i].source_file() != fv.source_file() || st[i].source_line() != fv.source_line());
}
BOOST_TEST(st[i]);
}
fv = st[i];
BOOST_TEST(hash_value(st[i]) == hash_value(fv));
}
boost::stacktrace::frame empty_frame;
BOOST_TEST(!empty_frame);
BOOST_TEST(empty_frame.source_file() == "");
BOOST_TEST(empty_frame.name() == "");
BOOST_TEST(empty_frame.source_line() == 0);
}
// Template parameter bool BySkip is to produce different functions on each BySkip. This simplifies debugging when one of the tests catches error
template <bool BySkip>
void test_empty_basic_stacktrace() {
typedef boost::stacktrace::stacktrace st_t;
st_t st = BySkip ? st_t(100500, 1024) : st_t(0, 0);
BOOST_TEST(!st);
BOOST_TEST(st.empty());
BOOST_TEST(st.size() == 0);
BOOST_TEST(st.begin() == st.end());
BOOST_TEST(st.cbegin() == st.end());
BOOST_TEST(st.cbegin() == st.cend());
BOOST_TEST(st.begin() == st.cend());
BOOST_TEST(st.rbegin() == st.rend());
BOOST_TEST(st.crbegin() == st.rend());
BOOST_TEST(st.crbegin() == st.crend());
BOOST_TEST(st.rbegin() == st.crend());
BOOST_TEST(hash_value(st) == hash_value(st_t(0, 0)));
BOOST_TEST(st == st_t(0, 0));
BOOST_TEST(!(st < st_t(0, 0)));
BOOST_TEST(!(st > st_t(0, 0)));
}
int main() {
test_deeply_nested_namespaces();
test_nested<15>();
test_comparisons();
test_iterators();
test_frame();
test_empty_basic_stacktrace<true>();
test_empty_basic_stacktrace<false>();
BOOST_TEST(&bar1 != &bar2);
boost::stacktrace::stacktrace b1 = bar1();
BOOST_TEST(b1.size() == 4);
boost::stacktrace::stacktrace b2 = bar2();
BOOST_TEST(b2.size() == 4);
test_comparisons_base(bar1(), bar2());
test_nested<300>();
BOOST_TEST(boost::stacktrace::stacktrace(0, 1).size() == 1);
BOOST_TEST(boost::stacktrace::stacktrace(1, 1).size() == 1);
return boost::report_errors();
}

View File

@@ -0,0 +1,89 @@
// 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)
#include <boost/stacktrace/stacktrace.hpp>
#if defined(BOOST_LEXICAL_CAST_TRY_LEXICAL_CONVERT_HPP) || defined(BOOST_LEXICAL_CAST_BAD_LEXICAL_CAST_HPP)
#error "LexicalCast headers leaked into the boost/stacktrace/stacktrace.hpp"
#endif
#if !defined(BOOST_USE_WINDOWS_H) && defined(_WINDOWS_H)
#error "windows.h header leaked into the boost/stacktrace/stacktrace.hpp"
#endif
#include <stdexcept>
using namespace boost::stacktrace;
#ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_ST_API BOOST_SYMBOL_EXPORT
#else
# define BOOST_ST_API
#endif
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
BOOST_ST_API BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1) {
if (i) {
return foo1(--i);
} else {
return foo1(i);
}
}
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 {
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 {
namespace very_very_very_very_very_very_long_namespace {
namespace very_very_very_very_very_very_long_namespace {
BOOST_ST_API BOOST_NOINLINE stacktrace get_backtrace_from_nested_namespaces() {
return stacktrace();
}
}}}}}}}}}}
BOOST_ST_API BOOST_NOINLINE 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;
return get_backtrace_from_nested_namespaces();
}
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace bar1_impl(int d = 0) {
boost::stacktrace::stacktrace result(0, 4);
if (result.size() < 4) {
if (d > 4) throw std::runtime_error("Stack is not growing in test OR stacktrace fails to work in `bar1` function.");
return bar1_impl(d + 1);
}
return result;
}
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace bar2_impl(int d = 0) {
boost::stacktrace::stacktrace result(0, 4);
if (result.size() < 4) {
if (d > 4) throw std::runtime_error("Stack is not growing in test OR stacktrace fails to work in `bar2` function.");
return bar2_impl(d + 1);
}
return result;
}
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace bar1() {
boost::stacktrace::stacktrace result = bar1_impl();
return result;
}
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace bar2() {
boost::stacktrace::stacktrace result = bar2_impl();
return result;
}

View File

@@ -0,0 +1,81 @@
// 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)
#include <boost/stacktrace.hpp>
#include <boost/core/lightweight_test.hpp>
#include <stdexcept>
#include <boost/functional/hash.hpp>
using boost::stacktrace::stacktrace;
using boost::stacktrace::frame;
#ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_ST_API BOOST_SYMBOL_IMPORT
#else
# define BOOST_ST_API
#endif
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
BOOST_ST_API std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1);
BOOST_ST_API stacktrace return_from_nested_namespaces();
BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo1(int i) {
if (i) {
return foo2(i - 1, foo1);
}
std::pair<stacktrace, stacktrace> ret;
try {
throw std::logic_error("test");
} catch (const std::logic_error& /*e*/) {
ret.second = stacktrace();
return ret;
}
}
void test_deeply_nested_namespaces() {
BOOST_TEST(return_from_nested_namespaces().size() == 0);
BOOST_TEST(return_from_nested_namespaces().empty());
BOOST_TEST(!return_from_nested_namespaces());
}
void test_nested() {
std::pair<stacktrace, stacktrace> res = foo2(15, foo1);
BOOST_TEST(!res.first);
BOOST_TEST(res.first.empty());
BOOST_TEST(res.first.size() == 0);
BOOST_TEST(res.second <= res.first);
BOOST_TEST(res.second >= res.first);
BOOST_TEST(res.second == res.first);
BOOST_TEST(res.second == res.first);
BOOST_TEST(!(res.second > res.first));
}
void test_empty_frame() {
boost::stacktrace::frame empty_frame;
BOOST_TEST(!empty_frame);
BOOST_TEST(empty_frame.source_file() == "");
BOOST_TEST(empty_frame.name() == "");
BOOST_TEST(empty_frame.source_line() == 0);
boost::stacktrace::frame f(0);
BOOST_TEST(f.name() == "");
BOOST_TEST(f.source_file() == "");
BOOST_TEST(f.source_line() == 0);
}
int main() {
test_deeply_nested_namespaces();
test_nested();
test_empty_frame();
return boost::report_errors();
}

View File

@@ -0,0 +1,79 @@
// Copyright 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)
#include <boost/stacktrace/detail/void_ptr_cast.hpp>
#include <boost/core/lightweight_test.hpp>
int foo1_func(int) { return 0; }
void foo2_func(int, int, ...) {}
struct test_struct {
int foo1_memb(int) const { return 0; }
void foo2_memb(int, int, ...) {}
};
template <class F1, class F2>
void test(F1 foo1, F2 foo2) {
using boost::stacktrace::detail::void_ptr_cast;
typedef void(*void_f_ptr)();
// Function/variable to void(*)()
void_f_ptr fp1 = void_ptr_cast<void_f_ptr>(foo1);
void_f_ptr fp2 = void_ptr_cast<void_f_ptr>(foo2);
BOOST_TEST(fp1);
BOOST_TEST(fp2);
BOOST_TEST(fp1 != fp2);
// Function/variable to void*
void* vp1 = void_ptr_cast<void*>(foo1);
void* vp2 = void_ptr_cast<void*>(foo2);
BOOST_TEST(vp1);
BOOST_TEST(vp2);
BOOST_TEST(vp1 != vp2);
// void* to void(*)()
void_f_ptr fp1_2 = void_ptr_cast<void_f_ptr>(vp1);
void_f_ptr fp2_2 = void_ptr_cast<void_f_ptr>(vp2);
BOOST_TEST(fp1_2);
BOOST_TEST(fp2_2);
BOOST_TEST(fp1_2 != fp2_2);
BOOST_TEST(fp1 == fp1_2);
BOOST_TEST(fp2 == fp2_2);
// void(*)() to void*
BOOST_TEST(void_ptr_cast<void*>(fp1) == vp1);
BOOST_TEST(void_ptr_cast<void*>(fp2) == vp2);
// void(*)() to function/variable
BOOST_TEST(void_ptr_cast<F1>(fp1) == foo1);
BOOST_TEST(void_ptr_cast<F2>(fp2) == foo2);
// void* to function/variable
BOOST_TEST(void_ptr_cast<F1>(vp1) == foo1);
BOOST_TEST(void_ptr_cast<F2>(vp2) == foo2);
}
int main() {
// Testing for functions
test(foo1_func, foo2_func);
typedef void(func_t)();
test(
boost::stacktrace::detail::void_ptr_cast<func_t* const>(foo1_func),
boost::stacktrace::detail::void_ptr_cast<func_t* const>(foo2_func)
);
// Testing for variables (just in case...)
int i = 0;
double j= 1;
test(&i, &j);
return boost::report_errors();
}

View File

@@ -0,0 +1,94 @@
// 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)
#include <boost/stacktrace/stacktrace_fwd.hpp>
#include <sstream>
#include <boost/stacktrace.hpp>
#include <boost/thread.hpp>
#include <boost/optional.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/timer/timer.hpp>
#ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_ST_API BOOST_SYMBOL_IMPORT
#else
# define BOOST_ST_API
#endif
using boost::stacktrace::stacktrace;
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
BOOST_ST_API std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1);
BOOST_ST_API stacktrace return_from_nested_namespaces();
BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo1(int i) {
if (i) {
return foo2(i - 1, foo1);
}
std::pair<stacktrace, stacktrace> ret;
try {
throw std::logic_error("test");
} catch (const std::logic_error& /*e*/) {
ret.second = stacktrace();
return ret;
}
}
void main_test_loop() {
std::size_t loops = 100;
int Depth = 25;
boost::optional<std::pair<stacktrace, stacktrace> > ethalon;
std::stringstream ss_ethalon;
while (--loops) {
std::pair<stacktrace, stacktrace> res = foo2(Depth, foo1);
if (ethalon) {
BOOST_TEST(res == *ethalon);
std::stringstream ss;
ss << res.first;
BOOST_TEST(ss.str() == ss_ethalon.str());
} else {
ethalon = res;
ss_ethalon << ethalon->first;
}
}
}
#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT) || defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST)
# include <windows.h>
# include "dbgeng.h"
#endif
int main() {
#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT)
::CoInitializeEx(0, COINIT_MULTITHREADED);
#elif defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST)
::CoInitializeEx(0, COINIT_APARTMENTTHREADED);
#endif
boost::timer::auto_cpu_timer t;
boost::thread t1(main_test_loop);
boost::thread t2(main_test_loop);
boost::thread t3(main_test_loop);
main_test_loop();
t1.join();
t2.join();
t3.join();
#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT) || defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST)
::CoUninitialize();
#endif
return boost::report_errors();
}