mirror of
https://github.com/boostorg/stacktrace.git
synced 2026-01-28 19:52:08 +00:00
Compare commits
94 Commits
boost_revi
...
boost-1.65
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8364ad1f5e | ||
|
|
b5e2058ec5 | ||
|
|
af78623e8a | ||
|
|
b84d6533f5 | ||
|
|
cd420b37ae | ||
|
|
d663d8b471 | ||
|
|
0c09c5d307 | ||
|
|
a9d92be86a | ||
|
|
b931f501d1 | ||
|
|
1614e8ff7d | ||
|
|
bcf01a77a7 | ||
|
|
86299b8a7e | ||
|
|
5afad6fcc7 | ||
|
|
f853dbfc69 | ||
|
|
9c1ed7fc95 | ||
|
|
ba2f260d95 | ||
|
|
77e69f036b | ||
|
|
cb65016e16 | ||
|
|
c3e5a98d4a | ||
|
|
be200269c1 | ||
|
|
9b7059f518 | ||
|
|
4eaaaeec3a | ||
|
|
f5318e3591 | ||
|
|
26a7e75bdb | ||
|
|
8d11eeb3ad | ||
|
|
a164f0385c | ||
|
|
bd52cde3b6 | ||
|
|
2381fa2011 | ||
|
|
77492bc517 | ||
|
|
576a5355e3 | ||
|
|
25efff8c87 | ||
|
|
29aaf100a8 | ||
|
|
ca4464d23c | ||
|
|
235226bdcc | ||
|
|
c8d526493d | ||
|
|
cff7191e46 | ||
|
|
e70847b918 | ||
|
|
63b4f96ba4 | ||
|
|
39247fbb32 | ||
|
|
25260ed667 | ||
|
|
a014c78b74 | ||
|
|
3d25e45a0d | ||
|
|
55063fd438 | ||
|
|
a562d4cb95 | ||
|
|
68c4f8be6a | ||
|
|
55791ad90c | ||
|
|
5c0176904a | ||
|
|
75296819ea | ||
|
|
269acd6929 | ||
|
|
12b3f98b98 | ||
|
|
141bc0a1d6 | ||
|
|
984b702a11 | ||
|
|
61d11f8d48 | ||
|
|
2e29ee7648 | ||
|
|
f2f66b0d2a | ||
|
|
fe5a0d9871 | ||
|
|
960f9d0f38 | ||
|
|
21c2484f75 | ||
|
|
e0fb46b62c | ||
|
|
fb29d75b3a | ||
|
|
96deb9688a | ||
|
|
a6bdf54c85 | ||
|
|
a6521b2b40 | ||
|
|
1a4ac5bac2 | ||
|
|
29859bf28e | ||
|
|
7342d0afd0 | ||
|
|
e072ec7a38 | ||
|
|
a50b0670d6 | ||
|
|
23ca1dab3b | ||
|
|
885f45e64f | ||
|
|
d990acd883 | ||
|
|
eac60a4709 | ||
|
|
23218809c1 | ||
|
|
a208f422a5 | ||
|
|
9fc256bee4 | ||
|
|
ce661c9c7b | ||
|
|
3678082434 | ||
|
|
3a49914d80 | ||
|
|
29da39c6a5 | ||
|
|
b784ccdebd | ||
|
|
287090e284 | ||
|
|
de9b588d1d | ||
|
|
fea1024491 | ||
|
|
c18532d7cc | ||
|
|
3b0e6a57a3 | ||
|
|
22261768ec | ||
|
|
d1380eba28 | ||
|
|
5664c752cb | ||
|
|
cc3c37a930 | ||
|
|
fb9de2bb6b | ||
|
|
27ec669657 | ||
|
|
46b0542350 | ||
|
|
6b3d993df1 | ||
|
|
9c1c343dad |
97
.gitattributes
vendored
Normal file
97
.gitattributes
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
* text=auto !eol svneol=native#text/plain
|
||||
*.gitattributes text svneol=native#text/plain
|
||||
|
||||
# Scriptish formats
|
||||
*.bat text svneol=native#text/plain
|
||||
*.bsh text svneol=native#text/x-beanshell
|
||||
*.cgi text svneol=native#text/plain
|
||||
*.cmd text svneol=native#text/plain
|
||||
*.js text svneol=native#text/javascript
|
||||
*.php text svneol=native#text/x-php
|
||||
*.pl text svneol=native#text/x-perl
|
||||
*.pm text svneol=native#text/x-perl
|
||||
*.py text svneol=native#text/x-python
|
||||
*.sh eol=lf svneol=LF#text/x-sh
|
||||
configure eol=lf svneol=LF#text/x-sh
|
||||
|
||||
# Image formats
|
||||
*.bmp binary svneol=unset#image/bmp
|
||||
*.gif binary svneol=unset#image/gif
|
||||
*.ico binary svneol=unset#image/ico
|
||||
*.jpeg binary svneol=unset#image/jpeg
|
||||
*.jpg binary svneol=unset#image/jpeg
|
||||
*.png binary svneol=unset#image/png
|
||||
*.tif binary svneol=unset#image/tiff
|
||||
*.tiff binary svneol=unset#image/tiff
|
||||
*.svg text svneol=native#image/svg%2Bxml
|
||||
|
||||
# Data formats
|
||||
*.pdf binary svneol=unset#application/pdf
|
||||
*.avi binary svneol=unset#video/avi
|
||||
*.doc binary svneol=unset#application/msword
|
||||
*.dsp text svneol=crlf#text/plain
|
||||
*.dsw text svneol=crlf#text/plain
|
||||
*.eps binary svneol=unset#application/postscript
|
||||
*.gz binary svneol=unset#application/gzip
|
||||
*.mov binary svneol=unset#video/quicktime
|
||||
*.mp3 binary svneol=unset#audio/mpeg
|
||||
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
|
||||
*.ps binary svneol=unset#application/postscript
|
||||
*.psd binary svneol=unset#application/photoshop
|
||||
*.rdf binary svneol=unset#text/rdf
|
||||
*.rss text svneol=unset#text/xml
|
||||
*.rtf binary svneol=unset#text/rtf
|
||||
*.sln text svneol=native#text/plain
|
||||
*.swf binary svneol=unset#application/x-shockwave-flash
|
||||
*.tgz binary svneol=unset#application/gzip
|
||||
*.vcproj text svneol=native#text/xml
|
||||
*.vcxproj text svneol=native#text/xml
|
||||
*.vsprops text svneol=native#text/xml
|
||||
*.wav binary svneol=unset#audio/wav
|
||||
*.xls binary svneol=unset#application/vnd.ms-excel
|
||||
*.zip binary svneol=unset#application/zip
|
||||
|
||||
# Text formats
|
||||
.htaccess text svneol=native#text/plain
|
||||
*.bbk text svneol=native#text/xml
|
||||
*.cmake text svneol=native#text/plain
|
||||
*.css text svneol=native#text/css
|
||||
*.dtd text svneol=native#text/xml
|
||||
*.htm text svneol=native#text/html
|
||||
*.html text svneol=native#text/html
|
||||
*.ini text svneol=native#text/plain
|
||||
*.log text svneol=native#text/plain
|
||||
*.mak text svneol=native#text/plain
|
||||
*.qbk text svneol=native#text/plain
|
||||
*.rst text svneol=native#text/plain
|
||||
*.sql text svneol=native#text/x-sql
|
||||
*.txt text svneol=native#text/plain
|
||||
*.xhtml text svneol=native#text/xhtml%2Bxml
|
||||
*.xml text svneol=native#text/xml
|
||||
*.xsd text svneol=native#text/xml
|
||||
*.xsl text svneol=native#text/xml
|
||||
*.xslt text svneol=native#text/xml
|
||||
*.xul text svneol=native#text/xul
|
||||
*.yml text svneol=native#text/plain
|
||||
boost-no-inspect text svneol=native#text/plain
|
||||
CHANGES text svneol=native#text/plain
|
||||
COPYING text svneol=native#text/plain
|
||||
INSTALL text svneol=native#text/plain
|
||||
Jamfile text svneol=native#text/plain
|
||||
Jamroot text svneol=native#text/plain
|
||||
Jamfile.v2 text svneol=native#text/plain
|
||||
Jamrules text svneol=native#text/plain
|
||||
Makefile* text svneol=native#text/plain
|
||||
README text svneol=native#text/plain
|
||||
TODO text svneol=native#text/plain
|
||||
|
||||
# Code formats
|
||||
*.c text svneol=native#text/plain
|
||||
*.cpp text svneol=native#text/plain
|
||||
*.h text svneol=native#text/plain
|
||||
*.hpp text svneol=native#text/plain
|
||||
*.ipp text svneol=native#text/plain
|
||||
*.pp text svneol=native#text/plain
|
||||
*.tpp text svneol=native#text/plain
|
||||
*.jam text svneol=native#text/plain
|
||||
*.java text svneol=native#text/plain
|
||||
@@ -28,7 +28,7 @@ env:
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE='*/numeric/conversion/converter_policies.hpp */boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE='*/numeric/conversion/converter_policies.hpp */boost/progress.hpp */filesystem/src/* */libs/timer/src/* */thread/src/* */pthread/once_atomic.cpp */src/pthread/thread.cpp */thread/src/future.cpp */boost/operators.hpp'
|
||||
|
||||
# Explicitly remove the following library from Boost. This may be usefull, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
@@ -42,6 +42,8 @@ env:
|
||||
- CXX_FLAGS="-std=c++98" LINK_FLAGS="" TOOLSET=gcc-6
|
||||
- CXX_FLAGS="-std=c++11" LINK_FLAGS="" TOOLSET=gcc-6
|
||||
- CXX_FLAGS="-std=c++1y" LINK_FLAGS="" TOOLSET=gcc-6
|
||||
- CXX_FLAGS="-std=c++11 -O0" LINK_FLAGS="" TOOLSET=gcc-6
|
||||
- CXX_FLAGS="-std=c++11 -O1" LINK_FLAGS="" TOOLSET=gcc-6
|
||||
#- CXX_FLAGS="-std=c++11 -stdlib=libc++" LINK_FLAGS="-stdlib=libc++" TOOLSET=clang
|
||||
#- CXX_FLAGS="-std=c++1y -stdlib=libc++" LINK_FLAGS="-stdlib=libc++" TOOLSET=clang
|
||||
|
||||
@@ -88,7 +90,8 @@ before_install:
|
||||
|
||||
script:
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
- ../../../b2 "testing.launcher=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.3 " address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -fsanitize=address,leak,undefined -DBOOST_TRAVISCI_BUILD $CXX_FLAGS" linkflags="$LINK_FLAGS --coverage -lasan -lubsan"
|
||||
- ../../../b2 -a "testing.launcher=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.3 " address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -fsanitize=address,leak,undefined -DBOOST_TRAVISCI_BUILD $CXX_FLAGS" linkflags="$LINK_FLAGS --coverage -lasan -lubsan"
|
||||
- ../../../b2 -a address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="-fsanitize=thread -DBOOST_TRAVISCI_BUILD $CXX_FLAGS" linkflags="$LINK_FLAGS -ltsan"
|
||||
|
||||
after_success:
|
||||
# Copying Coveralls data to a separate folder
|
||||
|
||||
10
README.md
10
README.md
@@ -1,18 +1,14 @@
|
||||
### Stacktrace
|
||||
Library for storing and printing backtraces.
|
||||
|
||||
[Documentation and examples.](http://apolukhin.github.io/stacktrace/index.html)
|
||||
[Documentation and examples.](http://boostorg.github.io/stacktrace/index.html)
|
||||
|
||||
|
||||
### Test results
|
||||
@ | Build | Tests coverage | More info
|
||||
----------------|-------------- | -------------- |-----------
|
||||
Develop branch: | [](https://travis-ci.org/apolukhin/stacktrace) [](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/develop) | [](https://coveralls.io/r/apolukhin/stacktrace?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/stacktrace.html)
|
||||
Master branch: | [](https://travis-ci.org/apolukhin/stacktrace) [](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/master) | [](https://coveralls.io/r/apolukhin/stacktrace?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/stacktrace.html)
|
||||
|
||||
|
||||
### Caution
|
||||
This is not an official Boost C++ library. It wasn't reviewed and can't be downloaded from www.boost.org. This library is available to the community to know real interest and get comments for refinement. The intention is to submit library to formal review, if community think that it is interesting!
|
||||
Develop branch: | [](https://travis-ci.org/boostorg/stacktrace) [](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/develop) | [](https://coveralls.io/github/boostorg/stacktrace?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/stacktrace.html)
|
||||
Master branch: | [](https://travis-ci.org/boostorg/stacktrace) [](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/master) | [](https://coveralls.io/github/boostorg/stacktrace?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/stacktrace.html)
|
||||
|
||||
|
||||
### License
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2016, Antony Polukhin.
|
||||
# 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
|
||||
@@ -11,8 +11,8 @@ project
|
||||
<target-os>linux:<cxxflags>"-fvisibility=hidden"
|
||||
;
|
||||
|
||||
lib dl : : <link>shared ;
|
||||
lib gcc_s : : <link>shared ;
|
||||
lib dl ;
|
||||
lib gcc_s ;
|
||||
lib Dbgeng ;
|
||||
lib ole32 ;
|
||||
|
||||
@@ -48,6 +48,9 @@ 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
|
||||
@@ -122,3 +125,18 @@ lib boost_stacktrace_windbg
|
||||
|
||||
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 ;
|
||||
|
||||
|
||||
@@ -7,10 +7,19 @@
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <unwind.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int main() {
|
||||
std::string s = "addr2line -h";
|
||||
|
||||
#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());
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <backtrace.h>
|
||||
#include <unwind.h>
|
||||
|
||||
int main() {
|
||||
backtrace_state* state = backtrace_create_state(
|
||||
|
||||
28
build/has_windbg_cached.cpp
Normal file
28
build/has_windbg_cached.cpp
Normal 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();
|
||||
}
|
||||
@@ -11,6 +11,7 @@ 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
|
||||
@@ -18,13 +19,19 @@ doxygen autodoc
|
||||
<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 ;
|
||||
@@ -41,7 +48,7 @@ boostbook standalone
|
||||
alias boostdoc
|
||||
: stacktrace
|
||||
:
|
||||
: <dependency>autodoc
|
||||
:
|
||||
: ;
|
||||
|
||||
explicit boostdoc ;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[library Boost.Stacktrace
|
||||
[quickbook 1.6]
|
||||
[version 1.0]
|
||||
[id stacktrace]
|
||||
[copyright 2016-2017 Antony Polukhin]
|
||||
[category Language Features Emulation]
|
||||
[license
|
||||
@@ -32,7 +33,7 @@ Boost.Stacktrace library is a simple C++03 library that provides information abo
|
||||
```
|
||||
#include <boost/stacktrace.hpp>
|
||||
|
||||
// ... somewere inside the `bar(int)` function that is called recursively:
|
||||
// ... somewhere inside the `bar(int)` function that is called recursively:
|
||||
std::cout << boost::stacktrace::stacktrace();
|
||||
```
|
||||
|
||||
@@ -53,7 +54,7 @@ Code from above will output something like this:
|
||||
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 boost_stacktrace.configuration_and_build section "Configuration and Build"] for allowing advanced features of the library. ]
|
||||
[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]
|
||||
@@ -64,7 +65,7 @@ Segmentation Faults and `std::terminate` calls sometimes happen in programs. Pro
|
||||
|
||||
`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/shared memory and parse it on program restart].]
|
||||
[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:
|
||||
|
||||
@@ -145,7 +146,7 @@ You can provide more information along with exception by embedding stacktraces i
|
||||
|
||||
[getting_started_class_traced]
|
||||
|
||||
* Write a helper class for throwing any exception with stacktrce:
|
||||
* Write a helper class for throwing any exception with stacktrace:
|
||||
|
||||
[getting_started_class_with_trace]
|
||||
|
||||
@@ -176,7 +177,7 @@ Code from above will output:
|
||||
|
||||
[section Enabling and disabling stacktraces]
|
||||
|
||||
At some point arises a requirement to easily enable/disable stacktraces for a whole project. That could be easily achived.
|
||||
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:
|
||||
|
||||
@@ -184,7 +185,7 @@ Just define *BOOST_STACKTRACE_LINK* for a whole project. Now you can enable/disa
|
||||
* link with other `boost_stacktrace_*` libraries
|
||||
|
||||
|
||||
See [link boost_stacktrace.configuration_and_build section "Configuration and Build"] for more info.
|
||||
See [link stacktrace.configuration_and_build section "Configuration and Build"] for more info.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -239,16 +240,16 @@ Terminate called:
|
||||
|
||||
[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 preocess. Here's another example with signal handlers.
|
||||
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 boost_stacktrace.getting_started.handle_terminates_aborts_and_seg "Handle terminates, aborts and Segmentation Faults"], but this time we are dumping stacktrace into shared memory:
|
||||
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 registring signal handlers and catching a signal, we may print stacktrace dumps on program restart:
|
||||
After registering signal handlers and catching a signal, we may print stacktrace dumps on program restart:
|
||||
|
||||
[getting_started_on_program_restart_shmem]
|
||||
|
||||
@@ -274,7 +275,8 @@ Previous run crashed and left trace in shared memory:
|
||||
15# 0x0000000000402999
|
||||
```
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -291,10 +293,13 @@ By default Boost.Stacktrace is a header-only library, but you may change that an
|
||||
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] / *BOOST_STACKTRACE_USE_WINDBG*] [*boost_stacktrace_windbg*] [ Uses COM to show debug info. ] [Windows] [yes] [yes]]
|
||||
[[['default for MSVC] / *BOOST_STACKTRACE_USE_WINDBG*] [*boost_stacktrace_windbg*] [ Uses COM to show debug info. ] [Windows] [yes] [no]]
|
||||
[[['default 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.] [Not MSVC compiler on POSIX or Windows] [no] [yes]]
|
||||
[[*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 it can be downloaded [@https://github.com/gcc-mirror/gcc/tree/master/libbacktrace from here] ] [GCC/MinGW/Clang... on POSIX or Windows] [yes] [yes]]
|
||||
[[*BOOST_STACKTRACE_USE_ADDR2LINE*] [*boost_stacktrace_addr2line*] [Use *addr2line* program to retrieve stacktrace. Requires linking with *libdl* library and calls `::fork`.] [GCC/MinGW/Clang... on POSIX] [yes] [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. ] ] [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* 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]. ] [GCC/MinGW/Clang... on POSIX or Windows] [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. ] [GCC/MinGW/Clang... 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]]
|
||||
]
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace std { inline void ignore_abort(){ std::exit(0); } }
|
||||
#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) {
|
||||
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();
|
||||
|
||||
@@ -11,15 +11,17 @@
|
||||
#include <cstdlib> // std::exit
|
||||
|
||||
void print_signal_handler_and_exit() {
|
||||
void* p = reinterpret_cast<void*>(::signal(SIGSEGV, SIG_DFL));
|
||||
boost::stacktrace::frame f(p);
|
||||
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) {
|
||||
void my_signal_handler(int /*signum*/) {
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,26 +21,17 @@ BOOST_NOINLINE void foo(int i) {
|
||||
bar(--i);
|
||||
}
|
||||
|
||||
#if defined(BOOST_GCC) && defined(BOOST_WINDOWS)
|
||||
|
||||
// MinGW workaround
|
||||
#include <cstdlib> // ::_Exit
|
||||
namespace std { using ::_Exit; }
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//[getting_started_terminate_handlers
|
||||
|
||||
#include <signal.h> // ::signal
|
||||
#include <cstdlib> // std::_Exit
|
||||
#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");
|
||||
std::_Exit(-1);
|
||||
::raise(SIGABRT);
|
||||
}
|
||||
//]
|
||||
|
||||
@@ -66,10 +57,11 @@ boost::interprocess::mapped_region g_region; // inited at program start
|
||||
|
||||
void my_signal_handler2(int signum) {
|
||||
::signal(signum, SIG_DFL);
|
||||
bool* b = static_cast<bool*>(g_region.get_address());
|
||||
*b = true; // flag that memory constains stacktrace
|
||||
boost::stacktrace::safe_dump_to(b + 1, g_region.get_size() - sizeof(bool));
|
||||
std::_Exit(-1);
|
||||
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);
|
||||
}
|
||||
//]
|
||||
|
||||
@@ -153,8 +145,8 @@ int run_3(const char* /*argv*/[]) {
|
||||
mapped_region m(g_shm, read_write, 0, shared_memory_size);
|
||||
m.swap(g_region);
|
||||
}
|
||||
bool* b = static_cast<bool*>(g_region.get_address());
|
||||
*b = false;
|
||||
void** f = static_cast<void**>(g_region.get_address());
|
||||
*f = 0;
|
||||
|
||||
::signal(SIGSEGV, &my_signal_handler2);
|
||||
::signal(SIGABRT, &my_signal_handler2);
|
||||
@@ -175,13 +167,13 @@ int run_4(const char* argv[]) {
|
||||
}
|
||||
|
||||
//[getting_started_on_program_restart_shmem
|
||||
bool* b = static_cast<bool*>(g_region.get_address()); // getting flag that memory constains stacktrace
|
||||
if (*b) { // checking that memory constains stacktrace
|
||||
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(b + 1, g_region.get_size() - sizeof(bool));
|
||||
= 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;
|
||||
*b = false; /*<-*/
|
||||
*f = 0; /*<-*/
|
||||
shared_memory_object::remove("shared_memory");
|
||||
if (std::string(argv[0]).find("noop") == std::string::npos) {
|
||||
if (!st) {
|
||||
@@ -207,38 +199,36 @@ int test_inplace() {
|
||||
const bool is_noop = !boost::stacktrace::stacktrace();
|
||||
|
||||
{
|
||||
boost::stacktrace::safe_dump_to("./backtrace2.dump");
|
||||
// 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() != ss2.size()) {
|
||||
std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
return 51;
|
||||
}
|
||||
|
||||
if (ss1 && ss1[0].name() != ss2[0].name()) {
|
||||
std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
return 52;
|
||||
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];
|
||||
boost::stacktrace::safe_dump_to(data, sizeof(data));
|
||||
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() != ss2.size()) {
|
||||
std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
return 53;
|
||||
}
|
||||
|
||||
if (ss1 && ss1[0].name() != ss2[0].name()) {
|
||||
std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
return 54;
|
||||
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';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,17 +13,28 @@
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/stacktrace/detail/try_demangle.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
|
||||
#if defined(BOOST_STACKTRACE_ADDR2LINE_LOCATION) && !defined(BOOST_NO_CXX11_CONSTEXPR)
|
||||
|
||||
constexpr bool is_abs_path(const char* path) BOOST_NOEXCEPT {
|
||||
return *path != '\0' && (
|
||||
*path == ':' || *path == '/' || is_abs_path(path + 1)
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
class addr2line_pipe {
|
||||
::FILE* p;
|
||||
::pid_t pid;
|
||||
@@ -34,7 +45,19 @@ public:
|
||||
, pid(0)
|
||||
{
|
||||
int pdes[2];
|
||||
char prog_name[] = "addr2line";
|
||||
#ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION
|
||||
char prog_name[] = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION );
|
||||
#if !defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CXX11_STATIC_ASSERT)
|
||||
static_assert(
|
||||
boost::stacktrace::detail::is_abs_path( BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION ) ),
|
||||
"BOOST_STACKTRACE_ADDR2LINE_LOCATION must be an absolute path"
|
||||
);
|
||||
#endif
|
||||
|
||||
#else
|
||||
char prog_name[] = "/usr/bin/addr2line";
|
||||
#endif
|
||||
|
||||
char* argp[] = {
|
||||
prog_name,
|
||||
const_cast<char*>(flag),
|
||||
@@ -50,19 +73,22 @@ public:
|
||||
pid = ::fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
// failed
|
||||
// Failed...
|
||||
::close(pdes[0]);
|
||||
::close(pdes[1]);
|
||||
return;
|
||||
|
||||
case 0:
|
||||
// we are the child
|
||||
// We are the child.
|
||||
::close(STDERR_FILENO);
|
||||
::close(pdes[0]);
|
||||
if (pdes[1] != STDOUT_FILENO) {
|
||||
::dup2(pdes[1], STDOUT_FILENO);
|
||||
}
|
||||
::execvp(prog_name, argp);
|
||||
|
||||
// Do not use `execlp()`, `execvp()`, and `execvpe()` here!
|
||||
// `exec*p*` functions are vulnerable to PATH variable evaluation attacks.
|
||||
::execv(prog_name, argp);
|
||||
::_exit(127);
|
||||
}
|
||||
|
||||
@@ -154,7 +180,7 @@ typedef to_string_impl_base<to_string_using_addr2line> to_string_impl;
|
||||
inline std::string name_impl(const void* addr) {
|
||||
std::string res = boost::stacktrace::detail::addr2line("-fe", addr);
|
||||
res = res.substr(0, res.find_last_of('\n'));
|
||||
res = boost::stacktrace::detail::try_demangle(res.c_str());
|
||||
res = boost::core::demangle(res.c_str());
|
||||
|
||||
if (res == "??") {
|
||||
res.clear();
|
||||
|
||||
33
include/boost/stacktrace/detail/collect_msvc.ipp
Normal file
33
include/boost/stacktrace/detail/collect_msvc.ipp
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_COLLECT_MSVC_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_COLLECT_MSVC_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
#include <boost/detail/winapi/stack_backtrace.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT {
|
||||
return boost::detail::winapi::RtlCaptureStackBackTrace(
|
||||
static_cast<boost::detail::winapi::ULONG_>(skip),
|
||||
static_cast<boost::detail::winapi::ULONG_>(max_frames_count),
|
||||
const_cast<boost::detail::winapi::PVOID_*>(out_frames),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::stacktrace
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_COLLECT_MSVC_IPP
|
||||
25
include/boost/stacktrace/detail/collect_noop.ipp
Normal file
25
include/boost/stacktrace/detail/collect_noop.ipp
Normal 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)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_COLLECT_NOOP_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_COLLECT_NOOP_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t this_thread_frames::collect(native_frame_ptr_t* /*out_frames*/, std::size_t /*max_frames_count*/, std::size_t /*skip*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_COLLECT_NOOP_IPP
|
||||
72
include/boost/stacktrace/detail/collect_unwind.ipp
Normal file
72
include/boost/stacktrace/detail/collect_unwind.ipp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_COLLECT_UNWIND_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_COLLECT_UNWIND_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
#include <unwind.h>
|
||||
#include <cstdio>
|
||||
|
||||
#if !defined(_GNU_SOURCE) && !defined(BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED) && !defined(BOOST_WINDOWS)
|
||||
#error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if _Unwind_Backtrace is available without `_GNU_SOURCE`."
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct unwind_state {
|
||||
std::size_t frames_to_skip;
|
||||
native_frame_ptr_t* current;
|
||||
native_frame_ptr_t* end;
|
||||
};
|
||||
|
||||
inline _Unwind_Reason_Code unwind_callback(::_Unwind_Context* context, void* arg) {
|
||||
// Note: do not write `::_Unwind_GetIP` because it is a macro on some platforms.
|
||||
// Use `_Unwind_GetIP` instead!
|
||||
unwind_state* const state = static_cast<unwind_state*>(arg);
|
||||
if (state->frames_to_skip) {
|
||||
--state->frames_to_skip;
|
||||
return _Unwind_GetIP(context) ? ::_URC_NO_REASON : ::_URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
*state->current = reinterpret_cast<native_frame_ptr_t>(
|
||||
_Unwind_GetIP(context)
|
||||
);
|
||||
|
||||
++state->current;
|
||||
if (!*(state->current - 1) || state->current == state->end) {
|
||||
return ::_URC_END_OF_STACK;
|
||||
}
|
||||
return ::_URC_NO_REASON;
|
||||
}
|
||||
|
||||
std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT {
|
||||
std::size_t frames_count = 0;
|
||||
if (!max_frames_count) {
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::unwind_state state = { skip + 1, out_frames, out_frames + max_frames_count };
|
||||
::_Unwind_Backtrace(&boost::stacktrace::detail::unwind_callback, &state);
|
||||
frames_count = state.current - out_frames;
|
||||
|
||||
if (frames_count && out_frames[frames_count - 1] == 0) {
|
||||
-- frames_count;
|
||||
}
|
||||
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_COLLECT_UNWIND_IPP
|
||||
159
include/boost/stacktrace/detail/frame_decl.hpp
Normal file
159
include/boost/stacktrace/detail/frame_decl.hpp
Normal file
@@ -0,0 +1,159 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_FRAME_DECL_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_FRAME_DECL_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp> // boost::stacktrace::detail::native_frame_ptr_t
|
||||
#include <boost/stacktrace/detail/void_ptr_cast.hpp>
|
||||
|
||||
#include <boost/stacktrace/detail/push_options.h>
|
||||
|
||||
/// @file boost/stacktrace/detail/frame_decl.hpp
|
||||
/// Use <boost/stacktrace/frame.hpp> header instead of this one!
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
/// @class boost::stacktrace::frame boost/stacktrace/detail/frame_decl.hpp <boost/stacktrace/frame.hpp>
|
||||
/// @brief Class that stores frame/function address and can get information about it at runtime.
|
||||
class frame {
|
||||
public:
|
||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
||||
|
||||
private:
|
||||
/// @cond
|
||||
native_frame_ptr_t addr_;
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
/// @brief Constructs frame that references NULL address.
|
||||
/// Calls to source_file() and source_line() will return empty string.
|
||||
/// Calls to source_line() will return 0.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
BOOST_CONSTEXPR frame() BOOST_NOEXCEPT
|
||||
: addr_(0)
|
||||
{}
|
||||
|
||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||
/// @brief Copy constructs frame.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
constexpr frame(const frame&) = default;
|
||||
|
||||
/// @brief Copy assigns frame.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
constexpr frame& operator=(const frame&) = default;
|
||||
#endif
|
||||
|
||||
/// @brief Constructs frame that references addr and could later generate information about that address using platform specific features.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
BOOST_CONSTEXPR explicit frame(native_frame_ptr_t addr) BOOST_NOEXCEPT
|
||||
: addr_(addr)
|
||||
{}
|
||||
|
||||
/// @brief Constructs frame that references function_addr and could later generate information about that function using platform specific features.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
template <class T>
|
||||
explicit frame(T* function_addr) BOOST_NOEXCEPT
|
||||
: addr_(boost::stacktrace::detail::void_ptr_cast<native_frame_ptr_t>(function_addr))
|
||||
{}
|
||||
|
||||
/// @returns Name of the frame (function name in a human readable form).
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
/// @throws std::bad_alloc if not enough memory to construct resulting string.
|
||||
BOOST_STACKTRACE_FUNCTION std::string name() const;
|
||||
|
||||
/// @returns Address of the frame function.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
BOOST_CONSTEXPR native_frame_ptr_t address() const BOOST_NOEXCEPT {
|
||||
return addr_;
|
||||
}
|
||||
|
||||
/// @returns Path to the source file, were the function of the frame is defined. Returns empty string
|
||||
/// if this->source_line() == 0.
|
||||
/// @throws std::bad_alloc if not enough memory to construct resulting string.
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
BOOST_STACKTRACE_FUNCTION std::string source_file() const;
|
||||
|
||||
/// @returns Code line in the source file, were the function of the frame is defined.
|
||||
/// @throws std::bad_alloc if not enough memory to construct string for internal needs.
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t source_line() const;
|
||||
|
||||
/// @brief Checks that frame is not references NULL address.
|
||||
/// @returns `true` if `this->address() != 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL()
|
||||
|
||||
/// @brief Checks that frame references NULL address.
|
||||
/// @returns `true` if `this->address() == 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT { return !address(); }
|
||||
|
||||
/// @cond
|
||||
BOOST_CONSTEXPR bool operator!() const BOOST_NOEXCEPT { return !address(); }
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
|
||||
namespace detail {
|
||||
BOOST_STACKTRACE_FUNCTION std::string to_string(const frame* frames, std::size_t size);
|
||||
} // namespace detail
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
|
||||
#include <boost/stacktrace/detail/pop_options.h>
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_FRAME_DECL_HPP
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
@@ -27,40 +28,45 @@
|
||||
# pragma comment(lib, "Dbgeng.lib")
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_WINDOWS
|
||||
# include <boost/stacktrace/detail/safe_dump_win.ipp>
|
||||
#else
|
||||
# include <boost/stacktrace/detail/safe_dump_posix.ipp>
|
||||
#endif
|
||||
|
||||
#if defined(DEFINE_GUID) && !defined(BOOST_MSVC)
|
||||
#ifdef __CRT_UUID_DECL // for __MINGW32__
|
||||
__CRT_UUID_DECL(IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8)
|
||||
__CRT_UUID_DECL(IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba)
|
||||
__CRT_UUID_DECL(IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50)
|
||||
#elif defined(DEFINE_GUID) && !defined(BOOST_MSVC)
|
||||
DEFINE_GUID(IID_IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8);
|
||||
DEFINE_GUID(IID_IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba);
|
||||
DEFINE_GUID(IID_IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Testing. Remove later
|
||||
//# define __uuidof(x) ::IID_ ## x
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t this_thread_frames::collect(void** memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
|
||||
return ::CaptureStackBackTrace(
|
||||
skip + 2,
|
||||
static_cast<boost::detail::winapi::ULONG_>(size),
|
||||
memory,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
class com_global_initer: boost::noncopyable {
|
||||
bool ok_;
|
||||
|
||||
public:
|
||||
com_global_initer() BOOST_NOEXCEPT {
|
||||
// We do not care about the result of the function call: any result is OK for us.
|
||||
::CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
com_global_initer() BOOST_NOEXCEPT
|
||||
: ok_(false)
|
||||
{
|
||||
// COINIT_MULTITHREADED means that we must serialize access to the objects manually.
|
||||
// This is the fastest way to work. If user calls CoInitializeEx before us - we
|
||||
// can end up with other mode (which is OK for us).
|
||||
//
|
||||
// If we call CoInitializeEx befire user - user may end up with different mode, which is a problem.
|
||||
// So we need to call that initialization function as late as possible.
|
||||
const boost::detail::winapi::DWORD_ res = ::CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
ok_ = (res == S_OK || res == S_FALSE);
|
||||
}
|
||||
|
||||
~com_global_initer() BOOST_NOEXCEPT {
|
||||
::CoUninitialize();
|
||||
if (ok_) {
|
||||
::CoUninitialize();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -94,155 +100,248 @@ public:
|
||||
};
|
||||
|
||||
|
||||
inline bool try_init_com(com_holder<::IDebugSymbols>& idebug, const com_global_initer& com) BOOST_NOEXCEPT {
|
||||
com_holder<::IDebugClient> iclient(com);
|
||||
::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr());
|
||||
|
||||
com_holder<::IDebugControl> icontrol(com);
|
||||
iclient->QueryInterface(__uuidof(IDebugControl), icontrol.to_void_ptr_ptr());
|
||||
|
||||
const bool res1 = (S_OK == iclient->AttachProcess(
|
||||
0,
|
||||
::GetCurrentProcessId(),
|
||||
DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)
|
||||
);
|
||||
if (!res1) {
|
||||
return false;
|
||||
static std::string minwg_demangling_workaround(const std::string& s) {
|
||||
#ifdef BOOST_GCC
|
||||
if (s.empty()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
const bool res2 = (S_OK == icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE));
|
||||
if (!res2) {
|
||||
return false;
|
||||
if (s[0] != '_') {
|
||||
return boost::core::demangle(('_' + s).c_str());
|
||||
}
|
||||
|
||||
const bool res = (S_OK == iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr()));
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return boost::core::demangle(s.c_str());
|
||||
#else
|
||||
return s;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline std::string get_name_impl(const com_holder<::IDebugSymbols>& idebug, const void* addr, std::string* module_name = 0) {
|
||||
std::string result;
|
||||
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
|
||||
class debugging_symbols: boost::noncopyable {
|
||||
static void try_init_com(com_holder< ::IDebugSymbols>& idebug, const com_global_initer& com) BOOST_NOEXCEPT {
|
||||
com_holder< ::IDebugClient> iclient(com);
|
||||
if (S_OK != ::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr())) {
|
||||
return;
|
||||
}
|
||||
|
||||
char name[256];
|
||||
name[0] = '\0';
|
||||
ULONG size = 0;
|
||||
bool res = (S_OK == idebug->GetNameByOffset(
|
||||
offset,
|
||||
name,
|
||||
sizeof(name),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
com_holder< ::IDebugControl> icontrol(com);
|
||||
const bool res0 = (S_OK == iclient->QueryInterface(
|
||||
__uuidof(IDebugControl),
|
||||
icontrol.to_void_ptr_ptr()
|
||||
));
|
||||
if (!res0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!res && size != 0) {
|
||||
result.resize(size);
|
||||
res = (S_OK == idebug->GetNameByOffset(
|
||||
const bool res1 = (S_OK == iclient->AttachProcess(
|
||||
0,
|
||||
::GetCurrentProcessId(),
|
||||
DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND
|
||||
));
|
||||
if (!res1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (S_OK != icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No cheking: QueryInterface sets the output parameter to NULL in case of error.
|
||||
iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr());
|
||||
}
|
||||
|
||||
#ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
|
||||
|
||||
boost::stacktrace::detail::com_global_initer com_;
|
||||
com_holder< ::IDebugSymbols> idebug_;
|
||||
public:
|
||||
debugging_symbols() BOOST_NOEXCEPT
|
||||
: com_()
|
||||
, idebug_(com_)
|
||||
{
|
||||
try_init_com(idebug_, com_);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef BOOST_NO_CXX11_THREAD_LOCAL
|
||||
# error Your compiler does not support C++11 thread_local storage. It`s impossible to build with BOOST_STACKTRACE_USE_WINDBG_CACHED.
|
||||
#endif
|
||||
|
||||
static com_holder< ::IDebugSymbols>& get_thread_local_debug_inst() BOOST_NOEXCEPT {
|
||||
// [class.mfct]: A static local variable or local type in a member function always refers to the same entity, whether
|
||||
// or not the member function is inline.
|
||||
static thread_local boost::stacktrace::detail::com_global_initer com;
|
||||
static thread_local com_holder< ::IDebugSymbols> idebug(com);
|
||||
|
||||
if (!idebug.is_inited()) {
|
||||
try_init_com(idebug, com);
|
||||
}
|
||||
|
||||
return idebug;
|
||||
}
|
||||
|
||||
com_holder< ::IDebugSymbols>& idebug_;
|
||||
public:
|
||||
debugging_symbols() BOOST_NOEXCEPT
|
||||
: idebug_( get_thread_local_debug_inst() )
|
||||
{}
|
||||
|
||||
#endif // #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
|
||||
|
||||
bool is_inited() const BOOST_NOEXCEPT {
|
||||
return idebug_.is_inited();
|
||||
}
|
||||
|
||||
std::string get_name_impl(const void* addr, std::string* module_name = 0) const {
|
||||
std::string result;
|
||||
if (!is_inited()) {
|
||||
return result;
|
||||
}
|
||||
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
|
||||
|
||||
char name[256];
|
||||
name[0] = '\0';
|
||||
ULONG size = 0;
|
||||
bool res = (S_OK == idebug_->GetNameByOffset(
|
||||
offset,
|
||||
&result[0],
|
||||
static_cast<ULONG>(result.size()),
|
||||
name,
|
||||
sizeof(name),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
} else if (res) {
|
||||
result = name;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
result.clear();
|
||||
if (!res && size != 0) {
|
||||
result.resize(size);
|
||||
res = (S_OK == idebug_->GetNameByOffset(
|
||||
offset,
|
||||
&result[0],
|
||||
static_cast<ULONG>(result.size()),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
} else if (res) {
|
||||
result = name;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
result.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::size_t delimiter = result.find_first_of('!');
|
||||
if (module_name) {
|
||||
*module_name = result.substr(0, delimiter);
|
||||
}
|
||||
|
||||
if (delimiter == std::string::npos) {
|
||||
// If 'delimiter' is equal to 'std::string::npos' then we have only module name.
|
||||
result.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
result = minwg_demangling_workaround(
|
||||
result.substr(delimiter + 1)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::size_t delimiter = result.find_first_of('!');
|
||||
if (delimiter == std::string::npos) {
|
||||
return result;
|
||||
std::size_t get_line_impl(const void* addr) const BOOST_NOEXCEPT {
|
||||
ULONG result = 0;
|
||||
if (!is_inited()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const bool is_ok = (S_OK == idebug_->GetLineByOffset(
|
||||
reinterpret_cast<ULONG64>(addr),
|
||||
&result,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
));
|
||||
|
||||
return (is_ok ? result : 0);
|
||||
}
|
||||
|
||||
if (module_name) {
|
||||
*module_name = result.substr(0, delimiter);
|
||||
}
|
||||
|
||||
result = result.substr(delimiter + 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
std::pair<std::string, std::size_t> get_source_file_line_impl(const void* addr) const {
|
||||
std::pair<std::string, std::size_t> result;
|
||||
if (!is_inited()) {
|
||||
return result;
|
||||
}
|
||||
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
|
||||
|
||||
char name[256];
|
||||
name[0] = 0;
|
||||
ULONG size = 0;
|
||||
ULONG line_num = 0;
|
||||
bool res = (S_OK == idebug_->GetLineByOffset(
|
||||
offset,
|
||||
&line_num,
|
||||
name,
|
||||
sizeof(name),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
|
||||
inline std::pair<std::string, std::size_t> get_source_file_line_impl(const com_holder<::IDebugSymbols>& idebug, const void* addr) {
|
||||
std::pair<std::string, std::size_t> result;
|
||||
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
|
||||
if (res) {
|
||||
result.first = name;
|
||||
result.second = line_num;
|
||||
return result;
|
||||
}
|
||||
|
||||
char name[256];
|
||||
name[0] = 0;
|
||||
ULONG size = 0;
|
||||
ULONG line_num = 0;
|
||||
bool res = (S_OK == idebug->GetLineByOffset(
|
||||
offset,
|
||||
&line_num,
|
||||
name,
|
||||
sizeof(name),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
if (!res && size == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (res) {
|
||||
result.first = name;
|
||||
result.first.resize(size);
|
||||
res = (S_OK == idebug_->GetLineByOffset(
|
||||
offset,
|
||||
&line_num,
|
||||
&result.first[0],
|
||||
static_cast<ULONG>(result.first.size()),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
result.second = line_num;
|
||||
|
||||
if (!res) {
|
||||
result.first.clear();
|
||||
result.second = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!res && size == 0) {
|
||||
return result;
|
||||
}
|
||||
void to_string_impl(const void* addr, std::string& res) const {
|
||||
if (!is_inited()) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.first.resize(size);
|
||||
res = (S_OK == idebug->GetLineByOffset(
|
||||
offset,
|
||||
&line_num,
|
||||
&result.first[0],
|
||||
static_cast<ULONG>(result.first.size()),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
result.second = line_num;
|
||||
std::string module_name;
|
||||
std::string name = this->get_name_impl(addr, &module_name);
|
||||
if (!name.empty()) {
|
||||
res += name;
|
||||
} else {
|
||||
res += to_hex_array(addr).data();
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
result.first.clear();
|
||||
result.second = 0;
|
||||
std::pair<std::string, std::size_t> source_line = this->get_source_file_line_impl(addr);
|
||||
if (!source_line.first.empty() && source_line.second) {
|
||||
res += " at ";
|
||||
res += source_line.first;
|
||||
res += ':';
|
||||
res += boost::lexical_cast<boost::array<char, 40> >(source_line.second).data();
|
||||
} else if (!module_name.empty()) {
|
||||
res += " in ";
|
||||
res += module_name;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void to_string_impl(const com_holder<::IDebugSymbols>& idebug, const void* addr, std::string& res) {
|
||||
std::string module_name;
|
||||
std::string name = boost::stacktrace::detail::get_name_impl(idebug, addr, &module_name);
|
||||
if (!name.empty()) {
|
||||
res += name;
|
||||
} else {
|
||||
res += to_hex_array(addr).data();
|
||||
}
|
||||
|
||||
std::pair<std::string, std::size_t> source_line
|
||||
= boost::stacktrace::detail::get_source_file_line_impl(idebug, addr);
|
||||
if (!source_line.first.empty() && source_line.second) {
|
||||
res += " at ";
|
||||
res += source_line.first;
|
||||
res += ':';
|
||||
res += boost::lexical_cast<boost::array<char, 40> >(source_line.second).data();
|
||||
} else if (!module_name.empty()) {
|
||||
res += " in ";
|
||||
res += module_name;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::string to_string(const frame* frames, std::size_t size) {
|
||||
boost::stacktrace::detail::com_global_initer com_guard;
|
||||
boost::stacktrace::detail::com_holder<::IDebugSymbols> idebug(com_guard);
|
||||
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
if (!idebug.is_inited()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -255,7 +354,7 @@ std::string to_string(const frame* frames, std::size_t size) {
|
||||
res += boost::lexical_cast<boost::array<char, 40> >(i).data();
|
||||
res += '#';
|
||||
res += ' ';
|
||||
to_string_impl(idebug, frames[i].address(), res);
|
||||
idebug.to_string_impl(frames[i].address(), res);
|
||||
res += '\n';
|
||||
}
|
||||
|
||||
@@ -265,55 +364,26 @@ std::string to_string(const frame* frames, std::size_t size) {
|
||||
} // namespace detail
|
||||
|
||||
std::string frame::name() const {
|
||||
boost::stacktrace::detail::com_global_initer com_guard;
|
||||
boost::stacktrace::detail::com_holder<::IDebugSymbols> idebug(com_guard);
|
||||
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return boost::stacktrace::detail::get_name_impl(idebug, addr_);
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
return idebug.get_name_impl(addr_);
|
||||
}
|
||||
|
||||
|
||||
std::string frame::source_file() const {
|
||||
boost::stacktrace::detail::com_global_initer com_guard;
|
||||
boost::stacktrace::detail::com_holder<::IDebugSymbols> idebug(com_guard);
|
||||
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
|
||||
return std::string();
|
||||
}
|
||||
return boost::stacktrace::detail::get_source_file_line_impl(idebug, addr_).first;
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
return idebug.get_source_file_line_impl(addr_).first;
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
ULONG line_num = 0;
|
||||
|
||||
boost::stacktrace::detail::com_global_initer com_guard;
|
||||
boost::stacktrace::detail::com_holder<::IDebugSymbols> idebug(com_guard);
|
||||
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const bool is_ok = (S_OK == idebug->GetLineByOffset(
|
||||
reinterpret_cast<ULONG64>(addr_),
|
||||
&line_num,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
));
|
||||
|
||||
return (is_ok ? line_num : 0);
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
return idebug.get_line_impl(addr_);
|
||||
}
|
||||
|
||||
std::string to_string(const frame& f) {
|
||||
boost::stacktrace::detail::com_global_initer com_guard;
|
||||
boost::stacktrace::detail::com_holder<::IDebugSymbols> idebug(com_guard);
|
||||
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string res;
|
||||
boost::stacktrace::detail::to_string_impl(idebug, f.address(), res);
|
||||
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
idebug.to_string_impl(f.address(), res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,25 +20,6 @@ std::string to_string(const frame* /*frames*/, std::size_t /*count*/) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::size_t this_thread_frames::collect(void** /*memory*/, std::size_t /*size*/, std::size_t /*skip*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(BOOST_WINDOWS)
|
||||
std::size_t dump(void* /*fd*/, void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
std::size_t dump(int /*fd*/, void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
std::size_t dump(const char* /*file*/, void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
std::string frame::name() const {
|
||||
|
||||
@@ -15,11 +15,10 @@
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/stacktrace/detail/try_demangle.hpp>
|
||||
#include <boost/stacktrace/detail/location_from_symbol.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <unwind.h>
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef BOOST_STACKTRACE_USE_BACKTRACE
|
||||
@@ -30,63 +29,16 @@
|
||||
# include <boost/stacktrace/detail/unwind_base_impls.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_WINDOWS
|
||||
# include <boost/stacktrace/detail/safe_dump_win.ipp>
|
||||
#else
|
||||
# include <boost/stacktrace/detail/safe_dump_posix.ipp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct unwind_state {
|
||||
std::size_t frames_to_skip;
|
||||
void** current;
|
||||
void** end;
|
||||
};
|
||||
|
||||
inline _Unwind_Reason_Code unwind_callback(::_Unwind_Context* context, void* arg) {
|
||||
unwind_state* state = static_cast<unwind_state*>(arg);
|
||||
if (state->frames_to_skip) {
|
||||
--state->frames_to_skip;
|
||||
return ::_Unwind_GetIP(context) ? ::_URC_NO_REASON : ::_URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
*state->current = reinterpret_cast<void*>(
|
||||
::_Unwind_GetIP(context)
|
||||
);
|
||||
|
||||
++state->current;
|
||||
if (!*(state->current - 1) || state->current == state->end) {
|
||||
return ::_URC_END_OF_STACK;
|
||||
}
|
||||
return ::_URC_NO_REASON;
|
||||
}
|
||||
|
||||
std::size_t this_thread_frames::collect(void** memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
|
||||
std::size_t frames_count = 0;
|
||||
if (!size) {
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::unwind_state state = { skip + 1, memory, memory + size };
|
||||
::_Unwind_Backtrace(&boost::stacktrace::detail::unwind_callback, &state);
|
||||
frames_count = state.current - memory;
|
||||
|
||||
if (frames_count && memory[frames_count - 1] == 0) {
|
||||
-- frames_count;
|
||||
}
|
||||
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
template <class Base>
|
||||
class to_string_impl_base: private Base {
|
||||
public:
|
||||
std::string operator()(const void* addr) {
|
||||
std::string operator()(boost::stacktrace::detail::native_frame_ptr_t addr) {
|
||||
Base::res.clear();
|
||||
Base::prepare_function_name(addr);
|
||||
if (!Base::res.empty()) {
|
||||
Base::res = boost::stacktrace::detail::try_demangle(Base::res.c_str());
|
||||
Base::res = boost::core::demangle(Base::res.c_str());
|
||||
} else {
|
||||
Base::res = to_hex_array(addr).data();
|
||||
}
|
||||
@@ -130,11 +82,11 @@ std::string to_string(const frame* frames, std::size_t size) {
|
||||
|
||||
|
||||
std::string frame::name() const {
|
||||
#ifndef BOOST_WINDOWS
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
::Dl_info dli;
|
||||
const bool dl_ok = !!::dladdr(addr_, &dli);
|
||||
if (dl_ok && dli.dli_sname) {
|
||||
return boost::stacktrace::detail::try_demangle(dli.dli_sname);
|
||||
return boost::core::demangle(dli.dli_sname);
|
||||
}
|
||||
#endif
|
||||
return boost::stacktrace::detail::name_impl(addr_);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/stacktrace/detail/try_demangle.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <backtrace.h>
|
||||
@@ -39,6 +39,34 @@ inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) BOOST_NOEXCEPT {
|
||||
// Do nothing, just return.
|
||||
}
|
||||
|
||||
|
||||
extern inline ::backtrace_state* construct_state() BOOST_NOEXCEPT {
|
||||
return ::backtrace_create_state(
|
||||
0, 0 /*thread-safe*/, boost::stacktrace::detail::libbacktrace_error_callback, 0
|
||||
);
|
||||
|
||||
// TODO: this does not seem to work well when this function is in .so:
|
||||
// Not async-signal-safe, so this method is not called from async-safe functions.
|
||||
//
|
||||
// This function is not async signal safe because:
|
||||
// * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
|
||||
// * No guarantees on `backtrace_create_state` function.
|
||||
|
||||
// [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
|
||||
|
||||
/*
|
||||
static ::backtrace_state* state = ::backtrace_create_state(
|
||||
0, 1 , boost::stacktrace::detail::libbacktrace_error_callback, 0
|
||||
);
|
||||
|
||||
return state;
|
||||
*/
|
||||
}
|
||||
|
||||
struct to_string_using_backtrace {
|
||||
std::string res;
|
||||
::backtrace_state* state;
|
||||
@@ -47,7 +75,15 @@ struct to_string_using_backtrace {
|
||||
|
||||
void prepare_function_name(const void* addr) {
|
||||
boost::stacktrace::detail::pc_data data = {&res, &filename, 0};
|
||||
::backtrace_pcinfo(state, reinterpret_cast<uintptr_t>(addr), boost::stacktrace::detail::libbacktrace_full_callback, 0, &data);
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
);
|
||||
}
|
||||
line = data.line;
|
||||
}
|
||||
|
||||
@@ -64,9 +100,7 @@ struct to_string_using_backtrace {
|
||||
}
|
||||
|
||||
to_string_using_backtrace() BOOST_NOEXCEPT {
|
||||
state = ::backtrace_create_state(
|
||||
0, 0, 0, 0
|
||||
);
|
||||
state = boost::stacktrace::detail::construct_state();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -76,14 +110,20 @@ typedef to_string_impl_base<to_string_using_backtrace> to_string_impl;
|
||||
inline std::string name_impl(const void* addr) {
|
||||
std::string res;
|
||||
|
||||
::backtrace_state* state = ::backtrace_create_state(
|
||||
0, 0, 0, 0
|
||||
);
|
||||
::backtrace_state* state = boost::stacktrace::detail::construct_state();
|
||||
|
||||
boost::stacktrace::detail::pc_data data = {&res, 0, 0};
|
||||
::backtrace_pcinfo(state, reinterpret_cast<uintptr_t>(addr), boost::stacktrace::detail::libbacktrace_full_callback, 0, &data);
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
);
|
||||
}
|
||||
if (!res.empty()) {
|
||||
res = boost::stacktrace::detail::try_demangle(res.c_str());
|
||||
res = boost::core::demangle(res.c_str());
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -94,24 +134,35 @@ inline std::string name_impl(const void* addr) {
|
||||
std::string frame::source_file() const {
|
||||
std::string res;
|
||||
|
||||
::backtrace_state* state = ::backtrace_create_state(
|
||||
0, 0, 0, 0
|
||||
);
|
||||
::backtrace_state* state = boost::stacktrace::detail::construct_state();
|
||||
|
||||
boost::stacktrace::detail::pc_data data = {0, &res, 0};
|
||||
::backtrace_pcinfo(state, reinterpret_cast<uintptr_t>(addr_), boost::stacktrace::detail::libbacktrace_full_callback, 0, &data);
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr_),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
::backtrace_state* state = ::backtrace_create_state(
|
||||
0, 0, 0, 0
|
||||
);
|
||||
::backtrace_state* state = boost::stacktrace::detail::construct_state();
|
||||
|
||||
boost::stacktrace::detail::pc_data data = {0, 0, 0};
|
||||
::backtrace_pcinfo(state, reinterpret_cast<uintptr_t>(addr_), boost::stacktrace::detail::libbacktrace_full_callback, 0, &data);
|
||||
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr_),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
);
|
||||
}
|
||||
|
||||
return data.line;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_WINDOWS
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
# include <dlfcn.h>
|
||||
#else
|
||||
# include <boost/detail/winapi/dll.hpp>
|
||||
@@ -21,7 +21,7 @@
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
class location_from_symbol {
|
||||
#ifndef BOOST_WINDOWS
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
::Dl_info dli_;
|
||||
|
||||
public:
|
||||
|
||||
12
include/boost/stacktrace/detail/pop_options.h
Normal file
12
include/boost/stacktrace/detail/pop_options.h
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// No include guards! Intentionally.
|
||||
|
||||
#ifdef BOOST_STACKTRACE_FUNCTION
|
||||
# undef BOOST_STACKTRACE_FUNCTION
|
||||
#endif
|
||||
|
||||
31
include/boost/stacktrace/detail/push_options.h
Normal file
31
include/boost/stacktrace/detail/push_options.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// No include guards! Intentionally.
|
||||
|
||||
// Link or header only
|
||||
#if !defined(BOOST_STACKTRACE_LINK) && defined(BOOST_STACKTRACE_DYN_LINK)
|
||||
# define BOOST_STACKTRACE_LINK
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_STACKTRACE_LINK) && !defined(BOOST_STACKTRACE_DYN_LINK) && defined(BOOST_ALL_DYN_LINK)
|
||||
# define BOOST_STACKTRACE_DYN_LINK
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_STACKTRACE_LINK
|
||||
# if defined(BOOST_STACKTRACE_DYN_LINK)
|
||||
# ifdef BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
|
||||
# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_EXPORT
|
||||
# else
|
||||
# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_IMPORT
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_STACKTRACE_FUNCTION
|
||||
# endif
|
||||
#elif !defined(BOOST_STACKTRACE_DOXYGEN_INVOKED)
|
||||
# define BOOST_STACKTRACE_FUNCTION inline
|
||||
#endif
|
||||
|
||||
37
include/boost/stacktrace/detail/safe_dump_noop.ipp
Normal file
37
include/boost/stacktrace/detail/safe_dump_noop.ipp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_SAFE_DUMP_NOOP_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_SAFE_DUMP_NOOP_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
|
||||
#if defined(BOOST_WINDOWS)
|
||||
std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
std::size_t dump(int /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_SAFE_DUMP_NOOP_IPP
|
||||
@@ -12,7 +12,7 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
#include <unistd.h> // ::write
|
||||
#include <fcntl.h> // ::open
|
||||
@@ -20,25 +20,35 @@
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t dump(int fd, void** memory, std::size_t size) BOOST_NOEXCEPT {
|
||||
std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
|
||||
// We do not retry, because this function must be typically called from signal handler so it's:
|
||||
// * to scary to continue in case of EINTR
|
||||
// * EAGAIN or EWOULDBLOCK may occur only in case of O_NONBLOCK is set for fd,
|
||||
// so it seems that user does not want to block
|
||||
if (::write(fd, memory, sizeof(void*) * size) == -1) {
|
||||
if (::write(fd, frames, sizeof(native_frame_ptr_t) * frames_count) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
std::size_t dump(const char* file, void** memory, std::size_t mem_size) BOOST_NOEXCEPT {
|
||||
const int fd = ::open(file, O_CREAT | O_WRONLY | O_TRUNC, S_IFREG | S_IWUSR | S_IRUSR);
|
||||
std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
|
||||
const int fd = ::open(
|
||||
file,
|
||||
O_CREAT | O_WRONLY | O_TRUNC,
|
||||
#if defined(S_IWUSR) && defined(S_IRUSR) // Workarounds for some Android OSes
|
||||
S_IWUSR | S_IRUSR
|
||||
#elif defined(S_IWRITE) && defined(S_IREAD)
|
||||
S_IWRITE | S_IREAD
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
);
|
||||
if (fd == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::size_t size = boost::stacktrace::detail::dump(fd, memory, mem_size);
|
||||
const std::size_t size = boost::stacktrace::detail::dump(fd, frames, frames_count);
|
||||
::close(fd);
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
|
||||
@@ -21,19 +21,21 @@
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/access_rights.hpp>
|
||||
|
||||
#include <windows.h> // CaptureStackBackTrace
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t dump(void* fd, void** memory, std::size_t mem_size) BOOST_NOEXCEPT {
|
||||
if (!boost::detail::winapi::WriteFile(fd, memory, static_cast<boost::detail::winapi::DWORD_>(sizeof(void*) * mem_size), 0, 0)) {
|
||||
std::size_t dump(void* fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
|
||||
boost::detail::winapi::DWORD_ written;
|
||||
const boost::detail::winapi::DWORD_ bytes_to_write = static_cast<boost::detail::winapi::DWORD_>(
|
||||
sizeof(native_frame_ptr_t) * frames_count
|
||||
);
|
||||
if (!boost::detail::winapi::WriteFile(fd, frames, bytes_to_write, &written, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mem_size;
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
std::size_t dump(const char* file, void** memory, std::size_t mem_size) BOOST_NOEXCEPT {
|
||||
std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
|
||||
void* const fd = boost::detail::winapi::CreateFileA(
|
||||
file,
|
||||
boost::detail::winapi::GENERIC_WRITE_,
|
||||
@@ -48,7 +50,7 @@ std::size_t dump(const char* file, void** memory, std::size_t mem_size) BOOST_NO
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::size_t size = boost::stacktrace::detail::dump(fd, memory, mem_size);
|
||||
const std::size_t size = boost::stacktrace::detail::dump(fd, frames, frames_count);
|
||||
boost::detail::winapi::CloseHandle(fd);
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_TRY_DEMANGLE_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_TRY_DEMANGLE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/demangle.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
inline std::string try_demangle(const char* mangled) {
|
||||
std::string res;
|
||||
|
||||
boost::core::scoped_demangled_name demangled(mangled);
|
||||
if (demangled.get()) {
|
||||
res = demangled.get();
|
||||
} else {
|
||||
res = mangled;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_TRY_DEMANGLE_HPP
|
||||
46
include/boost/stacktrace/detail/void_ptr_cast.hpp
Normal file
46
include/boost/stacktrace/detail/void_ptr_cast.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
|
||||
// Copyright 2015-2017 Antony Polukhin.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_VOID_PTR_CAST_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_VOID_PTR_CAST_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ * 100 + __GNUC_MINOR__ > 301)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
// GCC warns when reinterpret_cast between function pointer and object pointer occur.
|
||||
// This functionsuppress the warnings and ensures that such casts are safe.
|
||||
template <class To, class From>
|
||||
To void_ptr_cast(From* v) BOOST_NOEXCEPT {
|
||||
BOOST_STATIC_ASSERT_MSG(
|
||||
boost::is_pointer<To>::value,
|
||||
"`void_ptr_cast` function must be used only for casting to or from void pointers."
|
||||
);
|
||||
|
||||
BOOST_STATIC_ASSERT_MSG(
|
||||
sizeof(From*) == sizeof(To),
|
||||
"Pointer to function and pointer to object differ in size on your platform."
|
||||
);
|
||||
|
||||
return reinterpret_cast<To>(v);
|
||||
}
|
||||
|
||||
|
||||
}}} // boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_VOID_PTR_CAST_HPP
|
||||
|
||||
@@ -17,164 +17,20 @@
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
|
||||
// Link or header only
|
||||
#if !defined(BOOST_STACKTRACE_LINK) && defined(BOOST_STACKTRACE_DYN_LINK)
|
||||
# define BOOST_STACKTRACE_LINK
|
||||
#endif
|
||||
#include <boost/stacktrace/safe_dump_to.hpp> // boost::stacktrace::detail::native_frame_ptr_t
|
||||
|
||||
#if defined(BOOST_STACKTRACE_LINK) && !defined(BOOST_STACKTRACE_DYN_LINK) && defined(BOOST_ALL_DYN_LINK)
|
||||
# define BOOST_STACKTRACE_DYN_LINK
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_STACKTRACE_LINK
|
||||
# if defined(BOOST_STACKTRACE_DYN_LINK)
|
||||
# ifdef BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
|
||||
# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_EXPORT
|
||||
# else
|
||||
# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_IMPORT
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_STACKTRACE_FUNCTION
|
||||
# endif
|
||||
#elif !defined(BOOST_STACKTRACE_DOXYGEN_INVOKED)
|
||||
# define BOOST_STACKTRACE_FUNCTION inline
|
||||
#endif
|
||||
#include <boost/stacktrace/detail/frame_decl.hpp>
|
||||
#include <boost/stacktrace/detail/push_options.h>
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
class frame;
|
||||
|
||||
|
||||
namespace detail {
|
||||
BOOST_STACKTRACE_FUNCTION std::string to_string(const frame* frames, std::size_t size);
|
||||
|
||||
enum helper{ max_frames_dump = 128 };
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t from_dump(const char* filename, void** frames);
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(const char* file, void** memory, std::size_t size) BOOST_NOEXCEPT;
|
||||
#if defined(BOOST_WINDOWS)
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(void* fd, void** memory, std::size_t size) BOOST_NOEXCEPT;
|
||||
#else
|
||||
// POSIX
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(int fd, void** memory, std::size_t size) BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
|
||||
struct this_thread_frames { // struct is required to avoid warning about usage of inline+BOOST_NOINLINE
|
||||
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(void** memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Non-owning class that references the frame information stored inside the boost::stacktrace::stacktrace class.
|
||||
class frame {
|
||||
/// @cond
|
||||
const void* addr_;
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
/// @brief Constructs frame that references NULL address.
|
||||
/// Calls to source_file() and source_line() will return empty string.
|
||||
/// Calls to source_line() will return 0.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
frame() BOOST_NOEXCEPT
|
||||
: addr_(0)
|
||||
{}
|
||||
|
||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||
/// @brief Copy constructs frame.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
frame(const frame&) = default;
|
||||
|
||||
/// @brief Copy assigns frame.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
frame& operator=(const frame&) = default;
|
||||
#endif
|
||||
|
||||
/// @brief Constructs frame that references addr and could later generate information about that address using platform specific features.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
explicit frame(const void* addr) BOOST_NOEXCEPT
|
||||
: addr_(addr)
|
||||
{}
|
||||
|
||||
/// @returns Name of the frame (function name in a human readable form).
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
/// @throws std::bad_alloc if not enough memory to construct resulting string.
|
||||
BOOST_STACKTRACE_FUNCTION std::string name() const;
|
||||
|
||||
/// @returns Address of the frame function.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
const void* address() const BOOST_NOEXCEPT {
|
||||
return addr_;
|
||||
}
|
||||
|
||||
/// @returns Path to the source file, were the function of the frame is defined. Returns empty string
|
||||
/// if this->source_line() == 0.
|
||||
/// @throws std::bad_alloc if not enough memory to construct resulting string.
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
BOOST_STACKTRACE_FUNCTION std::string source_file() const;
|
||||
|
||||
/// @returns Code line in the source file, were the function of the frame is defined.
|
||||
/// @throws std::bad_alloc if not enough memory to construct string for internal needs.
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t source_line() const;
|
||||
|
||||
/// @brief Checks that frame is not references NULL address.
|
||||
/// @returns `true` if `this->address() != 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
|
||||
/// @brief Checks that frame references NULL address.
|
||||
/// @returns `true` if `this->address() == 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
bool empty() const BOOST_NOEXCEPT { return !address(); }
|
||||
|
||||
/// @cond
|
||||
bool operator!() const BOOST_NOEXCEPT { return !address(); }
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
/// Comparison operators that provide platform dependant ordering and have O(1) complexity; are Async-Handler-Safe.
|
||||
inline bool operator< (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() < rhs.address(); }
|
||||
inline bool operator> (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return rhs < lhs; }
|
||||
inline bool operator<=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); }
|
||||
inline bool operator>=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); }
|
||||
inline bool operator==(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() == rhs.address(); }
|
||||
inline bool operator!=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); }
|
||||
BOOST_CONSTEXPR inline bool operator< (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() < rhs.address(); }
|
||||
BOOST_CONSTEXPR inline bool operator> (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return rhs < lhs; }
|
||||
BOOST_CONSTEXPR inline bool operator<=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); }
|
||||
BOOST_CONSTEXPR inline bool operator>=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); }
|
||||
BOOST_CONSTEXPR inline bool operator==(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() == rhs.address(); }
|
||||
BOOST_CONSTEXPR inline bool operator!=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); }
|
||||
|
||||
/// Fast hashing support, O(1) complexity; Async-Handler-Safe.
|
||||
inline std::size_t hash_value(const frame& f) BOOST_NOEXCEPT {
|
||||
@@ -194,12 +50,12 @@ std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT
|
||||
|
||||
/// @cond
|
||||
|
||||
#undef BOOST_STACKTRACE_FUNCTION
|
||||
#include <boost/stacktrace/detail/pop_options.h>
|
||||
|
||||
#ifndef BOOST_STACKTRACE_LINK
|
||||
# if defined(BOOST_STACKTRACE_USE_NOOP)
|
||||
# include <boost/stacktrace/detail/frame_noop.ipp>
|
||||
# elif defined(BOOST_MSVC) || defined(BOOST_STACKTRACE_USE_WINDBG)
|
||||
# elif defined(BOOST_MSVC) || defined(BOOST_STACKTRACE_USE_WINDBG) || defined(BOOST_STACKTRACE_USE_WINDBG_CACHED)
|
||||
# include <boost/stacktrace/detail/frame_msvc.ipp>
|
||||
# else
|
||||
# include <boost/stacktrace/detail/frame_unwind.ipp>
|
||||
|
||||
@@ -12,38 +12,66 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
#include <boost/stacktrace/detail/push_options.h>
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
|
||||
#endif
|
||||
|
||||
/// @file safe_dump_to.hpp This header contains low-level async-signal-safe functions for dumping call stacks. Dumps are binary serialized arrays of `void*`,
|
||||
/// so you could read them by using 'od -tx8 -An stacktrace_dump_failename' Linux command or using boost::stacktrace::stacktrace::from_dump functions.
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
|
||||
/// @cond
|
||||
namespace detail {
|
||||
struct suppress_noinline_warnings {
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(void* memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
|
||||
void** mem = static_cast<void**>(memory);
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(mem, size / sizeof(void*) - 1, skip + 1);
|
||||
mem[frames_count] = 0;
|
||||
return frames_count + 1;
|
||||
|
||||
typedef const void* native_frame_ptr_t; // TODO: change to `typedef void(*native_frame_ptr_t)();`
|
||||
enum helper{ max_frames_dump = 128 };
|
||||
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t from_dump(const char* filename, native_frame_ptr_t* out_frames);
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
|
||||
#if defined(BOOST_WINDOWS)
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(void* fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
|
||||
#else
|
||||
// POSIX
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
|
||||
struct this_thread_frames { // struct is required to avoid warning about usage of inline+BOOST_NOINLINE
|
||||
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT;
|
||||
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(void* memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
|
||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
||||
|
||||
if (size < sizeof(native_frame_ptr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) BOOST_NOEXCEPT {
|
||||
void* buffer[boost::stacktrace::detail::max_frames_dump + 1];
|
||||
if (max_depth > boost::stacktrace::detail::max_frames_dump) {
|
||||
max_depth = boost::stacktrace::detail::max_frames_dump;
|
||||
}
|
||||
native_frame_ptr_t* mem = static_cast<native_frame_ptr_t*>(memory);
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(mem, size / sizeof(native_frame_ptr_t) - 1, skip + 1);
|
||||
mem[frames_count] = 0;
|
||||
return frames_count + 1;
|
||||
}
|
||||
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, max_depth, skip + 1);
|
||||
buffer[frames_count] = 0;
|
||||
return boost::stacktrace::detail::dump(file, buffer, frames_count + 1);
|
||||
template <class T>
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) BOOST_NOEXCEPT {
|
||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
||||
|
||||
native_frame_ptr_t buffer[boost::stacktrace::detail::max_frames_dump + 1];
|
||||
if (max_depth > boost::stacktrace::detail::max_frames_dump) {
|
||||
max_depth = boost::stacktrace::detail::max_frames_dump;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, max_depth, skip + 1);
|
||||
buffer[frames_count] = 0;
|
||||
return boost::stacktrace::detail::dump(file, buffer, frames_count + 1);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
/// @endcond
|
||||
|
||||
/// @brief Stores current function call sequence into the memory.
|
||||
@@ -52,13 +80,13 @@ namespace detail {
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param memory Preallocated buffer to store current function call sequence into.
|
||||
///
|
||||
/// @param size Size of the preallocated buffer.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(memory, size, 0);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, 0);
|
||||
}
|
||||
|
||||
/// @brief Stores current function call sequence into the memory.
|
||||
@@ -67,7 +95,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param skip How many top calls to skip and do not store.
|
||||
///
|
||||
@@ -75,7 +103,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST
|
||||
///
|
||||
/// @param size Size of the preallocated buffer.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, void* memory, std::size_t size) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(memory, size, skip);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, skip);
|
||||
}
|
||||
|
||||
|
||||
@@ -85,11 +113,11 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, void* memory, std::
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(file, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
/// @brief Opens a file and rewrites its content with current function call sequence.
|
||||
@@ -98,7 +126,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param skip How many top calls to skip and do not store.
|
||||
///
|
||||
@@ -106,7 +134,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, const char* file) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(file, skip, max_depth);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, skip, max_depth);
|
||||
}
|
||||
|
||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||
@@ -117,7 +145,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_dep
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) BOOST_NOEXCEPT;
|
||||
@@ -128,7 +156,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) BOOS
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param skip How many top calls to skip and do not store.
|
||||
///
|
||||
@@ -140,22 +168,22 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_dep
|
||||
#elif defined(BOOST_WINDOWS)
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(void* fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, void* fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(fd, skip, max_depth);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// POSIX
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(int fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, int fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(fd, skip, max_depth);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -163,4 +191,28 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_dep
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/pop_options.h>
|
||||
|
||||
#if !defined(BOOST_STACKTRACE_LINK) || defined(BOOST_STACKTRACE_INTERNAL_BUILD_LIBS)
|
||||
# if defined(BOOST_STACKTRACE_USE_NOOP)
|
||||
# include <boost/stacktrace/detail/safe_dump_noop.ipp>
|
||||
# include <boost/stacktrace/detail/collect_noop.ipp>
|
||||
# else
|
||||
# if defined(BOOST_WINDOWS)
|
||||
# include <boost/stacktrace/detail/safe_dump_win.ipp>
|
||||
# else
|
||||
# include <boost/stacktrace/detail/safe_dump_posix.ipp>
|
||||
# endif
|
||||
# if defined(BOOST_WINDOWS) && !defined(BOOST_GCC)
|
||||
# include <boost/stacktrace/detail/collect_msvc.ipp>
|
||||
# else
|
||||
# include <boost/stacktrace/detail/collect_unwind.ipp>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif // BOOST_STACKTRACE_SAFE_DUMP_TO_HPP
|
||||
|
||||
@@ -16,10 +16,20 @@
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <boost/container/vector.hpp>
|
||||
#include <vector>
|
||||
|
||||
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
||||
# include <type_traits>
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/stacktrace_fwd.hpp>
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
#include <boost/stacktrace/detail/frame_decl.hpp>
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
|
||||
#endif
|
||||
|
||||
/// @cond
|
||||
namespace boost {
|
||||
@@ -34,10 +44,11 @@ namespace boost { namespace stacktrace {
|
||||
/// @tparam Allocator Allocator to use during stack capture.
|
||||
template <class Allocator>
|
||||
class basic_stacktrace {
|
||||
boost::container::vector<frame, Allocator> impl_;
|
||||
std::vector<boost::stacktrace::frame, Allocator> impl_;
|
||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
||||
|
||||
/// @cond
|
||||
void fill(void** begin, std::size_t size) {
|
||||
void fill(native_frame_ptr_t* begin, std::size_t size) {
|
||||
if (!size) {
|
||||
return;
|
||||
}
|
||||
@@ -54,7 +65,7 @@ class basic_stacktrace {
|
||||
}
|
||||
|
||||
static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) BOOST_NOEXCEPT {
|
||||
const std::size_t ret = (buffer_size > sizeof(void*) ? buffer_size / sizeof(void*) : 0);
|
||||
const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0);
|
||||
return (ret > 1024 ? 1024 : ret); // Dealing with suspiciously big sizes
|
||||
}
|
||||
|
||||
@@ -66,7 +77,7 @@ class basic_stacktrace {
|
||||
|
||||
try {
|
||||
{ // Fast path without additional allocations
|
||||
void* buffer[buffer_size];
|
||||
native_frame_ptr_t buffer[buffer_size];
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size, frames_to_skip + 1);
|
||||
if (buffer_size > frames_count || frames_count >= max_depth) {
|
||||
const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
|
||||
@@ -76,18 +87,18 @@ class basic_stacktrace {
|
||||
}
|
||||
|
||||
// Failed to fit in `buffer_size`. Allocating memory:
|
||||
typedef typename Allocator::template rebind<void*>::other allocator_void_t;
|
||||
boost::container::vector<void*, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
|
||||
typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t;
|
||||
std::vector<native_frame_ptr_t, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
|
||||
do {
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buf.data(), buf.size(), frames_to_skip + 1);
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(&buf[0], buf.size(), frames_to_skip + 1);
|
||||
if (buf.size() > frames_count || frames_count >= max_depth) {
|
||||
const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
|
||||
fill(buf.data(), size);
|
||||
fill(&buf[0], size);
|
||||
return;
|
||||
}
|
||||
|
||||
buf.resize(buf.size() * 2);
|
||||
} while (1);
|
||||
} while (buf.size() < buf.max_size()); // close to `true`, but suppresses `C4127: conditional expression is constant`.
|
||||
} catch (...) {
|
||||
// ignore exception
|
||||
}
|
||||
@@ -95,18 +106,18 @@ class basic_stacktrace {
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
typedef typename boost::container::vector<frame, Allocator>::value_type value_type;
|
||||
typedef typename boost::container::vector<frame, Allocator>::allocator_type allocator_type;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_pointer pointer;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_pointer const_pointer;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_reference reference;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_reference const_reference;
|
||||
typedef typename boost::container::vector<frame, Allocator>::size_type size_type;
|
||||
typedef typename boost::container::vector<frame, Allocator>::difference_type difference_type;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_iterator iterator;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_iterator const_iterator;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_reverse_iterator reverse_iterator;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_reverse_iterator const_reverse_iterator;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::value_type value_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::allocator_type allocator_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer pointer;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer const_pointer;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference reference;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference const_reference;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::size_type size_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::difference_type difference_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator iterator;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator const_iterator;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator reverse_iterator;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
/// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
|
||||
///
|
||||
@@ -174,16 +185,27 @@ public:
|
||||
~basic_stacktrace() BOOST_NOEXCEPT = default;
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS)
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
|
||||
basic_stacktrace(basic_stacktrace&& st) = default;
|
||||
basic_stacktrace(basic_stacktrace&& st) BOOST_NOEXCEPT
|
||||
: impl_(std::move(st.impl_))
|
||||
{}
|
||||
|
||||
/// @b Complexity: O(st.size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
|
||||
basic_stacktrace& operator=(basic_stacktrace&& st) = default;
|
||||
basic_stacktrace& operator=(basic_stacktrace&& st)
|
||||
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
||||
BOOST_NOEXCEPT_IF(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
|
||||
#else
|
||||
BOOST_NOEXCEPT
|
||||
#endif
|
||||
{
|
||||
impl_ = std::move(st.impl_);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @returns Number of function names stored inside the class.
|
||||
@@ -262,11 +284,11 @@ public:
|
||||
bool operator!() const BOOST_NOEXCEPT { return !size(); }
|
||||
/// @endcond
|
||||
|
||||
const boost::container::vector<frame, Allocator>& as_vector() const BOOST_NOEXCEPT {
|
||||
const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const BOOST_NOEXCEPT {
|
||||
return impl_;
|
||||
}
|
||||
|
||||
/// Constructs stacktrace from basic_istreamable that references the dumped stacktrace.
|
||||
/// Constructs stacktrace from basic_istreamable that references the dumped stacktrace. Terminating zero frame is discarded.
|
||||
///
|
||||
/// @b Complexity: O(N)
|
||||
template <class Char, class Trait>
|
||||
@@ -284,38 +306,38 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* ptr = 0;
|
||||
native_frame_ptr_t ptr = 0;
|
||||
ret.impl_.reserve(frames_count);
|
||||
while (in.read(reinterpret_cast<Char*>(&ptr), sizeof(ptr))) {
|
||||
if (!ptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret.impl_.emplace_back(ptr);
|
||||
ret.impl_.push_back(frame(ptr));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Constructs stacktrace from raw memory dump.
|
||||
/// Constructs stacktrace from raw memory dump. Terminating zero frame is discarded.
|
||||
///
|
||||
/// @b Complexity: O(size) in worst case
|
||||
static basic_stacktrace from_dump(const void* begin, std::size_t size, const allocator_type& a = allocator_type()) {
|
||||
static basic_stacktrace from_dump(const void* begin, std::size_t buffer_size_in_bytes, const allocator_type& a = allocator_type()) {
|
||||
basic_stacktrace ret(0, 0, a);
|
||||
const void* const* first = static_cast<const void* const*>(begin);
|
||||
const std::size_t frames_count = frames_count_from_buffer_size(size);
|
||||
const native_frame_ptr_t* first = static_cast<const native_frame_ptr_t*>(begin);
|
||||
const std::size_t frames_count = frames_count_from_buffer_size(buffer_size_in_bytes);
|
||||
if (!frames_count) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const void* const* const last = first + frames_count;
|
||||
const native_frame_ptr_t* const last = first + frames_count;
|
||||
ret.impl_.reserve(frames_count);
|
||||
for (; first != last; ++first) {
|
||||
if (!*first) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret.impl_.emplace_back(*first);
|
||||
ret.impl_.push_back(frame(*first));
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -367,13 +389,17 @@ bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<
|
||||
/// Fast hashing support, O(st.size()) complexity; Async-Handler-Safe.
|
||||
template <class Allocator>
|
||||
std::size_t hash_value(const basic_stacktrace<Allocator>& st) BOOST_NOEXCEPT {
|
||||
return boost::hash_range(st.as_vector().data(), st.as_vector().data()+ st.as_vector().size());
|
||||
return boost::hash_range(st.as_vector().begin(), st.as_vector().end());
|
||||
}
|
||||
|
||||
/// Outputs stacktrace in a human readable format to output stream; unsafe to use in async handlers.
|
||||
template <class CharT, class TraitsT, class Allocator>
|
||||
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) {
|
||||
return os << boost::stacktrace::detail::to_string(bt.as_vector().data(), bt.size());
|
||||
if (bt) {
|
||||
os << boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size());
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
/// This is the typedef to use unless you'd like to provide a specific allocator to boost::stacktrace::basic_stacktrace.
|
||||
@@ -381,4 +407,8 @@ typedef basic_stacktrace<> stacktrace;
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // BOOST_STACKTRACE_STACKTRACE_HPP
|
||||
|
||||
35
index.html
Normal file
35
index.html
Normal 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>
|
||||
© 2014-2017 Antony Polukhin
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -7,4 +7,10 @@
|
||||
#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>
|
||||
|
||||
@@ -7,4 +7,10 @@
|
||||
#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>
|
||||
|
||||
@@ -6,4 +6,10 @@
|
||||
|
||||
#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>
|
||||
|
||||
@@ -6,4 +6,6 @@
|
||||
|
||||
#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>
|
||||
|
||||
@@ -7,3 +7,4 @@
|
||||
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
|
||||
#define BOOST_STACKTRACE_LINK
|
||||
#include <boost/stacktrace/detail/frame_msvc.ipp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
11
src/windbg_cached.cpp
Normal file
11
src/windbg_cached.cpp
Normal 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>
|
||||
164
test/Jamfile.v2
164
test/Jamfile.v2
@@ -13,18 +13,18 @@ lib ole32 ;
|
||||
|
||||
local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ;
|
||||
lib backtrace
|
||||
:
|
||||
:
|
||||
: <search>$(LIBBACKTRACE_PATH)/lib <link>static
|
||||
:
|
||||
: <include>$(LIBBACKTRACE_PATH)/include
|
||||
: <include>$(LIBBACKTRACE_PATH)/include
|
||||
;
|
||||
|
||||
|
||||
project
|
||||
: requirements
|
||||
<toolset>msvc:<asynch-exceptions>on
|
||||
<toolset>intel:<cxxflags>-wd2196
|
||||
<warnings>all
|
||||
<debug-symbols>on
|
||||
<test-info>always_show_run_output
|
||||
;
|
||||
|
||||
@@ -36,43 +36,130 @@ local RDYNAMIC = <target-os>freebsd:<linkflags>"-rdynamic" <target-os>solaris:<l
|
||||
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 UNWD_DEPS = $(HIDE_SYMBS) <target-os>linux:<library>dl [ check-target-builds ../build//addr2line : : <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 $(UNWD_DEPS) ;
|
||||
local LINKSHARED_WIND = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_windbg $(WIND_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) ;
|
||||
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) ;
|
||||
|
||||
lib test_impl_lib_backtrace : test_impl.cpp : $(LINKSHARED_BT) ;
|
||||
lib test_impl_lib_addr2line : test_impl.cpp : $(LINKSHARED_AD2L) ;
|
||||
lib test_impl_lib_windbg : test_impl.cpp : $(LINKSHARED_WIND) ;
|
||||
lib test_impl_lib_noop : test_impl.cpp : $(LINKSHARED_NOOP) ;
|
||||
# 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) ;
|
||||
|
||||
obj test_impl_nohide-obj : test_impl.cpp : $(LINKSHARED_BASIC) ;
|
||||
lib test_impl_lib_basic : test_impl_nohide-obj : $(LINKSHARED_BASIC) ;
|
||||
|
||||
test-suite stacktrace_tests
|
||||
:
|
||||
# Header only tests
|
||||
[ run test.cpp test_impl.cpp : : : <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : backtrace_ho ]
|
||||
[ run test.cpp test_impl.cpp : : : <define>BOOST_STACKTRACE_USE_ADDR2LINE $(UNWD_DEPS) : addr2line_ho ]
|
||||
[ run test_noop.cpp test_impl.cpp : : : <define>BOOST_STACKTRACE_USE_NOOP $(NOOP_DEPS) : noop_ho ]
|
||||
[ run test.cpp test_impl.cpp : : : $(WIND_DEPS) : windbg_ho ]
|
||||
[ run test.cpp test_impl.cpp : : : $(BASIC_DEPS) : basic_ho ]
|
||||
|
||||
# Test with shared linked implementations
|
||||
[ run test.cpp : : : <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) : backtrace_lib ]
|
||||
[ run test.cpp : : : <library>.//test_impl_lib_addr2line $(LINKSHARED_AD2L) : addr2line_lib ]
|
||||
[ run test.cpp : : : <library>.//test_impl_lib_windbg $(LINKSHARED_WIND) : windbg_lib ]
|
||||
[ run test_noop.cpp : : : <library>.//test_impl_lib_noop $(LINKSHARED_NOOP) : noop_lib ]
|
||||
[ run test.cpp : : : <library>.//test_impl_lib_basic $(LINKSHARED_BASIC) : basic_lib ]
|
||||
# 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.
|
||||
# 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) ;
|
||||
@@ -82,11 +169,22 @@ for local p in [ glob ../example/*.cpp ]
|
||||
additional_dependency = <library>/boost/filesystem//boost_filesystem <library>/boost/system//boost_system <target-os>linux:<library>rt ;
|
||||
}
|
||||
|
||||
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_BT) $(additional_dependency) : backtrace_$(p[1]:B) ] ;
|
||||
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_AD2L) $(additional_dependency) : addr2line_$(p[1]:B) ] ;
|
||||
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_WIND) $(additional_dependency) : windbg_$(p[1]:B) ] ;
|
||||
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_NOOP) $(additional_dependency) : noop_$(p[1]:B) ] ;
|
||||
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_BASIC) $(additional_dependency) : basic_$(p[1]:B) ] ;
|
||||
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 ] ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
|
||||
# and how it can be used with Boost libraries.
|
||||
#
|
||||
# File revision #3
|
||||
# File revision #5
|
||||
|
||||
init:
|
||||
- set BRANCH_TO_TEST=%APPVEYOR_REPO_BRANCH% # Change to branch you wish to test. Use %APPVEYOR_REPO_BRANCH% for current branch.
|
||||
@@ -29,9 +29,7 @@ skip_tags: true
|
||||
|
||||
before_build:
|
||||
- set PATH=%PATH%;C:\\MinGW\\bin
|
||||
# Set this to the name of the library
|
||||
- set PROJECT_TO_TEST=%APPVEYOR_PROJECT_NAME%
|
||||
- echo "Testing %PROJECT_TO_TEST%"
|
||||
- echo "Testing %APPVEYOR_PROJECT_NAME%"
|
||||
# Cloning Boost libraries (fast nondeep cloning)
|
||||
- set BOOST=C:/boost-local
|
||||
- git init %BOOST%
|
||||
@@ -39,19 +37,17 @@ before_build:
|
||||
- git remote add --no-tags -t %BRANCH_TO_TEST% origin https://github.com/boostorg/boost.git
|
||||
- git fetch --depth=1
|
||||
- git checkout %BRANCH_TO_TEST%
|
||||
- git submodule update --init --merge
|
||||
- git submodule update --init --merge --jobs 16
|
||||
- git remote set-branches --add origin %BRANCH_TO_TEST%
|
||||
- git pull --recurse-submodules
|
||||
- git status
|
||||
#- git pull --recurse-submodules # Updaes submodules to most recent version. Not required
|
||||
- rm -rf %BOOST%/libs/%BOOST_REMOVE%
|
||||
- mv %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%PROJECT_TO_TEST%
|
||||
- set TRAVIS_BUILD_DIR=%BOOST%/libs/%PROJECT_TO_TEST%
|
||||
- mv %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%APPVEYOR_PROJECT_NAME%
|
||||
|
||||
build_script:
|
||||
- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
|
||||
- bootstrap.bat
|
||||
- b2.exe headers
|
||||
- cd %BOOST%/libs/%PROJECT_TO_TEST%/test
|
||||
- cd %BOOST%/libs/%APPVEYOR_PROJECT_NAME%/test
|
||||
|
||||
after_build:
|
||||
before_test:
|
||||
|
||||
@@ -25,8 +25,9 @@ using boost::stacktrace::frame;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(BOOST_GCC) && defined(BOOST_WINDOWS) && !defined(BOOST_STACKTRACE_USE_BACKTRACE) && !defined(BOOST_STACKTRACE_USE_ADDR2LINE)
|
||||
// MinGW with basic functionality
|
||||
#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
|
||||
@@ -59,7 +60,9 @@ void test_deeply_nested_namespaces() {
|
||||
#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);
|
||||
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
|
||||
|
||||
@@ -110,7 +113,11 @@ void test_comparisons_base(Bt nst, Bt 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);
|
||||
@@ -147,51 +154,28 @@ void test_comparisons() {
|
||||
}
|
||||
|
||||
void test_iterators() {
|
||||
stacktrace nst = return_from_nested_namespaces();
|
||||
stacktrace st;
|
||||
|
||||
BOOST_TEST(nst.begin() != st.begin());
|
||||
BOOST_TEST(nst.cbegin() != st.cbegin());
|
||||
BOOST_TEST(nst.crbegin() != st.crbegin());
|
||||
BOOST_TEST(nst.rbegin() != st.rbegin());
|
||||
|
||||
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() == ++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(nst.end() != st.end());
|
||||
BOOST_TEST(nst.cend() != st.cend());
|
||||
BOOST_TEST(nst.crend() != st.crend());
|
||||
BOOST_TEST(nst.rend() != st.rend());
|
||||
|
||||
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.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()));
|
||||
@@ -226,10 +210,15 @@ void test_frame() {
|
||||
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());
|
||||
}
|
||||
@@ -288,7 +277,6 @@ int main() {
|
||||
BOOST_TEST(b2.size() == 4);
|
||||
test_comparisons_base(bar1(), bar2());
|
||||
|
||||
test_nested<250>();
|
||||
test_nested<300>();
|
||||
BOOST_TEST(boost::stacktrace::stacktrace(0, 1).size() == 1);
|
||||
BOOST_TEST(boost::stacktrace::stacktrace(1, 1).size() == 1);
|
||||
|
||||
@@ -5,7 +5,16 @@
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/stacktrace.hpp>
|
||||
#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;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <boost/stacktrace.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
|
||||
79
test/test_void_ptr_cast.cpp
Normal file
79
test/test_void_ptr_cast.cpp
Normal 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();
|
||||
}
|
||||
94
test/thread_safety_checking.cpp
Normal file
94
test/thread_safety_checking.cpp
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user