mirror of
https://github.com/boostorg/stacktrace.git
synced 2026-01-28 19:52:08 +00:00
Compare commits
243 Commits
boost_revi
...
boost-1.82
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12e3743e58 | ||
|
|
6db6fd0c01 | ||
|
|
57db1f511e | ||
|
|
308b7f6b08 | ||
|
|
b856a99f9f | ||
|
|
6bf1a98d97 | ||
|
|
cc4d16e2ad | ||
|
|
7c6778e9f4 | ||
|
|
e5940e7103 | ||
|
|
bac3611ad8 | ||
|
|
9e8510076d | ||
|
|
a60ee55b36 | ||
|
|
75b7986f97 | ||
|
|
3f3f9020fb | ||
|
|
898fedac41 | ||
|
|
79aff77771 | ||
|
|
1be59df18e | ||
|
|
1dae3faf43 | ||
|
|
99b7015508 | ||
|
|
18012f81da | ||
|
|
76f902f366 | ||
|
|
b37e0d8e9f | ||
|
|
9a114f8256 | ||
|
|
b75a37dc48 | ||
|
|
1631213c0c | ||
|
|
cadf1bc311 | ||
|
|
26f66b58e9 | ||
|
|
7b19672b67 | ||
|
|
67cc2e9017 | ||
|
|
4b4472cccb | ||
|
|
08d720adbd | ||
|
|
a00587f4d7 | ||
|
|
9c462940b1 | ||
|
|
7fdaebb8ef | ||
|
|
15f6b30f12 | ||
|
|
4a8b14b2d7 | ||
|
|
e4576bfae2 | ||
|
|
7985a04380 | ||
|
|
d84457e2a0 | ||
|
|
66aba44f79 | ||
|
|
e75d2ff93b | ||
|
|
a8a4cefb52 | ||
|
|
f931528c87 | ||
|
|
9b5bc54fe3 | ||
|
|
178d2875d7 | ||
|
|
ade7d54dc7 | ||
|
|
211d291253 | ||
|
|
b72cc6cdfd | ||
|
|
99e07cbea6 | ||
|
|
922305ea7d | ||
|
|
2fce6957d6 | ||
|
|
2cfcbf4247 | ||
|
|
0bddb90c1d | ||
|
|
b6bc847b0c | ||
|
|
6c5b7e51d5 | ||
|
|
acf5b12d02 | ||
|
|
9c3bdd4d0e | ||
|
|
dc0f0c752b | ||
|
|
09255fc94b | ||
|
|
293e1f43f6 | ||
|
|
7379a5cc08 | ||
|
|
7c7271d9bc | ||
|
|
6007c216b9 | ||
|
|
d5bbf7853a | ||
|
|
0be61ab0b8 | ||
|
|
43b837d181 | ||
|
|
2f75119cd0 | ||
|
|
36734b1531 | ||
|
|
2d810e294f | ||
|
|
6e79da7420 | ||
|
|
71acd94944 | ||
|
|
324a303fb0 | ||
|
|
876349f0d6 | ||
|
|
63d5d2730f | ||
|
|
248eedd52f | ||
|
|
c906a69c1d | ||
|
|
4f9da2ae71 | ||
|
|
1ad62e582a | ||
|
|
5c6740b680 | ||
|
|
d9d6512743 | ||
|
|
158a59ae51 | ||
|
|
839a1a127d | ||
|
|
411d92cbf3 | ||
|
|
1b7956a40d | ||
|
|
d708d17ecd | ||
|
|
d946b124ba | ||
|
|
39486260ae | ||
|
|
cbd625bd91 | ||
|
|
b08dab1c44 | ||
|
|
77405d8d7f | ||
|
|
324a24abba | ||
|
|
5e85e7414a | ||
|
|
4123beb4af | ||
|
|
f0a9ba6809 | ||
|
|
b414d35518 | ||
|
|
42bf318144 | ||
|
|
61c94e65e1 | ||
|
|
d573d2a405 | ||
|
|
9f232606cb | ||
|
|
d6f0c65a83 | ||
|
|
3089b733a8 | ||
|
|
99da94f5bd | ||
|
|
3f047cbfc4 | ||
|
|
e14dd6560a | ||
|
|
f328647e45 | ||
|
|
6d101ba4d6 | ||
|
|
c63afe54a2 | ||
|
|
745c6aa7a0 | ||
|
|
7a595a164f | ||
|
|
b4b84780b1 | ||
|
|
1289134b6d | ||
|
|
819f2b1c86 | ||
|
|
fb47f17836 | ||
|
|
b8dec8b126 | ||
|
|
7fedfa1265 | ||
|
|
4a5471a239 | ||
|
|
e4e2d4c3c1 | ||
|
|
14852ad597 | ||
|
|
87b4789289 | ||
|
|
e99f858990 | ||
|
|
c8165e7cf1 | ||
|
|
d6e2a56825 | ||
|
|
f8b8a806ed | ||
|
|
4603c1725d | ||
|
|
a0f948e9f5 | ||
|
|
7f20c8c676 | ||
|
|
31a630ced5 | ||
|
|
5b34577683 | ||
|
|
7cf669eaa6 | ||
|
|
910fe6ea4e | ||
|
|
40b792c7e4 | ||
|
|
b658a12183 | ||
|
|
caaea11dfa | ||
|
|
998334c3b5 | ||
|
|
57699543e8 | ||
|
|
940440bd3e | ||
|
|
168d9a7544 | ||
|
|
4fef2cb469 | ||
|
|
9523e26aad | ||
|
|
b7f4710c70 | ||
|
|
8f0735d9bd | ||
|
|
75f79a1177 | ||
|
|
8ab572d823 | ||
|
|
cdfac8033e | ||
|
|
c2ac4b28ba | ||
|
|
8558ac9112 | ||
|
|
eba6db7bde | ||
|
|
87a1285540 | ||
|
|
fd3b8c2784 | ||
|
|
8364ad1f5e | ||
|
|
b5e2058ec5 | ||
|
|
af78623e8a | ||
|
|
b84d6533f5 | ||
|
|
cd420b37ae | ||
|
|
d663d8b471 | ||
|
|
0c09c5d307 | ||
|
|
a9d92be86a | ||
|
|
b931f501d1 | ||
|
|
1614e8ff7d | ||
|
|
bcf01a77a7 | ||
|
|
86299b8a7e | ||
|
|
5afad6fcc7 | ||
|
|
f853dbfc69 | ||
|
|
9c1ed7fc95 | ||
|
|
ba2f260d95 | ||
|
|
77e69f036b | ||
|
|
cb65016e16 | ||
|
|
c3e5a98d4a | ||
|
|
be200269c1 | ||
|
|
9b7059f518 | ||
|
|
4eaaaeec3a | ||
|
|
f5318e3591 | ||
|
|
26a7e75bdb | ||
|
|
8d11eeb3ad | ||
|
|
a164f0385c | ||
|
|
bd52cde3b6 | ||
|
|
2381fa2011 | ||
|
|
77492bc517 | ||
|
|
576a5355e3 | ||
|
|
25efff8c87 | ||
|
|
29aaf100a8 | ||
|
|
ca4464d23c | ||
|
|
235226bdcc | ||
|
|
c8d526493d | ||
|
|
cff7191e46 | ||
|
|
e70847b918 | ||
|
|
63b4f96ba4 | ||
|
|
39247fbb32 | ||
|
|
25260ed667 | ||
|
|
a014c78b74 | ||
|
|
3d25e45a0d | ||
|
|
55063fd438 | ||
|
|
a562d4cb95 | ||
|
|
68c4f8be6a | ||
|
|
55791ad90c | ||
|
|
5c0176904a | ||
|
|
75296819ea | ||
|
|
269acd6929 | ||
|
|
12b3f98b98 | ||
|
|
141bc0a1d6 | ||
|
|
984b702a11 | ||
|
|
61d11f8d48 | ||
|
|
2e29ee7648 | ||
|
|
f2f66b0d2a | ||
|
|
fe5a0d9871 | ||
|
|
960f9d0f38 | ||
|
|
21c2484f75 | ||
|
|
e0fb46b62c | ||
|
|
fb29d75b3a | ||
|
|
96deb9688a | ||
|
|
a6bdf54c85 | ||
|
|
a6521b2b40 | ||
|
|
1a4ac5bac2 | ||
|
|
29859bf28e | ||
|
|
7342d0afd0 | ||
|
|
e072ec7a38 | ||
|
|
a50b0670d6 | ||
|
|
23ca1dab3b | ||
|
|
885f45e64f | ||
|
|
d990acd883 | ||
|
|
eac60a4709 | ||
|
|
23218809c1 | ||
|
|
a208f422a5 | ||
|
|
9fc256bee4 | ||
|
|
ce661c9c7b | ||
|
|
3678082434 | ||
|
|
3a49914d80 | ||
|
|
29da39c6a5 | ||
|
|
b784ccdebd | ||
|
|
287090e284 | ||
|
|
de9b588d1d | ||
|
|
fea1024491 | ||
|
|
c18532d7cc | ||
|
|
3b0e6a57a3 | ||
|
|
22261768ec | ||
|
|
d1380eba28 | ||
|
|
5664c752cb | ||
|
|
cc3c37a930 | ||
|
|
fb9de2bb6b | ||
|
|
27ec669657 | ||
|
|
46b0542350 | ||
|
|
6b3d993df1 | ||
|
|
9c1c343dad |
97
.gitattributes
vendored
Normal file
97
.gitattributes
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
* text=auto !eol svneol=native#text/plain
|
||||
*.gitattributes text svneol=native#text/plain
|
||||
|
||||
# Scriptish formats
|
||||
*.bat text svneol=native#text/plain
|
||||
*.bsh text svneol=native#text/x-beanshell
|
||||
*.cgi text svneol=native#text/plain
|
||||
*.cmd text svneol=native#text/plain
|
||||
*.js text svneol=native#text/javascript
|
||||
*.php text svneol=native#text/x-php
|
||||
*.pl text svneol=native#text/x-perl
|
||||
*.pm text svneol=native#text/x-perl
|
||||
*.py text svneol=native#text/x-python
|
||||
*.sh eol=lf svneol=LF#text/x-sh
|
||||
configure eol=lf svneol=LF#text/x-sh
|
||||
|
||||
# Image formats
|
||||
*.bmp binary svneol=unset#image/bmp
|
||||
*.gif binary svneol=unset#image/gif
|
||||
*.ico binary svneol=unset#image/ico
|
||||
*.jpeg binary svneol=unset#image/jpeg
|
||||
*.jpg binary svneol=unset#image/jpeg
|
||||
*.png binary svneol=unset#image/png
|
||||
*.tif binary svneol=unset#image/tiff
|
||||
*.tiff binary svneol=unset#image/tiff
|
||||
*.svg text svneol=native#image/svg%2Bxml
|
||||
|
||||
# Data formats
|
||||
*.pdf binary svneol=unset#application/pdf
|
||||
*.avi binary svneol=unset#video/avi
|
||||
*.doc binary svneol=unset#application/msword
|
||||
*.dsp text svneol=crlf#text/plain
|
||||
*.dsw text svneol=crlf#text/plain
|
||||
*.eps binary svneol=unset#application/postscript
|
||||
*.gz binary svneol=unset#application/gzip
|
||||
*.mov binary svneol=unset#video/quicktime
|
||||
*.mp3 binary svneol=unset#audio/mpeg
|
||||
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
|
||||
*.ps binary svneol=unset#application/postscript
|
||||
*.psd binary svneol=unset#application/photoshop
|
||||
*.rdf binary svneol=unset#text/rdf
|
||||
*.rss text svneol=unset#text/xml
|
||||
*.rtf binary svneol=unset#text/rtf
|
||||
*.sln text svneol=native#text/plain
|
||||
*.swf binary svneol=unset#application/x-shockwave-flash
|
||||
*.tgz binary svneol=unset#application/gzip
|
||||
*.vcproj text svneol=native#text/xml
|
||||
*.vcxproj text svneol=native#text/xml
|
||||
*.vsprops text svneol=native#text/xml
|
||||
*.wav binary svneol=unset#audio/wav
|
||||
*.xls binary svneol=unset#application/vnd.ms-excel
|
||||
*.zip binary svneol=unset#application/zip
|
||||
|
||||
# Text formats
|
||||
.htaccess text svneol=native#text/plain
|
||||
*.bbk text svneol=native#text/xml
|
||||
*.cmake text svneol=native#text/plain
|
||||
*.css text svneol=native#text/css
|
||||
*.dtd text svneol=native#text/xml
|
||||
*.htm text svneol=native#text/html
|
||||
*.html text svneol=native#text/html
|
||||
*.ini text svneol=native#text/plain
|
||||
*.log text svneol=native#text/plain
|
||||
*.mak text svneol=native#text/plain
|
||||
*.qbk text svneol=native#text/plain
|
||||
*.rst text svneol=native#text/plain
|
||||
*.sql text svneol=native#text/x-sql
|
||||
*.txt text svneol=native#text/plain
|
||||
*.xhtml text svneol=native#text/xhtml%2Bxml
|
||||
*.xml text svneol=native#text/xml
|
||||
*.xsd text svneol=native#text/xml
|
||||
*.xsl text svneol=native#text/xml
|
||||
*.xslt text svneol=native#text/xml
|
||||
*.xul text svneol=native#text/xul
|
||||
*.yml text svneol=native#text/plain
|
||||
boost-no-inspect text svneol=native#text/plain
|
||||
CHANGES text svneol=native#text/plain
|
||||
COPYING text svneol=native#text/plain
|
||||
INSTALL text svneol=native#text/plain
|
||||
Jamfile text svneol=native#text/plain
|
||||
Jamroot text svneol=native#text/plain
|
||||
Jamfile.v2 text svneol=native#text/plain
|
||||
Jamrules text svneol=native#text/plain
|
||||
Makefile* text svneol=native#text/plain
|
||||
README text svneol=native#text/plain
|
||||
TODO text svneol=native#text/plain
|
||||
|
||||
# Code formats
|
||||
*.c text svneol=native#text/plain
|
||||
*.cpp text svneol=native#text/plain
|
||||
*.h text svneol=native#text/plain
|
||||
*.hpp text svneol=native#text/plain
|
||||
*.ipp text svneol=native#text/plain
|
||||
*.pp text svneol=native#text/plain
|
||||
*.tpp text svneol=native#text/plain
|
||||
*.jam text svneol=native#text/plain
|
||||
*.java text svneol=native#text/plain
|
||||
171
.github/workflows/ci.yml
vendored
Normal file
171
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
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++-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: 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
|
||||
cxxstd: "14,17,latest"
|
||||
addrmd: 64
|
||||
os: windows-2022
|
||||
- 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 10 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
|
||||
120
.travis.yml
120
.travis.yml
@@ -1,120 +0,0 @@
|
||||
# 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)
|
||||
#
|
||||
# Copyright Antony Polukhin 2014-2016.
|
||||
|
||||
#
|
||||
# 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
|
||||
|
||||
sudo: false
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
# - clang
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
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
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE='*/numeric/conversion/converter_policies.hpp */boost/progress.hpp */filesystem/src/*'
|
||||
|
||||
# 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)
|
||||
|
||||
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
|
||||
|
||||
###############################################################################################################
|
||||
# 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
|
||||
packages:
|
||||
- git
|
||||
- python-yaml
|
||||
- gcc-6
|
||||
- g++-6
|
||||
- clang
|
||||
- libc++-dev
|
||||
|
||||
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/
|
||||
|
||||
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"
|
||||
|
||||
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"
|
||||
|
||||
# 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
|
||||
|
||||
# ... 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
|
||||
|
||||
# ... 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"
|
||||
|
||||
# Sending data to Coveralls
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- gem install coveralls-lcov
|
||||
- coveralls-lcov coverals/coverage.info
|
||||
106
CMakeLists.txt
Normal file
106
CMakeLists.txt
Normal 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()
|
||||
16
README.md
16
README.md
@@ -1,19 +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
|
||||
----------------|-------------- | -------------- |-----------
|
||||
Develop branch: | [](https://travis-ci.org/apolukhin/stacktrace) [](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/develop) | [](https://coveralls.io/r/apolukhin/stacktrace?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/stacktrace.html)
|
||||
Master branch: | [](https://travis-ci.org/apolukhin/stacktrace) [](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/master) | [](https://coveralls.io/r/apolukhin/stacktrace?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/stacktrace.html)
|
||||
|
||||
|
||||
### Caution
|
||||
This is not an official Boost C++ library. It wasn't reviewed and can't be downloaded from www.boost.org. This library is available to the community to know real interest and get comments for refinement. The intention is to submit library to formal review, if community think that it is interesting!
|
||||
Develop branch: | [](https://github.com/boostorg/stacktrace/actions/workflows/ci.yml) [](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/develop) | [](https://coveralls.io/github/boostorg/stacktrace?branch=develop) | [details...](https://www.boost.org/development/tests/develop/developer/stacktrace.html)
|
||||
Master branch: | [](https://github.com/boostorg/stacktrace/actions/workflows/ci.yml) [](https://ci.appveyor.com/project/apolukhin/stacktrace/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).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2016, Antony Polukhin.
|
||||
# Copyright (C) 2016-2022, 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,11 +8,11 @@
|
||||
project
|
||||
: source-location .
|
||||
: requirements
|
||||
<target-os>linux:<cxxflags>"-fvisibility=hidden"
|
||||
<visibility>hidden
|
||||
;
|
||||
|
||||
lib dl : : <link>shared ;
|
||||
lib gcc_s : : <link>shared ;
|
||||
lib dl ;
|
||||
lib gcc_s ;
|
||||
lib Dbgeng ;
|
||||
lib ole32 ;
|
||||
|
||||
@@ -48,6 +48,9 @@ explicit addr2line ;
|
||||
mp-run-simple has_windbg.cpp : : : <library>Dbgeng <library>ole32 : WinDbg ;
|
||||
explicit WinDbg ;
|
||||
|
||||
mp-run-simple has_windbg_cached.cpp : : : <library>Dbgeng <library>ole32 : WinDbgCached ;
|
||||
explicit WinDbgCached ;
|
||||
|
||||
lib boost_stacktrace_noop
|
||||
: # sources
|
||||
../src/noop.cpp
|
||||
@@ -59,8 +62,6 @@ lib boost_stacktrace_noop
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
;
|
||||
|
||||
boost-install boost_stacktrace_noop ;
|
||||
|
||||
lib boost_stacktrace_backtrace
|
||||
: # sources
|
||||
../src/backtrace.cpp
|
||||
@@ -75,8 +76,6 @@ lib boost_stacktrace_backtrace
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
;
|
||||
|
||||
boost-install boost_stacktrace_backtrace ;
|
||||
|
||||
lib boost_stacktrace_addr2line
|
||||
: # sources
|
||||
../src/addr2line.cpp
|
||||
@@ -90,8 +89,6 @@ lib boost_stacktrace_addr2line
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
;
|
||||
|
||||
boost-install boost_stacktrace_addr2line ;
|
||||
|
||||
lib boost_stacktrace_basic
|
||||
: # sources
|
||||
../src/basic.cpp
|
||||
@@ -105,8 +102,6 @@ lib boost_stacktrace_basic
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
;
|
||||
|
||||
boost-install boost_stacktrace_basic ;
|
||||
|
||||
lib boost_stacktrace_windbg
|
||||
: # sources
|
||||
../src/windbg.cpp
|
||||
@@ -120,5 +115,17 @@ lib boost_stacktrace_windbg
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
;
|
||||
|
||||
boost-install boost_stacktrace_windbg ;
|
||||
lib boost_stacktrace_windbg_cached
|
||||
: # sources
|
||||
../src/windbg_cached.cpp
|
||||
: # requirements
|
||||
<warnings>all
|
||||
<library>Dbgeng <library>ole32
|
||||
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
[ check-target-builds ../build//WinDbgCached : : <build>no ]
|
||||
: # default build
|
||||
: # usage-requirements
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
;
|
||||
|
||||
boost-install boost_stacktrace_noop boost_stacktrace_backtrace boost_stacktrace_addr2line boost_stacktrace_basic boost_stacktrace_windbg boost_stacktrace_windbg_cached ;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// 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,10 +7,19 @@
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <unwind.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int main() {
|
||||
std::string s = "addr2line -h";
|
||||
|
||||
#ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION
|
||||
std::string s = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION );
|
||||
s += " -h";
|
||||
#else
|
||||
std::string s = "/usr/bin/addr2line -h";
|
||||
#endif
|
||||
|
||||
return std::system(s.c_str());
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <backtrace.h>
|
||||
#ifdef BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
|
||||
# include BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
|
||||
#else
|
||||
# include <backtrace.h>
|
||||
#endif
|
||||
|
||||
#include <unwind.h>
|
||||
|
||||
int main() {
|
||||
backtrace_state* state = backtrace_create_state(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
28
build/has_windbg_cached.cpp
Normal file
28
build/has_windbg_cached.cpp
Normal 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();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright Antony Polukhin 2016-2017.
|
||||
# Copyright Antony Polukhin, 2016-2022.
|
||||
# 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,13 +19,19 @@ doxygen autodoc
|
||||
<doxygen:param>ENABLE_PREPROCESSING=YES
|
||||
<doxygen:param>EXPAND_ONLY_PREDEF=YES
|
||||
<doxygen:param>MACRO_EXPANSION=YES
|
||||
<doxygen:param>SEARCH_INCLUDES=YES
|
||||
<doxygen:param>SHORT_NAMES=NO
|
||||
<doxygen:param>INCLUDE_PATH=../../../
|
||||
<doxygen:param>"PREDEFINED=\"stl_type_info=std::type_info\" \\
|
||||
\"BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()=explicit operator bool() const noexcept;\" \\
|
||||
\"BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()=explicit constexpr operator bool() const noexcept;\" \\
|
||||
\"BOOST_STATIC_CONSTEXPR=static constexpr\" \\
|
||||
\"BOOST_FORCEINLINE=inline\" \\
|
||||
\"BOOST_STACKTRACE_FUNCTION=inline\" \\
|
||||
\"BOOST_CONSTEXPR=constexpr\" \\
|
||||
\"BOOST_STACKTRACE_DOXYGEN_INVOKED\""
|
||||
<xsl:param>"boost.doxygen.reftitle=Reference"
|
||||
<xsl:param>"boost.doxygen.refid=stacktrace.reference"
|
||||
;
|
||||
|
||||
xml stacktrace : stacktrace.qbk : <dependency>autodoc ;
|
||||
@@ -41,7 +48,7 @@ boostbook standalone
|
||||
alias boostdoc
|
||||
: stacktrace
|
||||
:
|
||||
: <dependency>autodoc
|
||||
:
|
||||
: ;
|
||||
|
||||
explicit boostdoc ;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
[library Boost.Stacktrace
|
||||
[quickbook 1.6]
|
||||
[version 1.0]
|
||||
[copyright 2016-2017 Antony Polukhin]
|
||||
[id stacktrace]
|
||||
[copyright 2016-2022 Antony Polukhin]
|
||||
[category Language Features Emulation]
|
||||
[license
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
@@ -32,7 +33,7 @@ Boost.Stacktrace library is a simple C++03 library that provides information abo
|
||||
```
|
||||
#include <boost/stacktrace.hpp>
|
||||
|
||||
// ... somewere inside the `bar(int)` function that is called recursively:
|
||||
// ... somewhere inside the `bar(int)` function that is called recursively:
|
||||
std::cout << boost::stacktrace::stacktrace();
|
||||
```
|
||||
|
||||
@@ -53,54 +54,9 @@ Code from above will output something like this:
|
||||
6# _start
|
||||
```
|
||||
|
||||
[note By default the Stacktrace library is very conservative in methods to decode stacktrace. If your output does not look as fancy as in example from above, see [link boost_stacktrace.configuration_and_build section "Configuration and Build"] for allowing advanced features of the library. ]
|
||||
[note By default the Stacktrace library is very conservative in methods to decode stacktrace. If your output does not look as fancy as in example from above, see [link stacktrace.configuration_and_build section "Configuration and Build"] for allowing advanced features of the library. ]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Handle terminates, aborts and Segmentation Faults]
|
||||
|
||||
Segmentation Faults and `std::terminate` calls sometimes happen in programs. Programmers usually wish to get as much information as possible on such incidents, so having a stacktrace will significantly improve debugging and fixing.
|
||||
|
||||
`std::terminate` calls `std::abort`, so we need to capture stack traces on Segmentation Faults and Abort signals.
|
||||
|
||||
[warning Writing a signal handler requires high attention! Only a few system calls allowed in signal handlers, so there's no cross platform way to print a stacktrace without a risk of deadlocking. The only way to deal with the problem - [*dump raw stacktrace into file/socket/shared memory and parse it on program restart].]
|
||||
|
||||
Let's write a handler to safely dump stacktrace:
|
||||
|
||||
[getting_started_terminate_handlers]
|
||||
|
||||
Registering our handler:
|
||||
|
||||
[getting_started_setup_handlers]
|
||||
|
||||
At program start we check for a file with stacktrace and if it exist - we're writing it in human readable format:
|
||||
|
||||
[getting_started_on_program_restart]
|
||||
|
||||
Now we'll get the following output on `std::terminate` call after the program restarts:
|
||||
|
||||
```
|
||||
Previous run crashed:
|
||||
0# 0x00007F2EC0A6A8EF
|
||||
1# my_signal_handler(int) at ../example/terminate_handler.cpp:37
|
||||
2# 0x00007F2EBFD84CB0
|
||||
3# 0x00007F2EBFD84C37
|
||||
4# 0x00007F2EBFD88028
|
||||
5# 0x00007F2EC0395BBD
|
||||
6# 0x00007F2EC0393B96
|
||||
7# 0x00007F2EC0393BE1
|
||||
8# bar(int) at ../example/terminate_handler.cpp:18
|
||||
9# foo(int) at ../example/terminate_handler.cpp:22
|
||||
10# bar(int) at ../example/terminate_handler.cpp:14
|
||||
11# foo(int) at ../example/terminate_handler.cpp:22
|
||||
12# main at ../example/terminate_handler.cpp:84
|
||||
13# 0x00007F2EBFD6FF45
|
||||
14# 0x0000000000402209
|
||||
```
|
||||
|
||||
[note Function names from shared libraries may not be decoded due to address space layout randomization. Still better than nothing.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Better asserts]
|
||||
@@ -134,18 +90,56 @@ Backtrace:
|
||||
|
||||
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. There are many ways to do that, here's how to doe that using Boost.Exception:
|
||||
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:
|
||||
|
||||
* Declare a `boost::error_info` typedef that holds the stacktrace:
|
||||
|
||||
[getting_started_class_traced]
|
||||
|
||||
* Write a helper class for throwing any exception with stacktrce:
|
||||
* Write a helper class for throwing any exception with stacktrace:
|
||||
|
||||
[getting_started_class_with_trace]
|
||||
|
||||
@@ -176,7 +170,7 @@ Code from above will output:
|
||||
|
||||
[section Enabling and disabling stacktraces]
|
||||
|
||||
At some point arises a requirement to easily enable/disable stacktraces for a whole project. That could be easily achived.
|
||||
At some point arises a requirement to easily enable/disable stacktraces for a whole project. That could be easily achieved.
|
||||
|
||||
Just define *BOOST_STACKTRACE_LINK* for a whole project. Now you can enable/disable stacktraces by just linking with different libraries:
|
||||
|
||||
@@ -184,7 +178,7 @@ Just define *BOOST_STACKTRACE_LINK* for a whole project. Now you can enable/disa
|
||||
* link with other `boost_stacktrace_*` libraries
|
||||
|
||||
|
||||
See [link boost_stacktrace.configuration_and_build section "Configuration and Build"] for more info.
|
||||
See [link stacktrace.configuration_and_build section "Configuration and Build"] for more info.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -239,16 +233,16 @@ Terminate called:
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[/
|
||||
[section Store stacktraces into shared memory]
|
||||
|
||||
There's a way to serialize stacktrace in async safe manner and share that serialized representation with another preocess. Here's another example with signal handlers.
|
||||
There's a way to serialize stacktrace in async safe manner and share that serialized representation with another process. Here's another example with signal handlers.
|
||||
|
||||
This example is very close to the [link boost_stacktrace.getting_started.handle_terminates_aborts_and_seg "Handle terminates, aborts and Segmentation Faults"], but this time we are dumping stacktrace into shared memory:
|
||||
This example is very close to the [link stacktrace.getting_started.handle_terminates_aborts_and_seg "Handle terminates, aborts and Segmentation Faults"], but this time we are dumping stacktrace into shared memory:
|
||||
|
||||
[getting_started_terminate_handlers_shmem]
|
||||
|
||||
After registring signal handlers and catching a signal, we may print stacktrace dumps on program restart:
|
||||
After registering signal handlers and catching a signal, we may print stacktrace dumps on program restart:
|
||||
|
||||
[getting_started_on_program_restart_shmem]
|
||||
|
||||
@@ -274,7 +268,8 @@ Previous run crashed and left trace in shared memory:
|
||||
15# 0x0000000000402999
|
||||
```
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -291,18 +286,51 @@ By default Boost.Stacktrace is a header-only library, but you may change that an
|
||||
In header only mode library could be tuned by macro. If one of the link macro from above is defined, you have to manually link with one of the libraries:
|
||||
[table:libconfig Config
|
||||
[[Macro name or default] [Library] [Effect] [Platforms] [Uses debug information [footnote This will provide more readable backtraces with *source code locations* if the binary is built with debug information.]] [Uses dynamic exports information [footnote This will provide readable function names in backtrace for functions that are exported by the binary. Compiling with `-rdynamic` flag, without `-fisibility=hidden` or marking functions as exported produce a better stacktraces.]] ]
|
||||
[[['default for MSVC] / *BOOST_STACKTRACE_USE_WINDBG*] [*boost_stacktrace_windbg*] [ Uses COM to show debug info. ] [Windows] [yes] [yes]]
|
||||
[[['default other platforms]] [*boost_stacktrace_basic*] [Uses compiler intrinsics to collect stacktrace and if possible `::dladdr` to show information about the symbol. Requires linking with *libdl* library on POSIX platforms.] [Not MSVC compiler on POSIX or Windows] [no] [yes]]
|
||||
[[*BOOST_STACKTRACE_USE_BACKTRACE*] [*boost_stacktrace_backtrace*] [Requires linking with *libdl* on POSIX and *libbacktrace* libraries. *libbacktrace* is probably already installed in your system, or built into your compiler. Otherwise it can be downloaded [@https://github.com/gcc-mirror/gcc/tree/master/libbacktrace from here] ] [GCC/MinGW/Clang... on POSIX or Windows] [yes] [yes]]
|
||||
[[*BOOST_STACKTRACE_USE_ADDR2LINE*] [*boost_stacktrace_addr2line*] [Use *addr2line* program to retrieve stacktrace. Requires linking with *libdl* library and calls `::fork`.] [GCC/MinGW/Clang... on POSIX] [yes] [yes]]
|
||||
[[['default for MSVC, Intel on Windows, MinGW-w64] / *BOOST_STACKTRACE_USE_WINDBG*] [*boost_stacktrace_windbg*] [ Uses `dbgeng.h` 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 `dbgeng.h` to show debug info and caches internals in TLS for better performance. Useful only for cases when traces are gathered very often. 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[footnote Some *libbacktrace* packages SEGFAULT if there's a concurrent work with the same `backtrace_state` instance. To avoid that issue the Boost.Stacktrace library uses `thread_local` states, unfortuantely this may consume a lot of memory if you often create and destroy execution threads in your application. Define *BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC* to force single instance, but make sure that [@https://github.com/boostorg/stacktrace/blob/develop/test/thread_safety_checking.cpp thread_safety_checking.cpp] works well in your setup. ]. *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 you use the library in header only mode, you just need to define *BOOST_STACKTRACE_USE_NOOP* for the whole project
|
||||
* if you wish to disable backtracing and *BOOST_STACKTRACE_LINK* is defined, you just need link with *-lboost_stacktrace_noop*
|
||||
* 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]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -24,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
|
||||
@@ -35,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) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -11,23 +11,23 @@
|
||||
#include <cstdlib> // std::exit
|
||||
|
||||
void print_signal_handler_and_exit() {
|
||||
void* p = reinterpret_cast<void*>(::signal(SIGSEGV, SIG_DFL));
|
||||
boost::stacktrace::frame f(p);
|
||||
typedef void(*function_t)(int);
|
||||
|
||||
function_t old_signal_function = ::signal(SIGSEGV, SIG_DFL);
|
||||
boost::stacktrace::frame f(old_signal_function);
|
||||
std::cout << f << std::endl;
|
||||
std::exit(0);
|
||||
}
|
||||
//]
|
||||
|
||||
|
||||
void my_signal_handler(int signum) {
|
||||
void my_signal_handler(int /*signum*/) {
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
int main() {
|
||||
::signal(SIGSEGV, &my_signal_handler);
|
||||
print_signal_handler_and_exit();
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -21,36 +21,46 @@ BOOST_NOINLINE void foo(int i) {
|
||||
bar(--i);
|
||||
}
|
||||
|
||||
#if defined(BOOST_GCC) && defined(BOOST_WINDOWS)
|
||||
|
||||
// MinGW workaround
|
||||
#include <cstdlib> // ::_Exit
|
||||
namespace std { using ::_Exit; }
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//[getting_started_terminate_handlers
|
||||
//[getting_started_signal_handlers
|
||||
|
||||
#include <signal.h> // ::signal
|
||||
#include <cstdlib> // std::_Exit
|
||||
#include <signal.h> // ::signal, ::raise
|
||||
#include <boost/stacktrace.hpp>
|
||||
|
||||
void my_signal_handler(int signum) {
|
||||
::signal(signum, SIG_DFL);
|
||||
|
||||
// Outputs nothing or trash on majority of platforms
|
||||
boost::stacktrace::safe_dump_to("./backtrace.dump");
|
||||
std::_Exit(-1);
|
||||
|
||||
::raise(SIGABRT);
|
||||
}
|
||||
//]
|
||||
|
||||
void setup_handlers() {
|
||||
//[getting_started_setup_handlers
|
||||
//[getting_started_setup_signel_handlers
|
||||
::signal(SIGSEGV, &my_signal_handler);
|
||||
::signal(SIGABRT, &my_signal_handler);
|
||||
//]
|
||||
}
|
||||
|
||||
|
||||
//[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;
|
||||
@@ -66,10 +76,11 @@ boost::interprocess::mapped_region g_region; // inited at program start
|
||||
|
||||
void my_signal_handler2(int signum) {
|
||||
::signal(signum, SIG_DFL);
|
||||
bool* b = static_cast<bool*>(g_region.get_address());
|
||||
*b = true; // flag that memory constains stacktrace
|
||||
boost::stacktrace::safe_dump_to(b + 1, g_region.get_size() - sizeof(bool));
|
||||
std::_Exit(-1);
|
||||
void** f = static_cast<void**>(g_region.get_address());
|
||||
*f = reinterpret_cast<void*>(1); // Setting flag that shared memory now constains stacktrace.
|
||||
boost::stacktrace::safe_dump_to(f + 1, g_region.get_size() - sizeof(void*));
|
||||
|
||||
::raise(SIGABRT);
|
||||
}
|
||||
//]
|
||||
|
||||
@@ -100,6 +111,15 @@ inline void copy_and_run(const char* exec_name, char param, bool not_null) {
|
||||
}
|
||||
}
|
||||
|
||||
int run_0(const char* /*argv*/[]) {
|
||||
//[getting_started_setup_terminate_handlers
|
||||
std::set_terminate(&my_terminate_handler);
|
||||
//]
|
||||
foo(5);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int run_1(const char* /*argv*/[]) {
|
||||
setup_handlers();
|
||||
foo(5);
|
||||
@@ -153,8 +173,8 @@ int run_3(const char* /*argv*/[]) {
|
||||
mapped_region m(g_shm, read_write, 0, shared_memory_size);
|
||||
m.swap(g_region);
|
||||
}
|
||||
bool* b = static_cast<bool*>(g_region.get_address());
|
||||
*b = false;
|
||||
void** f = static_cast<void**>(g_region.get_address());
|
||||
*f = 0;
|
||||
|
||||
::signal(SIGSEGV, &my_signal_handler2);
|
||||
::signal(SIGABRT, &my_signal_handler2);
|
||||
@@ -175,13 +195,13 @@ int run_4(const char* argv[]) {
|
||||
}
|
||||
|
||||
//[getting_started_on_program_restart_shmem
|
||||
bool* b = static_cast<bool*>(g_region.get_address()); // getting flag that memory constains stacktrace
|
||||
if (*b) { // checking that memory constains stacktrace
|
||||
void** f = static_cast<void**>(g_region.get_address());
|
||||
if (*f) { // Checking if memory constains stacktrace.
|
||||
boost::stacktrace::stacktrace st
|
||||
= boost::stacktrace::stacktrace::from_dump(b + 1, g_region.get_size() - sizeof(bool));
|
||||
= boost::stacktrace::stacktrace::from_dump(f + 1, g_region.get_size() - sizeof(bool));
|
||||
|
||||
std::cout << "Previous run crashed and left trace in shared memory:\n" << st << std::endl;
|
||||
*b = false; /*<-*/
|
||||
*f = 0; /*<-*/
|
||||
shared_memory_object::remove("shared_memory");
|
||||
if (std::string(argv[0]).find("noop") == std::string::npos) {
|
||||
if (!st) {
|
||||
@@ -207,38 +227,36 @@ int test_inplace() {
|
||||
const bool is_noop = !boost::stacktrace::stacktrace();
|
||||
|
||||
{
|
||||
boost::stacktrace::safe_dump_to("./backtrace2.dump");
|
||||
// This is very dependent on compiler and link flags. No sane way to make it work, because:
|
||||
// * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled.
|
||||
// * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length.
|
||||
const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to("./backtrace2.dump");
|
||||
boost::stacktrace::stacktrace ss2;
|
||||
std::ifstream ifs("./backtrace2.dump");
|
||||
boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(ifs);
|
||||
ifs.close();
|
||||
boost::filesystem::remove("./backtrace2.dump");
|
||||
|
||||
if (ss1.size() != ss2.size()) {
|
||||
std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
return 51;
|
||||
}
|
||||
|
||||
if (ss1 && ss1[0].name() != ss2[0].name()) {
|
||||
std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
return 52;
|
||||
if (ss1.size() + 1 != frames_ss1 || ss2.size() != ss1.size()) {
|
||||
std::cerr << "51: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
} else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) {
|
||||
std::cerr << "52: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// This is very dependent on compiler and link flags. No sane way to make it work, because:
|
||||
// * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled.
|
||||
// * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length.
|
||||
void* data[1024];
|
||||
boost::stacktrace::safe_dump_to(data, sizeof(data));
|
||||
const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to(data, sizeof(data));
|
||||
boost::stacktrace::stacktrace ss2;
|
||||
boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(data, sizeof(data));
|
||||
|
||||
if (ss1.size() != ss2.size()) {
|
||||
std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
return 53;
|
||||
}
|
||||
|
||||
if (ss1 && ss1[0].name() != ss2[0].name()) {
|
||||
std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
return 54;
|
||||
if (ss1.size() + 1 != frames_ss1 || ss1.size() != ss2.size()) {
|
||||
std::cerr << "53: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
} else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) {
|
||||
std::cerr << "54: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,6 +299,13 @@ int test_inplace() {
|
||||
|
||||
boost::filesystem::remove("./backtrace3.dump");
|
||||
|
||||
#ifdef BOOST_WINDOWS
|
||||
// `ss2` could be empty on some combinations of Windows+MSVC.
|
||||
if (!ss2) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ss1.size() != ss2.size()) {
|
||||
std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
|
||||
return 58;
|
||||
@@ -303,16 +328,24 @@ int test_inplace() {
|
||||
|
||||
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);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -35,7 +35,7 @@ BOOST_NOINLINE void oops(int i) {
|
||||
if (i >= 4)
|
||||
throw_with_trace(std::out_of_range("'i' must be less than 4 in oops()"));
|
||||
if (i <= 0)
|
||||
throw_with_trace(std::logic_error("'i' must not be greater than zero in oops()"));
|
||||
throw_with_trace(std::logic_error("'i' must be greater than zero in oops()"));
|
||||
//]
|
||||
foo(i);
|
||||
std::exit(1);
|
||||
@@ -68,8 +68,8 @@ int main() {
|
||||
std::cerr << e.what() << '\n';
|
||||
const boost::stacktrace::stacktrace* st = boost::get_error_info<traced>(e);
|
||||
if (st) {
|
||||
std::cerr << *st << '\n'; /*<-*/ std::exit(0); /*->*/
|
||||
} /*<-*/ std::exit(3); /*->*/
|
||||
std::cerr << *st << '\n'; /*<-*/ return 0; /*->*/
|
||||
} /*<-*/ return 3; /*->*/
|
||||
}
|
||||
//]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -29,6 +29,9 @@ 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 {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -13,7 +13,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
#include <boost/stacktrace/stacktrace.hpp>
|
||||
#include <boost/stacktrace/stacktrace.hpp> // Actually already includes all the headers
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
#endif // BOOST_STACKTRACE_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -13,17 +13,29 @@
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/stacktrace/detail/try_demangle.hpp>
|
||||
#include <boost/lexical_cast.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;
|
||||
@@ -34,7 +46,19 @@ public:
|
||||
, pid(0)
|
||||
{
|
||||
int pdes[2];
|
||||
char prog_name[] = "addr2line";
|
||||
#ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION
|
||||
char prog_name[] = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION );
|
||||
#if !defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CXX11_STATIC_ASSERT)
|
||||
static_assert(
|
||||
boost::stacktrace::detail::is_abs_path( BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION ) ),
|
||||
"BOOST_STACKTRACE_ADDR2LINE_LOCATION must be an absolute path"
|
||||
);
|
||||
#endif
|
||||
|
||||
#else
|
||||
char prog_name[] = "/usr/bin/addr2line";
|
||||
#endif
|
||||
|
||||
char* argp[] = {
|
||||
prog_name,
|
||||
const_cast<char*>(flag),
|
||||
@@ -50,19 +74,22 @@ public:
|
||||
pid = ::fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
// failed
|
||||
// Failed...
|
||||
::close(pdes[0]);
|
||||
::close(pdes[1]);
|
||||
return;
|
||||
|
||||
case 0:
|
||||
// we are the child
|
||||
// We are the child.
|
||||
::close(STDERR_FILENO);
|
||||
::close(pdes[0]);
|
||||
if (pdes[1] != STDOUT_FILENO) {
|
||||
::dup2(pdes[1], STDOUT_FILENO);
|
||||
}
|
||||
::execvp(prog_name, argp);
|
||||
|
||||
// Do not use `execlp()`, `execvp()`, and `execvpe()` here!
|
||||
// `exec*p*` functions are vulnerable to PATH variable evaluation attacks.
|
||||
::execv(prog_name, argp);
|
||||
::_exit(127);
|
||||
}
|
||||
|
||||
@@ -154,7 +181,7 @@ typedef to_string_impl_base<to_string_using_addr2line> to_string_impl;
|
||||
inline std::string name_impl(const void* addr) {
|
||||
std::string res = boost::stacktrace::detail::addr2line("-fe", addr);
|
||||
res = res.substr(0, res.find_last_of('\n'));
|
||||
res = boost::stacktrace::detail::try_demangle(res.c_str());
|
||||
res = boost::core::demangle(res.c_str());
|
||||
|
||||
if (res == "??") {
|
||||
res.clear();
|
||||
@@ -186,7 +213,7 @@ std::size_t frame::source_line() const {
|
||||
}
|
||||
res = res.substr(last + 1);
|
||||
|
||||
if (!boost::conversion::try_lexical_convert(res, line_num)) {
|
||||
if (!boost::stacktrace::detail::try_dec_convert(res.c_str(), line_num)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
33
include/boost/stacktrace/detail/collect_msvc.ipp
Normal file
33
include/boost/stacktrace/detail/collect_msvc.ipp
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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
|
||||
25
include/boost/stacktrace/detail/collect_noop.ipp
Normal file
25
include/boost/stacktrace/detail/collect_noop.ipp
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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
|
||||
106
include/boost/stacktrace/detail/collect_unwind.ipp
Normal file
106
include/boost/stacktrace/detail/collect_unwind.ipp
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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
|
||||
159
include/boost/stacktrace/detail/frame_decl.hpp
Normal file
159
include/boost/stacktrace/detail/frame_decl.hpp
Normal file
@@ -0,0 +1,159 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -14,63 +14,42 @@
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <windows.h>
|
||||
#include "dbgeng.h"
|
||||
|
||||
#include <boost/detail/winapi/get_current_process.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma comment(lib, "ole32.lib")
|
||||
# pragma comment(lib, "Dbgeng.lib")
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_WINDOWS
|
||||
# include <boost/stacktrace/detail/safe_dump_win.ipp>
|
||||
#else
|
||||
# include <boost/stacktrace/detail/safe_dump_posix.ipp>
|
||||
#endif
|
||||
|
||||
#if defined(DEFINE_GUID) && !defined(BOOST_MSVC)
|
||||
#ifdef __CRT_UUID_DECL // for __MINGW32__
|
||||
__CRT_UUID_DECL(IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8)
|
||||
__CRT_UUID_DECL(IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba)
|
||||
__CRT_UUID_DECL(IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50)
|
||||
#elif defined(DEFINE_GUID) && !defined(BOOST_MSVC)
|
||||
DEFINE_GUID(IID_IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8);
|
||||
DEFINE_GUID(IID_IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba);
|
||||
DEFINE_GUID(IID_IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Testing. Remove later
|
||||
//# define __uuidof(x) ::IID_ ## x
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t this_thread_frames::collect(void** memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
|
||||
return ::CaptureStackBackTrace(
|
||||
skip + 2,
|
||||
static_cast<boost::detail::winapi::ULONG_>(size),
|
||||
memory,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
class com_global_initer: boost::noncopyable {
|
||||
public:
|
||||
com_global_initer() BOOST_NOEXCEPT {
|
||||
// We do not care about the result of the function call: any result is OK for us.
|
||||
::CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
}
|
||||
~com_global_initer() BOOST_NOEXCEPT {
|
||||
::CoUninitialize();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class com_holder: boost::noncopyable {
|
||||
T* holder_;
|
||||
|
||||
public:
|
||||
com_holder(const com_global_initer&) BOOST_NOEXCEPT
|
||||
com_holder() BOOST_NOEXCEPT
|
||||
: holder_(0)
|
||||
{}
|
||||
|
||||
@@ -94,155 +73,260 @@ public:
|
||||
};
|
||||
|
||||
|
||||
inline bool try_init_com(com_holder<::IDebugSymbols>& idebug, const com_global_initer& com) BOOST_NOEXCEPT {
|
||||
com_holder<::IDebugClient> iclient(com);
|
||||
::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr());
|
||||
|
||||
com_holder<::IDebugControl> icontrol(com);
|
||||
iclient->QueryInterface(__uuidof(IDebugControl), icontrol.to_void_ptr_ptr());
|
||||
|
||||
const bool res1 = (S_OK == iclient->AttachProcess(
|
||||
0,
|
||||
::GetCurrentProcessId(),
|
||||
DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)
|
||||
);
|
||||
if (!res1) {
|
||||
return false;
|
||||
inline std::string mingw_demangling_workaround(const std::string& s) {
|
||||
#ifdef BOOST_GCC
|
||||
if (s.empty()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
const bool res2 = (S_OK == icontrol->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE));
|
||||
if (!res2) {
|
||||
return false;
|
||||
if (s[0] != '_') {
|
||||
return boost::core::demangle(('_' + s).c_str());
|
||||
}
|
||||
|
||||
const bool res = (S_OK == iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr()));
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return boost::core::demangle(s.c_str());
|
||||
#else
|
||||
return s;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline std::string get_name_impl(const com_holder<::IDebugSymbols>& idebug, const void* addr, std::string* module_name = 0) {
|
||||
std::string result;
|
||||
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
char name[256];
|
||||
name[0] = '\0';
|
||||
ULONG size = 0;
|
||||
bool res = (S_OK == idebug->GetNameByOffset(
|
||||
offset,
|
||||
name,
|
||||
sizeof(name),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
class debugging_symbols: boost::noncopyable {
|
||||
static void try_init_com(com_holder< ::IDebugSymbols>& idebug) BOOST_NOEXCEPT {
|
||||
com_holder< ::IDebugClient> iclient;
|
||||
if (S_OK != ::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!res && size != 0) {
|
||||
result.resize(size);
|
||||
res = (S_OK == idebug->GetNameByOffset(
|
||||
com_holder< ::IDebugControl> icontrol;
|
||||
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
|
||||
|
||||
com_holder< ::IDebugSymbols> idebug_;
|
||||
public:
|
||||
debugging_symbols() BOOST_NOEXCEPT
|
||||
{
|
||||
try_init_com(idebug_);
|
||||
}
|
||||
|
||||
#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 com_holder< ::IDebugSymbols> idebug;
|
||||
|
||||
if (!idebug.is_inited()) {
|
||||
try_init_com(idebug);
|
||||
}
|
||||
|
||||
return idebug;
|
||||
}
|
||||
|
||||
com_holder< ::IDebugSymbols>& idebug_;
|
||||
public:
|
||||
debugging_symbols() BOOST_NOEXCEPT
|
||||
: idebug_( get_thread_local_debug_inst() )
|
||||
{}
|
||||
|
||||
#endif // #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
|
||||
|
||||
bool is_inited() const BOOST_NOEXCEPT {
|
||||
return idebug_.is_inited();
|
||||
}
|
||||
|
||||
std::string get_name_impl(const void* addr, std::string* module_name = 0) const {
|
||||
std::string result;
|
||||
if (!is_inited()) {
|
||||
return result;
|
||||
}
|
||||
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
|
||||
|
||||
char name[256];
|
||||
name[0] = '\0';
|
||||
ULONG size = 0;
|
||||
bool res = (S_OK == idebug_->GetNameByOffset(
|
||||
offset,
|
||||
&result[0],
|
||||
static_cast<ULONG>(result.size()),
|
||||
name,
|
||||
sizeof(name),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
} else if (res) {
|
||||
result = name;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
result.clear();
|
||||
if (!res && size != 0) {
|
||||
result.resize(size);
|
||||
res = (S_OK == idebug_->GetNameByOffset(
|
||||
offset,
|
||||
&result[0],
|
||||
static_cast<ULONG>(result.size()),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
|
||||
// According to https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/dbgeng/nf-dbgeng-idebugsymbols-getnamebyoffset
|
||||
// "This size includes the space for the '\0' terminating character."
|
||||
result.resize(size - 1);
|
||||
} else if (res) {
|
||||
result.assign(name, size - 1);
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
result.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::size_t delimiter = result.find_first_of('!');
|
||||
if (module_name) {
|
||||
*module_name = result.substr(0, delimiter);
|
||||
}
|
||||
|
||||
if (delimiter == std::string::npos) {
|
||||
// If 'delimiter' is equal to 'std::string::npos' then we have only module name.
|
||||
result.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mingw_demangling_workaround(
|
||||
result.substr(delimiter + 1)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::size_t delimiter = result.find_first_of('!');
|
||||
if (delimiter == std::string::npos) {
|
||||
return result;
|
||||
std::size_t get_line_impl(const void* addr) const BOOST_NOEXCEPT {
|
||||
ULONG result = 0;
|
||||
if (!is_inited()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const bool is_ok = (S_OK == idebug_->GetLineByOffset(
|
||||
reinterpret_cast<ULONG64>(addr),
|
||||
&result,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
));
|
||||
|
||||
return (is_ok ? result : 0);
|
||||
}
|
||||
|
||||
if (module_name) {
|
||||
*module_name = result.substr(0, delimiter);
|
||||
}
|
||||
|
||||
result = result.substr(delimiter + 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
std::pair<std::string, std::size_t> get_source_file_line_impl(const void* addr) const {
|
||||
std::pair<std::string, std::size_t> result;
|
||||
if (!is_inited()) {
|
||||
return result;
|
||||
}
|
||||
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
|
||||
|
||||
char name[256];
|
||||
name[0] = 0;
|
||||
ULONG size = 0;
|
||||
ULONG line_num = 0;
|
||||
bool res = (S_OK == idebug_->GetLineByOffset(
|
||||
offset,
|
||||
&line_num,
|
||||
name,
|
||||
sizeof(name),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
|
||||
inline std::pair<std::string, std::size_t> get_source_file_line_impl(const com_holder<::IDebugSymbols>& idebug, const void* addr) {
|
||||
std::pair<std::string, std::size_t> result;
|
||||
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
|
||||
if (res) {
|
||||
result.first = name;
|
||||
result.second = line_num;
|
||||
return result;
|
||||
}
|
||||
|
||||
char name[256];
|
||||
name[0] = 0;
|
||||
ULONG size = 0;
|
||||
ULONG line_num = 0;
|
||||
bool res = (S_OK == idebug->GetLineByOffset(
|
||||
offset,
|
||||
&line_num,
|
||||
name,
|
||||
sizeof(name),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
if (!res && size == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (res) {
|
||||
result.first = name;
|
||||
result.first.resize(size);
|
||||
res = (S_OK == idebug_->GetLineByOffset(
|
||||
offset,
|
||||
&line_num,
|
||||
&result.first[0],
|
||||
static_cast<ULONG>(result.first.size()),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
trim_right_zeroes(result.first);
|
||||
result.second = line_num;
|
||||
|
||||
if (!res) {
|
||||
result.first.clear();
|
||||
result.second = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!res && size == 0) {
|
||||
return result;
|
||||
}
|
||||
void to_string_impl(const void* addr, std::string& res) const {
|
||||
if (!is_inited()) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.first.resize(size);
|
||||
res = (S_OK == idebug->GetLineByOffset(
|
||||
offset,
|
||||
&line_num,
|
||||
&result.first[0],
|
||||
static_cast<ULONG>(result.first.size()),
|
||||
&size,
|
||||
0
|
||||
));
|
||||
result.second = line_num;
|
||||
std::string module_name;
|
||||
std::string name = this->get_name_impl(addr, &module_name);
|
||||
if (!name.empty()) {
|
||||
res += name;
|
||||
} else {
|
||||
res += to_hex_array(addr).data();
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
result.first.clear();
|
||||
result.second = 0;
|
||||
std::pair<std::string, std::size_t> source_line = this->get_source_file_line_impl(addr);
|
||||
if (!source_line.first.empty() && source_line.second) {
|
||||
res += " at ";
|
||||
res += source_line.first;
|
||||
res += ':';
|
||||
res += boost::stacktrace::detail::to_dec_array(source_line.second).data();
|
||||
} else if (!module_name.empty()) {
|
||||
res += " in ";
|
||||
res += module_name;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void to_string_impl(const com_holder<::IDebugSymbols>& idebug, const void* addr, std::string& res) {
|
||||
std::string module_name;
|
||||
std::string name = boost::stacktrace::detail::get_name_impl(idebug, addr, &module_name);
|
||||
if (!name.empty()) {
|
||||
res += name;
|
||||
} else {
|
||||
res += to_hex_array(addr).data();
|
||||
}
|
||||
|
||||
std::pair<std::string, std::size_t> source_line
|
||||
= boost::stacktrace::detail::get_source_file_line_impl(idebug, addr);
|
||||
if (!source_line.first.empty() && source_line.second) {
|
||||
res += " at ";
|
||||
res += source_line.first;
|
||||
res += ':';
|
||||
res += boost::lexical_cast<boost::array<char, 40> >(source_line.second).data();
|
||||
} else if (!module_name.empty()) {
|
||||
res += " in ";
|
||||
res += module_name;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::string to_string(const frame* frames, std::size_t size) {
|
||||
boost::stacktrace::detail::com_global_initer com_guard;
|
||||
boost::stacktrace::detail::com_holder<::IDebugSymbols> idebug(com_guard);
|
||||
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
if (!idebug.is_inited()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -252,10 +336,10 @@ std::string to_string(const frame* frames, std::size_t size) {
|
||||
if (i < 10) {
|
||||
res += ' ';
|
||||
}
|
||||
res += boost::lexical_cast<boost::array<char, 40> >(i).data();
|
||||
res += boost::stacktrace::detail::to_dec_array(i).data();
|
||||
res += '#';
|
||||
res += ' ';
|
||||
to_string_impl(idebug, frames[i].address(), res);
|
||||
idebug.to_string_impl(frames[i].address(), res);
|
||||
res += '\n';
|
||||
}
|
||||
|
||||
@@ -265,55 +349,26 @@ std::string to_string(const frame* frames, std::size_t size) {
|
||||
} // namespace detail
|
||||
|
||||
std::string frame::name() const {
|
||||
boost::stacktrace::detail::com_global_initer com_guard;
|
||||
boost::stacktrace::detail::com_holder<::IDebugSymbols> idebug(com_guard);
|
||||
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return boost::stacktrace::detail::get_name_impl(idebug, addr_);
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
return idebug.get_name_impl(addr_);
|
||||
}
|
||||
|
||||
|
||||
std::string frame::source_file() const {
|
||||
boost::stacktrace::detail::com_global_initer com_guard;
|
||||
boost::stacktrace::detail::com_holder<::IDebugSymbols> idebug(com_guard);
|
||||
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
|
||||
return std::string();
|
||||
}
|
||||
return boost::stacktrace::detail::get_source_file_line_impl(idebug, addr_).first;
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
return idebug.get_source_file_line_impl(addr_).first;
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
ULONG line_num = 0;
|
||||
|
||||
boost::stacktrace::detail::com_global_initer com_guard;
|
||||
boost::stacktrace::detail::com_holder<::IDebugSymbols> idebug(com_guard);
|
||||
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const bool is_ok = (S_OK == idebug->GetLineByOffset(
|
||||
reinterpret_cast<ULONG64>(addr_),
|
||||
&line_num,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
));
|
||||
|
||||
return (is_ok ? line_num : 0);
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
return idebug.get_line_impl(addr_);
|
||||
}
|
||||
|
||||
std::string to_string(const frame& f) {
|
||||
boost::stacktrace::detail::com_global_initer com_guard;
|
||||
boost::stacktrace::detail::com_holder<::IDebugSymbols> idebug(com_guard);
|
||||
if (!boost::stacktrace::detail::try_init_com(idebug, com_guard)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string res;
|
||||
boost::stacktrace::detail::to_string_impl(idebug, f.address(), res);
|
||||
|
||||
boost::stacktrace::detail::debugging_symbols idebug;
|
||||
idebug.to_string_impl(f.address(), res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -20,25 +20,6 @@ std::string to_string(const frame* /*frames*/, std::size_t /*count*/) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::size_t this_thread_frames::collect(void** /*memory*/, std::size_t /*size*/, std::size_t /*skip*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(BOOST_WINDOWS)
|
||||
std::size_t dump(void* /*fd*/, void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
std::size_t dump(int /*fd*/, void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
std::size_t dump(const char* /*file*/, void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
std::string frame::name() const {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -15,11 +15,10 @@
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/stacktrace/detail/try_demangle.hpp>
|
||||
#include <boost/stacktrace/detail/location_from_symbol.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
|
||||
#include <unwind.h>
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef BOOST_STACKTRACE_USE_BACKTRACE
|
||||
@@ -30,63 +29,16 @@
|
||||
# include <boost/stacktrace/detail/unwind_base_impls.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_WINDOWS
|
||||
# include <boost/stacktrace/detail/safe_dump_win.ipp>
|
||||
#else
|
||||
# include <boost/stacktrace/detail/safe_dump_posix.ipp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct unwind_state {
|
||||
std::size_t frames_to_skip;
|
||||
void** current;
|
||||
void** end;
|
||||
};
|
||||
|
||||
inline _Unwind_Reason_Code unwind_callback(::_Unwind_Context* context, void* arg) {
|
||||
unwind_state* state = static_cast<unwind_state*>(arg);
|
||||
if (state->frames_to_skip) {
|
||||
--state->frames_to_skip;
|
||||
return ::_Unwind_GetIP(context) ? ::_URC_NO_REASON : ::_URC_END_OF_STACK;
|
||||
}
|
||||
|
||||
*state->current = reinterpret_cast<void*>(
|
||||
::_Unwind_GetIP(context)
|
||||
);
|
||||
|
||||
++state->current;
|
||||
if (!*(state->current - 1) || state->current == state->end) {
|
||||
return ::_URC_END_OF_STACK;
|
||||
}
|
||||
return ::_URC_NO_REASON;
|
||||
}
|
||||
|
||||
std::size_t this_thread_frames::collect(void** memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
|
||||
std::size_t frames_count = 0;
|
||||
if (!size) {
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::unwind_state state = { skip + 1, memory, memory + size };
|
||||
::_Unwind_Backtrace(&boost::stacktrace::detail::unwind_callback, &state);
|
||||
frames_count = state.current - memory;
|
||||
|
||||
if (frames_count && memory[frames_count - 1] == 0) {
|
||||
-- frames_count;
|
||||
}
|
||||
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
template <class Base>
|
||||
class to_string_impl_base: private Base {
|
||||
public:
|
||||
std::string operator()(const void* addr) {
|
||||
std::string operator()(boost::stacktrace::detail::native_frame_ptr_t addr) {
|
||||
Base::res.clear();
|
||||
Base::prepare_function_name(addr);
|
||||
if (!Base::res.empty()) {
|
||||
Base::res = boost::stacktrace::detail::try_demangle(Base::res.c_str());
|
||||
Base::res = boost::core::demangle(Base::res.c_str());
|
||||
} else {
|
||||
Base::res = to_hex_array(addr).data();
|
||||
}
|
||||
@@ -107,6 +59,9 @@ public:
|
||||
|
||||
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;
|
||||
@@ -115,7 +70,7 @@ std::string to_string(const frame* frames, std::size_t size) {
|
||||
if (i < 10) {
|
||||
res += ' ';
|
||||
}
|
||||
res += boost::lexical_cast<boost::array<char, 40> >(i).data();
|
||||
res += boost::stacktrace::detail::to_dec_array(i).data();
|
||||
res += '#';
|
||||
res += ' ';
|
||||
res += impl(frames[i].address());
|
||||
@@ -130,17 +85,25 @@ std::string to_string(const frame* frames, std::size_t size) {
|
||||
|
||||
|
||||
std::string frame::name() const {
|
||||
#ifndef BOOST_WINDOWS
|
||||
if (!addr_) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
::Dl_info dli;
|
||||
const bool dl_ok = !!::dladdr(addr_, &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::stacktrace::detail::try_demangle(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());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -13,10 +13,15 @@
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/stacktrace/detail/try_demangle.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
||||
#include <boost/stacktrace/detail/location_from_symbol.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
|
||||
#include <backtrace.h>
|
||||
#ifdef BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
|
||||
# include BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
|
||||
#else
|
||||
# include <backtrace.h>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
@@ -27,6 +32,18 @@ struct pc_data {
|
||||
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) {
|
||||
@@ -39,15 +56,87 @@ inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) BOOST_NOEXCEPT {
|
||||
// Do nothing, just return.
|
||||
}
|
||||
|
||||
// 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. I failed to localize the root cause:
|
||||
// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=87653
|
||||
|
||||
|
||||
#if !defined(BOOST_HAS_THREADS) || defined(BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC)
|
||||
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};
|
||||
::backtrace_pcinfo(state, reinterpret_cast<uintptr_t>(addr), boost::stacktrace::detail::libbacktrace_full_callback, 0, &data);
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
)
|
||||
||
|
||||
::backtrace_syminfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr),
|
||||
boost::stacktrace::detail::libbacktrace_syminfo_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
);
|
||||
}
|
||||
line = data.line;
|
||||
}
|
||||
|
||||
@@ -59,14 +148,12 @@ struct to_string_using_backtrace {
|
||||
res += " at ";
|
||||
res += filename;
|
||||
res += ':';
|
||||
res += boost::lexical_cast<boost::array<char, 40> >(line).data();
|
||||
res += boost::stacktrace::detail::to_dec_array(line).data();
|
||||
return true;
|
||||
}
|
||||
|
||||
to_string_using_backtrace() BOOST_NOEXCEPT {
|
||||
state = ::backtrace_create_state(
|
||||
0, 0, 0, 0
|
||||
);
|
||||
state = boost::stacktrace::detail::construct_state(prog_location);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -76,14 +163,29 @@ typedef to_string_impl_base<to_string_using_backtrace> to_string_impl;
|
||||
inline std::string name_impl(const void* addr) {
|
||||
std::string res;
|
||||
|
||||
::backtrace_state* state = ::backtrace_create_state(
|
||||
0, 0, 0, 0
|
||||
);
|
||||
boost::stacktrace::detail::program_location prog_location;
|
||||
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
|
||||
|
||||
boost::stacktrace::detail::pc_data data = {&res, 0, 0};
|
||||
::backtrace_pcinfo(state, reinterpret_cast<uintptr_t>(addr), boost::stacktrace::detail::libbacktrace_full_callback, 0, &data);
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
)
|
||||
||
|
||||
::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::stacktrace::detail::try_demangle(res.c_str());
|
||||
res = boost::core::demangle(res.c_str());
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -94,24 +196,45 @@ inline std::string name_impl(const void* addr) {
|
||||
std::string frame::source_file() const {
|
||||
std::string res;
|
||||
|
||||
::backtrace_state* state = ::backtrace_create_state(
|
||||
0, 0, 0, 0
|
||||
);
|
||||
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};
|
||||
::backtrace_pcinfo(state, reinterpret_cast<uintptr_t>(addr_), boost::stacktrace::detail::libbacktrace_full_callback, 0, &data);
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr_),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
::backtrace_state* state = ::backtrace_create_state(
|
||||
0, 0, 0, 0
|
||||
);
|
||||
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};
|
||||
::backtrace_pcinfo(state, reinterpret_cast<uintptr_t>(addr_), boost::stacktrace::detail::libbacktrace_full_callback, 0, &data);
|
||||
|
||||
if (state) {
|
||||
::backtrace_pcinfo(
|
||||
state,
|
||||
reinterpret_cast<uintptr_t>(addr_),
|
||||
boost::stacktrace::detail::libbacktrace_full_callback,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
&data
|
||||
);
|
||||
}
|
||||
|
||||
return data.line;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -12,23 +12,23 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_WINDOWS
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
# include <dlfcn.h>
|
||||
#else
|
||||
# include <boost/detail/winapi/dll.hpp>
|
||||
# include <boost/winapi/dll.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
class location_from_symbol {
|
||||
#ifndef BOOST_WINDOWS
|
||||
::Dl_info dli_;
|
||||
|
||||
public:
|
||||
explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT
|
||||
: dli_()
|
||||
{
|
||||
if (!::dladdr(addr, &dli_)) {
|
||||
if (!::dladdr(const_cast<void*>(addr), &dli_)) { // `dladdr` on Solaris accepts nonconst addresses
|
||||
dli_.dli_fname = 0;
|
||||
}
|
||||
}
|
||||
@@ -40,22 +40,32 @@ public:
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
return dli_.dli_fname;
|
||||
}
|
||||
#else
|
||||
BOOST_STATIC_CONSTEXPR boost::detail::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
|
||||
};
|
||||
|
||||
class program_location {
|
||||
public:
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class location_from_symbol {
|
||||
BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
|
||||
char file_name_[DEFAULT_PATH_SIZE_];
|
||||
|
||||
public:
|
||||
explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT {
|
||||
file_name_[0] = '\0';
|
||||
|
||||
boost::detail::winapi::MEMORY_BASIC_INFORMATION_ mbi;
|
||||
if (!boost::detail::winapi::VirtualQuery(addr, &mbi, sizeof(mbi))) {
|
||||
boost::winapi::MEMORY_BASIC_INFORMATION_ mbi;
|
||||
if (!boost::winapi::VirtualQuery(addr, &mbi, sizeof(mbi))) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::detail::winapi::HMODULE_ handle = reinterpret_cast<boost::detail::winapi::HMODULE_>(mbi.AllocationBase);
|
||||
if (!boost::detail::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
|
||||
boost::winapi::HMODULE_ handle = reinterpret_cast<boost::winapi::HMODULE_>(mbi.AllocationBase);
|
||||
if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
|
||||
file_name_[0] = '\0';
|
||||
return;
|
||||
}
|
||||
@@ -68,9 +78,28 @@ public:
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
return file_name_;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class program_location {
|
||||
BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
|
||||
char file_name_[DEFAULT_PATH_SIZE_];
|
||||
|
||||
public:
|
||||
program_location() BOOST_NOEXCEPT {
|
||||
file_name_[0] = '\0';
|
||||
|
||||
const boost::winapi::HMODULE_ handle = 0;
|
||||
if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
|
||||
file_name_[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
return file_name_[0] ? file_name_ : 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP
|
||||
|
||||
12
include/boost/stacktrace/detail/pop_options.h
Normal file
12
include/boost/stacktrace/detail/pop_options.h
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// No include guards! Intentionally.
|
||||
|
||||
#ifdef BOOST_STACKTRACE_FUNCTION
|
||||
# undef BOOST_STACKTRACE_FUNCTION
|
||||
#endif
|
||||
|
||||
31
include/boost/stacktrace/detail/push_options.h
Normal file
31
include/boost/stacktrace/detail/push_options.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// No include guards! Intentionally.
|
||||
|
||||
// Link or header only
|
||||
#if !defined(BOOST_STACKTRACE_LINK) && defined(BOOST_STACKTRACE_DYN_LINK)
|
||||
# define BOOST_STACKTRACE_LINK
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_STACKTRACE_LINK) && !defined(BOOST_STACKTRACE_DYN_LINK) && defined(BOOST_ALL_DYN_LINK)
|
||||
# define BOOST_STACKTRACE_DYN_LINK
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_STACKTRACE_LINK
|
||||
# if defined(BOOST_STACKTRACE_DYN_LINK)
|
||||
# ifdef BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
|
||||
# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_EXPORT
|
||||
# else
|
||||
# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_IMPORT
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_STACKTRACE_FUNCTION
|
||||
# endif
|
||||
#elif !defined(BOOST_STACKTRACE_DOXYGEN_INVOKED)
|
||||
# define BOOST_STACKTRACE_FUNCTION inline
|
||||
#endif
|
||||
|
||||
37
include/boost/stacktrace/detail/safe_dump_noop.ipp
Normal file
37
include/boost/stacktrace/detail/safe_dump_noop.ipp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -12,33 +12,44 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
#include <unistd.h> // ::write
|
||||
#include <fcntl.h> // ::open
|
||||
#include <sys/stat.h> // S_IWUSR and friends
|
||||
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t dump(int fd, void** memory, std::size_t size) BOOST_NOEXCEPT {
|
||||
std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
|
||||
// We do not retry, because this function must be typically called from signal handler so it's:
|
||||
// * to scary to continue in case of EINTR
|
||||
// * EAGAIN or EWOULDBLOCK may occur only in case of O_NONBLOCK is set for fd,
|
||||
// so it seems that user does not want to block
|
||||
if (::write(fd, memory, sizeof(void*) * size) == -1) {
|
||||
if (::write(fd, frames, sizeof(native_frame_ptr_t) * frames_count) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
std::size_t dump(const char* file, void** memory, std::size_t mem_size) BOOST_NOEXCEPT {
|
||||
const int fd = ::open(file, O_CREAT | O_WRONLY | O_TRUNC, S_IFREG | S_IWUSR | S_IRUSR);
|
||||
std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
|
||||
const int fd = ::open(
|
||||
file,
|
||||
O_CREAT | O_WRONLY | O_TRUNC,
|
||||
#if defined(S_IWUSR) && defined(S_IRUSR) // Workarounds for some Android OSes
|
||||
S_IWUSR | S_IRUSR
|
||||
#elif defined(S_IWRITE) && defined(S_IREAD)
|
||||
S_IWRITE | S_IREAD
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
);
|
||||
if (fd == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::size_t size = boost::stacktrace::detail::dump(fd, memory, mem_size);
|
||||
const std::size_t size = boost::stacktrace::detail::dump(fd, frames, frames_count);
|
||||
::close(fd);
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -12,45 +12,53 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
|
||||
#include <boost/detail/winapi/get_current_process.hpp>
|
||||
#include <boost/detail/winapi/file_management.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/access_rights.hpp>
|
||||
|
||||
#include <windows.h> // CaptureStackBackTrace
|
||||
#include <boost/winapi/get_current_process.hpp>
|
||||
#include <boost/winapi/file_management.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/access_rights.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t dump(void* fd, void** memory, std::size_t mem_size) BOOST_NOEXCEPT {
|
||||
if (!boost::detail::winapi::WriteFile(fd, memory, static_cast<boost::detail::winapi::DWORD_>(sizeof(void*) * mem_size), 0, 0)) {
|
||||
std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
#if 0 // This code potentially could cause deadlocks (according to the MSDN). Disabled
|
||||
boost::winapi::DWORD_ written;
|
||||
const boost::winapi::DWORD_ bytes_to_write = static_cast<boost::winapi::DWORD_>(
|
||||
sizeof(native_frame_ptr_t) * frames_count
|
||||
);
|
||||
if (!boost::winapi::WriteFile(fd, frames, bytes_to_write, &written, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mem_size;
|
||||
return frames_count;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t dump(const char* file, void** memory, std::size_t mem_size) BOOST_NOEXCEPT {
|
||||
void* const fd = boost::detail::winapi::CreateFileA(
|
||||
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
#if 0 // This code causing deadlocks on some platforms. Disabled
|
||||
void* const fd = boost::winapi::CreateFileA(
|
||||
file,
|
||||
boost::detail::winapi::GENERIC_WRITE_,
|
||||
boost::winapi::GENERIC_WRITE_,
|
||||
0,
|
||||
0,
|
||||
boost::detail::winapi::CREATE_ALWAYS_,
|
||||
boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
|
||||
boost::winapi::CREATE_ALWAYS_,
|
||||
boost::winapi::FILE_ATTRIBUTE_NORMAL_,
|
||||
0
|
||||
);
|
||||
|
||||
if (fd == boost::detail::winapi::invalid_handle_value) {
|
||||
if (fd == boost::winapi::invalid_handle_value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::size_t size = boost::stacktrace::detail::dump(fd, memory, mem_size);
|
||||
boost::detail::winapi::CloseHandle(fd);
|
||||
const std::size_t size = boost::stacktrace::detail::dump(fd, frames, frames_count);
|
||||
boost::winapi::CloseHandle(fd);
|
||||
return size;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
46
include/boost/stacktrace/detail/to_dec_array.hpp
Normal file
46
include/boost/stacktrace/detail/to_dec_array.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
29
include/boost/stacktrace/detail/try_dec_convert.hpp
Normal file
29
include/boost/stacktrace/detail/try_dec_convert.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_TRY_DEMANGLE_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_TRY_DEMANGLE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/demangle.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
inline std::string try_demangle(const char* mangled) {
|
||||
std::string res;
|
||||
|
||||
boost::core::scoped_demangled_name demangled(mangled);
|
||||
if (demangled.get()) {
|
||||
res = demangled.get();
|
||||
} else {
|
||||
res = mangled;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_TRY_DEMANGLE_HPP
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
46
include/boost/stacktrace/detail/void_ptr_cast.hpp
Normal file
46
include/boost/stacktrace/detail/void_ptr_cast.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
|
||||
// Copyright Antony Polukhin, 2015-2022.
|
||||
//
|
||||
// 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -17,164 +17,20 @@
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
|
||||
// Link or header only
|
||||
#if !defined(BOOST_STACKTRACE_LINK) && defined(BOOST_STACKTRACE_DYN_LINK)
|
||||
# define BOOST_STACKTRACE_LINK
|
||||
#endif
|
||||
#include <boost/stacktrace/safe_dump_to.hpp> // boost::stacktrace::detail::native_frame_ptr_t
|
||||
|
||||
#if defined(BOOST_STACKTRACE_LINK) && !defined(BOOST_STACKTRACE_DYN_LINK) && defined(BOOST_ALL_DYN_LINK)
|
||||
# define BOOST_STACKTRACE_DYN_LINK
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_STACKTRACE_LINK
|
||||
# if defined(BOOST_STACKTRACE_DYN_LINK)
|
||||
# ifdef BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
|
||||
# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_EXPORT
|
||||
# else
|
||||
# define BOOST_STACKTRACE_FUNCTION BOOST_SYMBOL_IMPORT
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_STACKTRACE_FUNCTION
|
||||
# endif
|
||||
#elif !defined(BOOST_STACKTRACE_DOXYGEN_INVOKED)
|
||||
# define BOOST_STACKTRACE_FUNCTION inline
|
||||
#endif
|
||||
#include <boost/stacktrace/detail/frame_decl.hpp>
|
||||
#include <boost/stacktrace/detail/push_options.h>
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
class frame;
|
||||
|
||||
|
||||
namespace detail {
|
||||
BOOST_STACKTRACE_FUNCTION std::string to_string(const frame* frames, std::size_t size);
|
||||
|
||||
enum helper{ max_frames_dump = 128 };
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t from_dump(const char* filename, void** frames);
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(const char* file, void** memory, std::size_t size) BOOST_NOEXCEPT;
|
||||
#if defined(BOOST_WINDOWS)
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(void* fd, void** memory, std::size_t size) BOOST_NOEXCEPT;
|
||||
#else
|
||||
// POSIX
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(int fd, void** memory, std::size_t size) BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
|
||||
struct this_thread_frames { // struct is required to avoid warning about usage of inline+BOOST_NOINLINE
|
||||
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(void** memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Non-owning class that references the frame information stored inside the boost::stacktrace::stacktrace class.
|
||||
class frame {
|
||||
/// @cond
|
||||
const void* addr_;
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
/// @brief Constructs frame that references NULL address.
|
||||
/// Calls to source_file() and source_line() will return empty string.
|
||||
/// Calls to source_line() will return 0.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
frame() BOOST_NOEXCEPT
|
||||
: addr_(0)
|
||||
{}
|
||||
|
||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||
/// @brief Copy constructs frame.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
frame(const frame&) = default;
|
||||
|
||||
/// @brief Copy assigns frame.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
frame& operator=(const frame&) = default;
|
||||
#endif
|
||||
|
||||
/// @brief Constructs frame that references addr and could later generate information about that address using platform specific features.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
explicit frame(const void* addr) BOOST_NOEXCEPT
|
||||
: addr_(addr)
|
||||
{}
|
||||
|
||||
/// @returns Name of the frame (function name in a human readable form).
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
/// @throws std::bad_alloc if not enough memory to construct resulting string.
|
||||
BOOST_STACKTRACE_FUNCTION std::string name() const;
|
||||
|
||||
/// @returns Address of the frame function.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
const void* address() const BOOST_NOEXCEPT {
|
||||
return addr_;
|
||||
}
|
||||
|
||||
/// @returns Path to the source file, were the function of the frame is defined. Returns empty string
|
||||
/// if this->source_line() == 0.
|
||||
/// @throws std::bad_alloc if not enough memory to construct resulting string.
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
BOOST_STACKTRACE_FUNCTION std::string source_file() const;
|
||||
|
||||
/// @returns Code line in the source file, were the function of the frame is defined.
|
||||
/// @throws std::bad_alloc if not enough memory to construct string for internal needs.
|
||||
///
|
||||
/// @b Complexity: unknown (lots of platform specific work).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Unsafe.
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t source_line() const;
|
||||
|
||||
/// @brief Checks that frame is not references NULL address.
|
||||
/// @returns `true` if `this->address() != 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
|
||||
/// @brief Checks that frame references NULL address.
|
||||
/// @returns `true` if `this->address() == 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
bool empty() const BOOST_NOEXCEPT { return !address(); }
|
||||
|
||||
/// @cond
|
||||
bool operator!() const BOOST_NOEXCEPT { return !address(); }
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
/// Comparison operators that provide platform dependant ordering and have O(1) complexity; are Async-Handler-Safe.
|
||||
inline bool operator< (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() < rhs.address(); }
|
||||
inline bool operator> (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return rhs < lhs; }
|
||||
inline bool operator<=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); }
|
||||
inline bool operator>=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); }
|
||||
inline bool operator==(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() == rhs.address(); }
|
||||
inline bool operator!=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); }
|
||||
BOOST_CONSTEXPR inline bool operator< (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() < rhs.address(); }
|
||||
BOOST_CONSTEXPR inline bool operator> (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return rhs < lhs; }
|
||||
BOOST_CONSTEXPR inline bool operator<=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); }
|
||||
BOOST_CONSTEXPR inline bool operator>=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); }
|
||||
BOOST_CONSTEXPR inline bool operator==(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() == rhs.address(); }
|
||||
BOOST_CONSTEXPR inline bool operator!=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); }
|
||||
|
||||
/// Fast hashing support, O(1) complexity; Async-Handler-Safe.
|
||||
inline std::size_t hash_value(const frame& f) BOOST_NOEXCEPT {
|
||||
@@ -194,12 +50,12 @@ std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT
|
||||
|
||||
/// @cond
|
||||
|
||||
#undef BOOST_STACKTRACE_FUNCTION
|
||||
#include <boost/stacktrace/detail/pop_options.h>
|
||||
|
||||
#ifndef BOOST_STACKTRACE_LINK
|
||||
# if defined(BOOST_STACKTRACE_USE_NOOP)
|
||||
# include <boost/stacktrace/detail/frame_noop.ipp>
|
||||
# elif defined(BOOST_MSVC) || defined(BOOST_STACKTRACE_USE_WINDBG)
|
||||
# elif defined(BOOST_MSVC) || defined(BOOST_STACKTRACE_USE_WINDBG) || defined(BOOST_STACKTRACE_USE_WINDBG_CACHED)
|
||||
# include <boost/stacktrace/detail/frame_msvc.ipp>
|
||||
# else
|
||||
# include <boost/stacktrace/detail/frame_unwind.ipp>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -12,38 +12,70 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
#if defined(BOOST_WINDOWS)
|
||||
#include <boost/winapi/config.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/push_options.h>
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
|
||||
#endif
|
||||
|
||||
/// @file safe_dump_to.hpp This header contains low-level async-signal-safe functions for dumping call stacks. Dumps are binary serialized arrays of `void*`,
|
||||
/// so you could read them by using 'od -tx8 -An stacktrace_dump_failename' Linux command or using boost::stacktrace::stacktrace::from_dump functions.
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
|
||||
/// @cond
|
||||
namespace detail {
|
||||
struct suppress_noinline_warnings {
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(void* memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
|
||||
void** mem = static_cast<void**>(memory);
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(mem, size / sizeof(void*) - 1, skip + 1);
|
||||
mem[frames_count] = 0;
|
||||
return frames_count + 1;
|
||||
|
||||
typedef const void* native_frame_ptr_t; // TODO: change to `typedef void(*native_frame_ptr_t)();`
|
||||
enum helper{ max_frames_dump = 128 };
|
||||
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t from_dump(const char* filename, native_frame_ptr_t* out_frames);
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
|
||||
#if defined(BOOST_WINDOWS)
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(void* fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
|
||||
#else
|
||||
// POSIX
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
|
||||
struct this_thread_frames { // struct is required to avoid warning about usage of inline+BOOST_NOINLINE
|
||||
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT;
|
||||
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(void* memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
|
||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
||||
|
||||
if (size < sizeof(native_frame_ptr_t)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) BOOST_NOEXCEPT {
|
||||
void* buffer[boost::stacktrace::detail::max_frames_dump + 1];
|
||||
if (max_depth > boost::stacktrace::detail::max_frames_dump) {
|
||||
max_depth = boost::stacktrace::detail::max_frames_dump;
|
||||
}
|
||||
native_frame_ptr_t* mem = static_cast<native_frame_ptr_t*>(memory);
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(mem, size / sizeof(native_frame_ptr_t) - 1, skip + 1);
|
||||
mem[frames_count] = 0;
|
||||
return frames_count + 1;
|
||||
}
|
||||
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, max_depth, skip + 1);
|
||||
buffer[frames_count] = 0;
|
||||
return boost::stacktrace::detail::dump(file, buffer, frames_count + 1);
|
||||
template <class T>
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) BOOST_NOEXCEPT {
|
||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
||||
|
||||
native_frame_ptr_t buffer[boost::stacktrace::detail::max_frames_dump + 1];
|
||||
if (max_depth > boost::stacktrace::detail::max_frames_dump) {
|
||||
max_depth = boost::stacktrace::detail::max_frames_dump;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, max_depth, skip + 1);
|
||||
buffer[frames_count] = 0;
|
||||
return boost::stacktrace::detail::dump(file, buffer, frames_count + 1);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
/// @endcond
|
||||
|
||||
/// @brief Stores current function call sequence into the memory.
|
||||
@@ -52,13 +84,13 @@ namespace detail {
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame. 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::suppress_noinline_warnings::safe_dump_to_impl(memory, size, 0);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, 0);
|
||||
}
|
||||
|
||||
/// @brief Stores current function call sequence into the memory.
|
||||
@@ -67,7 +99,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame. 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.
|
||||
///
|
||||
@@ -75,30 +107,30 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST
|
||||
///
|
||||
/// @param size Size of the preallocated buffer.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, void* memory, std::size_t size) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(memory, size, skip);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, skip);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Opens a file and rewrites its content with current function call sequence.
|
||||
/// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(file, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
/// @brief Opens a file and rewrites its content with current function call sequence.
|
||||
/// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param skip How many top calls to skip and do not store.
|
||||
///
|
||||
@@ -106,29 +138,29 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, const char* file) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(file, skip, max_depth);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, skip, max_depth);
|
||||
}
|
||||
|
||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||
|
||||
/// @brief Writes into the provided file descriptor the current function call sequence.
|
||||
/// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) BOOST_NOEXCEPT;
|
||||
|
||||
/// @brief Writes into the provided file descriptor the current function call sequence.
|
||||
/// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
///
|
||||
/// @returns Stored call sequence depth.
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
/// @param skip How many top calls to skip and do not store.
|
||||
///
|
||||
@@ -140,22 +172,22 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_dep
|
||||
#elif defined(BOOST_WINDOWS)
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(void* fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, void* fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(fd, skip, max_depth);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// POSIX
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(int fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, int fd) BOOST_NOEXCEPT {
|
||||
return boost::stacktrace::detail::suppress_noinline_warnings::safe_dump_to_impl(fd, skip, max_depth);
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -163,4 +195,28 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_dep
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/pop_options.h>
|
||||
|
||||
#if !defined(BOOST_STACKTRACE_LINK) || defined(BOOST_STACKTRACE_INTERNAL_BUILD_LIBS)
|
||||
# if defined(BOOST_STACKTRACE_USE_NOOP)
|
||||
# include <boost/stacktrace/detail/safe_dump_noop.ipp>
|
||||
# include <boost/stacktrace/detail/collect_noop.ipp>
|
||||
# else
|
||||
# if defined(BOOST_WINDOWS)
|
||||
# include <boost/stacktrace/detail/safe_dump_win.ipp>
|
||||
# else
|
||||
# include <boost/stacktrace/detail/safe_dump_posix.ipp>
|
||||
# endif
|
||||
# if defined(BOOST_WINDOWS) && !defined(BOOST_WINAPI_IS_MINGW) // MinGW does not provide RtlCaptureStackBackTrace. MinGW-w64 does.
|
||||
# include <boost/stacktrace/detail/collect_msvc.ipp>
|
||||
# else
|
||||
# include <boost/stacktrace/detail/collect_unwind.ipp>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif // BOOST_STACKTRACE_SAFE_DUMP_TO_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -13,20 +13,26 @@
|
||||
#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 <boost/container/vector.hpp>
|
||||
#include <vector>
|
||||
|
||||
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
||||
# include <type_traits>
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/stacktrace_fwd.hpp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
#include <boost/stacktrace/detail/frame_decl.hpp>
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
|
||||
/// @cond
|
||||
namespace boost {
|
||||
// Forward declaration
|
||||
template <class It> std::size_t hash_range(It, It);
|
||||
}
|
||||
/// @endcond
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
@@ -34,10 +40,11 @@ namespace boost { namespace stacktrace {
|
||||
/// @tparam Allocator Allocator to use during stack capture.
|
||||
template <class Allocator>
|
||||
class basic_stacktrace {
|
||||
boost::container::vector<frame, Allocator> impl_;
|
||||
std::vector<boost::stacktrace::frame, Allocator> impl_;
|
||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
||||
|
||||
/// @cond
|
||||
void fill(void** begin, std::size_t size) {
|
||||
void fill(native_frame_ptr_t* begin, std::size_t size) {
|
||||
if (!size) {
|
||||
return;
|
||||
}
|
||||
@@ -54,7 +61,7 @@ class basic_stacktrace {
|
||||
}
|
||||
|
||||
static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) BOOST_NOEXCEPT {
|
||||
const std::size_t ret = (buffer_size > sizeof(void*) ? buffer_size / sizeof(void*) : 0);
|
||||
const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0);
|
||||
return (ret > 1024 ? 1024 : ret); // Dealing with suspiciously big sizes
|
||||
}
|
||||
|
||||
@@ -64,49 +71,52 @@ class basic_stacktrace {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
BOOST_TRY {
|
||||
{ // Fast path without additional allocations
|
||||
void* buffer[buffer_size];
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size, frames_to_skip + 1);
|
||||
if (buffer_size > frames_count || frames_count >= max_depth) {
|
||||
const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
|
||||
fill(buffer, size);
|
||||
native_frame_ptr_t buffer[buffer_size];
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size < 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:
|
||||
typedef typename Allocator::template rebind<void*>::other allocator_void_t;
|
||||
boost::container::vector<void*, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
|
||||
#ifdef BOOST_NO_CXX11_ALLOCATOR
|
||||
typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t;
|
||||
#else
|
||||
typedef typename std::allocator_traits<Allocator>::template rebind_alloc<native_frame_ptr_t> allocator_void_t;
|
||||
#endif
|
||||
std::vector<native_frame_ptr_t, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
|
||||
do {
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buf.data(), buf.size(), frames_to_skip + 1);
|
||||
if (buf.size() > frames_count || frames_count >= max_depth) {
|
||||
const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
|
||||
fill(buf.data(), size);
|
||||
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 (1);
|
||||
} catch (...) {
|
||||
} 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:
|
||||
typedef typename boost::container::vector<frame, Allocator>::value_type value_type;
|
||||
typedef typename boost::container::vector<frame, Allocator>::allocator_type allocator_type;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_pointer pointer;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_pointer const_pointer;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_reference reference;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_reference const_reference;
|
||||
typedef typename boost::container::vector<frame, Allocator>::size_type size_type;
|
||||
typedef typename boost::container::vector<frame, Allocator>::difference_type difference_type;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_iterator iterator;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_iterator const_iterator;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_reverse_iterator reverse_iterator;
|
||||
typedef typename boost::container::vector<frame, Allocator>::const_reverse_iterator const_reverse_iterator;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::value_type value_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::allocator_type allocator_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer pointer;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer const_pointer;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference reference;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference const_reference;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::size_type size_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::difference_type difference_type;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator iterator;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator const_iterator;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator reverse_iterator;
|
||||
typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
/// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
|
||||
///
|
||||
@@ -174,16 +184,27 @@ public:
|
||||
~basic_stacktrace() BOOST_NOEXCEPT = default;
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS)
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
|
||||
basic_stacktrace(basic_stacktrace&& st) = default;
|
||||
basic_stacktrace(basic_stacktrace&& st) BOOST_NOEXCEPT
|
||||
: impl_(std::move(st.impl_))
|
||||
{}
|
||||
|
||||
/// @b Complexity: O(st.size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
|
||||
basic_stacktrace& operator=(basic_stacktrace&& st) = default;
|
||||
basic_stacktrace& operator=(basic_stacktrace&& st)
|
||||
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
||||
BOOST_NOEXCEPT_IF(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
|
||||
#else
|
||||
BOOST_NOEXCEPT
|
||||
#endif
|
||||
{
|
||||
impl_ = std::move(st.impl_);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @returns Number of function names stored inside the class.
|
||||
@@ -262,11 +283,11 @@ public:
|
||||
bool operator!() const BOOST_NOEXCEPT { return !size(); }
|
||||
/// @endcond
|
||||
|
||||
const boost::container::vector<frame, Allocator>& as_vector() const BOOST_NOEXCEPT {
|
||||
const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const BOOST_NOEXCEPT {
|
||||
return impl_;
|
||||
}
|
||||
|
||||
/// Constructs stacktrace from basic_istreamable that references the dumped stacktrace.
|
||||
/// Constructs stacktrace from basic_istreamable that references the dumped stacktrace. Terminating zero frame is discarded.
|
||||
///
|
||||
/// @b Complexity: O(N)
|
||||
template <class Char, class Trait>
|
||||
@@ -284,38 +305,42 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* ptr = 0;
|
||||
native_frame_ptr_t ptr = 0;
|
||||
ret.impl_.reserve(frames_count);
|
||||
while (in.read(reinterpret_cast<Char*>(&ptr), sizeof(ptr))) {
|
||||
if (!ptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret.impl_.emplace_back(ptr);
|
||||
ret.impl_.push_back(frame(ptr));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Constructs stacktrace from raw memory dump.
|
||||
/// Constructs stacktrace from raw memory dump. Terminating zero frame is discarded.
|
||||
///
|
||||
/// @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 size, const allocator_type& a = allocator_type()) {
|
||||
static basic_stacktrace from_dump(const void* begin, std::size_t buffer_size_in_bytes, const allocator_type& a = allocator_type()) {
|
||||
basic_stacktrace ret(0, 0, a);
|
||||
const void* const* first = static_cast<const void* const*>(begin);
|
||||
const std::size_t frames_count = frames_count_from_buffer_size(size);
|
||||
const native_frame_ptr_t* first = static_cast<const native_frame_ptr_t*>(begin);
|
||||
const std::size_t frames_count = frames_count_from_buffer_size(buffer_size_in_bytes);
|
||||
if (!frames_count) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const void* const* const last = first + frames_count;
|
||||
const native_frame_ptr_t* const last = first + frames_count;
|
||||
ret.impl_.reserve(frames_count);
|
||||
for (; first != last; ++first) {
|
||||
if (!*first) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret.impl_.emplace_back(*first);
|
||||
ret.impl_.push_back(frame(*first));
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -367,13 +392,23 @@ bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<
|
||||
/// Fast hashing support, O(st.size()) complexity; Async-Handler-Safe.
|
||||
template <class Allocator>
|
||||
std::size_t hash_value(const basic_stacktrace<Allocator>& st) BOOST_NOEXCEPT {
|
||||
return boost::hash_range(st.as_vector().data(), st.as_vector().data()+ st.as_vector().size());
|
||||
return boost::hash_range(st.as_vector().begin(), st.as_vector().end());
|
||||
}
|
||||
|
||||
/// Outputs stacktrace in a human readable format to output stream; unsafe to use in async handlers.
|
||||
/// 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 boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size());
|
||||
}
|
||||
|
||||
/// 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::detail::to_string(bt.as_vector().data(), bt.size());
|
||||
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.
|
||||
@@ -381,4 +416,8 @@ typedef basic_stacktrace<> stacktrace;
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // BOOST_STACKTRACE_STACKTRACE_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
35
index.html
Normal file
35
index.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (c) Antony Polukhin, 2014-2022
|
||||
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>
|
||||
© Antony Polukhin, 2014-2022
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -8,6 +8,7 @@
|
||||
"Antony Polukhin <antoshkka -at- gmail.com>"
|
||||
],
|
||||
"description": "Gather, store, copy and print backtraces.",
|
||||
"std": [ "c++23" ],
|
||||
"category": [
|
||||
"System", "Correctness"
|
||||
]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// 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_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>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// 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
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/frame_unwind.ipp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -6,4 +6,10 @@
|
||||
|
||||
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
|
||||
#define BOOST_STACKTRACE_LINK
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/frame_unwind.ipp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -6,4 +6,6 @@
|
||||
|
||||
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
|
||||
#define BOOST_STACKTRACE_LINK
|
||||
#define BOOST_STACKTRACE_USE_NOOP
|
||||
#include <boost/stacktrace/detail/frame_noop.ipp>
|
||||
#include <boost/stacktrace/detail/safe_dump_noop.ipp>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// 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,3 +7,4 @@
|
||||
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
|
||||
#define BOOST_STACKTRACE_LINK
|
||||
#include <boost/stacktrace/detail/frame_msvc.ipp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
11
src/windbg_cached.cpp
Normal file
11
src/windbg_cached.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright Antony Polukhin, 2016-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
|
||||
#define BOOST_STACKTRACE_USE_WINDBG_CACHED
|
||||
#include <boost/stacktrace/detail/frame_msvc.ipp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
231
test/Jamfile.v2
231
test/Jamfile.v2
@@ -1,10 +1,12 @@
|
||||
# Copyright (C) 2016-2017, 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 rt ;
|
||||
@@ -13,66 +15,179 @@ lib ole32 ;
|
||||
|
||||
local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ;
|
||||
lib backtrace
|
||||
:
|
||||
:
|
||||
: <search>$(LIBBACKTRACE_PATH)/lib <link>static
|
||||
:
|
||||
: <include>$(LIBBACKTRACE_PATH)/include
|
||||
: <include>$(LIBBACKTRACE_PATH)/include
|
||||
;
|
||||
|
||||
|
||||
project
|
||||
: requirements
|
||||
<toolset>msvc:<asynch-exceptions>on
|
||||
<toolset>intel:<cxxflags>-wd2196
|
||||
<target-os>linux:<linkflags>-lpthread
|
||||
<warnings>all
|
||||
<debug-symbols>on
|
||||
<test-info>always_show_run_output
|
||||
<visibility>hidden
|
||||
;
|
||||
|
||||
local RDYNAMIC = <target-os>freebsd:<linkflags>"-rdynamic" <target-os>solaris:<linkflags>"-Bdynamic" <target-os>aix:<linkflags>"-rdynamic"
|
||||
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" ;
|
||||
<target-os>darwin,<toolset>clang:<linkflags>"-rdynamic" <target-os>iphone:<linkflags>"-rdynamic"
|
||||
<define>BOOST_STACKTRACE_TEST_EXPORTS_TABLE_USAGE ;
|
||||
|
||||
local HIDE_SYMBS = <target-os>linux:<cxxflags>"-fvisibility=hidden" ;
|
||||
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 BT_DEPS = $(HIDE_SYMBS) <target-os>linux:<library>dl <library>backtrace [ check-target-builds ../build//libbacktrace : : <build>no ] ;
|
||||
local UNWD_DEPS = $(HIDE_SYMBS) <target-os>linux:<library>dl [ check-target-builds ../build//addr2line : : <build>no ] ;
|
||||
local WIND_DEPS = $(HIDE_SYMBS) <library>Dbgeng <library>ole32 [ check-target-builds ../build//WinDbg : : <build>no ] ;
|
||||
local NOOP_DEPS = $(HIDE_SYMBS) ;
|
||||
local BASIC_DEPS = $(RDYNAMIC) <target-os>linux:<library>dl [ check-target-builds ../build//WinDbg : <build>no ] ;
|
||||
local LINKSHARED_BT = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_backtrace $(BT_DEPS) ;
|
||||
local LINKSHARED_AD2L = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_addr2line $(AD2L_DEPS) ;
|
||||
local LINKSHARED_WIND = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_windbg $(WIND_DEPS) ;
|
||||
local LINKSHARED_WIND_CACHED = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_windbg_cached $(WICA_DEPS) ;
|
||||
local LINKSHARED_NOOP = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_noop $(NOOP_DEPS) ;
|
||||
local LINKSHARED_BASIC = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_basic $(BASIC_DEPS) $(FORCE_SYMBOL_EXPORT) ;
|
||||
|
||||
local LINKSHARED_BT = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_backtrace $(BT_DEPS) ;
|
||||
local LINKSHARED_AD2L = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_addr2line $(UNWD_DEPS) ;
|
||||
local LINKSHARED_WIND = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_windbg $(WIND_DEPS) ;
|
||||
local LINKSHARED_NOOP = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_noop $(NOOP_DEPS) ;
|
||||
local LINKSHARED_BASIC = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_basic $(BASIC_DEPS) ;
|
||||
# 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) ;
|
||||
|
||||
lib test_impl_lib_backtrace : test_impl.cpp : $(LINKSHARED_BT) ;
|
||||
lib test_impl_lib_addr2line : test_impl.cpp : $(LINKSHARED_AD2L) ;
|
||||
lib test_impl_lib_windbg : test_impl.cpp : $(LINKSHARED_WIND) ;
|
||||
lib test_impl_lib_noop : test_impl.cpp : $(LINKSHARED_NOOP) ;
|
||||
obj test_impl_nohide-obj : test_impl.cpp : <debug-symbols>on $(LINKSHARED_BASIC) ;
|
||||
lib test_impl_lib_basic : test_impl_nohide-obj : <debug-symbols>on $(LINKSHARED_BASIC) ;
|
||||
|
||||
|
||||
# Libs without debug symbols
|
||||
lib test_impl_lib_backtrace_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_BT) ;
|
||||
lib test_impl_lib_addr2line_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_AD2L) ;
|
||||
lib test_impl_lib_windbg_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_WIND) ;
|
||||
lib test_impl_lib_windbg_cached_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_WIND_CACHED) ;
|
||||
lib test_impl_lib_noop_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_NOOP) ;
|
||||
|
||||
obj test_impl_nohide_no_dbg-obj : test_impl.cpp : <debug-symbols>off $(LINKSHARED_BASIC) ;
|
||||
lib test_impl_lib_basic_no_dbg : test_impl_nohide_no_dbg-obj : <debug-symbols>off $(LINKSHARED_BASIC) ;
|
||||
|
||||
obj test_impl_nohide-obj : test_impl.cpp : $(LINKSHARED_BASIC) ;
|
||||
lib test_impl_lib_basic : test_impl_nohide-obj : $(LINKSHARED_BASIC) ;
|
||||
|
||||
test-suite stacktrace_tests
|
||||
:
|
||||
# Header only tests
|
||||
[ run test.cpp test_impl.cpp : : : <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : backtrace_ho ]
|
||||
[ run test.cpp test_impl.cpp : : : <define>BOOST_STACKTRACE_USE_ADDR2LINE $(UNWD_DEPS) : addr2line_ho ]
|
||||
[ run test_noop.cpp test_impl.cpp : : : <define>BOOST_STACKTRACE_USE_NOOP $(NOOP_DEPS) : noop_ho ]
|
||||
[ run test.cpp test_impl.cpp : : : $(WIND_DEPS) : windbg_ho ]
|
||||
[ run test.cpp test_impl.cpp : : : $(BASIC_DEPS) : basic_ho ]
|
||||
|
||||
# Test with shared linked implementations
|
||||
[ run test.cpp : : : <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) : backtrace_lib ]
|
||||
[ run test.cpp : : : <library>.//test_impl_lib_addr2line $(LINKSHARED_AD2L) : addr2line_lib ]
|
||||
[ run test.cpp : : : <library>.//test_impl_lib_windbg $(LINKSHARED_WIND) : windbg_lib ]
|
||||
[ run test_noop.cpp : : : <library>.//test_impl_lib_noop $(LINKSHARED_NOOP) : noop_lib ]
|
||||
[ run test.cpp : : : <library>.//test_impl_lib_basic $(LINKSHARED_BASIC) : basic_lib ]
|
||||
# Header only tests with debug symbols
|
||||
[ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : backtrace_ho ]
|
||||
[ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_BACKTRACE <define>BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC $(BT_DEPS) : backtrace_ho_static ]
|
||||
[ 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 ]
|
||||
|
||||
# Header only trivial
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : trivial_backtrace_ho ]
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_ADDR2LINE $(AD2L_DEPS) : trivial_addr2line_ho ]
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_NOOP $(NOOP_DEPS) : trivial_noop_ho ]
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on $(WIND_DEPS) : trivial_windbg_ho ]
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_WINDBG_CACHED $(WICA_DEPS) : trivial_windbg_cached_ho ]
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) : trivial_basic_ho ]
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(BASIC_DEPS) : trivial_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 ]
|
||||
|
||||
# Trivial test with shared linked implementations with debug symbols
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) : trivial_backtrace_lib ]
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_addr2line $(LINKSHARED_AD2L) : trivial_addr2line_lib ]
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg $(LINKSHARED_WIND) : trivial_windbg_lib ]
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg_cached $(LINKSHARED_WIND_CACHED) : trivial_windbg_cached_lib ]
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_noop $(LINKSHARED_NOOP) : trivial_noop_lib ]
|
||||
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_basic $(LINKSHARED_BASIC) : trivial_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_backtrace $(LINKSHARED_BT)
|
||||
<define>BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC
|
||||
: backtrace_lib_threaded_ststic ]
|
||||
[ 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 ]
|
||||
|
||||
##### 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 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 ]
|
||||
{
|
||||
local target_name = $(p[1]:B) ;
|
||||
@@ -82,11 +197,45 @@ for local p in [ glob ../example/*.cpp ]
|
||||
additional_dependency = <library>/boost/filesystem//boost_filesystem <library>/boost/system//boost_system <target-os>linux:<library>rt ;
|
||||
}
|
||||
|
||||
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_BT) $(additional_dependency) : backtrace_$(p[1]:B) ] ;
|
||||
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_AD2L) $(additional_dependency) : addr2line_$(p[1]:B) ] ;
|
||||
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_WIND) $(additional_dependency) : windbg_$(p[1]:B) ] ;
|
||||
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_NOOP) $(additional_dependency) : noop_$(p[1]:B) ] ;
|
||||
stacktrace_tests += [ run $(p) : : : $(LINKSHARED_BASIC) $(additional_dependency) : basic_$(p[1]:B) ] ;
|
||||
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 ;
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
# 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-2017.
|
||||
# Copyright Antony Polukhin, 2016-2022.
|
||||
|
||||
#
|
||||
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
|
||||
# and how it can be used with Boost libraries.
|
||||
#
|
||||
# File revision #3
|
||||
# File revision #5
|
||||
|
||||
init:
|
||||
- set BRANCH_TO_TEST=%APPVEYOR_REPO_BRANCH% # Change to branch you wish to test. Use %APPVEYOR_REPO_BRANCH% for current branch.
|
||||
@@ -29,9 +29,7 @@ skip_tags: true
|
||||
|
||||
before_build:
|
||||
- set PATH=%PATH%;C:\\MinGW\\bin
|
||||
# Set this to the name of the library
|
||||
- set PROJECT_TO_TEST=%APPVEYOR_PROJECT_NAME%
|
||||
- echo "Testing %PROJECT_TO_TEST%"
|
||||
- echo "Testing %APPVEYOR_PROJECT_NAME%"
|
||||
# Cloning Boost libraries (fast nondeep cloning)
|
||||
- set BOOST=C:/boost-local
|
||||
- git init %BOOST%
|
||||
@@ -39,19 +37,17 @@ before_build:
|
||||
- git remote add --no-tags -t %BRANCH_TO_TEST% origin https://github.com/boostorg/boost.git
|
||||
- git fetch --depth=1
|
||||
- git checkout %BRANCH_TO_TEST%
|
||||
- git submodule update --init --merge
|
||||
- git submodule update --init --merge --jobs 16
|
||||
- git remote set-branches --add origin %BRANCH_TO_TEST%
|
||||
- git pull --recurse-submodules
|
||||
- git status
|
||||
#- git pull --recurse-submodules # Updaes submodules to most recent version. Not required
|
||||
- rm -rf %BOOST%/libs/%BOOST_REMOVE%
|
||||
- mv %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%PROJECT_TO_TEST%
|
||||
- set TRAVIS_BUILD_DIR=%BOOST%/libs/%PROJECT_TO_TEST%
|
||||
- mv %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%APPVEYOR_PROJECT_NAME%
|
||||
|
||||
build_script:
|
||||
- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
|
||||
- bootstrap.bat
|
||||
- b2.exe headers
|
||||
- cd %BOOST%/libs/%PROJECT_TO_TEST%/test
|
||||
- cd %BOOST%/libs/%APPVEYOR_PROJECT_NAME%/test
|
||||
|
||||
after_build:
|
||||
before_test:
|
||||
|
||||
139
test/test.cpp
139
test/test.cpp
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -10,56 +10,36 @@
|
||||
#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
|
||||
|
||||
#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_ST_API
|
||||
# define BOOST_STACKTRACE_TEST_SHOULD_OUTPUT_READABLE_NAMES 1
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(BOOST_GCC) && defined(BOOST_WINDOWS) && !defined(BOOST_STACKTRACE_USE_BACKTRACE) && !defined(BOOST_STACKTRACE_USE_ADDR2LINE)
|
||||
// MinGW with basic functionality
|
||||
# define BOOST_STACKTRACE_SYMNAME 0
|
||||
#else
|
||||
# define BOOST_STACKTRACE_SYMNAME 1
|
||||
#endif
|
||||
|
||||
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
|
||||
BOOST_ST_API std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1);
|
||||
BOOST_ST_API stacktrace return_from_nested_namespaces();
|
||||
BOOST_ST_API boost::stacktrace::stacktrace bar1();
|
||||
BOOST_ST_API boost::stacktrace::stacktrace bar2();
|
||||
|
||||
BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo1(int i) {
|
||||
if (i) {
|
||||
return foo2(i - 1, foo1);
|
||||
}
|
||||
|
||||
std::pair<stacktrace, stacktrace> ret;
|
||||
try {
|
||||
throw std::logic_error("test");
|
||||
} catch (const std::logic_error& /*e*/) {
|
||||
ret.second = stacktrace();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void test_deeply_nested_namespaces() {
|
||||
std::stringstream ss;
|
||||
ss << return_from_nested_namespaces();
|
||||
std::cout << ss.str() << '\n';
|
||||
#if BOOST_STACKTRACE_SYMNAME
|
||||
#if BOOST_STACKTRACE_TEST_SHOULD_OUTPUT_READABLE_NAMES
|
||||
BOOST_TEST(ss.str().find("main") != std::string::npos);
|
||||
|
||||
BOOST_TEST(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos);
|
||||
BOOST_TEST(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos
|
||||
|| ss.str().find("1# return_from_nested_namespaces") != std::string::npos); // GCC with -O1 has strange inlining, so this line is true while the prev one is false.
|
||||
|
||||
BOOST_TEST(ss.str().find("return_from_nested_namespaces") != std::string::npos);
|
||||
#endif
|
||||
|
||||
@@ -67,16 +47,37 @@ void test_deeply_nested_namespaces() {
|
||||
BOOST_TEST(ns1 != return_from_nested_namespaces()); // Different addresses in test_deeply_nested_namespaces() function
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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() {
|
||||
std::pair<stacktrace, stacktrace> res = foo2(Depth, foo1);
|
||||
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());
|
||||
|
||||
@@ -89,18 +90,16 @@ void test_nested() {
|
||||
BOOST_TEST(ss1.str().find(" in ") != std::string::npos);
|
||||
BOOST_TEST(ss2.str().find(" in ") != std::string::npos);
|
||||
|
||||
#if BOOST_STACKTRACE_SYMNAME
|
||||
#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);
|
||||
|
||||
BOOST_TEST(ss1.str().find("foo2") != 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("foo1") != std::string::npos);
|
||||
BOOST_TEST(ss2.str().find("foo1") != 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>
|
||||
@@ -110,7 +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);
|
||||
@@ -147,51 +150,28 @@ void test_comparisons() {
|
||||
}
|
||||
|
||||
void test_iterators() {
|
||||
stacktrace nst = return_from_nested_namespaces();
|
||||
stacktrace st;
|
||||
|
||||
BOOST_TEST(nst.begin() != st.begin());
|
||||
BOOST_TEST(nst.cbegin() != st.cbegin());
|
||||
BOOST_TEST(nst.crbegin() != st.crbegin());
|
||||
BOOST_TEST(nst.rbegin() != st.rbegin());
|
||||
|
||||
BOOST_TEST(st.begin() == st.begin());
|
||||
BOOST_TEST(st.cbegin() == st.cbegin());
|
||||
BOOST_TEST(st.crbegin() == st.crbegin());
|
||||
BOOST_TEST(st.rbegin() == st.rbegin());
|
||||
|
||||
BOOST_TEST(++st.begin() == ++st.begin());
|
||||
BOOST_TEST(++st.cbegin() == ++st.cbegin());
|
||||
BOOST_TEST(++st.crbegin() == ++st.crbegin());
|
||||
BOOST_TEST(++st.rbegin() == ++st.rbegin());
|
||||
|
||||
BOOST_TEST(st.begin() + 1 == st.begin() + 1);
|
||||
BOOST_TEST(st.cbegin() + 1 == st.cbegin() + 1);
|
||||
BOOST_TEST(st.crbegin() + 1 == st.crbegin() + 1);
|
||||
BOOST_TEST(st.rbegin() + 1 == st.rbegin() + 1);
|
||||
|
||||
BOOST_TEST(nst.end() != st.end());
|
||||
BOOST_TEST(nst.cend() != st.cend());
|
||||
BOOST_TEST(nst.crend() != st.crend());
|
||||
BOOST_TEST(nst.rend() != st.rend());
|
||||
|
||||
BOOST_TEST(st.end() == st.end());
|
||||
BOOST_TEST(st.cend() == st.cend());
|
||||
BOOST_TEST(st.crend() == st.crend());
|
||||
BOOST_TEST(st.rend() == st.rend());
|
||||
|
||||
BOOST_TEST(--st.end() == --st.end());
|
||||
BOOST_TEST(--st.cend() == --st.cend());
|
||||
BOOST_TEST(--st.crend() == --st.crend());
|
||||
BOOST_TEST(--st.rend() == --st.rend());
|
||||
|
||||
|
||||
BOOST_TEST(st.end() > st.begin());
|
||||
BOOST_TEST(st.end() > st.cbegin());
|
||||
BOOST_TEST(st.cend() > st.cbegin());
|
||||
BOOST_TEST(st.cend() > st.begin());
|
||||
|
||||
|
||||
BOOST_TEST(st.size() == static_cast<std::size_t>(st.end() - st.begin()));
|
||||
BOOST_TEST(st.size() == static_cast<std::size_t>(st.end() - st.cbegin()));
|
||||
BOOST_TEST(st.size() == static_cast<std::size_t>(st.cend() - st.cbegin()));
|
||||
@@ -210,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);
|
||||
@@ -226,10 +206,15 @@ void test_frame() {
|
||||
BOOST_TEST(fv);
|
||||
if (i > 1 && i < min_size - 3) { // Begin ...and end of the trace may match, skipping
|
||||
BOOST_TEST(st[i] != fv);
|
||||
|
||||
#if !(defined(BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL) && defined(BOOST_MSVC))
|
||||
// MSVC can not get function name withhout debug symbols even if it is exported
|
||||
BOOST_TEST(st[i].name() != fv.name());
|
||||
BOOST_TEST(st[i] != fv);
|
||||
BOOST_TEST(st[i] < fv || st[i] > fv);
|
||||
BOOST_TEST(hash_value(st[i]) != hash_value(fv));
|
||||
#endif
|
||||
|
||||
if (st[i].source_line()) {
|
||||
BOOST_TEST(st[i].source_file() != fv.source_file() || st[i].source_line() != fv.source_line());
|
||||
}
|
||||
@@ -242,9 +227,9 @@ 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
|
||||
@@ -274,6 +259,7 @@ void test_empty_basic_stacktrace() {
|
||||
|
||||
int main() {
|
||||
test_deeply_nested_namespaces();
|
||||
test_frames_string_data_validity();
|
||||
test_nested<15>();
|
||||
test_comparisons();
|
||||
test_iterators();
|
||||
@@ -281,15 +267,14 @@ int main() {
|
||||
test_empty_basic_stacktrace<true>();
|
||||
test_empty_basic_stacktrace<false>();
|
||||
|
||||
BOOST_TEST(&bar1 != &bar2);
|
||||
boost::stacktrace::stacktrace b1 = bar1();
|
||||
BOOST_TEST(&make_some_stacktrace1 != &make_some_stacktrace2);
|
||||
boost::stacktrace::stacktrace b1 = make_some_stacktrace1();
|
||||
BOOST_TEST(b1.size() == 4);
|
||||
boost::stacktrace::stacktrace 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<250>();
|
||||
test_nested<300>();
|
||||
test_nested<260>(false);
|
||||
BOOST_TEST(boost::stacktrace::stacktrace(0, 1).size() == 1);
|
||||
BOOST_TEST(boost::stacktrace::stacktrace(1, 1).size() == 1);
|
||||
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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
|
||||
|
||||
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
|
||||
BOOST_ST_API BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1) {
|
||||
BOOST_ST_API BOOST_NOINLINE std::pair<stacktrace, stacktrace> function_from_library(int i, foo1_t foo1) {
|
||||
if (i) {
|
||||
return foo1(--i);
|
||||
} else {
|
||||
@@ -50,31 +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::stacktrace bar1_impl(int d = 0) {
|
||||
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 bar1_impl(d + 1);
|
||||
return make_some_stacktrace1_impl(d + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace bar2_impl(int d = 0) {
|
||||
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 bar2_impl(d + 1);
|
||||
return make_some_stacktrace2_impl(d + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace bar1() {
|
||||
boost::stacktrace::stacktrace result = bar1_impl();
|
||||
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 bar2() {
|
||||
boost::stacktrace::stacktrace result = bar2_impl();
|
||||
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
58
test/test_impl.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,21 @@
|
||||
// Copyright Antony Polukhin, 2016-2017.
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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;
|
||||
using boost::stacktrace::frame;
|
||||
|
||||
#ifdef BOOST_STACKTRACE_DYN_LINK
|
||||
# define BOOST_ST_API BOOST_SYMBOL_IMPORT
|
||||
#else
|
||||
# define BOOST_ST_API
|
||||
#endif
|
||||
|
||||
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
|
||||
BOOST_ST_API std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1);
|
||||
BOOST_ST_API stacktrace return_from_nested_namespaces();
|
||||
|
||||
|
||||
BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo1(int i) {
|
||||
if (i) {
|
||||
return foo2(i - 1, foo1);
|
||||
}
|
||||
|
||||
std::pair<stacktrace, stacktrace> ret;
|
||||
try {
|
||||
throw std::logic_error("test");
|
||||
} catch (const std::logic_error& /*e*/) {
|
||||
ret.second = stacktrace();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void test_deeply_nested_namespaces() {
|
||||
BOOST_TEST(return_from_nested_namespaces().size() == 0);
|
||||
BOOST_TEST(return_from_nested_namespaces().empty());
|
||||
@@ -45,7 +23,7 @@ void test_deeply_nested_namespaces() {
|
||||
}
|
||||
|
||||
void test_nested() {
|
||||
std::pair<stacktrace, stacktrace> res = foo2(15, foo1);
|
||||
std::pair<stacktrace, stacktrace> res = function_from_library(15, function_from_main_translation_unit);
|
||||
|
||||
BOOST_TEST(!res.first);
|
||||
BOOST_TEST(res.first.empty());
|
||||
|
||||
71
test/test_num_conv.cpp
Normal file
71
test/test_num_conv.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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();
|
||||
}
|
||||
15
test/test_trivial.cpp
Normal file
15
test/test_trivial.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright Antony Polukhin, 2022-2022.
|
||||
//
|
||||
// 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)
|
||||
|
||||
// See https://github.com/boostorg/stacktrace/issues/116
|
||||
|
||||
#include <boost/stacktrace/stacktrace.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << boost::stacktrace::stacktrace() << std::endl;
|
||||
}
|
||||
79
test/test_void_ptr_cast.cpp
Normal file
79
test/test_void_ptr_cast.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright 2017 Antony Polukhin.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/stacktrace/detail/void_ptr_cast.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
int foo1_func(int) { return 0; }
|
||||
void foo2_func(int, int, ...) {}
|
||||
|
||||
struct test_struct {
|
||||
int foo1_memb(int) const { return 0; }
|
||||
void foo2_memb(int, int, ...) {}
|
||||
};
|
||||
|
||||
template <class F1, class F2>
|
||||
void test(F1 foo1, F2 foo2) {
|
||||
using boost::stacktrace::detail::void_ptr_cast;
|
||||
|
||||
typedef void(*void_f_ptr)();
|
||||
|
||||
// Function/variable to void(*)()
|
||||
void_f_ptr fp1 = void_ptr_cast<void_f_ptr>(foo1);
|
||||
void_f_ptr fp2 = void_ptr_cast<void_f_ptr>(foo2);
|
||||
BOOST_TEST(fp1);
|
||||
BOOST_TEST(fp2);
|
||||
BOOST_TEST(fp1 != fp2);
|
||||
|
||||
// Function/variable to void*
|
||||
void* vp1 = void_ptr_cast<void*>(foo1);
|
||||
void* vp2 = void_ptr_cast<void*>(foo2);
|
||||
BOOST_TEST(vp1);
|
||||
BOOST_TEST(vp2);
|
||||
BOOST_TEST(vp1 != vp2);
|
||||
|
||||
// void* to void(*)()
|
||||
void_f_ptr fp1_2 = void_ptr_cast<void_f_ptr>(vp1);
|
||||
void_f_ptr fp2_2 = void_ptr_cast<void_f_ptr>(vp2);
|
||||
BOOST_TEST(fp1_2);
|
||||
BOOST_TEST(fp2_2);
|
||||
BOOST_TEST(fp1_2 != fp2_2);
|
||||
BOOST_TEST(fp1 == fp1_2);
|
||||
BOOST_TEST(fp2 == fp2_2);
|
||||
|
||||
// void(*)() to void*
|
||||
BOOST_TEST(void_ptr_cast<void*>(fp1) == vp1);
|
||||
BOOST_TEST(void_ptr_cast<void*>(fp2) == vp2);
|
||||
|
||||
// void(*)() to function/variable
|
||||
BOOST_TEST(void_ptr_cast<F1>(fp1) == foo1);
|
||||
BOOST_TEST(void_ptr_cast<F2>(fp2) == foo2);
|
||||
|
||||
// void* to function/variable
|
||||
BOOST_TEST(void_ptr_cast<F1>(vp1) == foo1);
|
||||
BOOST_TEST(void_ptr_cast<F2>(vp2) == foo2);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Testing for functions
|
||||
test(foo1_func, foo2_func);
|
||||
|
||||
typedef void(func_t)();
|
||||
test(
|
||||
boost::stacktrace::detail::void_ptr_cast<func_t* const>(foo1_func),
|
||||
boost::stacktrace::detail::void_ptr_cast<func_t* const>(foo2_func)
|
||||
);
|
||||
|
||||
// Testing for variables (just in case...)
|
||||
int i = 0;
|
||||
double j= 1;
|
||||
test(&i, &j);
|
||||
|
||||
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
57
test/thread_safety_checking.cpp
Normal file
57
test/thread_safety_checking.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright Antony Polukhin, 2016-2022.
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
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();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
26
test/torture.cpp
Normal file
26
test/torture.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user