Compare commits

...

124 Commits

Author SHA1 Message Date
Antony Polukhin
e99f858990 CI linkage fixes (4) 2018-02-23 22:02:22 +03:00
Antony Polukhin
c8165e7cf1 CI linkage fixes(3) 2018-02-23 10:55:01 +03:00
Antony Polukhin
d6e2a56825 CI linkage fixes(2) 2018-02-23 10:40:30 +03:00
Antony Polukhin
f8b8a806ed CI linkage fixes 2018-02-23 10:10:56 +03:00
Antony Polukhin
4603c1725d Fix warning, noted by Daniela Engert 2018-02-20 23:02:00 +03:00
Antony Polukhin
a0f948e9f5 Fix a typo. Fixes #42 2018-02-20 22:55:35 +03:00
Antony Polukhin
7f20c8c676 Disable async unsafe code 2018-01-29 23:22:31 +03:00
Antony Polukhin
31a630ced5 Use boost/container_hash/hash_fwd.hpp instead of manually forward declaring the hash_range function 2018-01-14 23:28:22 +03:00
Antony Polukhin
5b34577683 Relax some tests on Windows (refs #33) 2018-01-14 23:12:44 +03:00
Antony Polukhin
7cf669eaa6 Workaround for Boost.Exception+asan+exit(0) 2018-01-14 22:57:37 +03:00
Antony Polukhin
910fe6ea4e Disable more safe_dump tests for Windows 2018-01-11 22:39:23 +03:00
Antony Polukhin
40b792c7e4 Merge pull request #31 from Lastique/update_winapi
Update Boost.WinAPI usage to the new location and namespace
2018-01-11 22:37:25 +03:00
Antony Polukhin
b658a12183 Merge branch 'develop' into update_winapi 2018-01-11 22:08:11 +03:00
Antony Polukhin
caaea11dfa Merge branch 'develop' into update_winapi 2018-01-11 22:00:14 +03:00
Antony Polukhin
998334c3b5 Checking that safe_dump was causing hangs on Windows 2018-01-11 21:38:04 +03:00
Antony Polukhin
57699543e8 Comment out some C calls that seem to be signal unsafe on Windows 2018-01-11 11:08:07 +03:00
Antony Polukhin
940440bd3e Merge pull request #40 from DanielaE/fix/replace-deprecated-allocator-members
Most members of std::allocate are deprecated in C++17
2018-01-10 23:13:32 +03:00
Daniela Engert
168d9a7544 Most members of std::allocate are deprecated in C++17
Replace them by their cousins from std::allocator_traits.

Signed-off-by: Daniela Engert <dani@ngrt.de>
2017-12-27 18:56:33 +01:00
Antony Polukhin
4fef2cb469 Merge pull request #39 from boostorg/pr/fix-boost-install
Only use boost-install once
2017-12-20 10:53:56 +03:00
Peter Dimov
9523e26aad Only use boost-install once 2017-12-16 21:31:13 +02:00
Antony Polukhin
b7f4710c70 Merge pull request #38 from bebuch/develop
Include winapi only on windows
2017-11-24 23:28:22 +03:00
Benjamin Buch
8f0735d9bd Include winapi only on windows 2017-11-20 10:44:06 +01:00
Antony Polukhin
75f79a1177 Updated the docs to better reflect the MinGW situation. Refs #14, #34, #36 2017-11-12 22:31:35 +03:00
Antony Polukhin
8ab572d823 Docs improved. Fixes #35 2017-11-05 20:13:05 +03:00
Antony Polukhin
cdfac8033e Disable invalid test (refs #33) 2017-10-31 08:50:19 +03:00
Antony Polukhin
c2ac4b28ba Updated docs to describe stacktrace usage with MinGW (refs #14) 2017-10-31 08:44:26 +03:00
Antony Polukhin
8558ac9112 Added missing include. Fixes #32 2017-10-26 22:14:45 +03:00
Andrey Semashev
eba6db7bde Updated Boost.WinAPI usage to the new location and namespace. 2017-10-24 23:51:14 +03:00
Antony Polukhin
87a1285540 Some workarounds for MinGW+libbacktrace (refs #14) 2017-10-24 23:05:28 +03:00
Antony Polukhin
fd3b8c2784 Separate MinGW from MinGW-w64. This fixes some MinGW-w64 issues and simplifies fixage of #14 2017-10-13 21:36:16 +03:00
Antony Polukhin
8364ad1f5e Do not check for _GNU_SOURCE on Windows 2017-08-29 21:34:25 +03:00
Antony Polukhin
b5e2058ec5 Fixes for FreeBSD and other OSes that do not define _GNU_SOURCE but have _Unwind_Backtrace function 2017-08-29 20:27:18 +03:00
Antony Polukhin
af78623e8a Fix installations by renaming the preprocessor files (now uses extension .h instead of .pp). Issue #29 2017-08-27 00:11:43 +03:00
Antony Polukhin
b84d6533f5 Update build testing file (again) to deal with incorrect workaround for mingw 2017-08-08 01:29:06 +03:00
Antony Polukhin
cd420b37ae Update build testing file to deal with MinGW issue https://sourceforge.net/p/mingw-w64/bugs/527/ 2017-08-08 01:18:13 +03:00
Antony Polukhin
d663d8b471 Made terminate_handdler tests tolerate differences in stacktraces 2017-07-19 08:52:07 +03:00
Antony Polukhin
0c09c5d307 Additional check on buffer size for memory dumps 2017-07-18 23:14:40 +03:00
Antony Polukhin
a9d92be86a Slightly improve the docs and make more debug data available in test 2017-07-17 22:44:56 +03:00
Antony Polukhin
b931f501d1 Attempt to fix build issues on ICC+Windows (fixes #27) 2017-07-17 20:40:07 +03:00
Antony Polukhin
1614e8ff7d Fix typos in docs (including #25) 2017-07-16 08:51:24 +03:00
Antony Polukhin
bcf01a77a7 Merge pull request #26 from boostorg/fix-doc-build
Fix doc build
2017-07-16 08:46:18 +03:00
Daniel James
86299b8a7e Set the documentation reference id
The default one generated from the title was clashing with the boostbook
reference documentation.
2017-07-15 22:21:24 +01:00
Daniel James
5afad6fcc7 Remove redundant dependency on autodoc
It's not needed because 'stacktrace' already depends on autodoc.
2017-07-15 22:20:47 +01:00
Antony Polukhin
f853dbfc69 Fix ARM+Suse compilation 2017-07-15 17:35:31 +03:00
Antony Polukhin
9c1ed7fc95 Fix build with 'link=static runtime-link=static' flags. Fixes #23 on github 2017-07-05 22:53:38 +03:00
Antony Polukhin
ba2f260d95 Remove doubtful example from 'Getting Started' section 2017-07-04 23:31:23 +03:00
Antony Polukhin
77e69f036b Merge pull request #21 from Lastique/patch-1
Fix addr2line command line construction
2017-06-27 07:49:01 +03:00
Antony Polukhin
cb65016e16 Merge pull request #22 from Lastique/add-gitattributes
Add .gitattributes.
2017-06-27 07:47:35 +03:00
Andrey Semashev
c3e5a98d4a Added .pp extension. 2017-06-26 01:31:27 +03:00
Andrey Semashev
be200269c1 Added .gitattributes. 2017-06-26 01:26:37 +03:00
Andrey Semashev
9b7059f518 Fix addr2line command line construction 2017-06-26 01:17:25 +03:00
Antony Polukhin
4eaaaeec3a Use the Boost.WinAPI library and do not write stacktrace files into the folders of other libraries. Fixes #20 2017-06-24 20:42:29 +03:00
Antony Polukhin
f5318e3591 Updated and improved the documentation, fixed possible alignment issue in the terminate_handler example 2017-05-26 21:08:59 +03:00
Antony Polukhin
26a7e75bdb Update Appveyor script to version 5 2017-05-21 14:57:38 +03:00
Antony Polukhin
8d11eeb3ad Fix WinAPI missuse noted in #18 by pete-johnson 2017-05-16 10:28:56 +03:00
Antony Polukhin
a164f0385c Disable Intel warnings about inline+noinline on the function 2017-05-10 22:59:08 +03:00
Antony Polukhin
bd52cde3b6 Workarounds for Android and some other OSes that are pre 2003 POSIX 2017-05-08 13:02:44 +03:00
Antony Polukhin
2381fa2011 Suppress Intel compiler warnings about noinline+inline on the same function 2017-05-06 15:07:21 +03:00
Antony Polukhin
77492bc517 Added constructor to frame that accepts function addresses 2017-05-06 10:17:38 +03:00
Antony Polukhin
576a5355e3 Include <type_traits> if possible and use a more portable noexcept checking logic for move assignment 2017-05-04 09:18:57 +03:00
Antony Polukhin
25efff8c87 Added an error message on attempt to use the thread local chached windbg on a compilers without the thread_local support 2017-05-03 23:55:33 +03:00
Antony Polukhin
29aaf100a8 Revert "Enable usage of MSVC specific thread local storage attributes"
This reverts commit ca4464d23c.
2017-05-03 23:50:22 +03:00
Antony Polukhin
ca4464d23c Enable usage of MSVC specific thread local storage attributes 2017-05-03 23:47:12 +03:00
Antony Polukhin
235226bdcc Do neither test nor build cached windows implementation if thread_locacl is not supported 2017-05-03 23:40:27 +03:00
Antony Polukhin
c8d526493d Workarounds for this usage in constexpr functions in GCC 2017-05-01 22:30:09 +03:00
Antony Polukhin
cff7191e46 Fix MinGW warnings about extra ';' 2017-05-01 00:56:05 +03:00
Antony Polukhin
e70847b918 Attempt to workaround missing std::_Exit on old MSVCs and MinGWs 2017-05-01 00:50:40 +03:00
Antony Polukhin
63b4f96ba4 Fix compilation on pre-C++11 standard libraries 2017-04-29 21:43:03 +03:00
Antony Polukhin
39247fbb32 Fixed MSVC related compilation issues 2017-04-29 19:23:39 +03:00
Antony Polukhin
25260ed667 Fix warning 'conversion from 'size_t' to 'int', possible loss of data' 2017-04-29 12:06:10 +03:00
Antony Polukhin
a014c78b74 Fix MSVC 'conditional expression is constant' warning 2017-04-29 01:10:02 +03:00
Antony Polukhin
3d25e45a0d Fix MSVC warnings and add some doxygen workarounds for prettier reference section of the docs 2017-04-29 01:00:00 +03:00
Antony Polukhin
55063fd438 Add id to .qbk (refs #17) 2017-04-27 22:35:14 +03:00
Antony Polukhin
a562d4cb95 Fix compilation and links in README 2017-04-21 22:15:07 +03:00
Antony Polukhin
68c4f8be6a Added void_ptr_cast and tests for it 2017-04-21 21:57:31 +03:00
Antony Polukhin
55791ad90c Do not compare iterators from different containers 2017-04-21 00:26:31 +03:00
Antony Polukhin
5c0176904a Attempt to locate an issue on MSVC (2) 2017-04-21 00:11:38 +03:00
Antony Polukhin
75296819ea Attempt to locate an issue on MSVC 2017-04-20 22:44:31 +03:00
Antony Polukhin
269acd6929 Attempt to fox MSVC tests and fix coverage reports 2017-04-20 22:13:43 +03:00
Antony Polukhin
12b3f98b98 Update README links 2017-04-20 21:48:55 +03:00
Antony Polukhin
141bc0a1d6 Attempt to fix link errors on MSVC 2017-04-20 21:26:09 +03:00
Antony Polukhin
984b702a11 Fix MSVC compilation 2017-04-20 20:49:58 +03:00
Antony Polukhin
61d11f8d48 Separated the stack collecting from decoding headers, dropped windows.h dependency for capturing stack, added tests on minimal files inclusion for stack capturing headers 2017-04-20 20:09:49 +03:00
Antony Polukhin
2e29ee7648 Separation of stack collecting and stack decoding headers, part 3 2017-04-20 20:07:41 +03:00
Antony Polukhin
f2f66b0d2a Separation of stack collecting and stack decoding headers, part 2 2017-04-20 20:07:05 +03:00
Antony Polukhin
fe5a0d9871 Started the separation of stack collecting and stack decoding headers 2017-04-20 20:06:09 +03:00
Antony Polukhin
960f9d0f38 Use native_frame_ptr_t instead of void* and const void* 2017-04-20 20:04:27 +03:00
Antony Polukhin
21c2484f75 Added some constexprs to boost::stacktrace::frame 2017-04-20 20:02:55 +03:00
Antony Polukhin
e0fb46b62c Drop dependency to Boost.Container 2017-04-20 20:02:32 +03:00
Antony Polukhin
fb29d75b3a Harden the security by not evaluating the PATH variable in addr2line implementation 2017-04-19 22:28:45 +03:00
Antony Polukhin
96deb9688a Fixed incorrect usage of S_IFREG reported in #15 2017-04-19 22:27:38 +03:00
Antony Polukhin
a6bdf54c85 More COM related tests, measure speed of some of the test runs 2017-04-19 22:25:59 +03:00
Antony Polukhin
a6521b2b40 Added index.html file required by Boost 2017-04-18 10:03:06 +03:00
Antony Polukhin
1a4ac5bac2 Multithreaded tests without debug symbols now really do not use debug symbols. 2017-04-16 21:32:33 +03:00
Antony Polukhin
29859bf28e Updated the README 2017-04-16 18:39:32 +03:00
Antony Polukhin
7342d0afd0 Fix test for GCC -O1, make the test faster 2017-04-16 11:21:51 +03:00
Antony Polukhin
e072ec7a38 Test on more different flags 2017-04-16 09:32:11 +03:00
Antony Polukhin
a50b0670d6 Coverage fixes 2017-04-15 22:20:53 +03:00
Antony Polukhin
23ca1dab3b Less iterations for threaded test 2017-04-15 21:50:48 +03:00
Antony Polukhin
885f45e64f More aggressive thread safety testing, fix for the libbacktrace usage in shared library, TravisCI tweaks 2017-04-15 21:28:11 +03:00
Antony Polukhin
d990acd883 Fixes for coverage reports in CI (3) 2017-04-15 15:47:27 +03:00
Antony Polukhin
eac60a4709 Fixes for coverage reports in CI (2) 2017-04-15 15:32:38 +03:00
Antony Polukhin
23218809c1 Fixes for coverage reports in CI 2017-04-15 15:21:42 +03:00
Antony Polukhin
a208f422a5 Docs regenerated 2017-04-15 15:12:01 +03:00
Antony Polukhin
9fc256bee4 Fixes for cached msvc compilation 2017-04-15 14:56:21 +03:00
Antony Polukhin
ce661c9c7b Typo fix in chaced msvc 2017-04-15 13:20:00 +03:00
Antony Polukhin
3678082434 Added new option for MSVC: boost_stacktrace_windbg_cached 2017-04-15 13:00:26 +03:00
Antony Polukhin
3a49914d80 Moar fixes for MSVC tests (2) 2017-04-15 01:15:01 +03:00
Antony Polukhin
29da39c6a5 Moar fixes for MSVC tests 2017-04-15 00:22:06 +03:00
Antony Polukhin
b784ccdebd One more MSVC fix related to module only name apearing without function name 2017-04-14 23:20:33 +03:00
Antony Polukhin
287090e284 Fix function name extraction using MSVC and mark MSVC tests without debug info as tests that do not producs stacktraces 2017-04-14 22:59:13 +03:00
Antony Polukhin
de9b588d1d Many new tests, including naive thread safety test 2017-04-14 22:38:48 +03:00
Antony Polukhin
fea1024491 Typo fix in MSVC related code 2017-04-14 22:26:36 +03:00
Antony Polukhin
c18532d7cc Fix Appveyor builds 2017-04-14 22:09:27 +03:00
Antony Polukhin
3b0e6a57a3 MSVC refactoring. MinGW fixes from @ustrobot (issue #14) 2017-04-14 21:49:19 +03:00
Antony Polukhin
22261768ec Fix segfaults with libbacktrace while getting stack trace without debug info. Speedup and reduce memory usage while using libbacktrace 2017-04-14 21:46:24 +03:00
Antony Polukhin
d1380eba28 Apply Cygwin fixes from Peter Dimov 2017-03-18 16:50:38 +03:00
Antony Polukhin
5664c752cb Relax tests on MSVC 2017-03-18 13:38:15 +03:00
Antony Polukhin
cc3c37a930 Fixed typos 2017-03-18 13:26:22 +03:00
Antony Polukhin
fb9de2bb6b Drop windows.h inclusion in safe_dump_win.ipp 2017-03-18 13:13:43 +03:00
Antony Polukhin
27ec669657 Make MSVC tests less strict 2017-03-18 13:10:07 +03:00
Antony Polukhin
46b0542350 Replaced the hand written try_demangle function with core::demangle 2017-03-18 12:38:42 +03:00
Antony Polukhin
6b3d993df1 Remove the unportable +2 skips because MSVC could ignore BOOST_NOINCLUDE depending on linktime optimization flags 2017-03-18 12:27:11 +03:00
Antony Polukhin
9c1c343dad Fixed the accidental trigraphs/digraphs in frame_msvc.ipp 2017-03-18 12:22:52 +03:00
47 changed files with 1739 additions and 740 deletions

97
.gitattributes vendored Normal file
View 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

View File

@@ -2,7 +2,7 @@
# subject to the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# Copyright Antony Polukhin 2014-2016.
# Copyright Antony Polukhin 2014-2018.
#
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
@@ -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,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

View File

@@ -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: | [![Build Status](https://travis-ci.org/apolukhin/stacktrace.svg?branch=develop)](https://travis-ci.org/apolukhin/stacktrace) [![Build status](https://ci.appveyor.com/api/projects/status/e070eams56vu0lm6/branch/develop?svg=true)](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/develop) | [![Coverage Status](https://coveralls.io/repos/apolukhin/stacktrace/badge.png?branch=develop)](https://coveralls.io/r/apolukhin/stacktrace?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/stacktrace.html)
Master branch: | [![Build Status](https://travis-ci.org/apolukhin/stacktrace.svg?branch=master)](https://travis-ci.org/apolukhin/stacktrace) [![Build status](https://ci.appveyor.com/api/projects/status/e070eams56vu0lm6/branch/master?svg=true)](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/master) | [![Coverage Status](https://coveralls.io/repos/apolukhin/stacktrace/badge.png?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: | [![Build Status](https://travis-ci.org/boostorg/stacktrace.svg?branch=develop)](https://travis-ci.org/boostorg/stacktrace) [![Build status](https://ci.appveyor.com/api/projects/status/l3aak4j8k39rx08t/branch/develop?svg=true)](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/develop) | [![Coverage Status](https://coveralls.io/repos/github/boostorg/stacktrace/badge.svg?branch=develop)](https://coveralls.io/github/boostorg/stacktrace?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/stacktrace.html)
Master branch: | [![Build Status](https://travis-ci.org/boostorg/stacktrace.svg?branch=master)](https://travis-ci.org/boostorg/stacktrace) [![Build status](https://ci.appveyor.com/api/projects/status/l3aak4j8k39rx08t/branch/master?svg=true)](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/master) | [![Coverage Status](https://coveralls.io/repos/github/boostorg/stacktrace/badge.svg?branch=master)](https://coveralls.io/github/boostorg/stacktrace?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/stacktrace.html)
### License

View File

@@ -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,11 @@ 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 ;
local libraries ;
lib boost_stacktrace_noop
: # sources
../src/noop.cpp
@@ -59,7 +64,7 @@ lib boost_stacktrace_noop
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_noop ;
libraries += boost_stacktrace_noop ;
lib boost_stacktrace_backtrace
: # sources
@@ -75,7 +80,7 @@ lib boost_stacktrace_backtrace
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_backtrace ;
libraries += boost_stacktrace_backtrace ;
lib boost_stacktrace_addr2line
: # sources
@@ -90,7 +95,7 @@ lib boost_stacktrace_addr2line
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_addr2line ;
libraries += boost_stacktrace_addr2line ;
lib boost_stacktrace_basic
: # sources
@@ -105,7 +110,7 @@ lib boost_stacktrace_basic
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_basic ;
libraries += boost_stacktrace_basic ;
lib boost_stacktrace_windbg
: # sources
@@ -120,5 +125,21 @@ lib boost_stacktrace_windbg
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_windbg ;
libraries += 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
;
libraries += boost_stacktrace_windbg_cached ;
boost-install $(libraries) ;

View File

@@ -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());
}

View File

@@ -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(

View File

@@ -0,0 +1,28 @@
// Copyright Antony Polukhin, 2016-2017.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#include <string>
#include <cstring>
#include <windows.h>
#include "dbgeng.h"
#ifdef BOOST_NO_CXX11_THREAD_LOCAL
# error Your compiler does not support C++11 thread_local storage. It`s impossible to build with BOOST_STACKTRACE_USE_WINDBG_CACHED.
#endif
int foo() {
static thread_local std::string i = std::string();
return static_cast<int>(i.size());
}
int main() {
::CoInitializeEx(0, COINIT_MULTITHREADED);
return foo();
}

View File

@@ -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 ;

View File

@@ -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,9 @@ 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].]
[warning Not all the platforms provide means for even getting stacktrace in async signal safe way. No stack trace will be saved on such platforms. ]
Let's write a handler to safely dump stacktrace:
@@ -145,7 +148,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 +179,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 +187,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 +242,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 +277,8 @@ Previous run crashed and left trace in shared memory:
15# 0x0000000000402999
```
[endsect]
[endsect]
]
[endsect]
@@ -291,10 +295,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 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]]
[[['default for MSVC, Intel on Windows, MinGW-w64] / *BOOST_STACKTRACE_USE_WINDBG*] [*boost_stacktrace_windbg*] [ Uses COM to show debug info. May require linking with *ole32* and *dbgeng*. ] [MSVC, MinGW-w64, Intel on Windows] [yes] [no]]
[[['default for other platforms]] [*boost_stacktrace_basic*] [Uses compiler intrinsics to collect stacktrace and if possible `::dladdr` to show information about the symbol. Requires linking with *libdl* library on POSIX platforms.] [Any compiler on POSIX or MinGW] [no] [yes]]
[[*BOOST_STACKTRACE_USE_WINDBG_CACHED*] [*boost_stacktrace_windbg_cached*] [ Uses COM to show debug info and caches COM instances in TLS for better performance. Useful only for cases when traces are gathered very often. [footnote This may affect other components of your program that use COM, because this mode calls the `CoInitializeEx(0, COINIT_MULTITHREADED)` on first use and does not call `::CoUninitialize();` until the current thread is destroyed. ] May require linking with *ole32* and *dbgeng*. ] [MSVC, Intel on Windows] [yes] [no]]
[[*BOOST_STACKTRACE_USE_BACKTRACE*] [*boost_stacktrace_backtrace*] [Requires linking with *libdl* on POSIX and *libbacktrace* libraries. *libbacktrace* is probably already installed in your system, or built into your compiler.
Otherwise (if you are a *MinGW*/*MinGW-w64* user for example) it can be downloaded [@https://github.com/ianlancetaylor/libbacktrace from here] or [@https://github.com/gcc-mirror/gcc/tree/master/libbacktrace from here]. ] [Any compiler on POSIX, or MinGW, or MinGW-w64] [yes] [yes]]
[[*BOOST_STACKTRACE_USE_ADDR2LINE*] [*boost_stacktrace_addr2line*] [Use *addr2line* program to retrieve stacktrace. Requires linking with *libdl* library and `::fork` system call. Macro *BOOST_STACKTRACE_ADDR2LINE_LOCATION* must be defined to the absolute path to the addr2line executable if it is not located in /usr/bin/addr2line. ] [Any compiler on POSIX] [yes] [yes]]
[[*BOOST_STACKTRACE_USE_NOOP*] [*boost_stacktrace_noop*] [Use this if you wish to disable backtracing. `stacktrace::size()` with that macro always returns 0. ] [All] [no] [no]]
]
@@ -304,6 +311,25 @@ In header only mode library could be tuned by macro. If one of the link macro fr
* if you wish to disable backtracing and you use the library in header only mode, you just need to define *BOOST_STACKTRACE_USE_NOOP* for the whole project
* if you wish to disable backtracing and *BOOST_STACKTRACE_LINK* is defined, you just need link with *-lboost_stacktrace_noop*
[section MinGW and MinGW-w64 specific notes]
MinGW-w64 and MinGW (without -w64) users have to install libbacktrace for getting better stacktraces. Follow the instruction:
Let's assume that you've installed MinGW into C:\MinGW and downloaded [@https://github.com/ianlancetaylor/libbacktrace libbacktrace sources] into C:\libbacktrace-master
* Configure & build libbacktrace from console:
* C:\MinGW\msys\1.0\bin\sh.exe
* cd /c/libbacktrace-master
* ./configure CC=/c/MinGW/bin/gcc.exe CXX=/c/MinGW/bin/g++.exe
* make
* ./libtool --mode=install /usr/bin/install -c libbacktrace.la '/c/libbacktrace-master'
* Add info to the project-config.jam in the Boost folder:
* using gcc : 6 : "C:\\MinGW\\bin\\g++.exe" : <compileflags>-I"C:\\libbacktrace-master\\" <linkflags>-L"C:\\libbacktrace-master\\" ;
* Now you can use a header only version by defining *BOOST_STACKTRACE_USE_BACKTRACE* for your project or build the stacktrace library from Boost folder:
* b2.exe toolset=gcc-6 --with-stacktrace
[endsect]
[endsect]
[section Acknowledgements]

View File

@@ -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();

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2018.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -11,23 +11,23 @@
#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);
}
int main() {
::signal(SIGSEGV, &my_signal_handler);
print_signal_handler_and_exit();
return 2;
}

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2018.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -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';
}
}
@@ -281,6 +271,13 @@ int test_inplace() {
boost::filesystem::remove("./backtrace3.dump");
#ifdef BOOST_WINDOWS
// `ss2` could be empty on some combinations of Windows+MSVC.
if (!ss2) {
return 0;
}
#endif
if (ss1.size() != ss2.size()) {
std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
return 58;
@@ -303,11 +300,15 @@ int test_inplace() {
int main(int argc, const char* argv[]) {
if (argc < 2) {
#ifndef BOOST_WINDOWS
// We are copying files to make sure that stacktrace printing works independently from executable name
copy_and_run(argv[0], '1', true);
copy_and_run(argv[0], '2', false);
// There are some issues with async-safety of shared memory writes on Windows.
copy_and_run(argv[0], '3', true);
copy_and_run(argv[0], '4', false);
#endif
return test_inplace();
}

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2018.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -68,8 +68,8 @@ int main() {
std::cerr << e.what() << '\n';
const boost::stacktrace::stacktrace* st = boost::get_error_info<traced>(e);
if (st) {
std::cerr << *st << '\n'; /*<-*/ std::exit(0); /*->*/
} /*<-*/ std::exit(3); /*->*/
std::cerr << *st << '\n'; /*<-*/ return 0; /*->*/
} /*<-*/ return 3; /*->*/
}
//]

View File

@@ -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();

View 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/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::winapi::RtlCaptureStackBackTrace(
static_cast<boost::winapi::ULONG_>(skip),
static_cast<boost::winapi::ULONG_>(max_frames_count),
const_cast<boost::winapi::PVOID_*>(out_frames),
0
);
}
}}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_COLLECT_MSVC_IPP

View File

@@ -0,0 +1,25 @@
// Copyright Antony Polukhin, 2016-2017.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#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

View 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

View 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

View File

@@ -14,53 +14,57 @@
#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>
#include <windows.h>
#include "dbgeng.h"
#include <boost/detail/winapi/get_current_process.hpp>
#ifdef BOOST_MSVC
# pragma comment(lib, "ole32.lib")
# 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 DWORD res = ::CoInitializeEx(0, COINIT_MULTITHREADED);
ok_ = (res == S_OK || res == S_FALSE);
}
~com_global_initer() BOOST_NOEXCEPT {
::CoUninitialize();
if (ok_) {
::CoUninitialize();
}
}
};
@@ -94,155 +98,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 mingw_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 = mingw_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 +352,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 +362,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;
}

View File

@@ -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 {

View File

@@ -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_);

View File

@@ -13,7 +13,8 @@
#endif
#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 <backtrace.h>
@@ -39,15 +40,54 @@ 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.
}
inline ::backtrace_state* construct_state(const program_location& prog_location) BOOST_NOEXCEPT {
// Currently `backtrace_create_state` can not detect file name on Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82543
// That's why we provide a `prog_location` here.
return ::backtrace_create_state(
prog_location.name(), 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;
boost::stacktrace::detail::program_location prog_location;
::backtrace_state* state;
std::string filename;
std::size_t line;
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 +104,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(prog_location);
}
};
@@ -76,14 +114,21 @@ 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
);
boost::stacktrace::detail::program_location prog_location;
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
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 +139,37 @@ 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
);
boost::stacktrace::detail::program_location prog_location;
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
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
);
boost::stacktrace::detail::program_location prog_location;
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
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;
}

View File

@@ -12,16 +12,16 @@
# pragma once
#endif
#ifndef BOOST_WINDOWS
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
# include <dlfcn.h>
#else
# include <boost/detail/winapi/dll.hpp>
# include <boost/winapi/dll.hpp>
#endif
namespace boost { namespace stacktrace { namespace detail {
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
class location_from_symbol {
#ifndef BOOST_WINDOWS
::Dl_info dli_;
public:
@@ -40,22 +40,32 @@ public:
const char* name() const BOOST_NOEXCEPT {
return dli_.dli_fname;
}
#else
BOOST_STATIC_CONSTEXPR boost::detail::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
};
class program_location {
public:
const char* name() const BOOST_NOEXCEPT {
return 0;
}
};
#else
class location_from_symbol {
BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
char file_name_[DEFAULT_PATH_SIZE_];
public:
explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT {
file_name_[0] = '\0';
boost::detail::winapi::MEMORY_BASIC_INFORMATION_ mbi;
if (!boost::detail::winapi::VirtualQuery(addr, &mbi, sizeof(mbi))) {
boost::winapi::MEMORY_BASIC_INFORMATION_ mbi;
if (!boost::winapi::VirtualQuery(addr, &mbi, sizeof(mbi))) {
return;
}
boost::detail::winapi::HMODULE_ handle = reinterpret_cast<boost::detail::winapi::HMODULE_>(mbi.AllocationBase);
if (!boost::detail::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
boost::winapi::HMODULE_ handle = reinterpret_cast<boost::winapi::HMODULE_>(mbi.AllocationBase);
if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
file_name_[0] = '\0';
return;
}
@@ -68,9 +78,28 @@ public:
const char* name() const BOOST_NOEXCEPT {
return file_name_;
}
#endif
};
class program_location {
BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
char file_name_[DEFAULT_PATH_SIZE_];
public:
program_location() BOOST_NOEXCEPT {
file_name_[0] = '\0';
const boost::winapi::HMODULE_ handle = 0;
if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
file_name_[0] = '\0';
}
}
const char* name() const BOOST_NOEXCEPT {
return file_name_[0] ? file_name_ : 0;
}
};
#endif
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP

View 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

View 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

View 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

View File

@@ -12,33 +12,44 @@
# pragma once
#endif
#include <boost/stacktrace/frame.hpp>
#include <boost/stacktrace/safe_dump_to.hpp>
#include <unistd.h> // ::write
#include <fcntl.h> // ::open
#include <sys/stat.h> // S_IWUSR and friends
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;
}

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2018.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -12,45 +12,53 @@
# pragma once
#endif
#include <boost/stacktrace/frame.hpp>
#include <boost/stacktrace/safe_dump_to.hpp>
#include <boost/core/noncopyable.hpp>
#include <boost/detail/winapi/get_current_process.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/access_rights.hpp>
#include <windows.h> // CaptureStackBackTrace
#include <boost/winapi/get_current_process.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/access_rights.hpp>
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 {
#if 0 // This code potentially could cause deadlocks (according to the MSDN). Disabled
boost::winapi::DWORD_ written;
const boost::winapi::DWORD_ bytes_to_write = static_cast<boost::winapi::DWORD_>(
sizeof(native_frame_ptr_t) * frames_count
);
if (!boost::winapi::WriteFile(fd, frames, bytes_to_write, &written, 0)) {
return 0;
}
return mem_size;
return frames_count;
#endif
return 0;
}
std::size_t dump(const char* file, void** memory, std::size_t mem_size) BOOST_NOEXCEPT {
void* const fd = boost::detail::winapi::CreateFileA(
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
#if 0 // This code causing deadlocks on some platforms. Disabled
void* const fd = boost::winapi::CreateFileA(
file,
boost::detail::winapi::GENERIC_WRITE_,
boost::winapi::GENERIC_WRITE_,
0,
0,
boost::detail::winapi::CREATE_ALWAYS_,
boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
boost::winapi::CREATE_ALWAYS_,
boost::winapi::FILE_ATTRIBUTE_NORMAL_,
0
);
if (fd == boost::detail::winapi::invalid_handle_value) {
if (fd == boost::winapi::invalid_handle_value) {
return 0;
}
const std::size_t size = boost::stacktrace::detail::dump(fd, memory, mem_size);
boost::detail::winapi::CloseHandle(fd);
const std::size_t size = boost::stacktrace::detail::dump(fd, frames, frames_count);
boost::winapi::CloseHandle(fd);
return size;
#endif
return 0;
}
}}} // namespace boost::stacktrace::detail

View File

@@ -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

View 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

View File

@@ -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>

View File

@@ -12,38 +12,70 @@
# pragma once
#endif
#include <boost/stacktrace/frame.hpp>
#if defined(BOOST_WINDOWS)
#include <boost/winapi/config.hpp>
#endif
#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 +84,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 +99,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,30 +107,30 @@ 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);
}
/// @brief Opens a file and rewrites its content with current function call sequence.
/// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @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.
/// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @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,29 +138,29 @@ 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
/// @brief Writes into the provided file descriptor the current function call sequence.
/// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @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;
/// @brief Writes into the provided file descriptor the current function call sequence.
/// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @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 +172,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 +195,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_WINAPI_IS_MINGW) // MinGW does not provide RtlCaptureStackBackTrace. MinGW-w64 does.
# 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

View File

@@ -13,20 +13,24 @@
#endif
#include <boost/core/explicit_operator_bool.hpp>
#include <boost/container_hash/hash_fwd.hpp>
#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>
/// @cond
namespace boost {
// Forward declaration
template <class It> std::size_t hash_range(It, It);
}
/// @endcond
#ifdef BOOST_INTEL
# pragma warning(push)
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
#endif
namespace boost { namespace stacktrace {
@@ -34,10 +38,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 +59,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 +71,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 +81,22 @@ 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());
#ifdef BOOST_NO_CXX11_ALLOCATOR
typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t;
#else
typedef typename std::allocator_traits<Allocator>::template rebind_alloc<native_frame_ptr_t> allocator_void_t;
#endif
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 +104,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 +183,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 +282,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 +304,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 +387,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 +405,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
View File

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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
View File

@@ -0,0 +1,11 @@
// Copyright Antony Polukhin, 2016-2017.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_LINK
#define BOOST_STACKTRACE_USE_WINDBG_CACHED
#include <boost/stacktrace/detail/frame_msvc.ipp>
#include <boost/stacktrace/safe_dump_to.hpp>

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2016-2017, Antony Polukhin.
# Copyright (C) 2016-2018, 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
@@ -13,18 +13,19 @@ 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
<target-os>linux:<linkflags>-lpthread
<warnings>all
<debug-symbols>on
<test-info>always_show_run_output
;
@@ -36,43 +37,154 @@ 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 +194,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 ] ;
}

View File

@@ -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:

View File

@@ -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);

View File

@@ -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;

View File

@@ -7,6 +7,7 @@
#include <boost/stacktrace.hpp>
#include <boost/core/lightweight_test.hpp>
#include <stdexcept>
#include <boost/functional/hash.hpp>

View File

@@ -0,0 +1,79 @@
// Copyright 2017 Antony Polukhin.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/stacktrace/detail/void_ptr_cast.hpp>
#include <boost/core/lightweight_test.hpp>
int foo1_func(int) { return 0; }
void foo2_func(int, int, ...) {}
struct test_struct {
int foo1_memb(int) const { return 0; }
void foo2_memb(int, int, ...) {}
};
template <class F1, class F2>
void test(F1 foo1, F2 foo2) {
using boost::stacktrace::detail::void_ptr_cast;
typedef void(*void_f_ptr)();
// Function/variable to void(*)()
void_f_ptr fp1 = void_ptr_cast<void_f_ptr>(foo1);
void_f_ptr fp2 = void_ptr_cast<void_f_ptr>(foo2);
BOOST_TEST(fp1);
BOOST_TEST(fp2);
BOOST_TEST(fp1 != fp2);
// Function/variable to void*
void* vp1 = void_ptr_cast<void*>(foo1);
void* vp2 = void_ptr_cast<void*>(foo2);
BOOST_TEST(vp1);
BOOST_TEST(vp2);
BOOST_TEST(vp1 != vp2);
// void* to void(*)()
void_f_ptr fp1_2 = void_ptr_cast<void_f_ptr>(vp1);
void_f_ptr fp2_2 = void_ptr_cast<void_f_ptr>(vp2);
BOOST_TEST(fp1_2);
BOOST_TEST(fp2_2);
BOOST_TEST(fp1_2 != fp2_2);
BOOST_TEST(fp1 == fp1_2);
BOOST_TEST(fp2 == fp2_2);
// void(*)() to void*
BOOST_TEST(void_ptr_cast<void*>(fp1) == vp1);
BOOST_TEST(void_ptr_cast<void*>(fp2) == vp2);
// void(*)() to function/variable
BOOST_TEST(void_ptr_cast<F1>(fp1) == foo1);
BOOST_TEST(void_ptr_cast<F2>(fp2) == foo2);
// void* to function/variable
BOOST_TEST(void_ptr_cast<F1>(vp1) == foo1);
BOOST_TEST(void_ptr_cast<F2>(vp2) == foo2);
}
int main() {
// Testing for functions
test(foo1_func, foo2_func);
typedef void(func_t)();
test(
boost::stacktrace::detail::void_ptr_cast<func_t* const>(foo1_func),
boost::stacktrace::detail::void_ptr_cast<func_t* const>(foo2_func)
);
// Testing for variables (just in case...)
int i = 0;
double j= 1;
test(&i, &j);
return boost::report_errors();
}

View File

@@ -0,0 +1,94 @@
// Copyright Antony Polukhin, 2016-2017.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/stacktrace/stacktrace_fwd.hpp>
#include <sstream>
#include <boost/stacktrace.hpp>
#include <boost/thread.hpp>
#include <boost/optional.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/timer/timer.hpp>
#ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_ST_API BOOST_SYMBOL_IMPORT
#else
# define BOOST_ST_API
#endif
using boost::stacktrace::stacktrace;
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
BOOST_ST_API std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1);
BOOST_ST_API stacktrace return_from_nested_namespaces();
BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo1(int i) {
if (i) {
return foo2(i - 1, foo1);
}
std::pair<stacktrace, stacktrace> ret;
try {
throw std::logic_error("test");
} catch (const std::logic_error& /*e*/) {
ret.second = stacktrace();
return ret;
}
}
void main_test_loop() {
std::size_t loops = 100;
int Depth = 25;
boost::optional<std::pair<stacktrace, stacktrace> > ethalon;
std::stringstream ss_ethalon;
while (--loops) {
std::pair<stacktrace, stacktrace> res = foo2(Depth, foo1);
if (ethalon) {
BOOST_TEST(res == *ethalon);
std::stringstream ss;
ss << res.first;
BOOST_TEST(ss.str() == ss_ethalon.str());
} else {
ethalon = res;
ss_ethalon << ethalon->first;
}
}
}
#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT) || defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST)
# include <windows.h>
# include "dbgeng.h"
#endif
int main() {
#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT)
::CoInitializeEx(0, COINIT_MULTITHREADED);
#elif defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST)
::CoInitializeEx(0, COINIT_APARTMENTTHREADED);
#endif
boost::timer::auto_cpu_timer t;
boost::thread t1(main_test_loop);
boost::thread t2(main_test_loop);
boost::thread t3(main_test_loop);
main_test_loop();
t1.join();
t2.join();
t3.join();
#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT) || defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST)
::CoUninitialize();
#endif
return boost::report_errors();
}