Compare commits

...

311 Commits

Author SHA1 Message Date
Peter Dimov
79aff77771 Fix checks and build to work on Cygwin 2021-06-01 04:26:35 +03:00
Peter Dimov
1be59df18e Do not use find_package(Backtrace) 2021-06-01 03:39:23 +03:00
Peter Dimov
1dae3faf43 Check for backtrace both with Backtrace_HEADER and without it (it's set to execinfo.h on Linux and doesn't work, whereas backtrace.h does) 2021-06-01 02:59:06 +03:00
Peter Dimov
99b7015508 Define BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE 2021-06-01 01:56:34 +03:00
Peter Dimov
18012f81da Fix spelling of Backtrace_FOUND 2021-06-01 01:38:58 +03:00
Peter Dimov
76f902f366 Add CMakeLists.txt 2021-05-31 23:04:04 +03:00
Antony Polukhin
b37e0d8e9f use HTTPS links in Readme 2021-04-27 11:19:55 +03:00
Antony Polukhin
9a114f8256 update links in Readme, add badges, run coverage reports only from GithubActions 2021-04-24 21:46:32 +03:00
Antony Polukhin
b75a37dc48 do not run on MacOs in GithubActions CI 2021-04-24 20:25:35 +03:00
Antony Polukhin
1631213c0c update CI: fixes 2021-04-24 11:18:22 +03:00
Antony Polukhin
cadf1bc311 update CI: add depinst.py dirs 2021-04-24 10:38:35 +03:00
Antony Polukhin
26f66b58e9 update CIs 2021-04-23 20:38:10 +03:00
Antony Polukhin
7b19672b67 fix broken link 2021-04-23 20:29:34 +03:00
Antony Polukhin
67cc2e9017 Merge pull request #107 from sdarwin/githubactions
GitHub Actions config
2021-04-18 14:10:00 +03:00
sdarwin
4b4472cccb Add GitHub Actions config [ci skip] 2021-03-05 16:25:14 +00:00
Antony Polukhin
08d720adbd attempt to fix coverage reports 2021-01-04 19:08:40 +03:00
Antony Polukhin
a00587f4d7 update copyright years 2021-01-03 19:24:15 +03:00
Antony Polukhin
9c462940b1 Merge pull request #104 from sdarwin/lcov
update lcov in .travis.yml
2021-01-03 12:51:27 +03:00
sdarwin
7fdaebb8ef update lcov in .travis.yml 2020-12-30 15:51:38 +00:00
Antony Polukhin
15f6b30f12 Better support for pre-C++11 builds on clang (fixes #102) 2020-12-19 14:35:28 +03:00
Antony Polukhin
4a8b14b2d7 disable test on Windows 2020-12-18 11:04:34 +03:00
Antony Polukhin
e4576bfae2 attempt to deal with hangs on some platforms 2020-12-16 12:09:01 +03:00
Antony Polukhin
7985a04380 bigger warning for signal handlers (fixes #71) 2020-12-15 17:00:34 +03:00
Antony Polukhin
d84457e2a0 update meta info on stacktrace 2020-12-15 16:51:07 +03:00
Antony Polukhin
66aba44f79 do not recommend safe_dump_to (fixes #98) 2020-12-15 16:48:29 +03:00
Antony Polukhin
e75d2ff93b Merge pull request #91 from jeremiahar/develop
Add support for disabled exceptions
2020-05-28 16:48:43 +03:00
Jeremiah Rodriguez
a8a4cefb52 Add support for disabled exceptions 2020-05-26 13:28:32 -07:00
Antony Polukhin
f931528c87 CI fixes 2020-04-06 18:47:50 +03:00
Antony Polukhin
9b5bc54fe3 provide documentation on distribution of PDBs (fixes #55, #47) 2020-01-23 23:56:01 +03:00
Antony Polukhin
178d2875d7 Remove ugly things from the test (refs #86) 2020-01-21 09:14:40 +03:00
Antony Polukhin
ade7d54dc7 update copyright year 2020-01-18 14:11:02 +03:00
Antony Polukhin
211d291253 Merge pull request #84 from doj/develop
fix typo in stacktrace.qbk
2019-11-17 09:13:49 +03:00
Antony Polukhin
b72cc6cdfd Adjust coverage reports in CI (3) 2019-11-16 17:28:44 +03:00
Antony Polukhin
99e07cbea6 Adjust coverage reports in CI (2) 2019-11-16 13:11:08 +03:00
Antony Polukhin
922305ea7d Adjust CI coverage reports 2019-11-16 12:44:01 +03:00
Antony Polukhin
2fce6957d6 More CI workarounds 2019-11-16 10:51:49 +03:00
Antony Polukhin
2cfcbf4247 Update Jamfile.v2 2019-11-15 19:07:10 +03:00
Dirk Jagdmann
0bddb90c1d fix typo in stacktrace.qbk 2019-11-14 13:29:33 -08:00
Antony Polukhin
b6bc847b0c Fine tune inspect tool 2019-11-12 20:02:46 +03:00
Antony Polukhin
6c5b7e51d5 Install binutils 2019-11-12 19:28:48 +03:00
Antony Polukhin
acf5b12d02 Replace tabs with spaces 2019-11-12 10:16:57 +03:00
Antony Polukhin
9c3bdd4d0e Update .travis.yml 2019-11-12 10:14:53 +03:00
Antony Polukhin
dc0f0c752b CI fixes 2019-11-12 09:51:14 +03:00
Antony Polukhin
09255fc94b Update .travis.yml 2019-11-11 19:21:10 +03:00
Antony Polukhin
293e1f43f6 Typo fix 2019-07-26 19:01:10 +03:00
Antony Polukhin
7379a5cc08 Fix msvc-9 build 2019-07-26 17:12:52 +03:00
Antony Polukhin
7c7271d9bc CI coverage fixes (5) 2019-06-30 15:26:11 +03:00
Antony Polukhin
6007c216b9 CI coverage fixes (4) 2019-06-30 13:16:12 +03:00
Antony Polukhin
d5bbf7853a CI coverage fixes (3) 2019-06-30 12:30:30 +03:00
Antony Polukhin
0be61ab0b8 CI coverage fix (2) 2019-06-30 10:14:44 +03:00
Antony Polukhin
43b837d181 Attempt to fix coverage 2019-06-29 20:43:33 +03:00
Antony Polukhin
2f75119cd0 Use lcov 1.14 2019-06-29 11:40:10 +03:00
Antony Polukhin
36734b1531 Trim null characters on Windows (fixes #78) 2019-06-29 10:44:27 +03:00
Antony Polukhin
2d810e294f Try to reproduce the error from #78 in tests 2019-06-28 22:38:49 +03:00
Antony Polukhin
6e79da7420 Fix frame info output with TSAN 2019-06-28 11:12:35 +03:00
Antony Polukhin
71acd94944 Fix empty frame info output with TSAN 2019-06-28 10:41:44 +03:00
Antony Polukhin
324a303fb0 Better diagnostics for test 2019-06-27 13:17:08 +03:00
Antony Polukhin
876349f0d6 Use gold linker for TSAN 2019-06-27 10:38:37 +03:00
Antony Polukhin
63d5d2730f Fix CI runs with thread sanitizer 2019-06-26 18:11:26 +03:00
Antony Polukhin
248eedd52f Fix ubsan library version 2019-06-26 14:50:20 +03:00
Antony Polukhin
c906a69c1d Test on GCC-8 because of tsan issues in GCC-6 2019-06-26 13:46:45 +03:00
Antony Polukhin
4f9da2ae71 Manually force rebuild for thread sanitizer tests 2019-06-26 13:12:34 +03:00
Antony Polukhin
1ad62e582a Add comment about async signal safety for PR #70 2019-01-12 22:37:31 +03:00
Antony Polukhin
5c6740b680 Merge branch 'develop' of github.com:boostorg/stacktrace into develop 2019-01-12 22:15:24 +03:00
Antony Polukhin
d9d6512743 Update copyright years 2019-01-12 22:15:16 +03:00
Antony Polukhin
158a59ae51 Merge pull request #70 from ivanarh/use_execinfo_backtrace
Added an option to use libc backtrace function from execinfo.h
2019-01-11 21:59:44 +03:00
Antony Polukhin
839a1a127d Update collect_unwind.ipp 2019-01-11 13:27:43 +03:00
Ivan Ponomarev
411d92cbf3 Forced backtrace() function usage on iOS, 32-bit ARM architecture. Used macros from Boost predef. 2019-01-09 23:07:37 +03:00
Ivan Ponomarev
1b7956a40d Added an ability to use libc backtrace() function (from execinfo.h) instead of _Unwind_Backtrace on Unix-like systems. Useful on iOS 32-bit ARM where _Unwind_Backtrace symbol is undefined. 2019-01-09 01:04:47 +03:00
Antony Polukhin
d708d17ecd Suppress warning (fixes #69) 2019-01-05 13:48:53 +03:00
Antony Polukhin
d946b124ba Fix typo noted by Telegram user PRoSToC0der 2018-12-13 11:00:33 +03:00
Antony Polukhin
39486260ae Merge pull request #67 from JanEisenhauer/develop
Collect at most as many frames as requested.
2018-10-30 10:49:47 +03:00
Jan Eisenhauer
cbd625bd91 fixup! Postprocessing to limit the trace to max_depth is no longer necessary. 2018-10-29 15:12:34 +01:00
Jan Eisenhauer
b08dab1c44 Postprocessing to limit the trace to max_depth is no longer necessary. 2018-10-29 14:34:16 +01:00
Jan Eisenhauer
77405d8d7f Collect at most as many frames as requested. 2018-10-29 14:30:59 +01:00
Jan Eisenhauer
324a24abba Evade the min macro from Windows headers. 2018-10-29 14:06:42 +01:00
Jan Eisenhauer
5e85e7414a Collect at most as many frames as requested. 2018-10-29 13:27:36 +01:00
Antony Polukhin
4123beb4af fix memory consumption when using libbacktrace and speedup trace decoding 2018-10-07 20:08:27 +03:00
Antony Polukhin
f0a9ba6809 Add long tests that detect leaks 2018-10-06 20:39:13 +03:00
Antony Polukhin
b414d35518 Add missing include 2018-10-05 11:10:17 +03:00
Antony Polukhin
42bf318144 Make the traces comparison test more reliable 2018-10-05 10:58:36 +03:00
Antony Polukhin
61c94e65e1 force the hidden visibility using new b2 feature 2018-09-22 22:05:30 +03:00
Antony Polukhin
d573d2a405 add tests for basic impl for cases when symbols are not exported 2018-09-19 23:12:47 +03:00
Antony Polukhin
9f232606cb make tests less verbose 2018-09-19 23:03:47 +03:00
Antony Polukhin
d6f0c65a83 fix typos and use BOOST_SYMBOL_VISIBLE 2018-09-17 09:56:24 +03:00
Antony Polukhin
3089b733a8 Win related issues in tests fixed 2018-09-17 00:12:46 +03:00
Antony Polukhin
99da94f5bd Rework the tests, deal with visibility issues, make sure that libbacktrace implementation now uses export tables 2018-09-16 23:23:33 +03:00
Antony Polukhin
3f047cbfc4 Fix damn web ui artifacts 2018-09-13 20:25:59 +03:00
Antony Polukhin
e14dd6560a Fixes for tests run with hidden visibility
Related to the changes in https://github.com/boostorg/boost/pull/190
2018-09-13 19:58:55 +03:00
Antony Polukhin
f328647e45 More docs improvemnts for the #62 2018-09-13 18:23:37 +03:00
Antony Polukhin
6d101ba4d6 Improve docs for #62 2018-09-13 18:19:56 +03:00
Antony Polukhin
c63afe54a2 Fix #61 2018-08-29 12:37:40 +03:00
Antony Polukhin
745c6aa7a0 Merge pull request #60 from driesdeschout/develop
Libbacktrace fallback to sym info when debug info is missing or incomplete
2018-08-20 10:18:19 +03:00
Dries Deschout
7a595a164f Fix style 2018-08-20 09:03:12 +02:00
Dries Deschout
b4b84780b1 Libbacktrace fallback to sym info in name_impl 2018-08-20 09:02:29 +02:00
Dries Deschout
1289134b6d Libbacktrace fallback to sym info when debug info is missing or incomplete 2018-08-13 14:58:21 +02:00
Antony Polukhin
819f2b1c86 bump copyright years 2018-08-07 22:41:22 +03:00
Antony Polukhin
fb47f17836 Allow to specify exact location of the backtrace.h header. Fixes #59 2018-08-07 22:29:00 +03:00
Antony Polukhin
b8dec8b126 Added to_string function for the boost::stacktrace::basic_stacktrace classes. Fixes #57 2018-07-28 17:12:03 +03:00
Antony Polukhin
7fedfa1265 Add info that the library is proposed for C++20 2018-06-11 18:55:06 +03:00
Antony Polukhin
4a5471a239 const_cast address to void* to avoid compile issues on platforms that have dladdr(void*, Dl_info*). Issue #54 2018-05-23 22:27:46 +03:00
Antony Polukhin
e4e2d4c3c1 Add missing include for tests 2018-04-15 14:19:01 +03:00
Antony Polukhin
14852ad597 Merge pull request #51 from boostorg/droping_dependencies
Drop dependency on lexical_cast and add more tests
2018-04-15 13:02:02 +03:00
Antony Polukhin
87b4789289 Drop dependency on lexical_cast and add more tests 2018-03-14 22:33:04 +03:00
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
Antony Polukhin
9f68fe4e9a Make test more tolerant to filesystem faults 2017-03-17 07:25:18 +03:00
Antony Polukhin
b6fad0f575 Make sure that frames with 0x0 addresses are not stored 2017-03-16 23:10:09 +03:00
Antony Polukhin
5552c97150 MinGW fixes. Docs updated to satisfy the prereview requests 2017-03-16 22:46:21 +03:00
Antony Polukhin
3f48887f2e Another attempt to remove MSVC specific extensions (4) 2017-03-04 05:13:40 +03:00
Antony Polukhin
cdf7ef74e7 Another attempt to remove MSVC specific extensions (3) 2017-03-04 04:17:51 +03:00
Antony Polukhin
affbfef4b6 Another attempt to remove MSVC specific extensions (2) 2017-03-04 03:56:15 +03:00
Antony Polukhin
e420e0a071 Another attempt to remove MSVC specific extensions 2017-03-04 03:21:31 +03:00
Antony Polukhin
34ff2dfc04 Experimenting with MinGW and stacktracing on Windows 2017-03-03 08:36:51 +03:00
Antony Polukhin
7f45997fb2 Restore __uuidof crappy extension usage for crappy COM technology 2017-03-03 05:40:29 +03:00
Antony Polukhin
abd8afb6ec Tuning frame_msvc in attempt to use less MSVC extensions 2017-03-03 04:52:08 +03:00
Antony Polukhin
876b68d81c Fix one more issue with MinGW tests (4) 2017-03-02 00:12:34 +03:00
Antony Polukhin
6ddf49e565 Fix one more issue with MinGW tests (3) 2017-03-02 00:00:27 +03:00
Antony Polukhin
53d6ce5987 Fix one more issue with MinGW tests (2) 2017-03-01 23:46:29 +03:00
Antony Polukhin
1c6fa29299 Fix one more issue with MinGW tests 2017-03-01 23:25:28 +03:00
Antony Polukhin
4191419560 Fixing MinGW (3) 2017-02-25 23:24:48 +03:00
Antony Polukhin
7b6a8e84f7 MinGW fixes (2). Do not include unused headers 2017-02-25 23:09:36 +03:00
Antony Polukhin
94f73fe616 MinGW fixes 2017-02-24 09:07:11 +03:00
Antony Polukhin
ca6fc8b312 Typo fix for MinGW 2017-02-24 08:31:17 +03:00
Antony Polukhin
b0e04ac94d Run MinGW tests too (thanks to Pavel Filinov for showing that appveyor ability) 2017-02-24 08:21:00 +03:00
Antony Polukhin
d92c405ec1 Another attempt to fix MinGW builds 2017-02-24 08:19:50 +03:00
Antony Polukhin
6a146fe7e3 Fix MinGW compilation 2017-02-20 23:13:47 +03:00
Antony Polukhin
672a1dcbe3 Minor fixes for the docs 2017-02-14 17:30:29 +03:00
Antony Polukhin
00a13698e0 Attempt to fix MSVC tests 2017-02-07 23:26:14 +03:00
Antony Polukhin
116dd872b8 Allow users to easily skip frames (API change), add more tests and update docs 2017-02-07 22:58:22 +03:00
Antony Polukhin
eb9fcf8050 Removed internals from stacktraces, added more tests on safe dumping 2017-02-07 22:55:19 +03:00
Antony Polukhin
a246a5c148 Minor addition to the docs 2017-02-06 23:33:03 +03:00
Antony Polukhin
675ab7d65d Fix addr2line detection 2017-02-06 23:11:58 +03:00
Antony Polukhin
441d38af76 Drop version info in dump 2017-02-06 22:55:27 +03:00
Antony Polukhin
9c08e254f1 Fix MinGW compilation 2017-02-04 22:52:28 +03:00
Antony Polukhin
b842cb2284 Quickfix 2017-02-04 22:34:51 +03:00
Antony Polukhin
8050e4ea8e Better from_dump implementation (2) 2017-02-04 22:05:41 +03:00
Antony Polukhin
ab6e88f1d0 Better from_dump implementation 2017-02-04 21:40:35 +03:00
Antony Polukhin
270786eb1e Added dump format version 2017-02-04 21:22:28 +03:00
Antony Polukhin
ca0a912125 Fix issue with reading from stream 2017-02-04 02:59:31 +03:00
Antony Polukhin
fd8c0d0bc3 More debug info for the example 2017-02-04 02:43:29 +03:00
Antony Polukhin
925a90472e Fixes for signal-hdling example 2017-02-03 23:11:39 +03:00
Antony Polukhin
a462364409 Use more functions from boost::detail::winapi rather than from global namespace 2017-01-28 12:51:48 +03:00
Antony Polukhin
224750cbef Added more examples on safe_dump_to (shared memory example) and changed interface of safe dumping into the memory 2017-01-27 21:56:27 +03:00
Antony Polukhin
9146cedb94 Attempt to fix test on WIN platform (3) 2017-01-27 00:02:00 +03:00
Antony Polukhin
34fdd6077e Attempt to fix test on WIN platform (2) 2017-01-26 23:49:53 +03:00
Antony Polukhin
0875781884 Attempt to fix test on WIN platform 2017-01-26 23:38:19 +03:00
Antony Polukhin
843c6e4291 Provide more info in case of failed test 2017-01-26 23:23:51 +03:00
Antony Polukhin
ea6e7fabe9 Improve docs and move safe dumping into a separate header file 2017-01-26 22:22:40 +03:00
Antony Polukhin
d26dc67be6 Implemented safe dumping and loading 2017-01-26 22:21:24 +03:00
Antony Polukhin
d535c5a0b1 Do not take into account boost::filesystem library coverage, when counting stacktrace library coverage 2017-01-20 22:11:26 +03:00
Antony Polukhin
e4c3542c96 Even more fixes 2017-01-19 23:02:08 +03:00
Antony Polukhin
fc0063de37 More fixes for the async-safe stack dumping 2017-01-19 22:41:45 +03:00
Antony Polukhin
bc5b4fad18 MSVC fixes 2017-01-19 22:15:22 +03:00
Antony Polukhin
13fe06063b Added initial version of safe dumping 2017-01-19 21:59:37 +03:00
Antony Polukhin
c9315559a3 Improved docs by describing macro and libraries 2017-01-15 22:43:31 +03:00
Antony Polukhin
c221f0c2dd Multiple minor fixes, improved docs, changed the example to use Boost.Exception 2017-01-13 22:36:25 +03:00
Antony Polukhin
1c5274f9fa Big refactoring: no more backends, only macro to enable additional functionality 2017-01-13 22:33:37 +03:00
Antony Polukhin
bd616a7249 Make a basic usecase the default one, add tests and create a target library for that 2017-01-13 22:31:03 +03:00
Antony Polukhin
3ec1c49c3b Separate code for addr2line, libbacktrace and basic 2017-01-13 22:28:53 +03:00
Antony Polukhin
c5843350f0 Move code around 2017-01-08 21:33:23 +03:00
Antony Polukhin
7a40dc90ae Qualify all the calls, do not mix std:: and :: function usage, detail::pc_data refactored to avoid copying 2017-01-08 20:50:53 +03:00
Antony Polukhin
85c31f691d Macro for enabling/disabling addr2line usage 2017-01-08 12:05:45 +03:00
Antony Polukhin
f37eea04fa Optimize ostream operator with libbackend 2017-01-08 00:14:05 +03:00
Antony Polukhin
b7bf4b5932 Use libbacktrace, added more tests 2017-01-08 00:00:17 +03:00
Antony Polukhin
a2431640b9 Move around code in test to make Coveralls happy and produce more reliable coverage results 2017-01-03 16:09:02 +03:00
Antony Polukhin
34306df187 Added more tests with long stacktraces 2017-01-03 14:42:31 +03:00
Antony Polukhin
3f543731fa Added tests with long stacktraces 2017-01-03 14:36:01 +03:00
Antony Polukhin
c45c8ff0e4 Optimized printing stacktraces on Win 2017-01-03 14:11:30 +03:00
Antony Polukhin
053b9f5606 Typo fix for Win 2017-01-03 13:41:26 +03:00
Antony Polukhin
6de0fe088b Micro optimizations and bugfixes for Win 2017-01-03 13:27:15 +03:00
Antony Polukhin
d6c1350952 Improve backtrace formatting and output more information into the backtrace when source file info is unawailable 2017-01-03 12:58:28 +03:00
Antony Polukhin
36061d4ef8 Move code around, prepare for optimizing the stack ostreaming operators 2017-01-03 11:59:55 +03:00
Antony Polukhin
7149a04002 Optimize frame printing 2017-01-03 00:06:20 +03:00
Antony Polukhin
898380d622 Relax one of the tests 2017-01-02 23:10:52 +03:00
Antony Polukhin
5a9ba3342d Set lines count to zero on second failed attempt to get line number 2017-01-02 22:47:35 +03:00
Antony Polukhin
8f06ce9b3d Preparations for optimized streaming of frames and stacktraces 2017-01-02 21:15:25 +03:00
Antony Polukhin
0b7fae6e48 Relax one of the tests: looks like ::backtrace() call sometimes outputs itself into the stacktrace 2016-12-26 22:47:11 +03:00
Antony Polukhin
60ac93f79f Fix [move]assignemnt operators 2016-12-26 22:20:08 +03:00
Antony Polukhin
16ef077fa4 Fix unsigned overflow in basic_stacktrace constructor, improve some tests, make sure that skipping 2 frames does not show internals to the user 2016-12-26 22:18:27 +03:00
Antony Polukhin
2893578446 detail::backend class does not own data any more 2016-12-26 22:15:53 +03:00
Antony Polukhin
99e4b53742 Started reimplementing stacktrace with Allocator 2016-12-26 22:12:29 +03:00
Antony Polukhin
ec7abcdf68 Fixed MacOS examples 2016-12-26 22:11:23 +03:00
Antony Polukhin
41ed839e49 Added thanks to Bjorn Reese 2016-12-17 14:09:40 +03:00
Antony Polukhin
9d1a2d652b Call CoUninitialize after all the COM methods were used 2016-12-17 11:41:55 +03:00
Antony Polukhin
b23664a769 Added info about develop branch to the README.md 2016-12-17 11:27:02 +03:00
Antony Polukhin
b282f55342 Fix issues found by Udo Steinbach 2016-12-17 11:25:08 +03:00
Antony Polukhin
dce55ef2ef Merge pull request #9 from JonKalb/master
Better Motivation docs
2016-12-17 12:21:21 +04:00
Jon Kalb
fb5927eef8 Better Motivation docs
Clean up the wording in the Motivation section.
2016-12-16 00:12:27 -08:00
69 changed files with 4341 additions and 1572 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

188
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,188 @@
name: CI
on:
pull_request:
push:
branches:
- master
- develop
- feature/**
env:
UBSAN_OPTIONS: print_stacktrace=1
jobs:
posix:
strategy:
fail-fast: false
matrix:
include:
- toolset: gcc-7
cxxstd: "03,11,14,17"
os: ubuntu-18.04
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
- toolset: gcc-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
linkflags: "linkflags=--coverage -lasan -lubsan"
launcher: "testing.launcher=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.6"
gcov_tool: "gcov-10"
- toolset: clang
compiler: clang++-3.7
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.7
- toolset: clang
compiler: clang++-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
cxxflags: "cxxflags=--coverage"
linkflags: "linkflags=--coverage"
gcov_tool: "llvm-cov-9 gcov"
- toolset: clang
compiler: clang++-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
# TODO: fix and uncomment
#- toolset: clang
# cxxstd: "03,11,14,17,2a"
# os: macos-10.15
# cxxflags: "cxxflags=-fsanitize=address,undefined -fno-sanitize-recover=undefined -D_GNU_SOURCE=1"
# linkflags: "linkflags=-fsanitize=address,undefined"
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 10 https://github.com/boostorg/boost.git boost-root
cd boost-root
git submodule update --init --depth 10 --jobs 2 tools/boostdep tools/inspect libs/filesystem
python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 3" filesystem
rm -rf libs/$LIBRARY/*
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
python tools/boostdep/depinst/depinst.py --include benchmark --include example --include examples --include tools --git_args "--depth 10 --jobs 3" $LIBRARY
./bootstrap.sh
./b2 -d0 headers
./b2 -j4 variant=debug tools/inspect/build
- name: Create user-config.jam
if: matrix.compiler
run: |
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
- name: Run tests
run: |
cd ../boost-root
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release "${{matrix.cxxflags}}" "${{matrix.linkflags}}" "${{matrix.launcher}}"
dist/bin/inspect libs/$LIBRARY
- name: Prepare coverage data
if: matrix.gcov_tool
run: |
mkdir -p $GITHUB_WORKSPACE/coveralls
echo -e "#!/bin/bash\nexec ${{matrix.gcov_tool}} \"\$@\"" > $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh
chmod +x $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh
wget https://github.com/linux-test-project/lcov/archive/v1.15.zip
unzip v1.15.zip
LCOV="`pwd`/lcov-1.15/bin/lcov --gcov-tool $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh"
echo "$LCOV --directory ../boost-root/bin.v2/libs/$LIBRARY/ --base-directory `pwd`/libs/$LIBRARY/test --capture --output-file $GITHUB_WORKSPACE/coveralls/coverage.info"
$LCOV --directory ../boost-root/bin.v2/libs/$LIBRARY/ --base-directory ../boost-root/ --capture --output-file $GITHUB_WORKSPACE/coveralls/coverage.info
$LCOV --remove $GITHUB_WORKSPACE/coveralls/coverage.info "/usr*" "*/$LIBRARY/test/*" ${{matrix.ignore_coverage}} "*/$LIBRARY/tests/*" "*/$LIBRARY/examples/*" "*/$LIBRARY/example/*" -o $GITHUB_WORKSPACE/coveralls/coverage.info
cd ../boost-root
OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$LIBRARY\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
echo $OTHER_LIBS
eval "$LCOV --remove $GITHUB_WORKSPACE/coveralls/coverage.info $OTHER_LIBS -o $GITHUB_WORKSPACE/coveralls/coverage.info"
- name: Coveralls
uses: coverallsapp/github-action@master
if: matrix.gcov_tool
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./coveralls/coverage.info
parallel: true
windows:
strategy:
fail-fast: false
matrix:
include:
- toolset: msvc-14.1
cxxstd: "14,17,latest"
addrmd: 64
os: windows-2016
- toolset: msvc-14.2
cxxstd: "14,17,latest"
addrmd: 64
os: windows-2019
#- toolset: gcc
# cxxstd: "03,11,14,17,2a"
# addrmd: 64
# os: windows-2019
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --include benchmark --include example --include examples --include tools --git_args "--jobs 3" %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
- name: Run tests
shell: cmd
run: |
cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release
finish:
needs: posix
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.github_token }}
parallel-finished: true

View File

@@ -2,119 +2,160 @@
# 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-2021.
#
# 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 #7
# File revision #10
sudo: false
language: cpp
compiler:
- gcc
# - clang
os: linux
os:
- linux
# `--coverage` flags required to generate coverage info for Coveralls
matrix:
include:
- env: B2_ARGS='cxxstd=98,03,11,14,1y toolset=gcc-6 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD -fno-rtti" linkflags="--coverage -lasan -lubsan" "testing.launcher=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.3"' GCOVTOOL='gcov-6'
name: "GCC-6, no RTTI"
addons:
apt:
sources: ubuntu-toolchain-r-test
packages: g++-6
env:
global:
# Autodetect Boost branch by using the following code: - BRANCH_TO_TEST=$TRAVIS_BRANCH
# or just directly specify it
#- BRANCH_TO_TEST=$TRAVIS_BRANCH
- BRANCH_TO_TEST=develop
- env: B2_ARGS='cxxstd=98,03,11,14,1z toolset=gcc-8 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -lasan -lubsan" "testing.launcher=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.5"' GCOVTOOL='gcov-8'
name: "GCC-8"
sudo: required # Required by leak sanitizer
addons:
apt:
sources: ubuntu-toolchain-r-test
packages: g++-8
# 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'
- env: B2_ARGS='cxxstd=98,0x toolset=gcc-4.6 cxxflags="--coverage -DBOOST_TRAVISCI_BUILD" linkflags="--coverage"' GCOVTOOL='gcov-4.6'
name: "GCC-4.6"
addons:
apt:
sources: ubuntu-toolchain-r-test
packages: g++-4.6
# 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`.
#
# By default is eaual to - BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
# This will force to use local repo content, instead of the Boost's default.
- BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
# - env: B2_ARGS='cxxstd=98,03,11,14,1y toolset=gcc-8 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD -fno-exceptions" linkflags="--coverage -lasan -lubsan"'
# name: "GCC-8, no exceptions"
# sudo: required # Required by leak sanitizer
# addons:
# apt:
# sources: ubuntu-toolchain-r-test
# packages: g++-8
matrix:
# Note that "--coverage -fsanitize=address,leak,undefined -DBOOST_TRAVISCI_BUILD" are added automatically lower in code
- 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 -stdlib=libc++" LINK_FLAGS="-stdlib=libc++" TOOLSET=clang
#- CXX_FLAGS="-std=c++1y -stdlib=libc++" LINK_FLAGS="-stdlib=libc++" TOOLSET=clang
# Not running UBSan because it gives an error for some tests:
# test_impl.cpp:14:16: runtime error: call to function (unknown) through pointer to incorrect function type 'std::pair<stacktrace, stacktrace> (*)(int)'
- env: B2_ARGS='cxxstd=98,03,11,14,1z toolset=clang-8 cxxflags="--coverage -fsanitize=address,leak -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -fsanitize=address,leak"' GCOVTOOL='gcov_for_clang.sh'
name: "Clang-8"
sudo: required # Required by leak sanitizer
addons:
apt:
sources: llvm-toolchain-trusty-8
packages: clang-8
# Sanitizers disabled for this toolset as they started causing link troubles:
# hidden symbol `_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE11__recommendEm' isn't defined
- env: B2_ARGS='cxxstd=03,11,14 toolset=clang-libc++ cxxflags="--coverage -DBOOST_TRAVISCI_BUILD" linkflags="--coverage"' GCOVTOOL='gcov_for_clang.sh'
name: "Clang-3.8, libc++"
addons:
apt:
packages: libc++-dev
###############################################################################################################
# From this point and below code is same for all the Boost libs
###############################################################################################################
# Installing additional tools
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- git-core
sources: git-core
packages:
- git
- python-yaml
- gcc-6
- g++-6
- clang
- libc++-dev
- binutils # for addr2line tests of Boost.Stacktrace
before_install:
# Set this to the name of the library
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
# Cloning Boost libraries (fast nondeep cloning)
- BOOST=$HOME/boost-local
- echo "Testing $PROJECT_TO_TEST, to remove $BOOST/libs/$BOOST_REMOVE, testing branch $BRANCH_TO_TEST"
- git init $BOOST
- cd $BOOST
- 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 --jobs=3 --init --merge
- git remote set-branches --add origin $BRANCH_TO_TEST
- git pull --recurse-submodules
- git status
- rm -rf $BOOST/libs/$BOOST_REMOVE
- mv $TRAVIS_BUILD_DIR $BOOST/libs/$PROJECT_TO_TEST
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
- ./bootstrap.sh
- ./b2 headers
- cd $BOOST/libs/$PROJECT_TO_TEST/test/
# Autodetect Boost branch by using the following code: - BOOST_BRANCH=$TRAVIS_BRANCH
# or just directly specify it
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
# Files, which coverage results must be ignored (files from other projects).
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
- IGNORE_COVERAGE='*/filesystem/src/* */thread/src/pthread/* */thread/src/future.cpp */timer/src/* operators.hpp'
# boost-local/libs/ folder to put this library into. This may be useful, if you're for example running Travis
# from `Boost.DLL` repo while Boost already has `dll` and with to replace `dll` with content of`Boost.DLL`.
#
# Otherwise just leave the default value - BOOST_LIBS_FOLDER=$(basename $TRAVIS_BUILD_DIR)
- BOOST_LIBS_FOLDER=$(basename $TRAVIS_BUILD_DIR)
# Global options for sanitizers
- UBSAN_OPTIONS=print_stacktrace=1
- LSAN_OPTIONS=verbosity=1:log_threads=1
# Cloning minimal set of Boost libraries
- BOOST=$HOME/boost-local
- git clone -b $BOOST_BRANCH --depth 10 https://github.com/boostorg/boost.git $BOOST
- cd $BOOST
- git submodule update --init --depth 10 --jobs 2 tools/build tools/boostdep tools/inspect libs/filesystem libs/interprocess # Boost.Interprocess is required for examples
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" $BOOST/libs/filesystem
# Replacing Boost module with this project and installing Boost dependencies
- echo "Testing $BOOST/libs/$BOOST_LIBS_FOLDER moved from $TRAVIS_BUILD_DIR, branch $BOOST_BRANCH"
- rm -rf $BOOST/libs/$BOOST_LIBS_FOLDER || true
- mv $TRAVIS_BUILD_DIR $BOOST/libs/$BOOST_LIBS_FOLDER
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" $BOOST_LIBS_FOLDER
- git status
# Adding missing toolsets and preparing Boost headers
- ./bootstrap.sh
- ./b2 headers
- ./b2 -j4 variant=debug tools/inspect/build
- |-
echo "using gcc ;" >> ~/user-config.jam
echo "using clang ;" >> ~/user-config.jam
echo "using clang : 3.8 : clang++-3.8 ;" >> ~/user-config.jam
echo "using clang : 4 : clang++-4.0 ;" >> ~/user-config.jam
echo "using clang : 5 : clang++-5.0 ;" >> ~/user-config.jam
echo "using clang : 6 : clang++-6.0 ;" >> ~/user-config.jam
echo "using clang : 7 : clang++-7.0 ;" >> ~/user-config.jam
echo "using clang : 8 : clang++-8 ;" >> ~/user-config.jam
echo "using clang : libc++ : clang++-libc++ ;" >> ~/user-config.jam
- cd $BOOST/libs/$BOOST_LIBS_FOLDER/test/
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"
- sh -c "../../../b2 -j2 $B2_ARGS"
- ../../../dist/bin/inspect ..
after_success:
# Copying Coveralls data to a separate folder
- mkdir -p $TRAVIS_BUILD_DIR/coverals
- find ../../../bin.v2/ -name "*.gcda" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- find ../../../bin.v2/ -name "*.gcno" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- find ../../../bin.v2/ -name "*.da" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- find ../../../bin.v2/ -name "*.no" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- wget https://github.com/linux-test-project/lcov/archive/v1.12.zip
- unzip v1.12.zip
- LCOV="`pwd`/lcov-1.12/bin/lcov --gcov-tool gcov-6"
- exit 0 # We run coverage repoprts from GithubActions
# Preparing Coveralls data by changind data format to a readable one
- echo "$LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info"
- $LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
# Copying Coveralls data to a separate folder
- mkdir -p $TRAVIS_BUILD_DIR/coverals
- wget https://github.com/linux-test-project/lcov/archive/v1.15.zip
- unzip v1.15.zip
- LCOV="`pwd`/lcov-1.15/bin/lcov --gcov-tool $GCOVTOOL"
- mkdir -p ~/.local/bin
- echo -e '#!/bin/bash\nexec llvm-cov gcov "$@"' > ~/.local/bin/gcov_for_clang.sh
- chmod 755 ~/.local/bin/gcov_for_clang.sh
# ... erasing /test/ /example/ folder data
- cd $BOOST
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "/usr*" "*/$PROJECT_TO_TEST/test/*" $IGNORE_COVERAGE "*/$PROJECT_TO_TEST/tests/*" "*/$PROJECT_TO_TEST/examples/*" "*/$PROJECT_TO_TEST/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
# Preparing Coveralls data by changind data format to a readable one
- echo "$LCOV --directory $BOOST/bin.v2/libs/$BOOST_LIBS_FOLDER --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info"
- $LCOV --directory $BOOST/bin.v2/libs/$BOOST_LIBS_FOLDER --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
# ... erasing data that is not related to this project directly
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$PROJECT_TO_TEST\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
- echo $OTHER_LIBS
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info"
# ... erasing /test/ /example/ folder data
- cd $BOOST
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "/usr*" "*/$BOOST_LIBS_FOLDER/test/*" $IGNORE_COVERAGE "*/$BOOST_LIBS_FOLDER/tests/*" "*/$BOOST_LIBS_FOLDER/examples/*" "*/$BOOST_LIBS_FOLDER/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
# Sending data to Coveralls
- cd $TRAVIS_BUILD_DIR
- gem install coveralls-lcov
- coveralls-lcov coverals/coverage.info
# ... erasing data that is not related to this project directly
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*" "\*\/libs\/\1\/src\/\*"/g'| sed "/\"\*\/boost\/$BOOST_LIBS_FOLDER\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
- echo $OTHER_LIBS
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info"
# Sending data to Coveralls
- cd $TRAVIS_BUILD_DIR
- gem install coveralls-lcov
- coveralls-lcov coverals/coverage.info

106
CMakeLists.txt Normal file
View File

@@ -0,0 +1,106 @@
# Copyright 2020, 2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.16)
project(boost_stacktrace VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
function(stacktrace_add_library suffix opt libs defs)
if(NOT opt)
return()
endif()
add_library(boost_stacktrace_${suffix}
src/${suffix}.cpp
)
add_library(Boost::stacktrace_${suffix} ALIAS boost_stacktrace_${suffix})
target_include_directories(boost_stacktrace_${suffix} PUBLIC include)
target_link_libraries(boost_stacktrace_${suffix}
PUBLIC
Boost::array
Boost::config
Boost::container_hash
Boost::core
Boost::predef
Boost::static_assert
Boost::type_traits
Boost::winapi
PRIVATE
${libs}
)
target_compile_definitions(boost_stacktrace_${suffix}
PUBLIC BOOST_STACKTRACE_NO_LIB
PRIVATE BOOST_STACKTRACE_SOURCE ${defs}
)
if(BUILD_SHARED_LIBS)
target_compile_definitions(boost_stacktrace_${suffix} PUBLIC BOOST_STACKTRACE_DYN_LINK)
else()
target_compile_definitions(boost_stacktrace_${suffix} PUBLIC BOOST_STACKTRACE_STATIC_LINK)
endif()
if(BOOST_SUPERPROJECT_VERSION AND NOT CMAKE_VERSION VERSION_LESS 3.13)
boost_install(TARGETS boost_stacktrace_${suffix} VERSION ${BOOST_SUPERPROJECT_VERSION} HEADER_DIRECTORY include)
endif()
endfunction()
include(CheckCXXSourceCompiles)
function(stacktrace_check var source incs libs defs)
set(CMAKE_REQUIRED_INCLUDES "${incs}")
list(APPEND CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/build")
set(CMAKE_REQUIRED_LIBRARIES "${libs}")
set(CMAKE_REQUIRED_DEFINITIONS "${defs}")
check_cxx_source_compiles("#include \"${source}\"" ${var})
set(${var} ${${var}} PARENT_SCOPE)
endfunction()
stacktrace_check(BOOST_STACKTRACE_HAS_BACKTRACE has_backtrace.cpp "" "backtrace" "")
set(_default_addr2line ON)
if(WIN32 AND NOT CMAKE_CXX_PLATFORM_ID MATCHES "Cygwin")
set(_default_addr2line OFF)
endif()
stacktrace_check(BOOST_STACKTRACE_HAS_WINDBG has_windbg.cpp "" "dbgeng;ole32" "")
stacktrace_check(BOOST_STACKTRACE_HAS_WINDBG_CACHED has_windbg_cached.cpp "${CMAKE_CURRENT_SOURCE_DIR}/../config/include" "dbgeng;ole32" "")
option(BOOST_STACKTRACE_ENABLE_NOOP "Boost.Stacktrace: build boost_stacktrace_noop" ON)
option(BOOST_STACKTRACE_ENABLE_BACKTRACE "Boost.Stacktrace: build boost_stacktrace_backtrace" ${BOOST_STACKTRACE_HAS_BACKTRACE})
option(BOOST_STACKTRACE_ENABLE_ADDR2LINE "Boost.Stacktrace: build boost_stacktrace_addr2line" ${_default_addr2line})
option(BOOST_STACKTRACE_ENABLE_BASIC "Boost.Stacktrace: build boost_stacktrace_basic" ON)
option(BOOST_STACKTRACE_ENABLE_WINDBG "Boost.Stacktrace: build boost_stacktrace_windbg" ${BOOST_STACKTRACE_HAS_WINDBG})
option(BOOST_STACKTRACE_ENABLE_WINDBG_CACHED "Boost.Stacktrace: build boost_stacktrace_windbg_cached" ${BOOST_STACKTRACE_HAS_WINDBG_CACHED})
unset(_default_addr2line)
message(STATUS "Boost.Stacktrace: "
"noop ${BOOST_STACKTRACE_ENABLE_NOOP}, "
"backtrace ${BOOST_STACKTRACE_ENABLE_BACKTRACE}, "
"addr2line ${BOOST_STACKTRACE_ENABLE_ADDR2LINE}, "
"basic ${BOOST_STACKTRACE_ENABLE_BASIC}, "
"windbg ${BOOST_STACKTRACE_ENABLE_WINDBG}, "
"windbg_cached ${BOOST_STACKTRACE_ENABLE_WINDBG_CACHED}"
)
stacktrace_add_library(noop ${BOOST_STACKTRACE_ENABLE_NOOP} "" "")
stacktrace_add_library(backtrace ${BOOST_STACKTRACE_ENABLE_BACKTRACE} "backtrace" "")
stacktrace_add_library(addr2line ${BOOST_STACKTRACE_ENABLE_ADDR2LINE} "" "")
stacktrace_add_library(basic ${BOOST_STACKTRACE_ENABLE_BASIC} "" "")
stacktrace_add_library(windbg ${BOOST_STACKTRACE_ENABLE_WINDBG} "dbgeng;ole32" "_GNU_SOURCE=1")
stacktrace_add_library(windbg_cached ${BOOST_STACKTRACE_ENABLE_WINDBG_CACHED} "dbgeng;ole32" "_GNU_SOURCE=1")
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()

View File

@@ -1,18 +1,17 @@
### Stacktrace
# [Boost.Stacktrace](https://boost.org/libs/stacktrace)
Library for storing and printing backtraces.
[Documentation and examples.](http://apolukhin.github.io/stacktrace/index.html)
Boost.Stacktrace is a part of the [Boost C++ Libraries](https://github.com/boostorg).
### Test results
@ | Build | Tests coverage | More info
----------------|-------------- | -------------- |-----------
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: | [![CI](https://github.com/boostorg/stacktrace/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/stacktrace/actions/workflows/ci.yml) [![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...](https://www.boost.org/development/tests/develop/developer/stacktrace.html)
Master branch: | [![CI](https://github.com/boostorg/stacktrace/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/stacktrace/actions/workflows/ci.yml) [![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...](https://www.boost.org/development/tests/master/developer/stacktrace.html)
[Latest developer documentation](https://www.boost.org/doc/libs/develop/doc/html/stacktrace.html)
### License
Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
Distributed under the [Boost Software License, Version 1.0](https://boost.org/LICENSE_1_0.txt).

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2016, Antony Polukhin.
# Copyright (C) 2016-2019, 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
@@ -8,12 +8,22 @@
project
: source-location .
: requirements
<target-os>linux:<cxxflags>"-fvisibility=hidden"
<visibility>hidden
;
lib dl : : <link>shared ;
lib gcc_s : : <link>shared ;
lib Dbghelp ;
lib dl ;
lib gcc_s ;
lib Dbgeng ;
lib ole32 ;
local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ;
lib backtrace
:
: <search>$(LIBBACKTRACE_PATH)/lib <link>static
:
: <include>$(LIBBACKTRACE_PATH)/include
;
actions mp_simple_run_action
{
@@ -29,15 +39,20 @@ rule mp-run-simple ( sources + : args * : input-files * : requirements * : targe
alias $(target-name) : $(target-name).output ;
}
mp-run-simple has_backtrace.cpp : : : : backtrace ;
explicit backtrace ;
mp-run-simple has_backtrace.cpp : : : <library>backtrace : libbacktrace ;
explicit libbacktrace ;
mp-run-simple has_unwind.cpp : : : : unwind ;
explicit unwind ;
mp-run-simple has_addr2line.cpp : : : : addr2line ;
explicit addr2line ;
mp-run-simple has_windbg.cpp : : : : WinDbg ;
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
@@ -49,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
@@ -57,36 +72,52 @@ lib boost_stacktrace_backtrace
: # requirements
<warnings>all
<target-os>linux:<library>dl
<library>backtrace
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
[ check-target-builds ../build//backtrace : : <build>no ]
[ check-target-builds ../build//libbacktrace : : <build>no ]
: # default build
: # usage-requirements
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_backtrace ;
libraries += boost_stacktrace_backtrace ;
lib boost_stacktrace_unwind
lib boost_stacktrace_addr2line
: # sources
../src/unwind.cpp
../src/addr2line.cpp
: # requirements
<warnings>all
<target-os>linux:<library>dl
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
[ check-target-builds ../build//unwind : : <build>no ]
[ check-target-builds ../build//addr2line : : <build>no ]
: # default build
: # usage-requirements
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_unwind ;
libraries += boost_stacktrace_addr2line ;
lib boost_stacktrace_basic
: # sources
../src/basic.cpp
: # requirements
<warnings>all
<target-os>linux:<library>dl
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
[ check-target-builds ../build//WinDbg : <build>no ]
: # default build
: # usage-requirements
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
libraries += boost_stacktrace_basic ;
lib boost_stacktrace_windbg
: # sources
../src/windbg.cpp
: # requirements
<warnings>all
<library>Dbghelp
<library>Dbgeng <library>ole32
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
[ check-target-builds ../build//WinDbg : : <build>no ]
: # default build
@@ -94,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) ;

25
build/has_addr2line.cpp Normal file
View File

@@ -0,0 +1,25 @@
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstdlib>
#include <string>
#include <boost/config.hpp>
#include <unwind.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
#ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION
std::string s = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION );
s += " -h";
#else
std::string s = "/usr/bin/addr2line -h";
#endif
return std::system(s.c_str());
}

View File

@@ -1,14 +1,15 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2020.
//
// 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 <dlfcn.h>
#include <execinfo.h>
#include <backtrace.h>
#include <unwind.h>
int main() {
void* buffer[10];
::backtrace(buffer, 10);
backtrace_state* state = backtrace_create_state(
0, 1, 0, 0
);
(void)state;
}

View File

@@ -1,16 +1,13 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstring>
#include <windows.h>
#include "Dbgeng.h"
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "Dbgeng.lib")
#include "dbgeng.h"
int main() {
CoInitializeEx(0, COINIT_MULTITHREADED);
::CoInitializeEx(0, COINIT_MULTITHREADED);
}

View File

@@ -0,0 +1,28 @@
// Copyright Antony Polukhin, 2016-2020.
//
// 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

@@ -1,4 +1,4 @@
# Copyright Antony Polukhin 2016.
# Copyright Antony Polukhin 2016-2021.
# Use, modification, and distribution are
# subject to the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -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,12 +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_STACKTRACE_FUNCTION\" \\
\"BOOST_FORCEINLINE=inline\" \\
\"BOOST_STACKTRACE_FUNCTION=inline\" \\
\"BOOST_CONSTEXPR=constexpr\" \\
\"BOOST_STACKTRACE_DOXYGEN_INVOKED\""
<xsl:param>"boost.doxygen.reftitle=Boost.Stacktrace Header Reference"
<xsl:param>"boost.doxygen.reftitle=Reference"
<xsl:param>"boost.doxygen.refid=stacktrace.reference"
;
xml stacktrace : stacktrace.qbk : <dependency>autodoc ;
@@ -31,7 +39,7 @@ boostbook standalone
:
stacktrace
:
<xsl:param>boost.root=http://www.boost.org/doc/libs/1_61_0
<xsl:param>boost.root=http://www.boost.org/doc/libs/1_63_0
# <xsl:param>boost.root=../../../..
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
;
@@ -40,7 +48,7 @@ boostbook standalone
alias boostdoc
: stacktrace
:
: <dependency>autodoc
:
: ;
explicit boostdoc ;

View File

@@ -1,7 +1,8 @@
[library Boost.Stacktrace
[quickbook 1.6]
[version 1.0]
[copyright 2016 Antony Polukhin]
[id stacktrace]
[copyright 2016-2021 Antony Polukhin]
[category Language Features Emulation]
[license
Distributed under the Boost Software License, Version 1.0.
@@ -11,11 +12,9 @@
]
[section Motivation]
How to display the call sequence in C++? From what function was called the current function? What call sequence led to an exception?
How can one display the call sequence in C++? What function called the current function? What call sequence led to an exception?
Boost.Stacktrace library is a simple library that provides information about call sequence in a human-readable form.
[warning This is not an official Boost library! It wasn't reviewed and can't be downloaded from www.boost.org. This library is available to the community to know real interest and get comments for refinement. The intention is to submit library for formal review, if community thinks that it is interesting!]
Boost.Stacktrace library is a simple C++03 library that provides information about call sequence in a human-readable form.
[endsect]
@@ -34,7 +33,7 @@ Boost.Stacktrace library is a simple library that provides information about cal
```
#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();
```
@@ -51,62 +50,12 @@ Code from above will output something like this:
2# bar(int) at /path/to/source/file.cpp:70
3# bar(int) at /path/to/source/file.cpp:70
4# main at /path/to/main.cpp:93
5# __libc_start_main
5# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
6# _start
```
[endsect]
[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. ]
[section Handle terminates, aborts and Segmentation Faults]
Segmentation Faults and `std::terminate` calls sometimes happen in programs. Programmers usually wish to get as much information as possible on such incidents, so having a stacktrace will significantly improve debugging and fixing.
To deal with Segmentation Faults and `std::terminate` calls we would need to write handlers:
[getting_started_terminate_handlers]
After that we can set them as a default handlers and get some more information on incidents:
[getting_started_setup_handlers]
Now we'll get the following output on `std::terminate` call:
```
Terminate called:
0# boost::stacktrace::detail::backend::backend(void**, unsigned long)
1# my_terminate_handler() at boost/libs/stacktrace/example/terminate_handler.cpp:37
2# 0x7f624107a6b6
3# 0x7f624107a701
4# bar(int) at boost/libs/stacktrace/example/terminate_handler.cpp:18
5# foo(int) at boost/libs/stacktrace/example/terminate_handler.cpp:22
6# bar(int) at boost/libs/stacktrace/example/terminate_handler.cpp:18
7# foo(int) at boost/libs/stacktrace/example/terminate_handler.cpp:22
8# main at boost/libs/stacktrace/example/terminate_handler.cpp:64
9# __libc_start_main
10# _start
```
And the following output on Abort:
```
Signal 6, backtrace:
0# boost::stacktrace::detail::backend::backend(void**, unsigned long)
1# my_signal_handler(int)
2# 0x7f6240a3a4b0
3# gsignal
4# abort
5# my_terminate_handler()
6# 0x7f624107a6b6
7# 0x7f624107a701
8# bar(int) at boost/libs/stacktrace/example/terminate_handler.cpp:18
9# foo(int) at boost/libs/stacktrace/example/terminate_handler.cpp:22
10# bar(int) at boost/libs/stacktrace/example/terminate_handler.cpp:18
11# foo(int) at boost/libs/stacktrace/example/terminate_handler.cpp:22
12# main at boost/libs/stacktrace/example/terminate_handler.cpp:64
13# __libc_start_main
14# _start
```
The output stacktrace may be corrupted by previous actions. But now at least some basic information is available to work with.
[endsect]
@@ -128,40 +77,77 @@ We've defined the `BOOST_ENABLE_ASSERT_DEBUG_HANDLER` macro for the whole projec
```
Expression 'i < N' is false in function 'T& boost::array<T, N>::operator[](boost::array<T, N>::size_type) [with T = int; long unsigned int N = 5ul; boost::array<T, N>::reference = int&; boost::array<T, N>::size_type = long unsigned int]': out of range.
Backtrace:
0# boost::stacktrace::detail::backend::backend(void**, unsigned long)
1# boost::assertion_failed_msg(char const*, char const*, char const*, char const*, long) at boost/libs/stacktrace/example/assert_handler.cpp:38
2# boost::array<int, 5ul>::operator[](unsigned long)
3# bar(int) at boost/libs/stacktrace/example/assert_handler.cpp:16
4# foo(int) at boost/libs/stacktrace/example/assert_handler.cpp:24
5# bar(int) at boost/libs/stacktrace/example/assert_handler.cpp:20
6# foo(int) at boost/libs/stacktrace/example/assert_handler.cpp:24
7# main at boost/libs/stacktrace/example/assert_handler.cpp:53
8# __libc_start_main
9# _start
0# boost::assertion_failed_msg(char const*, char const*, char const*, char const*, long) at ../example/assert_handler.cpp:39
1# boost::array<int, 5ul>::operator[](unsigned long) at ../../../boost/array.hpp:124
2# bar(int) at ../example/assert_handler.cpp:17
3# foo(int) at ../example/assert_handler.cpp:25
4# bar(int) at ../example/assert_handler.cpp:17
5# foo(int) at ../example/assert_handler.cpp:25
6# main at ../example/assert_handler.cpp:54
7# 0x00007F991FD69F45 in /lib/x86_64-linux-gnu/libc.so.6
8# 0x0000000000401139
```
Now we do know the steps that led to the assertion and can find the error without debugger.
[endsect]
[section Handle terminates]
`std::terminate` calls sometimes happen in programs. Programmers usually wish to get as much information as possible on such incidents, so having a stacktrace significantly improves debugging and fixing.
Here's how to write a terminate handler that dumps stacktrace:
[getting_started_terminate_handlers]
Here's how to register it:
[getting_started_setup_terminate_handlers]
Now we'll get the following output on `std::terminate` call:
```
Previous run crashed:
0# my_terminate_handler(int) at ../example/terminate_handler.cpp:37
1# __cxxabiv1::__terminate(void (*)()) at ../../../../src/libstdc++-v3/libsupc++/eh_terminate.cc:48
2# 0x00007F3CE65E5901 in /usr/lib/x86_64-linux-gnu/libstdc++.so.6
3# bar(int) at ../example/terminate_handler.cpp:18
4# foo(int) at ../example/terminate_handler.cpp:22
5# bar(int) at ../example/terminate_handler.cpp:14
6# foo(int) at ../example/terminate_handler.cpp:22
7# main at ../example/terminate_handler.cpp:84
8# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
9# 0x0000000000402209
```
[warning There's a temptation to write a signal handler that prints the stacktrace on `SIGSEGV` or abort. Unfortunately, there's no cross platform way to do that without a risk of deadlocking. Not all the platforms provide means for even getting stacktrace in async signal safe way.
Signal handler is often invoked on a separate stack and trash is returned on attempt to get a trace!
Generic recommendation is to *avoid signal handlers! Use* platform specific ways to store and decode *core files*.
]
[endsect]
[section Exceptions with stacktrace]
You can provide more information along with exception by embedding stacktraces into the exception. For that you will need to:
You can provide more information along with exception by embedding stacktraces into the exception. There are many ways to do that, here's how to do that using Boost.Exception:
* Write a basic class that holds the stacktrace:
* Declare a `boost::error_info` typedef that holds the stacktrace:
[getting_started_class_traced]
* Write a helper class for appending class `traced` to any exception:
* Write a helper class for throwing any exception with stacktrace:
[getting_started_class_with_trace]
* Throw `with_trace<Exception>` instead of just `Exception`:
* Use `throw_with_trace(E);` instead of just `throw E;`:
[getting_started_throwing_with_trace]
* Catch exceptions by `traced`:
* Process exceptions:
[getting_started_catching_trace]
@@ -169,32 +155,30 @@ Code from above will output:
```
'i' must not be greater than zero in oops()
Backtrace:
0# boost::stacktrace::detail::backend::backend(void**, unsigned long)
1# traced::traced() at boost/libs/stacktrace/example/throwing_st.cpp:20
2# with_trace<std::logic_error>::with_trace<char const (&) [44]>(char const (&) [44]) at boost/libs/stacktrace/example/throwing_st.cpp:33
3# oops(int)
4# bar(int) at boost/libs/stacktrace/example/throwing_st.cpp:70
5# foo(int) at boost/libs/stacktrace/example/throwing_st.cpp:75
6# bar(int) at boost/libs/stacktrace/example/throwing_st.cpp:65
7# foo(int) at boost/libs/stacktrace/example/throwing_st.cpp:75
8# main at boost/libs/stacktrace/example/throwing_st.cpp:93
9# __libc_start_main
10# _start
0# void throw_with_trace<std::logic_error>(std::logic_error const&) at ../example/throwing_st.cpp:22
1# oops(int) at ../example/throwing_st.cpp:38
2# bar(int) at ../example/throwing_st.cpp:54
3# foo(int) at ../example/throwing_st.cpp:59
4# bar(int) at ../example/throwing_st.cpp:49
5# foo(int) at ../example/throwing_st.cpp:59
6# main at ../example/throwing_st.cpp:76
7# 0x00007FAC113BEF45 in /lib/x86_64-linux-gnu/libc.so.6
8# 0x0000000000402ED9
```
[endsect]
[section Enabling and disabling stacktraces]
At some point arises a requirement to easily enable/disable stacktraces for a whole project. That could be easily 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 backends:
Just define *BOOST_STACKTRACE_LINK* for a whole project. Now you can enable/disable stacktraces by just linking with different libraries:
* link with `boost_stacktrace_noop` to disable backtracing
* link with other backends to output backtraces
* link with other `boost_stacktrace_*` libraries
See [link boost_stacktrace.build_macros_and_backends section "Build, Macros and Backends"] for more info.
See [link stacktrace.configuration_and_build section "Configuration and Build"] for more info.
[endsect]
@@ -229,7 +213,7 @@ my_signal_handler(int) at boost/libs/stacktrace/example/debug_function.cpp:21
[section Global control over stacktrace output format]
You may control maximal stacktrace length using [macroref BOOST_STACKTRACE_DEFAULT_MAX_DEPTH] and even override the behavior of default stacktrace output operator by defining the macro from Boost.Config [macroref BOOST_USER_CONFIG] to point to a file like following:
You may override the behavior of default stacktrace output operator by defining the macro from Boost.Config [macroref BOOST_USER_CONFIG] to point to a file like following:
[getting_started_user_config]
@@ -241,45 +225,112 @@ Code from above will output:
```
Terminate called:
0# boost::stacktrace::detail::backend::backend(void**, unsigned long)
1# bar(int)
2# foo(int)
3# bar(int)
4# foo(int)
0# bar(int)
1# foo(int)
2# bar(int)
3# foo(int)
```
[endsect]
[/
[section Store stacktraces into shared memory]
There's a way to serialize stacktrace in async safe manner and share that serialized representation with another process. Here's another example with signal handlers.
This example is very close to the [link stacktrace.getting_started.handle_terminates_aborts_and_seg "Handle terminates, aborts and Segmentation Faults"], but this time we are dumping stacktrace into shared memory:
[getting_started_terminate_handlers_shmem]
After registering signal handlers and catching a signal, we may print stacktrace dumps on program restart:
[getting_started_on_program_restart_shmem]
The program output will be the following:
```
Previous run crashed and left trace in shared memory:
0# 0x00007FD51C7218EF
1# my_signal_handler2(int) at ../example/terminate_handler.cpp:68
2# 0x00007FD51B833CB0
3# 0x00007FD51B833C37
4# 0x00007FD51B837028
5# 0x00007FD51BE44BBD
6# 0x00007FD51BE42B96
7# 0x00007FD51BE42BE1
8# bar(int) at ../example/terminate_handler.cpp:18
9# foo(int) at ../example/terminate_handler.cpp:22
10# bar(int) at ../example/terminate_handler.cpp:14
11# foo(int) at ../example/terminate_handler.cpp:22
12# run_3(char const**) at ../example/terminate_handler.cpp:152
13# main at ../example/terminate_handler.cpp:207
14# 0x00007FD51B81EF45
15# 0x0000000000402999
```
[endsect]
]
[endsect]
[section Build, Macros and Backends]
[section Configuration and Build]
By default Boost.Stacktrace is a header-only library and it attempts to detect the tracing backend automatically.
You can define the following macros to explicitly specify backend that you're willing to use in header-only mode (those macros have no effect if defined *BOOST_STACKTRACE_LINK* or *BOOST_STACKTRACE_DYN_LINK*):
[table:configbackend Header only backend specifications
[[Macro name] [Effect] [Platforms] [Uses debug information [footnote This will provide more readable backtraces 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.]] [Async signal safe[footnote Absolutely safe to construct instances of [classref boost::stacktrace::stacktrace] in async signal handlers using that backend.]]]
[[*BOOST_STACKTRACE_USE_UNWIND*] [Use unwind tracing backend. This is the best known backend for POSIX systems that requires LSB Core Specification 4.1 from OS. Requires linking with libdl library.] [POSIX] [yes] [yes] [yes]]
[[*BOOST_STACKTRACE_USE_WINDBG*] [Use Windows specific tracing backend that uses DbgHelp. This is the best and only known backend for Windows platform that requires linking with DbgHelp library.] [Windows] [yes] [yes] [???]]
[[*BOOST_STACKTRACE_USE_BACKTRACE*] [Use tracing backend that calls POSIX function `backtrace`. Requires linking with libdl library.] [POSIX] [no] [yes] [no]]
[[*BOOST_STACKTRACE_USE_NOOP*] [Use noop tracing backend that does nothing. Use this backend if you wish to disable backtracing, `stacktrace::size()` with that backend always return 0. ] [POSIX and Windows] [no] [no] [yes]]
]
You may use the following macros to improve build times or to be able to switch backends without recompiling your project:
By default Boost.Stacktrace is a header-only library, but you may change that and use the following macros to improve build times or to be able to tune library without recompiling your project:
[table:linkmacro Link macros
[[Macro name] [Effect]]
[[*BOOST_STACKTRACE_LINK*] [Disable header-only build and require linking with shared or static library that contains the tracing backend. If *BOOST_ALL_DYN_LINK* is defined, then link with shared library.]]
[[*BOOST_STACKTRACE_DYN_LINK*] [Disable header-only build and require linking with shared library that contains tracing backend.]]
[[*BOOST_STACKTRACE_LINK*] [Disable header-only build and require linking with shared or static library that contains the tracing implementation. If *BOOST_ALL_DYN_LINK* is defined, then link with shared library.]]
[[*BOOST_STACKTRACE_DYN_LINK*] [Disable header-only build and require linking with shared library that contains tracing implementation.]]
]
If one of the link macros is defined, you have to manually link your binary with one of the libraries that has the backend implementation:
* boost_stacktrace_unwind
* boost_stacktrace_windbg
* boost_stacktrace_backtrace
* boost_stacktrace_noop
In header only mode library could be tuned by macro. If one of the link macro from above is defined, you have to manually link with one of the libraries:
[table:libconfig Config
[[Macro name or default] [Library] [Effect] [Platforms] [Uses debug information [footnote This will provide more readable backtraces with *source code locations* if the binary is built with debug information.]] [Uses dynamic exports information [footnote This will provide readable function names in backtrace for functions that are exported by the binary. Compiling with `-rdynamic` flag, without `-fisibility=hidden` or marking functions as exported produce a better stacktraces.]] ]
[[['default for MSVC, Intel on Windows, MinGW-w64] / *BOOST_STACKTRACE_USE_WINDBG*] [*boost_stacktrace_windbg*] [ Uses COM to show debug info. May require linking with *ole32* and *dbgeng*. ] [MSVC, MinGW-w64, Intel on Windows] [yes] [no]]
[[['default for other platforms]] [*boost_stacktrace_basic*] [Uses compiler intrinsics to collect stacktrace and if possible `::dladdr` to show information about the symbol. Requires linking with *libdl* library on POSIX platforms.] [Any compiler on POSIX or MinGW] [no] [yes]]
[[*BOOST_STACKTRACE_USE_WINDBG_CACHED*] [*boost_stacktrace_windbg_cached*] [ Uses COM to show debug info and caches COM instances in TLS for better performance. Useful only for cases when traces are gathered very often. [footnote This may affect other components of your program that use COM, because this mode calls the `CoInitializeEx(0, COINIT_MULTITHREADED)` on first use and does not call `::CoUninitialize();` until the current thread is destroyed. ] May require linking with *ole32* and *dbgeng*. ] [MSVC, Intel on Windows] [yes] [no]]
[[*BOOST_STACKTRACE_USE_BACKTRACE*] [*boost_stacktrace_backtrace*] [Requires linking with *libdl* on POSIX and *libbacktrace* libraries. *libbacktrace* is probably already installed in your system[footnote If you are using Clang with libstdc++ you could get into troubles of including `<backtrace.h>`, because on some platforms Clang does not search for headers in the GCC's include paths and any attempt to add GCC's include path leads to linker errors. To explicitly specify a path to the `<backtrace.h>` header you could define the *BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE* to a full path to the header. For example on Ubuntu Xenial use the command line option *-DBOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE=</usr/lib/gcc/x86_64-linux-gnu/5/include/backtrace.h>* while building with Clang. ], or built into your compiler.
Otherwise (if you are a *MinGW*/*MinGW-w64* user for example) it can be downloaded [@https://github.com/ianlancetaylor/libbacktrace from here] or [@https://github.com/gcc-mirror/gcc/tree/master/libbacktrace from here]. ] [Any compiler on POSIX, or MinGW, or MinGW-w64] [yes] [yes]]
[[*BOOST_STACKTRACE_USE_ADDR2LINE*] [*boost_stacktrace_addr2line*] [Use *addr2line* program to retrieve stacktrace. Requires linking with *libdl* library and `::fork` system call. Macro *BOOST_STACKTRACE_ADDR2LINE_LOCATION* must be defined to the absolute path to the addr2line executable if it is not located in /usr/bin/addr2line. ] [Any compiler on POSIX] [yes] [yes]]
[[*BOOST_STACKTRACE_USE_NOOP*] [*boost_stacktrace_noop*] [Use this if you wish to disable backtracing. `stacktrace::size()` with that macro always returns 0. ] [All] [no] [no]]
]
[*Examples:]
* if you wish to switch to more powerful implementation on Clang/MinGW and *BOOST_STACKTRACE_LINK* is defined, you just need link with "*-lboost_stacktrace_backtrace -ldl -lbacktrace*" or "*-lboost_stacktrace_addr2line -ldl*"
* if you wish to disable backtracing and *BOOST_STACKTRACE_LINK* is defined, you just need link with *-lboost_stacktrace_noop*
* 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 and recompile it
[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]
[section Windows deployment and symbol files]
Function names may not be resolved after deployment of your application to a different system.
There are multiple ways to deal with that issue if you distribute PDB files along with your application:
* Link your application and shared libraries with a properly set `/PDBALTPATH` flag, for example `/PDBALTPATH:%_PDB%`. See [@https://docs.microsoft.com/en-us/cpp/build/reference/pdbaltpath-use-alternate-pdb-path official documentation for more info].
* Set the `_NT_ALT_SYMBOL_PATH` or `_NT_SYMBOL_PATH` environment variables of the target system to the path of the PDBs. See [@https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/symbol-path#controlling-the-symbol-path official documentation for more info].
[endsect]
[endsect]
@@ -287,8 +338,10 @@ If one of the link macros is defined, you have to manually link your binary with
In order of helping and advising:
* Great thanks to Bjorn Reese for highlighting the async-signal-safety issues.
* Great thanks to Nat Goodspeed for requesting [classref boost::stacktrace::frame] like class.
* Great thanks to Niall Douglas for making an initial review, helping with some platforms and giving great hints on library design.
* Great thanks to all the library reviewers.
[endsect]

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -6,6 +6,7 @@
#define BOOST_ENABLE_ASSERT_HANDLER
#include <cstdlib> // std::exit
#include <boost/array.hpp>
BOOST_NOINLINE void foo(int i);
BOOST_NOINLINE void bar(int i);
@@ -23,9 +24,6 @@ BOOST_NOINLINE void foo(int i) {
bar(--i);
}
namespace std { inline void ignore_abort(){ std::exit(0); } }
#define abort ignore_abort
//[getting_started_assert_handlers
// BOOST_ENABLE_ASSERT_DEBUG_HANDLER is defined for the whole project
@@ -34,10 +32,11 @@ 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();
/*<-*/ std::exit(0); /*->*/
/*=std::abort();*/
}
inline void assertion_failed(char const* expr, char const* function, char const* file, long line) {

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -8,25 +8,26 @@
#include <signal.h> // ::signal
#include <boost/stacktrace/frame.hpp>
#include <iostream> // std::cerr
#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.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -21,47 +21,338 @@ BOOST_NOINLINE void foo(int i) {
bar(--i);
}
inline void ignore_exit(int){ std::exit(0); }
#define _Exit ignore_exit
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//[getting_started_terminate_handlers
//[getting_started_signal_handlers
#include <exception> // std::set_terminate, std::abort
#include <signal.h> // ::signal
#include <signal.h> // ::signal, ::raise
#include <boost/stacktrace.hpp>
#include <iostream> // std::cerr
void my_terminate_handler() {
std::cerr << "Terminate called:\n" << boost::stacktrace::stacktrace() << '\n';
std::abort();
}
void my_signal_handler(int signum) {
::signal(signum, SIG_DFL);
boost::stacktrace::stacktrace bt;
if (bt) {
std::cerr << "Signal " << signum << ", backtrace:\n" << boost::stacktrace::stacktrace() << '\n'; // ``[footnote Strictly speaking this code is not async-signal-safe, because it uses std::cerr. [link boost_stacktrace.build_macros_and_backends Section "Build, Macros and Backends"] describes async-signal-safe backends, so if you will use the noop backend code becomes absolutely valid as that backens always returns 0 frames and `operator<<` will be never called. ]``
}
_Exit(-1);
// Outputs nothing or trash on majority of platforms
boost::stacktrace::safe_dump_to("./backtrace.dump");
::raise(SIGABRT);
}
//]
void setup_handlers() {
//[getting_started_setup_handlers
std::set_terminate(&my_terminate_handler);
//[getting_started_setup_signel_handlers
::signal(SIGSEGV, &my_signal_handler);
::signal(SIGABRT, &my_signal_handler);
//]
}
int main() {
setup_handlers();
//[getting_started_terminate_handlers
#include <cstdlib> // std::abort
#include <exception> // std::set_terminate
#include <iostream> // std::cerr
#include <boost/stacktrace.hpp>
void my_terminate_handler() {
try {
std::cerr << boost::stacktrace::stacktrace();
} catch (...) {}
std::abort();
}
//]
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOST_CONSTEXPR_OR_CONST std::size_t shared_memory_size = 4096 * 8;
//[getting_started_terminate_handlers_shmem
#include <boost/stacktrace.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
boost::interprocess::shared_memory_object g_shm; // inited at program start
boost::interprocess::mapped_region g_region; // inited at program start
void my_signal_handler2(int signum) {
::signal(signum, SIG_DFL);
void** f = static_cast<void**>(g_region.get_address());
*f = reinterpret_cast<void*>(1); // Setting flag that shared memory now constains stacktrace.
boost::stacktrace::safe_dump_to(f + 1, g_region.get_size() - sizeof(void*));
::raise(SIGABRT);
}
//]
#include <iostream> // std::cerr
#include <fstream> // std::ifstream
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
inline void copy_and_run(const char* exec_name, char param, bool not_null) {
std::cout << "Running with param " << param << std::endl;
boost::filesystem::path command = exec_name;
command = command.parent_path() / (command.stem().string() + param + command.extension().string());
boost::filesystem::copy_file(exec_name, command, boost::filesystem::copy_option::overwrite_if_exists);
boost::filesystem::path command_args = command;
command_args += ' ';
command_args += param;
const int ret = std::system(command_args.string().c_str());
std::cout << "End Running with param " << param << "; ret code is " << ret << std::endl;
boost::system::error_code ignore;
boost::filesystem::remove(command, ignore);
if (not_null && !ret) {
std::exit(97);
} else if (!not_null && ret) {
std::exit(ret);
}
}
int run_0(const char* /*argv*/[]) {
//[getting_started_setup_terminate_handlers
std::set_terminate(&my_terminate_handler);
//]
foo(5);
return 2;
return 1;
}
int run_1(const char* /*argv*/[]) {
setup_handlers();
foo(5);
return 11;
}
int run_2(const char* argv[]) {
if (!boost::filesystem::exists("./backtrace.dump")) {
if (std::string(argv[0]).find("noop") == std::string::npos) {
return 21;
}
boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(std::cin);
if (st) {
return 22;
}
return 0;
}
//[getting_started_on_program_restart
if (boost::filesystem::exists("./backtrace.dump")) {
// there is a backtrace
std::ifstream ifs("./backtrace.dump");
boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(ifs);
std::cout << "Previous run crashed:\n" << st << std::endl; /*<-*/
if (!st) {
return 23;
} /*->*/
// cleaning up
ifs.close();
boost::filesystem::remove("./backtrace.dump");
}
//]
return 0;
}
int run_3(const char* /*argv*/[]) {
using namespace boost::interprocess;
{
shared_memory_object shm_obj(open_or_create, "shared_memory", read_write);
shm_obj.swap(g_shm);
}
g_shm.truncate(shared_memory_size);
{
mapped_region m(g_shm, read_write, 0, shared_memory_size);
m.swap(g_region);
}
void** f = static_cast<void**>(g_region.get_address());
*f = 0;
::signal(SIGSEGV, &my_signal_handler2);
::signal(SIGABRT, &my_signal_handler2);
foo(5);
return 31;
}
int run_4(const char* argv[]) {
using namespace boost::interprocess;
{
shared_memory_object shm_obj(open_only, "shared_memory", read_write);
shm_obj.swap(g_shm);
}
{
mapped_region m(g_shm, read_write, 0, shared_memory_size);
m.swap(g_region);
}
//[getting_started_on_program_restart_shmem
void** f = static_cast<void**>(g_region.get_address());
if (*f) { // Checking if memory constains stacktrace.
boost::stacktrace::stacktrace st
= boost::stacktrace::stacktrace::from_dump(f + 1, g_region.get_size() - sizeof(bool));
std::cout << "Previous run crashed and left trace in shared memory:\n" << st << std::endl;
*f = 0; /*<-*/
shared_memory_object::remove("shared_memory");
if (std::string(argv[0]).find("noop") == std::string::npos) {
if (!st) {
return 43;
}
} else {
if (st) {
return 44;
}
}
} else {
return 42; /*->*/
}
//]
return 0;
}
#include <sstream>
int test_inplace() {
const bool is_noop = !boost::stacktrace::stacktrace();
{
// This is very dependent on compiler and link flags. No sane way to make it work, because:
// * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled.
// * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length.
const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to("./backtrace2.dump");
boost::stacktrace::stacktrace ss2;
std::ifstream ifs("./backtrace2.dump");
boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(ifs);
ifs.close();
boost::filesystem::remove("./backtrace2.dump");
if (ss1.size() + 1 != frames_ss1 || ss2.size() != ss1.size()) {
std::cerr << "51: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n';
} else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) {
std::cerr << "52: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
}
}
{
// This is very dependent on compiler and link flags. No sane way to make it work, because:
// * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled.
// * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length.
void* data[1024];
const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to(data, sizeof(data));
boost::stacktrace::stacktrace ss2;
boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(data, sizeof(data));
if (ss1.size() + 1 != frames_ss1 || ss1.size() != ss2.size()) {
std::cerr << "53: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n';
} else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) {
std::cerr << "54: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
}
}
{
void* data[1024];
boost::stacktrace::safe_dump_to(1024, data, sizeof(data));
if (boost::stacktrace::stacktrace::from_dump(data, sizeof(data))) {
std::cerr << "Stacktrace not empty!\n";
return 55;
}
}
{
void* data[1024];
boost::stacktrace::safe_dump_to(1, data, sizeof(data));
if (!is_noop && !boost::stacktrace::stacktrace::from_dump(data, sizeof(data))) {
std::cerr << "Stacktrace empty!\n";
return 56;
}
const std::size_t size_1_skipped = boost::stacktrace::stacktrace::from_dump(data, sizeof(data)).size();
boost::stacktrace::safe_dump_to(0, data, sizeof(data));
const std::size_t size_0_skipped = boost::stacktrace::stacktrace::from_dump(data, sizeof(data)).size();
if (!is_noop && (size_1_skipped + 1 != size_0_skipped)) {
std::cerr << "failed to skip 1 frame!\n";
return 57;
}
}
{
boost::stacktrace::safe_dump_to(0, 1, "./backtrace3.dump");
std::ifstream ifs("./backtrace3.dump");
boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(ifs);
ifs.close();
boost::stacktrace::safe_dump_to(1, 1, "./backtrace3.dump");
ifs.open("./backtrace3.dump");
boost::stacktrace::stacktrace ss2 = boost::stacktrace::stacktrace::from_dump(ifs);
ifs.close();
boost::filesystem::remove("./backtrace3.dump");
#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;
}
if (!is_noop && ss1.size() != 1) {
std::cerr << "Stacktraces does not have size 1:\n" << ss1 << '\n';
return 59;
}
if (ss1 && ss1[0].address() == ss2[0].address()) {
std::cerr << "Stacktraces must differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
return 60;
}
}
return 0;
}
int main(int argc, const char* argv[]) {
if (argc < 2) {
// On Windows the debugger could be active. In that case tests hang and the CI run fails.
#ifndef BOOST_WINDOWS
copy_and_run(argv[0], '0', true);
// 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();
}
switch (argv[1][0]) {
case '0': return run_0(argv);
case '1': return run_1(argv);
case '2': return run_2(argv);
case '3': return run_3(argv);
case '4': return run_4(argv);
}
return 404;
}

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -6,37 +6,21 @@
#include <boost/config.hpp>
#if defined(BOOST_NO_CXX11_NOEXCEPT) || defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
int main(){}
#else
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//[getting_started_class_traced
#include <boost/stacktrace.hpp>
#include <boost/exception/all.hpp>
struct traced {
const boost::stacktrace::stacktrace trace;
virtual const char* what() const noexcept = 0;
virtual ~traced(){}
};
typedef boost::error_info<struct tag_stacktrace, boost::stacktrace::stacktrace> traced;
//]
//[getting_started_class_with_trace
template <class Exception>
struct with_trace : public Exception, public traced {
template <class... Args>
with_trace(Args&&... args)
: Exception(std::forward<Args>(args)...)
{}
const char* what() const noexcept {
return Exception::what();
}
};
template <class E>
void throw_with_trace(const E& e) {
throw boost::enable_error_info(e)
<< traced(boost::stacktrace::stacktrace());
}
//]
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,9 +33,9 @@ BOOST_NOINLINE void bar(int i);
BOOST_NOINLINE void oops(int i) {
//[getting_started_throwing_with_trace
if (i >= 4)
throw with_trace<std::out_of_range>("'i' must be less than 4 in oops()");
throw_with_trace(std::out_of_range("'i' must be less than 4 in oops()"));
if (i <= 0)
throw with_trace<std::logic_error>("'i' must not be greater than zero in oops()");
throw_with_trace(std::logic_error("'i' must be greater than zero in oops()"));
//]
foo(i);
std::exit(1);
@@ -80,18 +64,15 @@ int main() {
//[getting_started_catching_trace
try {
foo(5); // testing assert handler
} catch (const traced& e) {
std::cerr << e.what() << '\n';
if (e.trace) {
std::cerr << "Backtrace:\n" << e.trace << '\n';
} /*<-*/ std::exit(0); /*->*/
} catch (const std::exception& e) {
std::cerr << e.what() << '\n'; /*<-*/ std::exit(3); /*->*/
std::cerr << e.what() << '\n';
const boost::stacktrace::stacktrace* st = boost::get_error_info<traced>(e);
if (st) {
std::cerr << *st << '\n'; /*<-*/ return 0; /*->*/
} /*<-*/ return 3; /*->*/
}
//]
return 5;
}
#endif

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -9,15 +9,14 @@
#ifndef USER_CONFIG_HPP
#define USER_CONFIG_HPP
#define BOOST_STACKTRACE_DEFAULT_MAX_DEPTH 5
#include <boost/stacktrace/stacktrace_fwd.hpp>
#include <iosfwd>
namespace boost { namespace stacktrace {
template <class CharT, class TraitsT, std::size_t Depth>
std::basic_ostream<CharT, TraitsT>& do_stream_st(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Depth>& bt);
template <class CharT, class TraitsT, class Allocator>
std::basic_ostream<CharT, TraitsT>& do_stream_st(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt);
template <class CharT, class TraitsT>
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const stacktrace& bt) {
@@ -30,11 +29,14 @@ std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT
#ifndef USER_CONFIG2_HPP
#define USER_CONFIG2_HPP
#include <ios> // std::streamsize
//[getting_started_user_config_impl
namespace boost { namespace stacktrace {
template <class CharT, class TraitsT, std::size_t Depth>
std::basic_ostream<CharT, TraitsT>& do_stream_st(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Depth>& bt) {
template <class CharT, class TraitsT, class Allocator>
std::basic_ostream<CharT, TraitsT>& do_stream_st(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) {
const std::streamsize w = os.width();
const std::size_t frames = bt.size();
for (std::size_t i = 0; i < frames; ++i) {

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -14,5 +14,6 @@
#include <boost/stacktrace/frame.hpp>
#include <boost/stacktrace/stacktrace.hpp>
#include <boost/stacktrace/safe_dump_to.hpp>
#endif // BOOST_STACKTRACE_HPP

View File

@@ -1,86 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_STACKTRACE_CONST_ITERATOR_HPP
#define BOOST_STACKTRACE_CONST_ITERATOR_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/iterator/iterator_facade.hpp>
#include <boost/assert.hpp>
#include <boost/stacktrace/frame.hpp>
namespace boost { namespace stacktrace {
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
/// Random access iterator over frames that returns boost::stacktrace::frame on dereference
class const_iterator: implementation_details {};
#else
// Forward declarations
template <std::size_t> class basic_stacktrace;
class const_iterator: public boost::iterator_facade<
const_iterator,
frame,
boost::random_access_traversal_tag,
frame>
{
typedef boost::iterator_facade<
const_iterator,
frame,
boost::random_access_traversal_tag,
frame
> base_t;
const boost::stacktrace::detail::backend* impl_;
std::size_t frame_no_;
const_iterator(const boost::stacktrace::detail::backend* impl, std::size_t frame_no) BOOST_NOEXCEPT
: impl_(impl)
, frame_no_(frame_no)
{}
template <std::size_t> friend class basic_stacktrace;
friend class ::boost::iterators::iterator_core_access;
frame dereference() const BOOST_NOEXCEPT {
return frame(impl_->get_address(frame_no_));
}
bool equal(const const_iterator& it) const BOOST_NOEXCEPT {
return impl_ == it.impl_ && frame_no_ == it.frame_no_;
}
void increment() BOOST_NOEXCEPT {
++frame_no_;
}
void decrement() BOOST_NOEXCEPT {
--frame_no_;
}
void advance(std::size_t n) BOOST_NOEXCEPT {
frame_no_ += n;
}
base_t::difference_type distance_to(const const_iterator& it) const {
BOOST_ASSERT(impl_ == it.impl_);
return it.frame_no_ - frame_no_;
}
};
#endif // #ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_CONST_ITERATOR_HPP

View File

@@ -0,0 +1,226 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_ADDR2LINE_IMPLS_HPP
#define BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <boost/stacktrace/detail/to_dec_array.hpp>
#include <boost/stacktrace/detail/try_dec_convert.hpp>
#include <boost/core/demangle.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;
public:
explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) BOOST_NOEXCEPT
: p(0)
, pid(0)
{
int pdes[2];
#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),
const_cast<char*>(exec_path),
const_cast<char*>(addr),
0
};
if (::pipe(pdes) < 0) {
return;
}
pid = ::fork();
switch (pid) {
case -1:
// Failed...
::close(pdes[0]);
::close(pdes[1]);
return;
case 0:
// We are the child.
::close(STDERR_FILENO);
::close(pdes[0]);
if (pdes[1] != STDOUT_FILENO) {
::dup2(pdes[1], STDOUT_FILENO);
}
// Do not use `execlp()`, `execvp()`, and `execvpe()` here!
// `exec*p*` functions are vulnerable to PATH variable evaluation attacks.
::execv(prog_name, argp);
::_exit(127);
}
p = ::fdopen(pdes[0], "r");
::close(pdes[1]);
}
operator ::FILE*() const BOOST_NOEXCEPT {
return p;
}
~addr2line_pipe() BOOST_NOEXCEPT {
if (p) {
::fclose(p);
int pstat = 0;
::kill(pid, SIGKILL);
::waitpid(pid, &pstat, 0);
}
}
};
inline std::string addr2line(const char* flag, const void* addr) {
std::string res;
boost::stacktrace::detail::location_from_symbol loc(addr);
if (!loc.empty()) {
res = loc.name();
} else {
res.resize(16);
int rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
while (rlin_size == static_cast<int>(res.size() - 1)) {
res.resize(res.size() * 4);
rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
}
if (rlin_size == -1) {
res.clear();
return res;
}
res.resize(rlin_size);
}
addr2line_pipe p(flag, res.c_str(), to_hex_array(addr).data());
res.clear();
if (!p) {
return res;
}
char data[32];
while (!::feof(p)) {
if (::fgets(data, sizeof(data), p)) {
res += data;
} else {
break;
}
}
// Trimming
while (!res.empty() && (res[res.size() - 1] == '\n' || res[res.size() - 1] == '\r')) {
res.erase(res.size() - 1);
}
return res;
}
struct to_string_using_addr2line {
std::string res;
void prepare_function_name(const void* addr) {
res = boost::stacktrace::frame(addr).name();
}
bool prepare_source_location(const void* addr) {
//return addr2line("-Cfipe", addr); // Does not seem to work in all cases
std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", addr);
if (!source_line.empty() && source_line[0] != '?') {
res += " at ";
res += source_line;
return true;
}
return false;
}
};
template <class Base> class to_string_impl_base;
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::core::demangle(res.c_str());
if (res == "??") {
res.clear();
}
return res;
}
} // namespace detail
std::string frame::source_file() const {
std::string res;
res = boost::stacktrace::detail::addr2line("-e", addr_);
res = res.substr(0, res.find_last_of(':'));
if (res == "??") {
res.clear();
}
return res;
}
std::size_t frame::source_line() const {
std::size_t line_num = 0;
std::string res = boost::stacktrace::detail::addr2line("-e", addr_);
const std::size_t last = res.find_last_of(':');
if (last == std::string::npos) {
return 0;
}
res = res.substr(last + 1);
if (!boost::stacktrace::detail::try_dec_convert(res.c_str(), line_num)) {
return 0;
}
return line_num;
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_ADDR2LINE_IMPLS_HPP

View File

@@ -1,125 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_STACKTRACE_DETAIL_BACKEND_HPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <string>
// 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
// Backend autodetection
#if !defined(BOOST_STACKTRACE_USE_NOOP) && !defined(BOOST_STACKTRACE_USE_WINDBG) && !defined(BOOST_STACKTRACE_USE_UNWIND) \
&& !defined(BOOST_STACKTRACE_USE_BACKTRACE) && !defined(BOOST_STACKTRACE_USE_HEADER)
#if defined(__has_include) && (!defined(__GNUC__) || __GNUC__ > 4 || BOOST_CLANG)
# if __has_include("Dbgeng.h")
# define BOOST_STACKTRACE_USE_WINDBG
# else
# define BOOST_STACKTRACE_USE_UNWIND
# endif
#else
# if defined(BOOST_WINDOWS)
# define BOOST_STACKTRACE_USE_WINDBG
# else
# define BOOST_STACKTRACE_USE_UNWIND
# endif
#endif
#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
#else
# define BOOST_STACKTRACE_FUNCTION inline
#endif
namespace boost { namespace stacktrace { namespace detail {
// Class that implements the actual backtracing
class backend {
std::size_t hash_code_;
std::size_t frames_count_;
void** data_;
void copy_frames_from(const backend& b) BOOST_NOEXCEPT {
if (data_ == b.data_) {
return;
}
for (std::size_t i = 0; i < frames_count_; ++i) {
data_[i] = b.data_[i];
}
}
public:
BOOST_STACKTRACE_FUNCTION backend(void** memory, std::size_t size) BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION static std::string get_name(const void* addr);
const void* get_address(std::size_t frame_no) const BOOST_NOEXCEPT {
return frame_no < frames_count_ ? data_[frame_no] : 0;
}
BOOST_STACKTRACE_FUNCTION static std::string get_source_file(const void* addr);
BOOST_STACKTRACE_FUNCTION static std::size_t get_source_line(const void* addr);
BOOST_STACKTRACE_FUNCTION bool operator< (const backend& rhs) const BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION bool operator==(const backend& rhs) const BOOST_NOEXCEPT;
backend(const backend& b, void** memory) BOOST_NOEXCEPT
: hash_code_(b.hash_code_)
, frames_count_(b.frames_count_)
, data_(memory)
{
copy_frames_from(b);
}
backend& operator=(const backend& b) BOOST_NOEXCEPT {
hash_code_ = b.hash_code_;
frames_count_ = b.frames_count_;
copy_frames_from(b);
return *this;
}
std::size_t size() const BOOST_NOEXCEPT {
return frames_count_;
}
std::size_t hash_code() const BOOST_NOEXCEPT {
return hash_code_;
}
};
}}} // namespace boost::stacktrace::detail
/// @cond
#undef BOOST_STACKTRACE_FUNCTION
#ifndef BOOST_STACKTRACE_LINK
# include <boost/stacktrace/detail/backend.ipp>
#endif
/// @endcond
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_HPP

View File

@@ -1,27 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_STACKTRACE_DETAIL_BACKEND_IPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/detail/backend.hpp>
#if defined(BOOST_STACKTRACE_USE_NOOP)
# include <boost/stacktrace/detail/backend_noop.hpp>
#elif defined(BOOST_STACKTRACE_USE_WINDBG)
# include <boost/stacktrace/detail/backend_windows.hpp>
#elif defined(BOOST_STACKTRACE_USE_BACKTRACE) || defined(BOOST_STACKTRACE_USE_UNWIND)
# include <boost/stacktrace/detail/backend_linux.hpp>
#else
# error No suitable backtrace backend found
#endif
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_IPP

View File

@@ -1,49 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_STACKTRACE_DETAIL_BACKEND_COMMON_IPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_COMMON_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <algorithm>
namespace boost { namespace stacktrace { namespace detail {
bool backend::operator< (const backend& rhs) const BOOST_NOEXCEPT {
if (frames_count_ != rhs.frames_count_) {
return frames_count_ < rhs.frames_count_;
} else if (hash_code_ != rhs.hash_code_) {
return hash_code_ < rhs.hash_code_;
} else if (data_ == rhs.data_) {
return false;
}
return std::lexicographical_compare(
data_, data_ + frames_count_,
rhs.data_, rhs.data_ + rhs.frames_count_
);
}
bool backend::operator==(const backend& rhs) const BOOST_NOEXCEPT {
if (hash_code_ != rhs.hash_code_ || frames_count_ != rhs.frames_count_) {
return false;
} else if (data_ == rhs.data_) {
return true;
}
return std::equal(
data_, data_ + frames_count_,
rhs.data_
);
}
}}}
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_COMMON_IPP

View File

@@ -1,249 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_STACKTRACE_DETAIL_BACKEND_LINUX_HPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_LINUX_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/core/demangle.hpp>
#include <boost/functional/hash.hpp>
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <boost/lexical_cast/try_lexical_convert.hpp>
#if defined(BOOST_STACKTRACE_USE_UNWIND)
#include <unwind.h>
#endif
#include <dlfcn.h>
#include <execinfo.h>
#include <cstdio>
#include <sys/types.h>
#include <sys/wait.h>
namespace boost { namespace stacktrace { namespace detail {
class addr2line_pipe {
FILE* p;
pid_t pid;
public:
explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) BOOST_NOEXCEPT
: p(0)
, pid(0)
{
int pdes[2];
char prog_name[] = "addr2line";
char* argp[] = {
prog_name,
const_cast<char*>(flag),
const_cast<char*>(exec_path),
const_cast<char*>(addr),
0
};
if (pipe(pdes) < 0) {
return;
}
pid = fork();
switch (pid) {
case -1:
// failed
close(pdes[0]);
close(pdes[1]);
return;
case 0:
// we are the child
close(STDERR_FILENO);
close(pdes[0]);
if (pdes[1] != STDOUT_FILENO) {
dup2(pdes[1], STDOUT_FILENO);
}
execvp(prog_name, argp);
_exit(127);
}
p = fdopen(pdes[0], "r");
close(pdes[1]);
}
operator FILE*() const BOOST_NOEXCEPT {
return p;
}
~addr2line_pipe() BOOST_NOEXCEPT {
if (p) {
fclose(p);
int pstat = 0;
kill(pid, SIGKILL);
waitpid(pid, &pstat, 0);
}
}
};
static inline std::string addr2line(const char* flag, const void* addr) {
std::string res;
Dl_info dli;
if (!!dladdr(addr, &dli) && dli.dli_fname) {
res = dli.dli_fname;
} else {
res.resize(16);
int rlin_size = readlink("/proc/self/exe", &res[0], res.size() - 1);
while (rlin_size == static_cast<int>(res.size() - 1)) {
res.resize(res.size() * 4);
rlin_size = readlink("/proc/self/exe", &res[0], res.size() - 1);
}
if (rlin_size == -1) {
res.clear();
return res;
}
res.resize(rlin_size);
}
addr2line_pipe p(flag, res.c_str(), to_hex_array(addr).data());
res.clear();
if (!p) {
return res;
}
char data[32];
while (!std::feof(p)) {
if (std::fgets(data, sizeof(data), p)) {
res += data;
} else {
break;
}
}
// Trimming
while (!res.empty() && (res[res.size() - 1] == '\n' || res[res.size() - 1] == '\r')) {
res.erase(res.size() - 1);
}
return res;
}
static 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;
}
#if defined(BOOST_STACKTRACE_USE_UNWIND)
struct unwind_state {
void** current;
void** end;
};
inline _Unwind_Reason_Code unwind_callback(struct _Unwind_Context* context, void* arg) {
unwind_state* state = static_cast<unwind_state*>(arg);
*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;
}
#endif
backend::backend(void** memory, std::size_t size) BOOST_NOEXCEPT
: hash_code_(0)
, frames_count_(0)
, data_(memory)
{
if (!size) {
return;
}
#if defined(BOOST_STACKTRACE_USE_UNWIND)
unwind_state state = { data_, data_ + size };
_Unwind_Backtrace(&unwind_callback, &state);
frames_count_ = state.current - data_;
#elif defined(BOOST_STACKTRACE_USE_BACKTRACE)
frames_count_ = ::backtrace(data_, size);
#else
# error No stacktrace backend defined. Define BOOST_STACKTRACE_USE_UNWIND or BOOST_STACKTRACE_USE_BACKTRACE
#endif
if (data_[frames_count_ - 1] == 0) {
-- frames_count_;
}
hash_code_ = boost::hash_range(data_, data_ + frames_count_);
}
std::string backend::get_name(const void* addr) {
std::string res;
Dl_info dli;
if (!!dladdr(addr, &dli) && dli.dli_sname) {
res = try_demangle(dli.dli_sname);
} else {
res = addr2line("-fe", addr);
res = res.substr(0, res.find_last_of('\n'));
res = try_demangle(res.c_str());
}
if (res == "??") {
res.clear();
}
return res;
}
std::string backend::get_source_file(const void* addr) {
std::string res = addr2line("-e", addr);
res = res.substr(0, res.find_last_of(':'));
if (res == "??") {
res.clear();
}
return res;
}
std::size_t backend::get_source_line(const void* addr) {
std::string res = addr2line("-e", addr);
const std::size_t last = res.find_last_of(':');
if (last == std::string::npos) {
return 0;
}
res = res.substr(last + 1);
std::size_t line_num = 0;
if (!boost::conversion::try_lexical_convert(res, line_num)) {
return 0;
}
return line_num;
}
}}} // namespace boost::stacktrace::detail
#include <boost/stacktrace/detail/backend_common.ipp>
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LINUX_HPP

View File

@@ -1,46 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_STACKTRACE_DETAIL_BACKEND_NOOP_HPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_NOOP_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace stacktrace { namespace detail {
backend::backend(void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT
: hash_code_(0)
, frames_count_(0)
, data_(0)
{}
std::string backend::get_name(const void* /*addr*/) {
return std::string();
}
std::string backend::get_source_file(const void* /*addr*/) {
return std::string();
}
std::size_t backend::get_source_line(const void* /*addr*/) {
return 0;
}
bool backend::operator< (const backend& /*rhs*/) const BOOST_NOEXCEPT {
return false;
}
bool backend::operator==(const backend& /*rhs*/) const BOOST_NOEXCEPT {
return true;
}
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LIBUNWIND_HPP

View File

@@ -1,221 +0,0 @@
// Copyright Antony Polukhin, 2016.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_STACKTRACE_DETAIL_BACKEND_WINDOWS_HPP
#define BOOST_STACKTRACE_DETAIL_BACKEND_WINDOWS_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/core/noncopyable.hpp>
#include <boost/functional/hash.hpp>
#include <windows.h>
#include "Dbgeng.h"
#include <boost/detail/winapi/get_current_process.hpp>
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "Dbgeng.lib")
namespace boost { namespace stacktrace { namespace detail {
template <class T>
class com_holder: boost::noncopyable {
T* holder_;
public:
com_holder() BOOST_NOEXCEPT
: holder_(0)
{}
T* operator->() const BOOST_NOEXCEPT {
return holder_;
}
void** to_void_ptr_ptr() BOOST_NOEXCEPT {
return reinterpret_cast<void**>(&holder_);
}
bool is_inited() const BOOST_NOEXCEPT {
return !!holder_;
}
void reset() const BOOST_NOEXCEPT {
if (holder_) {
holder_->Release();
}
}
~com_holder() BOOST_NOEXCEPT {
reset();
}
};
inline bool try_init_com(com_holder<IDebugSymbols>& idebug_) BOOST_NOEXCEPT {
if (idebug_.is_inited()) {
return true;
}
CoInitializeEx(0, COINIT_MULTITHREADED);
com_holder<IDebugClient> iclient;
DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr());
com_holder<IDebugControl> icontrol;
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;
}
const bool res2 = (S_OK == icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE));
if (!res2) {
return false;
}
const bool res = (S_OK == iclient->QueryInterface(__uuidof(IDebugSymbols), idebug_.to_void_ptr_ptr()));
if (!res) {
idebug_.reset();
return false;
}
return true;
}
backend::backend(void** memory, std::size_t size) BOOST_NOEXCEPT
: hash_code_(0)
, frames_count_(0)
, data_(memory)
{
boost::detail::winapi::ULONG_ hc = 0;
frames_count_ = CaptureStackBackTrace(
0,
static_cast<boost::detail::winapi::ULONG_>(size),
data_,
&hc
);
boost::hash_combine(hash_code_, hc);
}
std::string backend::get_name(const void* addr) {
std::string result;
com_holder<IDebugSymbols> idebug_;
if (!try_init_com(idebug_)) {
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,
name,
sizeof(name),
&size,
0
));
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;
}
std::string backend::get_source_file(const void* addr) {
std::string result;
com_holder<IDebugSymbols> idebug_;
if (!try_init_com(idebug_)) {
return result;
}
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
char name[256];
name[0] = 0;
ULONG size = 0;
bool res = (S_OK == idebug_->GetLineByOffset(
offset,
0,
name,
sizeof(name),
&size,
0
));
if (!res && size != 0) {
result.resize(size);
res = (S_OK == idebug_->GetLineByOffset(
offset,
0,
&result[0],
static_cast<ULONG>(result.size()),
&size,
0
));
} else if (res) {
result = name;
}
if (!res) {
result.clear();
}
return result;
}
std::size_t backend::get_source_line(const void* addr) {
ULONG line_num = 0;
com_holder<IDebugSymbols> idebug_;
if (!try_init_com(idebug_)) {
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);
}
}}} // namespace boost::stacktrace::detail
#include <boost/stacktrace/detail/backend_common.ipp>
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LINUX_HPP

View File

@@ -0,0 +1,33 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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-2021.
//
// 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,106 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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>
// On iOS 32-bit ARM architecture _Unwind_Backtrace function doesn't exist, symbol is undefined.
// Forcing libc backtrace() function usage.
#include <boost/predef.h>
#if defined(BOOST_OS_IOS_AVAILABLE) && defined(BOOST_ARCH_ARM_AVAILABLE) && BOOST_VERSION_NUMBER_MAJOR(BOOST_ARCH_ARM) < 8
#define BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION
#endif
#if defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
#include <execinfo.h>
#include <algorithm>
#else
#include <unwind.h>
#endif
#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 {
#if !defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
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;
}
#endif //!defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
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;
}
skip += 1;
#if defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
// According to https://opensource.apple.com/source/Libc/Libc-1272.200.26/gen/backtrace.c.auto.html
// it looks like the `::backtrace` is async signal safe.
frames_count = static_cast<size_t>(::backtrace(const_cast<void **>(out_frames), static_cast<int>(max_frames_count)));
// NOTE: There is no way to pass "skip" count to backtrace function so we need to perform left shift operation.
// If number of elements in result backtrace is >= max_frames_count then "skip" elements are wasted.
if (frames_count && skip) {
if (skip >= frames_count) {
frames_count = 0;
} else {
std::copy(out_frames + skip, out_frames + frames_count, out_frames);
frames_count -= skip;
}
}
#else
boost::stacktrace::detail::unwind_state state = { skip, out_frames, out_frames + max_frames_count };
::_Unwind_Backtrace(&boost::stacktrace::detail::unwind_callback, &state);
frames_count = state.current - out_frames;
#endif //defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
if (frames_count && out_frames[frames_count - 1] == 0) {
-- frames_count;
}
return frames_count;
}
}}} // namespace boost::stacktrace::detail
#undef BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION
#endif // BOOST_STACKTRACE_DETAIL_COLLECT_UNWIND_IPP

View File

@@ -0,0 +1,159 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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

@@ -0,0 +1,403 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_MSVC_IPP
#define BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/frame.hpp>
#include <boost/core/demangle.hpp>
#include <boost/core/noncopyable.hpp>
#include <boost/stacktrace/detail/to_dec_array.hpp>
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <windows.h>
#include "dbgeng.h"
#ifdef BOOST_MSVC
# pragma comment(lib, "ole32.lib")
# pragma comment(lib, "Dbgeng.lib")
#endif
#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 {
class com_global_initer: boost::noncopyable {
bool ok_;
public:
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 {
if (ok_) {
::CoUninitialize();
}
}
};
template <class T>
class com_holder: boost::noncopyable {
T* holder_;
public:
com_holder(const com_global_initer&) BOOST_NOEXCEPT
: holder_(0)
{}
T* operator->() const BOOST_NOEXCEPT {
return holder_;
}
void** to_void_ptr_ptr() BOOST_NOEXCEPT {
return reinterpret_cast<void**>(&holder_);
}
bool is_inited() const BOOST_NOEXCEPT {
return !!holder_;
}
~com_holder() BOOST_NOEXCEPT {
if (holder_) {
holder_->Release();
}
}
};
inline std::string mingw_demangling_workaround(const std::string& s) {
#ifdef BOOST_GCC
if (s.empty()) {
return s;
}
if (s[0] != '_') {
return boost::core::demangle(('_' + s).c_str());
}
return boost::core::demangle(s.c_str());
#else
return s;
#endif
}
inline void trim_right_zeroes(std::string& s) {
// MSVC-9 does not have back() and pop_back() functions in std::string
while (!s.empty()) {
const std::size_t last = static_cast<std::size_t>(s.size() - 1);
if (s[last] != '\0') {
break;
}
s.resize(last);
}
}
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;
}
com_holder< ::IDebugControl> icontrol(com);
const bool res0 = (S_OK == iclient->QueryInterface(
__uuidof(IDebugControl),
icontrol.to_void_ptr_ptr()
));
if (!res0) {
return;
}
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,
name,
sizeof(name),
&size,
0
));
if (!res && size != 0) {
result.resize(size);
res = (S_OK == idebug_->GetNameByOffset(
offset,
&result[0],
static_cast<ULONG>(result.size()),
&size,
0
));
trim_right_zeroes(result);
} 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;
}
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);
}
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
));
if (res) {
result.first = name;
result.second = line_num;
return result;
}
if (!res && size == 0) {
return result;
}
result.first.resize(size);
res = (S_OK == idebug_->GetLineByOffset(
offset,
&line_num,
&result.first[0],
static_cast<ULONG>(result.first.size()),
&size,
0
));
trim_right_zeroes(result.first);
result.second = line_num;
if (!res) {
result.first.clear();
result.second = 0;
}
return result;
}
void to_string_impl(const void* addr, std::string& res) const {
if (!is_inited()) {
return;
}
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();
}
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::stacktrace::detail::to_dec_array(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::debugging_symbols idebug;
if (!idebug.is_inited()) {
return std::string();
}
std::string res;
res.reserve(64 * size);
for (std::size_t i = 0; i < size; ++i) {
if (i < 10) {
res += ' ';
}
res += boost::stacktrace::detail::to_dec_array(i).data();
res += '#';
res += ' ';
idebug.to_string_impl(frames[i].address(), res);
res += '\n';
}
return res;
}
} // namespace detail
std::string frame::name() const {
boost::stacktrace::detail::debugging_symbols idebug;
return idebug.get_name_impl(addr_);
}
std::string frame::source_file() const {
boost::stacktrace::detail::debugging_symbols idebug;
return idebug.get_source_file_line_impl(addr_).first;
}
std::size_t frame::source_line() const {
boost::stacktrace::detail::debugging_symbols idebug;
return idebug.get_line_impl(addr_);
}
std::string to_string(const frame& f) {
std::string res;
boost::stacktrace::detail::debugging_symbols idebug;
idebug.to_string_impl(f.address(), res);
return res;
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP

View File

@@ -0,0 +1,44 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_NOOP_IPP
#define BOOST_STACKTRACE_DETAIL_FRAME_NOOP_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/frame.hpp>
namespace boost { namespace stacktrace { namespace detail {
std::string to_string(const frame* /*frames*/, std::size_t /*count*/) {
return std::string();
}
} // namespace detail
std::string frame::name() const {
return std::string();
}
std::string frame::source_file() const {
return std::string();
}
std::size_t frame::source_line() const {
return 0;
}
std::string to_string(const frame& /*f*/) {
return std::string();
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_FRAME_NOOP_IPP

View File

@@ -0,0 +1,114 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_UNWIND_IPP
#define BOOST_STACKTRACE_DETAIL_FRAME_UNWIND_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/frame.hpp>
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <boost/stacktrace/detail/location_from_symbol.hpp>
#include <boost/stacktrace/detail/to_dec_array.hpp>
#include <boost/core/demangle.hpp>
#include <cstdio>
#ifdef BOOST_STACKTRACE_USE_BACKTRACE
# include <boost/stacktrace/detail/libbacktrace_impls.hpp>
#elif defined(BOOST_STACKTRACE_USE_ADDR2LINE)
# include <boost/stacktrace/detail/addr2line_impls.hpp>
#else
# include <boost/stacktrace/detail/unwind_base_impls.hpp>
#endif
namespace boost { namespace stacktrace { namespace detail {
template <class Base>
class to_string_impl_base: private Base {
public:
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::core::demangle(Base::res.c_str());
} else {
Base::res = to_hex_array(addr).data();
}
if (Base::prepare_source_location(addr)) {
return Base::res;
}
boost::stacktrace::detail::location_from_symbol loc(addr);
if (!loc.empty()) {
Base::res += " in ";
Base::res += loc.name();
}
return Base::res;
}
};
std::string to_string(const frame* frames, std::size_t size) {
std::string res;
if (size == 0) {
return res;
}
res.reserve(64 * size);
to_string_impl impl;
for (std::size_t i = 0; i < size; ++i) {
if (i < 10) {
res += ' ';
}
res += boost::stacktrace::detail::to_dec_array(i).data();
res += '#';
res += ' ';
res += impl(frames[i].address());
res += '\n';
}
return res;
}
} // namespace detail
std::string frame::name() const {
if (!addr_) {
return std::string();
}
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
::Dl_info dli;
const bool dl_ok = !!::dladdr(const_cast<void*>(addr_), &dli); // `dladdr` on Solaris accepts nonconst addresses
if (dl_ok && dli.dli_sname) {
return boost::core::demangle(dli.dli_sname);
}
#endif
return boost::stacktrace::detail::name_impl(addr_);
}
std::string to_string(const frame& f) {
if (!f) {
return std::string();
}
boost::stacktrace::detail::to_string_impl impl;
return impl(f.address());
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_FRAME_UNWIND_IPP

View File

@@ -0,0 +1,244 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_LIBBACKTRACE_IMPLS_HPP
#define BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <boost/stacktrace/detail/to_dec_array.hpp>
#include <boost/stacktrace/detail/location_from_symbol.hpp>
#include <boost/core/demangle.hpp>
#ifdef BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
# include BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
#else
# include <backtrace.h>
#endif
namespace boost { namespace stacktrace { namespace detail {
struct pc_data {
std::string* function;
std::string* filename;
std::size_t line;
};
inline void libbacktrace_syminfo_callback(void *data, uintptr_t /*pc*/, const char *symname, uintptr_t /*symval*/, uintptr_t /*symsize*/) {
pc_data& d = *static_cast<pc_data*>(data);
if (d.function && symname) {
*d.function = symname;
}
}
// Old versions of libbacktrace have different signature for the callback
inline void libbacktrace_syminfo_callback(void *data, uintptr_t pc, const char *symname, uintptr_t symval) {
boost::stacktrace::detail::libbacktrace_syminfo_callback(data, pc, symname, symval, 0);
}
inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *filename, int lineno, const char *function) {
pc_data& d = *static_cast<pc_data*>(data);
if (d.filename && filename) {
*d.filename = filename;
}
if (d.function && function) {
*d.function = function;
}
d.line = lineno;
return 0;
}
inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) BOOST_NOEXCEPT {
// Do nothing, just return.
}
// 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.
//
// 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.
BOOST_SYMBOL_VISIBLE inline ::backtrace_state* construct_state(const program_location& prog_location) BOOST_NOEXCEPT {
// [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
// TODO: The most obvious solution:
//
//static ::backtrace_state* state = ::backtrace_create_state(
// prog_location.name(),
// 1, // allow safe concurrent usage of the same state
// boost::stacktrace::detail::libbacktrace_error_callback,
// 0 // pointer to data that will be passed to callback
//);
//
//
// Unfortunately, that solution segfaults when `construct_state()` function is in .so file
// and multiple threads concurrently work with state.
#ifndef BOOST_HAS_THREADS
static
#else
// Result of `construct_state()` invocation is not stored by the callers, so `thread_local`
// gives a single `state` per thread and that state is not shared between threads in any way.
# ifndef BOOST_NO_CXX11_THREAD_LOCAL
thread_local
# elif defined(__GNUC__) && !defined(__clang__)
static __thread
# else
/* just a local variable */
# endif
#endif
::backtrace_state* state = ::backtrace_create_state(
prog_location.name(),
0,
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};
if (state) {
::backtrace_pcinfo(
state,
reinterpret_cast<uintptr_t>(addr),
boost::stacktrace::detail::libbacktrace_full_callback,
boost::stacktrace::detail::libbacktrace_error_callback,
&data
)
||
::backtrace_syminfo(
state,
reinterpret_cast<uintptr_t>(addr),
boost::stacktrace::detail::libbacktrace_syminfo_callback,
boost::stacktrace::detail::libbacktrace_error_callback,
&data
);
}
line = data.line;
}
bool prepare_source_location(const void* /*addr*/) {
if (filename.empty() || !line) {
return false;
}
res += " at ";
res += filename;
res += ':';
res += boost::stacktrace::detail::to_dec_array(line).data();
return true;
}
to_string_using_backtrace() BOOST_NOEXCEPT {
state = boost::stacktrace::detail::construct_state(prog_location);
}
};
template <class Base> class to_string_impl_base;
typedef to_string_impl_base<to_string_using_backtrace> to_string_impl;
inline std::string name_impl(const void* addr) {
std::string res;
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};
if (state) {
::backtrace_pcinfo(
state,
reinterpret_cast<uintptr_t>(addr),
boost::stacktrace::detail::libbacktrace_full_callback,
boost::stacktrace::detail::libbacktrace_error_callback,
&data
)
||
::backtrace_syminfo(
state,
reinterpret_cast<uintptr_t>(addr),
boost::stacktrace::detail::libbacktrace_syminfo_callback,
boost::stacktrace::detail::libbacktrace_error_callback,
&data
);
}
if (!res.empty()) {
res = boost::core::demangle(res.c_str());
}
return res;
}
} // namespace detail
std::string frame::source_file() const {
std::string res;
if (!addr_) {
return res;
}
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};
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 {
if (!addr_) {
return 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};
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;
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP

View File

@@ -0,0 +1,105 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_LOCATION_FROM_SYMBOL_HPP
#define BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
# include <dlfcn.h>
#else
# include <boost/winapi/dll.hpp>
#endif
namespace boost { namespace stacktrace { namespace detail {
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
class location_from_symbol {
::Dl_info dli_;
public:
explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT
: dli_()
{
if (!::dladdr(const_cast<void*>(addr), &dli_)) { // `dladdr` on Solaris accepts nonconst addresses
dli_.dli_fname = 0;
}
}
bool empty() const BOOST_NOEXCEPT {
return !dli_.dli_fname;
}
const char* name() const BOOST_NOEXCEPT {
return dli_.dli_fname;
}
};
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::winapi::MEMORY_BASIC_INFORMATION_ mbi;
if (!boost::winapi::VirtualQuery(addr, &mbi, sizeof(mbi))) {
return;
}
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;
}
}
bool empty() const BOOST_NOEXCEPT {
return file_name_[0] == '\0';
}
const char* name() const BOOST_NOEXCEPT {
return file_name_;
}
};
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

@@ -1,11 +1,12 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// 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 <unwind.h>
// No include guards! Intentionally.
int main() {
#ifdef BOOST_STACKTRACE_FUNCTION
# undef BOOST_STACKTRACE_FUNCTION
#endif
}

View File

@@ -0,0 +1,31 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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-2021.
//
// 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

@@ -0,0 +1,59 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_POSIX_IPP
#define BOOST_STACKTRACE_DETAIL_SAFE_DUMP_POSIX_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#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, 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, frames, sizeof(native_frame_ptr_t) * frames_count) == -1) {
return 0;
}
return frames_count;
}
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, frames, frames_count);
::close(fd);
return size;
}
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_SAFE_DUMP_POSIX_IPP

View File

@@ -0,0 +1,66 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_WIN_IPP
#define BOOST_STACKTRACE_DETAIL_SAFE_DUMP_WIN_IPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/safe_dump_to.hpp>
#include <boost/core/noncopyable.hpp>
#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*/, 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 frames_count;
#endif
return 0;
}
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::winapi::GENERIC_WRITE_,
0,
0,
boost::winapi::CREATE_ALWAYS_,
boost::winapi::FILE_ATTRIBUTE_NORMAL_,
0
);
if (fd == boost::winapi::invalid_handle_value) {
return 0;
}
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
#endif // BOOST_STACKTRACE_DETAIL_SAFE_DUMP_WIN_IPP

View File

@@ -0,0 +1,46 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_TO_DEC_ARRAY_HPP
#define BOOST_STACKTRACE_DETAIL_TO_DEC_ARRAY_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/array.hpp>
namespace boost { namespace stacktrace { namespace detail {
// We do not use boost::lexical_cast in this function to reduce module dependencies
inline boost::array<char, 40> to_dec_array(std::size_t value) BOOST_NOEXCEPT {
boost::array<char, 40> ret;
if (!value) {
ret[0] = '0';
ret[1] = '\0';
return ret;
}
std::size_t digits = 0;
for (std::size_t value_copy = value; value_copy; value_copy /= 10) {
++ digits;
}
for (std::size_t i = 1; i <= digits; ++i) {
ret[digits - i] = static_cast<char>('0' + (value % 10));
value /= 10;
}
ret[digits] = '\0';
return ret;
}
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_TO_DEC_ARRAY_HPP

View File

@@ -1,11 +1,11 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// 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_STACKTRACE_TO_HEX_ARRAY_HPP
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_TO_HEX_ARRAY_HPP
#ifndef BOOST_STACKTRACE_DETAIL_TO_HEX_ARRAY_HPP
#define BOOST_STACKTRACE_DETAIL_TO_HEX_ARRAY_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
@@ -51,4 +51,4 @@ inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(const void* ad
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_TO_HEX_ARRAY_HPP
#endif // BOOST_STACKTRACE_DETAIL_TO_HEX_ARRAY_HPP

View File

@@ -0,0 +1,29 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_DEC_CONVERT_HPP
#define BOOST_STACKTRACE_DETAIL_TRY_DEC_CONVERT_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <cstdlib>
namespace boost { namespace stacktrace { namespace detail {
// We do not use boost::lexical_cast in this function to reduce module dependencies
inline bool try_dec_convert(const char* s, std::size_t& res) BOOST_NOEXCEPT {
char* end_ptr = 0;
res = std::strtoul(s, &end_ptr, 10);
return *end_ptr == '\0';
}
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_TRY_DEC_CONVERT_HPP

View File

@@ -0,0 +1,50 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_UNWIND_BASE_IMPLS_HPP
#define BOOST_STACKTRACE_DETAIL_UNWIND_BASE_IMPLS_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/frame.hpp>
namespace boost { namespace stacktrace { namespace detail {
struct to_string_using_nothing {
std::string res;
void prepare_function_name(const void* addr) {
res = boost::stacktrace::frame(addr).name();
}
bool prepare_source_location(const void* /*addr*/) const BOOST_NOEXCEPT {
return false;
}
};
template <class Base> class to_string_impl_base;
typedef to_string_impl_base<to_string_using_nothing> to_string_impl;
inline std::string name_impl(const void* /*addr*/) {
return std::string();
}
} // namespace detail
std::string frame::source_file() const {
return std::string();
}
std::size_t frame::source_line() const {
return 0;
}
}} // namespace boost::stacktrace
#endif // BOOST_STACKTRACE_DETAIL_UNWIND_BASE_IMPLS_HPP

View File

@@ -0,0 +1,46 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2021 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

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -16,142 +16,52 @@
#include <string>
#include <boost/core/explicit_operator_bool.hpp>
#include <boost/stacktrace/detail/backend.hpp>
#include <boost/stacktrace/safe_dump_to.hpp> // boost::stacktrace::detail::native_frame_ptr_t
#include <boost/stacktrace/detail/frame_decl.hpp>
#include <boost/stacktrace/detail/push_options.h>
namespace boost { namespace stacktrace {
/// 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() wil lreturn 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 can extract information from addr at runtime.
///
/// @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 Async-Handler-Safety: Unsafe.
/// @throws std::bad_alloc if not enough memory to construct resulting string.
std::string name() const {
return boost::stacktrace::detail::backend::get_name(address());
}
/// @returns Address of the frame function.
///
/// @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 Async-Handler-Safety: Unsafe.
std::string source_file() const {
return boost::stacktrace::detail::backend::get_source_file(address());
}
/// @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 Async-Handler-Safety: Unsafe.
std::size_t source_line() const {
return boost::stacktrace::detail::backend::get_source_line(address());
}
/// @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); }
/// Hashing support, O(1) complexity; Async-Handler-Safe.
/// Fast hashing support, O(1) complexity; Async-Handler-Safe.
inline std::size_t hash_value(const frame& f) BOOST_NOEXCEPT {
return reinterpret_cast<std::size_t>(f.address());
}
/// Outputs stacktrace::frame in a human readable format to string; unsafe to use in async handlers.
BOOST_STACKTRACE_FUNCTION std::string to_string(const frame& f);
/// Outputs stacktrace::frame in a human readable format to output stream; unsafe to use in async handlers.
template <class CharT, class TraitsT>
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const frame& f) {
std::string name = f.name();
if (!name.empty()) {
os << name;
} else {
os << f.address();
}
const std::size_t source_line = f.source_line();
if (source_line) {
os << " at " << f.source_file() << ':' << source_line;
}
return os;
return os << boost::stacktrace::to_string(f);
}
}} // namespace boost::stacktrace
/// @cond
#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) || defined(BOOST_STACKTRACE_USE_WINDBG_CACHED)
# include <boost/stacktrace/detail/frame_msvc.ipp>
# else
# include <boost/stacktrace/detail/frame_unwind.ipp>
# endif
#endif
/// @endcond
#endif // BOOST_STACKTRACE_FRAME_HPP

View File

@@ -0,0 +1,222 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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_SAFE_DUMP_TO_HPP
#define BOOST_STACKTRACE_SAFE_DUMP_TO_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#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 {
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;
}
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;
}
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.
///
/// @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 including terminating zero frame. To get the actually consumed bytes multiply this value by the sizeof(boost::stacktrace::frame::native_frame_ptr_t)
///
/// @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::this_thread_frames::safe_dump_to_impl(memory, size, 0);
}
/// @brief Stores current function call sequence into the memory.
///
/// @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 including terminating zero frame. To get the actually consumed bytes multiply this value by the sizeof(boost::stacktrace::frame::native_frame_ptr_t)
///
/// @param skip How many top calls to skip and do not store.
///
/// @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(std::size_t skip, void* memory, std::size_t size) BOOST_NOEXCEPT {
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 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 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::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 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 including terminating zero frame.
///
/// @param skip How many top calls to skip and do not store.
///
/// @param max_depth Max call sequence depth to collect.
///
/// @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::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 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 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 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 including terminating zero frame.
///
/// @param skip How many top calls to skip and do not store.
///
/// @param max_depth Max call sequence depth to collect.
///
/// @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, platform_specific_descriptor fd) BOOST_NOEXCEPT;
#elif defined(BOOST_WINDOWS)
BOOST_FORCEINLINE std::size_t safe_dump_to(void* fd) BOOST_NOEXCEPT {
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::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::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::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
}
#endif
}} // 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

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -13,77 +13,206 @@
#endif
#include <boost/core/explicit_operator_bool.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/container_hash/hash_fwd.hpp>
#include <iosfwd>
#include <string>
#include <vector>
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
# include <type_traits>
#endif
#include <boost/stacktrace/stacktrace_fwd.hpp>
#include <boost/stacktrace/detail/backend.hpp>
#include <boost/stacktrace/frame.hpp>
#include <boost/stacktrace/const_iterator.hpp>
#include <boost/stacktrace/safe_dump_to.hpp>
#include <boost/stacktrace/detail/frame_decl.hpp>
#ifdef BOOST_INTEL
# pragma warning(push)
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
#endif
namespace boost { namespace stacktrace {
/// Class that on construction copies minimal information about call stack into its internals and provides access to that information.
/// @tparam Depth Max stack frames count that this class may hold. Equal to basic_stacktrace::max_depth.
template <std::size_t Depth>
/// @tparam Allocator Allocator to use during stack capture.
template <class Allocator>
class basic_stacktrace {
std::vector<boost::stacktrace::frame, Allocator> impl_;
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
/// @cond
void* impl_[Depth ? Depth : 1];
boost::stacktrace::detail::backend back_;
void fill(native_frame_ptr_t* begin, std::size_t size) {
if (!size) {
return;
}
impl_.reserve(static_cast<std::size_t>(size));
for (std::size_t i = 0; i < size; ++i) {
if (!begin[i]) {
return;
}
impl_.push_back(
frame(begin[i])
);
}
}
static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) BOOST_NOEXCEPT {
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
}
BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) {
BOOST_CONSTEXPR_OR_CONST std::size_t buffer_size = 128;
if (!max_depth) {
return;
}
BOOST_TRY {
{ // Fast path without additional allocations
native_frame_ptr_t buffer[buffer_size];
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size < max_depth ? buffer_size : max_depth, frames_to_skip + 1);
if (buffer_size > frames_count || frames_count == max_depth) {
fill(buffer, frames_count);
return;
}
}
// Failed to fit in `buffer_size`. Allocating memory:
#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[0], buf.size() < max_depth ? buf.size() : max_depth, frames_to_skip + 1);
if (buf.size() > frames_count || frames_count == max_depth) {
fill(&buf[0], frames_count);
return;
}
buf.resize(buf.size() * 2);
} while (buf.size() < buf.max_size()); // close to `true`, but suppresses `C4127: conditional expression is constant`.
} BOOST_CATCH (...) {
// ignore exception
}
BOOST_CATCH_END
}
/// @endcond
public:
/// Max stack frames count that this class may hold. Equal to Depth template parameter.
BOOST_STATIC_CONSTEXPR std::size_t max_depth = Depth;
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;
typedef frame reference;
typedef boost::stacktrace::const_iterator iterator;
typedef boost::stacktrace::const_iterator const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
/// @brief Stores the current function call sequence inside the class.
/// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) for noop backend.
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Depends on backend, see "Build, Macros and Backends" section.
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
BOOST_FORCEINLINE basic_stacktrace() BOOST_NOEXCEPT
: impl_()
, back_(impl_, Depth)
{
init(0 , static_cast<std::size_t>(-1));
}
/// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
///
/// @param a Allocator that would be passed to underlying storeage.
BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) BOOST_NOEXCEPT
: impl_(a)
{
init(0 , static_cast<std::size_t>(-1));
}
/// @brief Stores [skip, skip + max_depth) of the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
///
/// @param skip How many top calls to skip and do not store in *this.
///
/// @param max_depth Max call sequence depth to collect.
///
/// @param a Allocator that would be passed to underlying storeage.
///
/// @throws Nothing. Note that default construction of allocator may throw, however it is
/// performed outside the constructor and exception in `allocator_type()` would not result in calling `std::terminate`.
BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) BOOST_NOEXCEPT
: impl_(a)
{
init(skip , max_depth);
}
/// @b Complexity: O(st.size())
///
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
basic_stacktrace(const basic_stacktrace& st)
: impl_(st.impl_)
{}
/// @b Complexity: O(st.size())
///
/// @b Async-Handler-Safety: Safe.
basic_stacktrace(const basic_stacktrace& st) BOOST_NOEXCEPT
: impl_()
, back_(st.back_, impl_)
{}
/// @b Complexity: O(st.size())
///
/// @b Async-Handler-Safety: Safe.
basic_stacktrace& operator=(const basic_stacktrace& st) BOOST_NOEXCEPT {
back_ = st.back_;
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
basic_stacktrace& operator=(const basic_stacktrace& st) {
impl_ = st.impl_;
return *this;
}
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
~basic_stacktrace() BOOST_NOEXCEPT {}
/// @b Async-Handler-Safety: Safe if Allocator::deallocate is async signal safe.
~basic_stacktrace() BOOST_NOEXCEPT = default;
#endif
#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) 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)
#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.
///
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
std::size_t size() const BOOST_NOEXCEPT {
return back_.size();
size_type size() const BOOST_NOEXCEPT {
return impl_.size();
}
/// @param frame_no Zero based index of frame to return. 0
@@ -91,47 +220,46 @@ public:
/// index close to this->size() contains function `main()`.
/// @returns frame that references the actual frame info, stored inside *this.
///
/// @b Complexity: Amortized O(1), O(1) for noop backend.
/// @b Complexity: O(1).
///
/// @b Async-Handler-Safety: Safe.
frame operator[](std::size_t frame_no) const BOOST_NOEXCEPT {
return *(cbegin() + frame_no);
const_reference operator[](std::size_t frame_no) const BOOST_NOEXCEPT {
return impl_[frame_no];
}
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator begin() const BOOST_NOEXCEPT { return impl_.begin(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator cbegin() const BOOST_NOEXCEPT { return impl_.begin(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator end() const BOOST_NOEXCEPT { return impl_.end(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator cend() const BOOST_NOEXCEPT { return impl_.end(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator begin() const BOOST_NOEXCEPT { return const_iterator(&back_, 0); }
const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator cbegin() const BOOST_NOEXCEPT { return const_iterator(&back_, 0); }
const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator end() const BOOST_NOEXCEPT { return const_iterator(&back_, size()); }
const_reverse_iterator rend() const BOOST_NOEXCEPT { return impl_.rend(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(&back_, size()); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, 0) ); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, 0) ); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_reverse_iterator rend() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, size()) ); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_reverse_iterator crend() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(&back_, size()) ); }
const_reverse_iterator crend() const BOOST_NOEXCEPT { return impl_.rend(); }
/// @brief Allows to check that stack trace capturing was successful.
@@ -142,7 +270,6 @@ public:
/// @b Async-Handler-Safety: Safe.
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
/// @brief Allows to check that stack trace failed.
/// @returns `true` if `this->size() == 0`
///
@@ -151,83 +278,145 @@ public:
/// @b Async-Handler-Safety: Safe.
bool empty() const BOOST_NOEXCEPT { return !size(); }
/// @brief Compares stacktraces for less, order is platform dependant.
///
/// @b Complexity: Amortized O(1); worst case O(size())
///
/// @b Async-Handler-Safety: Safe.
bool operator< (const basic_stacktrace& rhs) const BOOST_NOEXCEPT {
return back_ < rhs.back_;
}
/// @brief Compares stacktraces for equality.
///
/// @b Complexity: Amortized O(1); worst case O(size())
///
/// @b Async-Handler-Safety: Safe.
bool operator==(const basic_stacktrace& rhs) const BOOST_NOEXCEPT {
return back_ == rhs.back_;
}
/// @brief Returns hashed code of the stacktrace.
///
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
std::size_t hash_code() const BOOST_NOEXCEPT { return back_.hash_code(); }
/// @cond
bool operator!() const BOOST_NOEXCEPT { return !size(); }
/// @endcond
const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const BOOST_NOEXCEPT {
return impl_;
}
/// Constructs stacktrace from basic_istreamable that references the dumped stacktrace. Terminating zero frame is discarded.
///
/// @b Complexity: O(N)
template <class Char, class Trait>
static basic_stacktrace from_dump(std::basic_istream<Char, Trait>& in, const allocator_type& a = allocator_type()) {
typedef typename std::basic_istream<Char, Trait>::pos_type pos_type;
basic_stacktrace ret(0, 0, a);
// reserving space
const pos_type pos = in.tellg();
in.seekg(0, in.end);
const std::size_t frames_count = frames_count_from_buffer_size(static_cast<std::size_t>(in.tellg()));
in.seekg(pos);
if (!frames_count) {
return ret;
}
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_.push_back(frame(ptr));
}
return ret;
}
/// Constructs stacktrace from raw memory dump. Terminating zero frame is discarded.
///
/// @param begin Begining of the memory where the stacktrace was saved using the boost::stacktrace::safe_dump_to
///
/// @param buffer_size_in_bytes Size of the memory. Usually the same value that was passed to the boost::stacktrace::safe_dump_to
///
/// @b Complexity: O(size) in worst case
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 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 native_frame_ptr_t* const last = first + frames_count;
ret.impl_.reserve(frames_count);
for (; first != last; ++first) {
if (!*first) {
break;
}
ret.impl_.push_back(frame(*first));
}
return ret;
}
};
/// @brief Compares stacktraces for less, order is platform dependent.
///
/// @b Complexity: Amortized O(1); worst case O(size())
///
/// @b Async-Handler-Safety: Safe.
template <class Allocator1, class Allocator2>
bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
return lhs.size() < rhs.size() || (lhs.size() == rhs.size() && lhs.as_vector() < rhs.as_vector());
}
/// @brief Compares stacktraces for equality.
///
/// @b Complexity: Amortized O(1); worst case O(size())
///
/// @b Async-Handler-Safety: Safe.
template <class Allocator1, class Allocator2>
bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
return lhs.as_vector() == rhs.as_vector();
}
/// Comparison operators that provide platform dependant ordering and have amortized O(1) complexity; O(size()) worst case complexity; are Async-Handler-Safe.
template <std::size_t Depth>
bool operator> (const basic_stacktrace<Depth>& lhs, const basic_stacktrace<Depth>& rhs) BOOST_NOEXCEPT {
template <class Allocator1, class Allocator2>
bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
return rhs < lhs;
}
template <std::size_t Depth>
bool operator<=(const basic_stacktrace<Depth>& lhs, const basic_stacktrace<Depth>& rhs) BOOST_NOEXCEPT {
template <class Allocator1, class Allocator2>
bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
return !(lhs > rhs);
}
template <std::size_t Depth>
bool operator>=(const basic_stacktrace<Depth>& lhs, const basic_stacktrace<Depth>& rhs) BOOST_NOEXCEPT {
template <class Allocator1, class Allocator2>
bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
return !(lhs < rhs);
}
template <std::size_t Depth>
bool operator!=(const basic_stacktrace<Depth>& lhs, const basic_stacktrace<Depth>& rhs) BOOST_NOEXCEPT {
template <class Allocator1, class Allocator2>
bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
return !(lhs == rhs);
}
/// Hashing support, O(1) complexity; Async-Handler-Safe.
template <std::size_t Depth>
std::size_t hash_value(const basic_stacktrace<Depth>& st) BOOST_NOEXCEPT {
return st.hash_code();
/// 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().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, std::size_t Depth>
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Depth>& bt) {
const std::streamsize w = os.width();
const std::size_t frames = bt.size();
for (std::size_t i = 0; i < frames; ++i) {
os.width(2);
os << i;
os.width(w);
os << "# ";
os << bt[i];
os << '\n';
/// Returns std::string with the stacktrace in a human readable format; unsafe to use in async handlers.
template <class Allocator>
std::string to_string(const basic_stacktrace<Allocator>& bt) {
if (!bt) {
return std::string();
}
return os;
return boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size());
}
typedef basic_stacktrace<BOOST_STACKTRACE_DEFAULT_MAX_DEPTH> stacktrace;
/// Outputs stacktrace in a human readable format to the output stream `os`; 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::to_string(bt);
}
/// This is the typedef to use unless you'd like to provide a specific allocator to boost::stacktrace::basic_stacktrace.
typedef basic_stacktrace<> stacktrace;
}} // namespace boost::stacktrace
#ifdef BOOST_INTEL
# pragma warning(pop)
#endif
#endif // BOOST_STACKTRACE_STACKTRACE_HPP

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -8,32 +8,21 @@
#define BOOST_STACKTRACE_STACKTRACE_FWD_HPP
#include <cstddef>
#include <memory>
/// @file stacktrace_fwd.hpp This header contains only forward declarations of
/// boost::stacktrace::frame, boost::stacktrace::const_iterator, boost::stacktrace::basic_stacktrace
/// boost::stacktrace::frame, boost::stacktrace::basic_stacktrace, boost::stacktrace::stacktrace
/// and does not include any other Boost headers.
#ifndef BOOST_STACKTRACE_DEFAULT_MAX_DEPTH
/// You may define this macro to some positive integer to limit the max stack frames count for the boost::stacktrace::stacktrace class.
/// This macro does not affect the boost::stacktrace::basic_stacktrace.
///
/// @b Default: 100
#define BOOST_STACKTRACE_DEFAULT_MAX_DEPTH 100
#endif
/// @cond
namespace boost { namespace stacktrace {
class frame;
class const_iterator;
template <std::size_t Depth>
class basic_stacktrace;
typedef basic_stacktrace<BOOST_STACKTRACE_DEFAULT_MAX_DEPTH> stacktrace;
template <class Allocator = std::allocator<frame> > class basic_stacktrace;
typedef basic_stacktrace<> stacktrace;
}} // namespace boost::stacktrace
/// @endcond
#endif // BOOST_STACKTRACE_STACKTRACE_FWD_HPP

35
index.html Normal file
View File

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<!--
Copyright (c) 2014-2021 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=https://www.boost.org/doc/libs/master/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="https://www.boost.org/doc/libs/master/doc/html/stacktrace.html">https://www.boost.org/doc/libs/master/doc/html/stacktrace.html</a>
</p>
<p>
&copy; 2014-2021 Antony Polukhin
</p>
</body>
</html>

View File

@@ -8,6 +8,7 @@
"Antony Polukhin <antoshkka -at- gmail.com>"
],
"description": "Gather, store, copy and print backtraces.",
"std": [ "c++23" ],
"category": [
"System", "Correctness"
]

16
src/addr2line.cpp Normal file
View File

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

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -7,4 +7,10 @@
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_BACKTRACE
#define BOOST_STACKTRACE_LINK
#include <boost/stacktrace/detail/backend.ipp>
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <boost/stacktrace/detail/frame_unwind.ipp>
#include <boost/stacktrace/safe_dump_to.hpp>

15
src/basic.cpp Normal file
View File

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

View File

@@ -1,10 +1,11 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
#define BOOST_STACKTRACE_USE_NOOP
#define BOOST_STACKTRACE_LINK
#include <boost/stacktrace/detail/backend.ipp>
#define BOOST_STACKTRACE_USE_NOOP
#include <boost/stacktrace/detail/frame_noop.ipp>
#include <boost/stacktrace/detail/safe_dump_noop.ipp>

View File

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

View File

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

View File

@@ -1,64 +1,245 @@
# Copyright (C) 2016, Antony Polukhin.
# Copyright (C) 2016-2021, Antony Polukhin.
#
# Use, modification and distribution is subject to the Boost Software License,
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
import ../../config/checks/config : requires ;
lib dl : : <link>shared ;
lib gcc_s ;
lib Dbghelp ;
lib rt ;
lib Dbgeng ;
lib ole32 ;
local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ;
lib backtrace
:
: <search>$(LIBBACKTRACE_PATH)/lib <link>static
:
: <include>$(LIBBACKTRACE_PATH)/include
;
project
: requirements
<toolset>msvc:<asynch-exceptions>on
<toolset>intel:<cxxflags>-wd2196
<target-os>linux:<linkflags>-lpthread
<warnings>all
<debug-symbols>on
<test-info>always_show_run_output
<target-os>linux:<cxxflags>"-fvisibility=hidden"
<visibility>hidden
;
local FORCE_SYMBOL_EXPORT = <target-os>freebsd:<linkflags>"-rdynamic" <target-os>solaris:<linkflags>"-Bdynamic" <target-os>aix:<linkflags>"-rdynamic"
<target-os>qnxnto,<toolset>qcc:<linkflags>"-Bdynamic" <target-os>qnxnto,<toolset>gcc:<linkflags>"-rdynamic"
<target-os>android:<linkflags>"-rdynamic" <target-os>linux:<linkflags>"-rdynamic" <target-os>darwin,<toolset>gcc:<linkflags>"-dynamic"
<target-os>darwin,<toolset>clang:<linkflags>"-rdynamic" <target-os>iphone:<linkflags>"-rdynamic"
<define>BOOST_STACKTRACE_TEST_EXPORTS_TABLE_USAGE ;
local BT_DEPS = <target-os>linux:<library>dl [ check-target-builds ../build//backtrace : : <build>no ] ;
local UNWD_DEPS = <target-os>linux:<library>dl [ check-target-builds ../build//unwind : : <build>no ] ;
local WIND_DEPS = <library>Dbghelp [ check-target-builds ../build//WinDbg : : <build>no ] ;
local NOOP_DEPS = ;
local AUTO_DEPS = <target-os>linux:<library>dl [ check-target-builds ../build//WinDbg : <library>Dbghelp ] ;
local BT_DEPS = <target-os>linux:<library>dl <library>backtrace [ check-target-builds ../build//libbacktrace : : <build>no ] ;
local AD2L_DEPS = <target-os>linux:<library>dl [ check-target-builds ../build//addr2line : : <build>no ]
<define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL # Some old versions of addr2line may not produce readable names for a modern compilers
;
local WIND_DEPS = <library>Dbgeng <library>ole32 [ check-target-builds ../build//WinDbg : : <build>no ] ;
local WICA_DEPS = <library>Dbgeng <library>ole32 [ check-target-builds ../build//WinDbgCached : : <build>no ] ;
local NOOP_DEPS = ;
local BASIC_DEPS = <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_UNWD = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_unwind $(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_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) $(FORCE_SYMBOL_EXPORT) ;
# 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) ;
lib test_impl_lib_backtrace : test_impl.cpp : $(LINKSHARED_BT) ;
lib test_impl_lib_unwind : test_impl.cpp : $(LINKSHARED_UNWD) ;
lib test_impl_lib_windbg : test_impl.cpp : $(LINKSHARED_WIND) ;
lib test_impl_lib_noop : test_impl.cpp : $(LINKSHARED_NOOP) ;
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_UNWIND $(UNWD_DEPS) : unwind_ho ]
[ run test.cpp test_impl.cpp : : : <define>BOOST_STACKTRACE_USE_WINDBG $(WIND_DEPS) : windbg_ho ]
[ run test_noop.cpp test_impl.cpp : : : <define>BOOST_STACKTRACE_USE_NOOP $(NOOP_DEPS) : noop_ho ]
[ run test.cpp test_impl.cpp : : : $(AUTO_DEPS) : autodetect_ho ]
# Test with shared linked backends
[ run test.cpp : : : <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) : backtrace_lib ]
[ run test.cpp : : : <library>.//test_impl_lib_unwind $(LINKSHARED_UNWD) : unwind_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 ]
# 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 $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) : basic_ho ]
[ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(BASIC_DEPS) : basic_ho_empty ]
# 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 $(FORCE_SYMBOL_EXPORT) $(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 $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) : basic_ho_no_dbg ]
[ run test.cpp test_impl.cpp : : : <debug-symbols>off <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(BASIC_DEPS) : basic_ho_no_dbg_empty ]
[ 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) $(FORCE_SYMBOL_EXPORT) : 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 ]
[ run test_num_conv.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 ]
{
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_BT) : backtrace_$(p[1]:B) ] ;
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_UNWD) : unwind_$(p[1]:B) ] ;
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_WIND) : windbg_$(p[1]:B) ] ;
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_NOOP) : noop_$(p[1]:B) ] ;
stacktrace_tests += [ run $(p) : : : $(AUTO_DEPS) : autodetect_$(p[1]:B) ] ;
local target_name = $(p[1]:B) ;
local additional_dependency = ;
if $(target_name) = "terminate_handler"
{
additional_dependency = <library>/boost/filesystem//boost_filesystem <library>/boost/system//boost_system <target-os>linux:<library>rt ;
}
if $(target_name) = "throwing_st"
{
additional_dependency = [ requires rtti ] ;
}
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 ] ;
}
# Very long tests for detecting memory leaks and corruptions
test-suite stacktrace_torture
:
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : torture_backtrace_ho ]
#[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_ADDR2LINE $(AD2L_DEPS) : torture_addr2line_ho ]
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on $(WIND_DEPS) : torture_windbg_ho ]
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_WINDBG_CACHED $(WICA_DEPS) : torture_windbg_cached_ho ]
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) : torture_basic_ho ]
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(BASIC_DEPS) : torture_basic_ho_empty ]
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) : torture_backtrace_lib ]
#[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_addr2line $(LINKSHARED_AD2L) : torture_addr2line_lib ]
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg $(LINKSHARED_WIND) : torture_windbg_lib ]
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg_cached $(LINKSHARED_WIND_CACHED) : torture_windbg_cached_lib ]
[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_basic $(LINKSHARED_BASIC) : torture_basic_lib ]
;
explicit stacktrace_torture ;

View File

@@ -2,27 +2,23 @@
# 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 2016.
# Copyright Antony Polukhin 2016-2021.
#
# 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 #2
# File revision #5
init:
- set BRANCH_TO_TEST=%APPVEYOR_REPO_BRANCH%
- set BOOST_REMOVE=stacktrace
os: Visual Studio 2015
configuration: Debug
platform: x64
- set BRANCH_TO_TEST=%APPVEYOR_REPO_BRANCH% # Change to branch you wish to test. Use %APPVEYOR_REPO_BRANCH% for current branch.
- set BOOST_REMOVE=stacktrace # Remove this folder from lib from full clone of Boost. If you are testing `any` repo, write here `any`.
###############################################################################################################
# From this point and below code is same for all the Boost libs
###############################################################################################################
version: 1.61.{build}-{branch}
version: 1.64.{build}-{branch}
# branches to build
branches:
@@ -32,9 +28,8 @@ branches:
skip_tags: true
before_build:
# Set this to the name of the library
- set PROJECT_TO_TEST=%APPVEYOR_PROJECT_NAME%
- echo "Testing %PROJECT_TO_TEST%"
- set PATH=%PATH%;C:\\MinGW\\bin
- echo "Testing %APPVEYOR_PROJECT_NAME%"
# Cloning Boost libraries (fast nondeep cloning)
- set BOOST=C:/boost-local
- git init %BOOST%
@@ -42,24 +37,22 @@ 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:
test_script:
- ..\..\..\b2.exe address-model=64 architecture=x86 cxxflags="-DBOOST_TRAVISCI_BUILD" -sBOOST_BUILD_PATH=.
- ..\..\..\b2.exe address-model=32 architecture=x86 toolset=msvc,gcc cxxflags="-DBOOST_TRAVISCI_BUILD" -sBOOST_BUILD_PATH=.
after_test:
on_success:

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -10,47 +10,74 @@
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <cctype>
#include <boost/core/lightweight_test.hpp>
#include <boost/functional/hash.hpp>
#include "test_impl.hpp"
using boost::stacktrace::stacktrace;
using boost::stacktrace::frame;
#ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_ST_API BOOST_SYMBOL_IMPORT
#else
# define BOOST_ST_API
#endif
BOOST_ST_API std::pair<stacktrace, stacktrace> foo2(int i);
BOOST_ST_API std::pair<stacktrace, stacktrace> foo1(int i);
BOOST_ST_API stacktrace return_from_nested_namespaces();
BOOST_ST_API boost::stacktrace::basic_stacktrace<4> bar1();
BOOST_ST_API boost::stacktrace::basic_stacktrace<4> bar2();
#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_TEST_SHOULD_OUTPUT_READABLE_NAMES 0
#else
# define BOOST_STACKTRACE_TEST_SHOULD_OUTPUT_READABLE_NAMES 1
#endif
void test_deeply_nested_namespaces() {
std::stringstream ss;
ss << return_from_nested_namespaces();
std::cout << ss.str() << '\n';
#if BOOST_STACKTRACE_TEST_SHOULD_OUTPUT_READABLE_NAMES
BOOST_TEST(ss.str().find("main") != std::string::npos);
#if defined(BOOST_STACKTRACE_DYN_LINK)
BOOST_TEST(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos
|| ss.str().find("return_from_nested_namespaces") != std::string::npos);
|| ss.str().find("1# return_from_nested_namespaces") != std::string::npos); // GCC with -O1 has strange inlining, so this line is true while the prev one is false.
BOOST_TEST(ss.str().find("return_from_nested_namespaces") != std::string::npos);
#endif
stacktrace ns1 = return_from_nested_namespaces();
BOOST_TEST(ns1 != return_from_nested_namespaces()); // Different addresses in test_deeply_nested_namespaces() function
}
void test_nested() {
std::size_t count_unprintable_chars(const std::string& s) {
std::size_t result = 0;
for (std::size_t i = 0; i < s.size(); ++i) {
result += (std::isprint(s[i]) ? 0 : 1);
}
std::pair<stacktrace, stacktrace> res = foo2(15);
return result;
}
void test_frames_string_data_validity() {
stacktrace trace = return_from_nested_namespaces();
for (std::size_t i = 0; i < trace.size(); ++i) {
BOOST_TEST_EQ(count_unprintable_chars(trace[i].source_file()), 0);
BOOST_TEST_EQ(count_unprintable_chars(trace[i].name()), 0);
}
BOOST_TEST(to_string(trace).find('\0') == std::string::npos);
}
// Template parameter Depth is to produce different functions on each Depth. This simplifies debugging when one of the tests catches error
template <std::size_t Depth>
void test_nested(bool print = true) {
std::pair<stacktrace, stacktrace> res = function_from_library(Depth, function_from_main_translation_unit);
std::stringstream ss1, ss2;
ss1 << res.first;
ss2 << res.second;
std::cout << "'" << ss1.str() << "'\n\n" << ss2.str() << std::endl;
if (print) {
std::cout << "'" << ss1.str() << "'\n\n" << ss2.str() << std::endl;
}
BOOST_TEST(!ss1.str().empty());
BOOST_TEST(!ss2.str().empty());
@@ -59,17 +86,20 @@ void test_nested() {
BOOST_TEST(ss1.str().find(" 1# ") != std::string::npos);
BOOST_TEST(ss2.str().find(" 1# ") != std::string::npos);
BOOST_TEST(ss1.str().find(" in ") != std::string::npos);
BOOST_TEST(ss2.str().find(" in ") != std::string::npos);
#if BOOST_STACKTRACE_TEST_SHOULD_OUTPUT_READABLE_NAMES
BOOST_TEST(ss1.str().find("main") != std::string::npos);
BOOST_TEST(ss2.str().find("main") != std::string::npos);
#if defined(BOOST_STACKTRACE_DYN_LINK) || !defined(BOOST_STACKTRACE_USE_BACKTRACE)
BOOST_TEST(ss1.str().find("foo1") != std::string::npos);
BOOST_TEST(ss1.str().find("foo2") != std::string::npos);
BOOST_TEST(ss2.str().find("foo1") != std::string::npos);
BOOST_TEST(ss2.str().find("foo2") != std::string::npos);
BOOST_TEST(ss1.str().find("function_from_library") != std::string::npos);
BOOST_TEST(ss2.str().find("function_from_library") != std::string::npos);
BOOST_TEST(ss1.str().find("function_from_main_translation_unit") != std::string::npos);
BOOST_TEST(ss2.str().find("function_from_main_translation_unit") != std::string::npos);
#endif
//BOOST_TEST(false);
}
template <class Bt>
@@ -79,6 +109,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);
@@ -115,60 +150,37 @@ 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()));
BOOST_TEST(st.size() == static_cast<std::size_t>(st.cend() - st.begin()));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.rend(), st.rbegin())));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.rend(), st.crbegin())));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.crend(), st.crbegin())));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.crend(), st.rbegin())));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.rbegin(), st.rend())));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.crbegin(), st.rend())));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.crbegin(), st.crend())));
BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.rbegin(), st.crend())));
boost::stacktrace::stacktrace::iterator it = st.begin();
@@ -178,7 +190,7 @@ void test_iterators() {
void test_frame() {
stacktrace nst = return_from_nested_namespaces();
stacktrace st;
stacktrace st = make_some_stacktrace1();
const std::size_t min_size = (nst.size() < st.size() ? nst.size() : st.size());
BOOST_TEST(min_size > 2);
@@ -190,15 +202,22 @@ void test_frame() {
BOOST_TEST(st[i] <= st[i]);
BOOST_TEST(st[i] >= st[i]);
frame fv = nst[2];
frame fv = nst[i];
BOOST_TEST(fv);
if (i >= 2 && i < min_size - 3) { // Begin and end of the trace may match, skipping them
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));
BOOST_TEST(st[i].source_line() == 0 || st[i].source_file() != fv.source_file());
#endif
if (st[i].source_line()) {
BOOST_TEST(st[i].source_file() != fv.source_file() || st[i].source_line() != fv.source_line());
}
BOOST_TEST(st[i]);
}
@@ -208,14 +227,16 @@ void test_frame() {
boost::stacktrace::frame empty_frame;
BOOST_TEST(!empty_frame);
BOOST_TEST(empty_frame.source_file() == "");
BOOST_TEST(empty_frame.name() == "");
BOOST_TEST(empty_frame.source_line() == 0);
BOOST_TEST_EQ(empty_frame.source_file(), "");
BOOST_TEST_EQ(empty_frame.name(), "");
BOOST_TEST_EQ(empty_frame.source_line(), 0);
}
// Template parameter bool BySkip is to produce different functions on each BySkip. This simplifies debugging when one of the tests catches error
template <bool BySkip>
void test_empty_basic_stacktrace() {
typedef boost::stacktrace::basic_stacktrace<0> st_t;
st_t st;
typedef boost::stacktrace::stacktrace st_t;
st_t st = BySkip ? st_t(100500, 1024) : st_t(0, 0);
BOOST_TEST(!st);
BOOST_TEST(st.empty());
@@ -230,26 +251,32 @@ void test_empty_basic_stacktrace() {
BOOST_TEST(st.crbegin() == st.crend());
BOOST_TEST(st.rbegin() == st.crend());
BOOST_TEST(hash_value(st) == hash_value(st_t()));
BOOST_TEST(st == st_t());
BOOST_TEST(!(st < st_t()));
BOOST_TEST(!(st > st_t()));
BOOST_TEST(hash_value(st) == hash_value(st_t(0, 0)));
BOOST_TEST(st == st_t(0, 0));
BOOST_TEST(!(st < st_t(0, 0)));
BOOST_TEST(!(st > st_t(0, 0)));
}
int main() {
test_deeply_nested_namespaces();
test_nested();
test_frames_string_data_validity();
test_nested<15>();
test_comparisons();
test_iterators();
test_frame();
test_empty_basic_stacktrace();
test_empty_basic_stacktrace<true>();
test_empty_basic_stacktrace<false>();
BOOST_TEST(&bar1 != &bar2);
boost::stacktrace::basic_stacktrace<4> b1 = bar1();
BOOST_TEST(&make_some_stacktrace1 != &make_some_stacktrace2);
boost::stacktrace::stacktrace b1 = make_some_stacktrace1();
BOOST_TEST(b1.size() == 4);
boost::stacktrace::basic_stacktrace<4> b2 = bar2();
boost::stacktrace::stacktrace b2 = make_some_stacktrace2();
BOOST_TEST(b2.size() == 4);
test_comparisons_base(bar1(), bar2());
test_comparisons_base(make_some_stacktrace1(), make_some_stacktrace2());
test_nested<260>(false);
BOOST_TEST(boost::stacktrace::stacktrace(0, 1).size() == 1);
BOOST_TEST(boost::stacktrace::stacktrace(1, 1).size() == 1);
return boost::report_errors();
}

View File

@@ -1,39 +1,15 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/stacktrace.hpp>
#include <stdexcept>
#define BOOST_STACKTRACE_TEST_IMPL_LIB 1
#include "test_impl.hpp"
using namespace boost::stacktrace;
#ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_ST_API BOOST_SYMBOL_EXPORT
#else
# define BOOST_ST_API
#endif
BOOST_ST_API BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo1(int i);
BOOST_ST_API BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo2(int i);
std::pair<stacktrace, stacktrace> foo1(int i) {
if (i) {
return foo2(i - 1);
}
std::pair<stacktrace, stacktrace> ret;
try {
throw std::logic_error("test");
} catch (const std::logic_error& /*e*/) {
ret.second = stacktrace();
return ret;
}
}
std::pair<stacktrace, stacktrace> foo2(int i) {
BOOST_ST_API BOOST_NOINLINE std::pair<stacktrace, stacktrace> function_from_library(int i, foo1_t foo1) {
if (i) {
return foo1(--i);
} else {
@@ -66,13 +42,31 @@ BOOST_ST_API BOOST_NOINLINE stacktrace return_from_nested_namespaces() {
return get_backtrace_from_nested_namespaces();
}
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::basic_stacktrace<4> bar1() {
boost::stacktrace::basic_stacktrace<4> result;
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace make_some_stacktrace1_impl(int d = 0) {
boost::stacktrace::stacktrace result(0, 4);
if (result.size() < 4) {
if (d > 4) throw std::runtime_error("Stack is not growing in test OR stacktrace fails to work in `bar1` function.");
return make_some_stacktrace1_impl(d + 1);
}
return result;
}
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::basic_stacktrace<4> bar2() {
boost::stacktrace::basic_stacktrace<4> result;
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace make_some_stacktrace2_impl(int d = 0) {
boost::stacktrace::stacktrace result(0, 4);
if (result.size() < 4) {
if (d > 4) throw std::runtime_error("Stack is not growing in test OR stacktrace fails to work in `bar2` function.");
return make_some_stacktrace2_impl(d + 1);
}
return result;
}
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace make_some_stacktrace1() {
boost::stacktrace::stacktrace result = make_some_stacktrace1_impl();
return result;
}
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace make_some_stacktrace2() {
boost::stacktrace::stacktrace result = make_some_stacktrace2_impl();
return result;
}

58
test/test_impl.hpp Normal file
View File

@@ -0,0 +1,58 @@
// Copyright Antony Polukhin, 2016-2021.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/stacktrace/stacktrace.hpp>
#if defined(BOOST_LEXICAL_CAST_TRY_LEXICAL_CONVERT_HPP) || defined(BOOST_LEXICAL_CAST_BAD_LEXICAL_CAST_HPP)
#error "LexicalCast headers leaked into the boost/stacktrace/stacktrace.hpp"
#endif
#if !defined(BOOST_USE_WINDOWS_H) && defined(_WINDOWS_H)
#error "windows.h header leaked into the boost/stacktrace/stacktrace.hpp"
#endif
#include <stdexcept>
using namespace boost::stacktrace;
#ifdef BOOST_STACKTRACE_DYN_LINK
# ifdef BOOST_STACKTRACE_TEST_IMPL_LIB
# define BOOST_ST_API BOOST_SYMBOL_EXPORT
# else
# define BOOST_ST_API BOOST_SYMBOL_IMPORT
# endif
#else
# ifdef BOOST_STACKTRACE_TEST_EXPORTS_TABLE_USAGE
# define BOOST_ST_API BOOST_SYMBOL_VISIBLE
# else
# define BOOST_ST_API
# endif
#endif
typedef std::pair<boost::stacktrace::stacktrace, boost::stacktrace::stacktrace> st_pair;
typedef st_pair (*foo1_t)(int i);
BOOST_ST_API st_pair function_from_library(int i, foo1_t foo1);
BOOST_ST_API boost::stacktrace::stacktrace return_from_nested_namespaces();
BOOST_ST_API boost::stacktrace::stacktrace make_some_stacktrace1();
BOOST_ST_API boost::stacktrace::stacktrace make_some_stacktrace2();
#ifdef BOOST_STACKTRACE_TEST_EXPORTS_TABLE_USAGE
BOOST_SYMBOL_VISIBLE
#endif
inline st_pair function_from_main_translation_unit(int i) {
if (i) {
return function_from_library(i - 1, function_from_main_translation_unit);
}
std::pair<stacktrace, stacktrace> ret;
try {
throw std::logic_error("test");
} catch (const std::logic_error& /*e*/) {
ret.second = stacktrace();
return ret;
}
}

View File

@@ -1,41 +1,33 @@
// Copyright Antony Polukhin, 2016.
// Copyright Antony Polukhin, 2016-2021.
//
// 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 "test_impl.hpp"
#include <boost/stacktrace.hpp>
#include <boost/core/lightweight_test.hpp>
#include <stdexcept>
#include <boost/functional/hash.hpp>
using boost::stacktrace::stacktrace;
BOOST_SYMBOL_IMPORT std::pair<stacktrace, stacktrace> foo2(int i);
BOOST_SYMBOL_IMPORT std::pair<stacktrace, stacktrace> foo1(int i);
BOOST_SYMBOL_IMPORT stacktrace return_from_nested_namespaces();
using boost::stacktrace::frame;
void test_deeply_nested_namespaces() {
BOOST_TEST(return_from_nested_namespaces().size() == 0);
BOOST_TEST(return_from_nested_namespaces().begin()->name() == "");
BOOST_TEST(return_from_nested_namespaces().empty());
BOOST_TEST(!return_from_nested_namespaces());
}
void test_nested() {
std::pair<stacktrace, stacktrace> res = foo2(15);
std::pair<stacktrace, stacktrace> res = function_from_library(15, function_from_main_translation_unit);
BOOST_TEST(!res.first);
BOOST_TEST(res.first.empty());
BOOST_TEST(res.first.size() == 0);
BOOST_TEST(res.first.begin()->name() == "");
BOOST_TEST(res.first.begin()->source_file() == "");
BOOST_TEST(res.first.begin()->source_line() == 0);
BOOST_TEST(!res.second);
BOOST_TEST(res.second.size() == 0);
BOOST_TEST(res.second.begin()->name() == "");
BOOST_TEST(res.second.begin()->source_file() == "");
BOOST_TEST(res.second.begin()->source_line() == 0);
BOOST_TEST(res.second[0].name() == "");
BOOST_TEST(res.second[0].source_file() == "");
BOOST_TEST(res.second[0].source_line() == 0);
BOOST_TEST(res.second[0].address() == 0);
BOOST_TEST(res.second <= res.first);
BOOST_TEST(res.second >= res.first);
@@ -50,6 +42,11 @@ void test_empty_frame() {
BOOST_TEST(empty_frame.source_file() == "");
BOOST_TEST(empty_frame.name() == "");
BOOST_TEST(empty_frame.source_line() == 0);
boost::stacktrace::frame f(0);
BOOST_TEST(f.name() == "");
BOOST_TEST(f.source_file() == "");
BOOST_TEST(f.source_line() == 0);
}
int main() {

71
test/test_num_conv.cpp Normal file
View File

@@ -0,0 +1,71 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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/to_dec_array.hpp>
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <boost/stacktrace/detail/try_dec_convert.hpp>
#include <boost/core/lightweight_test.hpp>
#include <string>
#include <iostream>
void test_to_hex_array() {
const void* ptr = 0;
BOOST_TEST(std::string(boost::stacktrace::detail::to_hex_array(ptr).data()).find("0x0") != std::string::npos);
ptr = reinterpret_cast<const void*>(0x10);
BOOST_TEST(std::string(boost::stacktrace::detail::to_hex_array(ptr).data()).find("10") != std::string::npos);
ptr = reinterpret_cast<void*>(0x19);
BOOST_TEST(std::string(boost::stacktrace::detail::to_hex_array(ptr).data()).find("19") != std::string::npos);
ptr = reinterpret_cast<void*>(0x999999);
BOOST_TEST(std::string(boost::stacktrace::detail::to_hex_array(ptr).data()).find("999999") != std::string::npos);
}
void test_to_dec_array() {
BOOST_TEST_EQ(std::string(boost::stacktrace::detail::to_dec_array(0).data()), std::string("0"));
BOOST_TEST_EQ(std::string(boost::stacktrace::detail::to_dec_array(10).data()), std::string("10"));
BOOST_TEST_EQ(std::string(boost::stacktrace::detail::to_dec_array(19).data()), std::string("19"));
BOOST_TEST_EQ(std::string(boost::stacktrace::detail::to_dec_array(999999).data()), std::string("999999"));
}
void test_try_dec_convert() {
std::size_t res = 0;
BOOST_TEST(boost::stacktrace::detail::try_dec_convert("0", res));
BOOST_TEST(res == 0);
BOOST_TEST(boost::stacktrace::detail::try_dec_convert("+0", res));
BOOST_TEST(res == 0);
BOOST_TEST(boost::stacktrace::detail::try_dec_convert("10", res));
BOOST_TEST(res == 10);
BOOST_TEST(boost::stacktrace::detail::try_dec_convert("19", res));
BOOST_TEST(res == 19);
BOOST_TEST(boost::stacktrace::detail::try_dec_convert("+19", res));
BOOST_TEST(res == 19);
BOOST_TEST(boost::stacktrace::detail::try_dec_convert("9999", res));
BOOST_TEST(res == 9999);
BOOST_TEST(!boost::stacktrace::detail::try_dec_convert("q", res));
BOOST_TEST(!boost::stacktrace::detail::try_dec_convert("0z", res));
BOOST_TEST(!boost::stacktrace::detail::try_dec_convert("0u", res));
BOOST_TEST(!boost::stacktrace::detail::try_dec_convert("+0u", res));
}
int main() {
test_to_hex_array();
test_to_dec_array();
test_try_dec_convert();
return boost::report_errors();
}

View File

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

View File

@@ -0,0 +1,72 @@
// Copyright Antony Polukhin, 2016-2021.
//
// 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 "test_impl.hpp"
#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>
using boost::stacktrace::stacktrace;
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 = function_from_library(Depth, function_from_main_translation_unit);
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();
}

26
test/torture.cpp Normal file
View File

@@ -0,0 +1,26 @@
// Copyright Antony Polukhin, 2018.
//
// 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)
// This file tests for memory leaks. Some of the backtrace implementations
// consume memory for internal needs and incorrect usage of those implementations
// could lead to segfaults. Sanitizers do not detect such misuse, but this
// test and `top` does.
#include <boost/stacktrace.hpp>
#include <iostream>
#include "test_impl.hpp"
int main() {
int result = 0;
for (unsigned i = 0; i < 10000000; ++i) {
result += make_some_stacktrace1()[0].source_line();
}
std::cerr << "OK\nLines count " << result;
}