mirror of
https://github.com/boostorg/stacktrace.git
synced 2026-01-28 19:52:08 +00:00
Compare commits
164 Commits
boost-1.70
...
apolukhin-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
762b4916fc | ||
|
|
3c756ad478 | ||
|
|
005bcbad7d | ||
|
|
b105972fbc | ||
|
|
c624479813 | ||
|
|
3f79aee92f | ||
|
|
da94896d2d | ||
|
|
0a1f8ac9a0 | ||
|
|
7c79d84614 | ||
|
|
e95c2723d8 | ||
|
|
9028c8a413 | ||
|
|
b37fc77b5d | ||
|
|
aa97b1a34c | ||
|
|
23e1213f54 | ||
|
|
ad121dbed0 | ||
|
|
981e37c218 | ||
|
|
cbf0df774d | ||
|
|
34e56c4e90 | ||
|
|
f32bd5a543 | ||
|
|
79fc075655 | ||
|
|
6624a0aaeb | ||
|
|
ca76415503 | ||
|
|
4352901d19 | ||
|
|
2820ed36b5 | ||
|
|
1a389747a3 | ||
|
|
1db160d566 | ||
|
|
1b16c5d6ae | ||
|
|
274aeaa351 | ||
|
|
a615135de0 | ||
|
|
32749a7041 | ||
|
|
08d4f46333 | ||
|
|
97bc049bcb | ||
|
|
98ed11d235 | ||
|
|
f1c5cd8963 | ||
|
|
94f11c52eb | ||
|
|
f6f3623594 | ||
|
|
aad95c2667 | ||
|
|
a95e7e5860 | ||
|
|
8b79199a2a | ||
|
|
6e39a41abf | ||
|
|
5747f85c0b | ||
|
|
c093aef138 | ||
|
|
66c0f7a54f | ||
|
|
aacfc2e557 | ||
|
|
80af3a44c3 | ||
|
|
69260779d1 | ||
|
|
2c83563695 | ||
|
|
39afcefb64 | ||
|
|
d1b7a61353 | ||
|
|
351b03d522 | ||
|
|
a33e198cf6 | ||
|
|
824f0c0ea7 | ||
|
|
f783534b0f | ||
|
|
27093f24cb | ||
|
|
12e07fcca1 | ||
|
|
95caaeaf99 | ||
|
|
906bb0b551 | ||
|
|
87ef7f6950 | ||
|
|
f6d4e117cd | ||
|
|
0d8aed6bc9 | ||
|
|
3de5aea554 | ||
|
|
e9e0b6c3d4 | ||
|
|
1fd3665a71 | ||
|
|
0ec802df84 | ||
|
|
4f2da0e653 | ||
|
|
8b1699c9d3 | ||
|
|
dc5cd9d1f3 | ||
|
|
fbcd543b51 | ||
|
|
d849b145a6 | ||
|
|
760203fde5 | ||
|
|
6a7510bd5e | ||
|
|
959b65f303 | ||
|
|
d6320cc5a7 | ||
|
|
22a2c3920b | ||
|
|
fc21c82b27 | ||
|
|
ae87ac9bcf | ||
|
|
15b12e6e95 | ||
|
|
34441a64c8 | ||
|
|
abba18524f | ||
|
|
c6e7712868 | ||
|
|
c836328054 | ||
|
|
71da3cfd56 | ||
|
|
95065ca638 | ||
|
|
b9a0a12f1c | ||
|
|
4cf47389c1 | ||
|
|
d904d26f4f | ||
|
|
cd4c5fe554 | ||
|
|
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 |
502
.github/workflows/ci.yml
vendored
Normal file
502
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,502 @@
|
||||
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-12
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-22.04
|
||||
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
|
||||
linkflags: "linkflags=--coverage -lasan -lubsan"
|
||||
gcov_tool: "gcov-12"
|
||||
launcher: "testing.launcher=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.8"
|
||||
- toolset: gcc-9
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-22.04
|
||||
- toolset: clang-15
|
||||
cxxstd: "03,11,14,17,2a"
|
||||
os: ubuntu-22.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@v4
|
||||
|
||||
- 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.16.zip
|
||||
unzip v1.16.zip
|
||||
LCOV="`pwd`/lcov-1.16/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@v4
|
||||
|
||||
- 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
|
||||
|
||||
posix-cmake-subdir:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-20.04, ubuntu-22.04, macos-12, macos-13, macos-14 ]
|
||||
shared: [ OFF, ON ]
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt-get -y 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 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Use library with add_subdirectory
|
||||
run: |
|
||||
cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBUILD_SHARED_LIBS=${{matrix.shared}} ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
posix-cmake-install:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-20.04, ubuntu-22.04, macos-12, macos-13, macos-14 ]
|
||||
shared: [ OFF, ON ]
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt-get -y 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 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local -DBUILD_SHARED_LIBS=${{matrix.shared}} ..
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build .
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target install
|
||||
|
||||
- name: Use the installed library
|
||||
run: |
|
||||
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
|
||||
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
cmake --build .
|
||||
export LD_LIBRARY_PATH=$HOME/.local/lib:$LD_LIBRARY_PATH
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
posix-cmake-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-20.04, ubuntu-22.04, macos-12, macos-13, macos-14 ]
|
||||
shared: [ OFF, ON ]
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt-get -y 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 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Configure (Debug)
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build_debug__ && cd __build_debug__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON -DBUILD_SHARED_LIBS=${{matrix.shared}} -DCMAKE_BUILD_TYPE=Debug ..
|
||||
|
||||
- name: Build tests (Debug)
|
||||
run: |
|
||||
cd ../boost-root/__build_debug__
|
||||
cmake --build . --target tests
|
||||
|
||||
- name: Run tests (Debug)
|
||||
run: |
|
||||
cd ../boost-root/__build_debug__
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
windows-cmake-subdir:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ windows-2019, windows-2022 ]
|
||||
shared: [ OFF, ON ]
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
|
||||
- name: Use library with add_subdirectory (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBUILD_SHARED_LIBS=${{matrix.shared}} ..
|
||||
cmake --build . --config Debug
|
||||
ctest --output-on-failure --no-tests=error -C Debug
|
||||
|
||||
- name: Use library with add_subdirectory (RelWithDebInfo)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test/__build__
|
||||
cmake --build . --config RelWithDebInfo
|
||||
ctest --output-on-failure --no-tests=error -C RelWithDebInfo
|
||||
|
||||
windows-cmake-install:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ windows-2019, windows-2022 ]
|
||||
shared: [ OFF, ON ]
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
|
||||
- name: Configure
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix -DBUILD_SHARED_LIBS=${{matrix.shared}} ..
|
||||
|
||||
- name: Install (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target install --config Debug
|
||||
|
||||
- name: Install (RelWithDebInfo)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target install --config RelWithDebInfo
|
||||
|
||||
- name: Use the installed library (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test && mkdir __build__ && cd __build__
|
||||
cmake -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
|
||||
cmake --build . --config Debug
|
||||
PATH C:\cmake-prefix\bin;%PATH%
|
||||
ctest --output-on-failure --no-tests=error -C Debug
|
||||
|
||||
- name: Use the installed library (RelWithDebInfo)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test/__build__
|
||||
cmake --build . --config RelWithDebInfo
|
||||
PATH C:\cmake-prefix\bin;%PATH%
|
||||
ctest --output-on-failure --no-tests=error -C RelWithDebInfo
|
||||
|
||||
windows-cmake-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ windows-2019, windows-2022 ]
|
||||
shared: [ OFF, ON ]
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
|
||||
- name: Configure
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DBUILD_TESTING=ON -DBUILD_SHARED_LIBS=${{matrix.shared}} ..
|
||||
|
||||
- name: Build tests (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target tests --config Debug
|
||||
|
||||
- name: Run tests (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
ctest --output-on-failure --no-tests=error -C Debug
|
||||
|
||||
- name: Build tests (RelWithDebInfo)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target tests --config RelWithDebInfo
|
||||
|
||||
- name: Run tests (RelWithDebInfo)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
ctest --output-on-failure --no-tests=error -C RelWithDebInfo
|
||||
123
.travis.yml
123
.travis.yml
@@ -1,123 +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-2019.
|
||||
|
||||
#
|
||||
# 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/* */libs/timer/src/* */thread/src/* */pthread/once_atomic.cpp */src/pthread/thread.cpp */thread/src/future.cpp */boost/operators.hpp'
|
||||
|
||||
# Explicitly remove the following library from Boost. This may be usefull, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# 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 -O0" LINK_FLAGS="" TOOLSET=gcc-6
|
||||
- CXX_FLAGS="-std=c++11 -O1" LINK_FLAGS="" TOOLSET=gcc-6
|
||||
#- CXX_FLAGS="-std=c++11 -stdlib=libc++" LINK_FLAGS="-stdlib=libc++" TOOLSET=clang
|
||||
#- CXX_FLAGS="-std=c++1y -stdlib=libc++" LINK_FLAGS="-stdlib=libc++" TOOLSET=clang
|
||||
|
||||
###############################################################################################################
|
||||
# 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 -a "testing.launcher=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.3 " address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -fsanitize=address,undefined -DBOOST_TRAVISCI_BUILD $CXX_FLAGS" linkflags="$LINK_FLAGS --coverage -lasan -lubsan"
|
||||
- ../../../b2 -a address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="-fsanitize=thread -DBOOST_TRAVISCI_BUILD $CXX_FLAGS" linkflags="$LINK_FLAGS -ltsan"
|
||||
|
||||
after_success:
|
||||
# Copying Coveralls data to a separate folder
|
||||
- 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
|
||||
134
CMakeLists.txt
Normal file
134
CMakeLists.txt
Normal file
@@ -0,0 +1,134 @@
|
||||
# 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::config
|
||||
Boost::container_hash
|
||||
Boost::core
|
||||
Boost::predef
|
||||
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;${CMAKE_DL_LIBS}" "")
|
||||
stacktrace_add_library(addr2line ${BOOST_STACKTRACE_ENABLE_ADDR2LINE} "${CMAKE_DL_LIBS}" "")
|
||||
stacktrace_add_library(basic ${BOOST_STACKTRACE_ENABLE_BASIC} "${CMAKE_DL_LIBS}" "")
|
||||
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")
|
||||
|
||||
# boost_stacktrace, default library
|
||||
|
||||
add_library(boost_stacktrace INTERFACE)
|
||||
add_library(Boost::stacktrace ALIAS boost_stacktrace)
|
||||
|
||||
target_include_directories(boost_stacktrace INTERFACE include)
|
||||
|
||||
if(BOOST_STACKTRACE_ENABLE_WINDBG)
|
||||
|
||||
target_link_libraries(boost_stacktrace INTERFACE Boost::stacktrace_windbg)
|
||||
|
||||
elseif(BOOST_STACKTRACE_ENABLE_BACKTRACE)
|
||||
|
||||
target_link_libraries(boost_stacktrace INTERFACE Boost::stacktrace_backtrace)
|
||||
|
||||
elseif(BOOST_STACKTRACE_ENABLE_ADDR2LINE)
|
||||
|
||||
target_link_libraries(boost_stacktrace INTERFACE Boost::stacktrace_addr2line)
|
||||
|
||||
elseif(BOOST_STACKTRACE_ENABLE_BASIC)
|
||||
|
||||
target_link_libraries(boost_stacktrace INTERFACE Boost::stacktrace_basic)
|
||||
|
||||
elseif(BOOST_STACKTRACE_ENABLE_NOOP)
|
||||
|
||||
target_link_libraries(boost_stacktrace INTERFACE Boost::stacktrace_noop)
|
||||
|
||||
endif()
|
||||
|
||||
#
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
|
||||
add_subdirectory(test)
|
||||
|
||||
endif()
|
||||
12
README.md
12
README.md
@@ -1,15 +1,17 @@
|
||||
### Stacktrace
|
||||
# [Boost.Stacktrace](https://boost.org/libs/stacktrace)
|
||||
|
||||
Library for storing and printing backtraces.
|
||||
|
||||
[Documentation and examples.](http://boostorg.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/boostorg/stacktrace) [](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/develop) | [](https://coveralls.io/github/boostorg/stacktrace?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/stacktrace.html)
|
||||
Master branch: | [](https://travis-ci.org/boostorg/stacktrace) [](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/master) | [](https://coveralls.io/github/boostorg/stacktrace?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/stacktrace.html)
|
||||
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).
|
||||
|
||||
50
build.jam
Normal file
50
build.jam
Normal file
@@ -0,0 +1,50 @@
|
||||
# Copyright René Ferdinand Rivera Morell 2023-2024
|
||||
# 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)
|
||||
|
||||
require-b2 5.2 ;
|
||||
|
||||
constant boost_dependencies :
|
||||
<library>/boost/config//boost_config
|
||||
<library>/boost/container_hash//boost_container_hash
|
||||
<library>/boost/core//boost_core
|
||||
<library>/boost/predef//boost_predef
|
||||
<target-os>windows:<library>/boost/winapi//boost_winapi ;
|
||||
|
||||
project /boost/stacktrace
|
||||
: common-requirements
|
||||
<include>include
|
||||
;
|
||||
|
||||
explicit
|
||||
[ alias boost_stacktrace_addr2line : build//boost_stacktrace_addr2line ]
|
||||
[ alias boost_stacktrace_backtrace : build//boost_stacktrace_backtrace ]
|
||||
[ alias boost_stacktrace_basic : build//boost_stacktrace_basic ]
|
||||
[ alias boost_stacktrace_from_exception : build//boost_stacktrace_from_exception ]
|
||||
[ alias boost_stacktrace_noop : build//boost_stacktrace_noop ]
|
||||
[ alias boost_stacktrace_windbg : build//boost_stacktrace_windbg ]
|
||||
[ alias boost_stacktrace_windbg_cached : build//boost_stacktrace_windbg_cached ]
|
||||
[ alias boost_stacktrace : boost_stacktrace_noop ]
|
||||
[ alias all :
|
||||
boost_stacktrace_addr2line
|
||||
boost_stacktrace_backtrace
|
||||
boost_stacktrace_basic
|
||||
boost_stacktrace_from_exception
|
||||
boost_stacktrace_noop
|
||||
boost_stacktrace_windbg
|
||||
boost_stacktrace_windbg_cached
|
||||
test
|
||||
]
|
||||
;
|
||||
|
||||
call-if : boost-library stacktrace
|
||||
: install
|
||||
boost_stacktrace_addr2line
|
||||
boost_stacktrace_backtrace
|
||||
boost_stacktrace_basic
|
||||
boost_stacktrace_from_exception
|
||||
boost_stacktrace_noop
|
||||
boost_stacktrace_windbg
|
||||
boost_stacktrace_windbg_cached
|
||||
;
|
||||
@@ -1,13 +1,26 @@
|
||||
# Copyright (C) 2016-2019, Antony Polukhin.
|
||||
# Copyright (C) 2016-2024, 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)
|
||||
#
|
||||
|
||||
require-b2 5.0.1 ;
|
||||
import-search /boost/config/checks ;
|
||||
import config : requires ;
|
||||
import feature ;
|
||||
import property ;
|
||||
|
||||
constant boost_dependencies_private :
|
||||
<library>/boost/assert//boost_assert
|
||||
;
|
||||
|
||||
project
|
||||
: source-location .
|
||||
: common-requirements $(boost_dependencies)
|
||||
: requirements
|
||||
[ requires cxx11_rvalue_references ]
|
||||
$(boost_dependencies_private)
|
||||
: default-build
|
||||
<visibility>hidden
|
||||
;
|
||||
|
||||
@@ -16,13 +29,14 @@ lib gcc_s ;
|
||||
lib Dbgeng ;
|
||||
lib ole32 ;
|
||||
|
||||
feature.feature boost.stacktrace.from_exception : on off : optional propagated ;
|
||||
|
||||
local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ;
|
||||
lib backtrace
|
||||
:
|
||||
:
|
||||
: <search>$(LIBBACKTRACE_PATH)/lib <link>static
|
||||
:
|
||||
: <include>$(LIBBACKTRACE_PATH)/include
|
||||
: <include>$(LIBBACKTRACE_PATH)/include
|
||||
;
|
||||
|
||||
actions mp_simple_run_action
|
||||
@@ -51,8 +65,6 @@ explicit WinDbg ;
|
||||
mp-run-simple has_windbg_cached.cpp : : : <library>Dbgeng <library>ole32 : WinDbgCached ;
|
||||
explicit WinDbgCached ;
|
||||
|
||||
local libraries ;
|
||||
|
||||
lib boost_stacktrace_noop
|
||||
: # sources
|
||||
../src/noop.cpp
|
||||
@@ -62,10 +74,9 @@ lib boost_stacktrace_noop
|
||||
: # default build
|
||||
: # usage-requirements
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
<define>BOOST_STACKTRACE_NO_LIB=1
|
||||
;
|
||||
|
||||
libraries += boost_stacktrace_noop ;
|
||||
|
||||
lib boost_stacktrace_backtrace
|
||||
: # sources
|
||||
../src/backtrace.cpp
|
||||
@@ -74,14 +85,13 @@ lib boost_stacktrace_backtrace
|
||||
<target-os>linux:<library>dl
|
||||
<library>backtrace
|
||||
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
[ check-target-builds ../build//libbacktrace : : <build>no ]
|
||||
[ check-target-builds libbacktrace : : <build>no ]
|
||||
: # default build
|
||||
: # usage-requirements
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
<define>BOOST_STACKTRACE_NO_LIB=1
|
||||
;
|
||||
|
||||
libraries += boost_stacktrace_backtrace ;
|
||||
|
||||
lib boost_stacktrace_addr2line
|
||||
: # sources
|
||||
../src/addr2line.cpp
|
||||
@@ -89,14 +99,13 @@ lib boost_stacktrace_addr2line
|
||||
<warnings>all
|
||||
<target-os>linux:<library>dl
|
||||
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
[ check-target-builds ../build//addr2line : : <build>no ]
|
||||
[ check-target-builds addr2line : : <build>no ]
|
||||
: # default build
|
||||
: # usage-requirements
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
<define>BOOST_STACKTRACE_NO_LIB=1
|
||||
;
|
||||
|
||||
libraries += boost_stacktrace_addr2line ;
|
||||
|
||||
lib boost_stacktrace_basic
|
||||
: # sources
|
||||
../src/basic.cpp
|
||||
@@ -104,14 +113,13 @@ lib boost_stacktrace_basic
|
||||
<warnings>all
|
||||
<target-os>linux:<library>dl
|
||||
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
[ check-target-builds ../build//WinDbg : <build>no ]
|
||||
[ check-target-builds WinDbg : <build>no ]
|
||||
: # default build
|
||||
: # usage-requirements
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
<define>BOOST_STACKTRACE_NO_LIB=1
|
||||
;
|
||||
|
||||
libraries += boost_stacktrace_basic ;
|
||||
|
||||
lib boost_stacktrace_windbg
|
||||
: # sources
|
||||
../src/windbg.cpp
|
||||
@@ -119,14 +127,13 @@ lib boost_stacktrace_windbg
|
||||
<warnings>all
|
||||
<library>Dbgeng <library>ole32
|
||||
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
[ check-target-builds ../build//WinDbg : : <build>no ]
|
||||
[ check-target-builds WinDbg : : <build>no ]
|
||||
: # default build
|
||||
: # usage-requirements
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
<define>BOOST_STACKTRACE_NO_LIB=1
|
||||
;
|
||||
|
||||
libraries += boost_stacktrace_windbg ;
|
||||
|
||||
lib boost_stacktrace_windbg_cached
|
||||
: # sources
|
||||
../src/windbg_cached.cpp
|
||||
@@ -134,12 +141,44 @@ lib boost_stacktrace_windbg_cached
|
||||
<warnings>all
|
||||
<library>Dbgeng <library>ole32
|
||||
<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
[ check-target-builds ../build//WinDbgCached : : <build>no ]
|
||||
[ check-target-builds WinDbgCached : : <build>no ]
|
||||
: # default build
|
||||
: # usage-requirements
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
<define>BOOST_STACKTRACE_NO_LIB=1
|
||||
;
|
||||
|
||||
libraries += boost_stacktrace_windbg_cached ;
|
||||
rule build-stacktrace-from-exception ( props * )
|
||||
{
|
||||
local enabled = [ property.select <boost.stacktrace.from_exception> : $(props) ] ;
|
||||
switch $(enabled:G=)
|
||||
{
|
||||
case "on" : return ;
|
||||
case "off" : return <build>no ;
|
||||
}
|
||||
|
||||
boost-install $(libraries) ;
|
||||
local arch = [ property.select <architecture> : $(props) ] ;
|
||||
if $(arch) && ( $(arch:G=) != x86 )
|
||||
{
|
||||
return <build>no ;
|
||||
}
|
||||
}
|
||||
|
||||
lib boost_stacktrace_from_exception
|
||||
: # sources
|
||||
../src/from_exception.cpp
|
||||
: # requirements
|
||||
<warnings>all
|
||||
<target-os>linux:<library>dl
|
||||
|
||||
# Enable build when explicitly requested, or by default, when on x86
|
||||
<conditional>@build-stacktrace-from-exception
|
||||
|
||||
# Require usable libbacktrace on other platforms
|
||||
# [ check-target-builds libbacktrace : : <build>no ]
|
||||
: # default build
|
||||
: # usage-requirements
|
||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||
<define>BOOST_STACKTRACE_NO_LIB=1
|
||||
<define>BOOST_STACKTRACE_LINKED_WITH_FROM_EXCEPTION=1
|
||||
;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// 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() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// 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-2019.
|
||||
# Copyright Antony Polukhin, 2016-2024.
|
||||
# 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)
|
||||
@@ -9,9 +9,9 @@ import doxygen ;
|
||||
|
||||
doxygen autodoc
|
||||
:
|
||||
[ glob ../../../boost/stacktrace.hpp ]
|
||||
[ glob ../../../boost/stacktrace/*.hpp ]
|
||||
[ glob ../../../boost/stacktrace/detail/frame_decl.hpp ]
|
||||
[ glob ../include/boost/stacktrace.hpp ]
|
||||
[ glob ../include/boost/stacktrace/*.hpp ]
|
||||
[ glob ../include/boost/stacktrace/detail/frame_decl.hpp ]
|
||||
:
|
||||
<doxygen:param>EXTRACT_ALL=NO
|
||||
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
|
||||
@@ -22,6 +22,9 @@ doxygen autodoc
|
||||
<doxygen:param>SEARCH_INCLUDES=YES
|
||||
<doxygen:param>SHORT_NAMES=NO
|
||||
<doxygen:param>INCLUDE_PATH=../../../
|
||||
<doxygen:param>"ALIASES= \\
|
||||
\"asyncsafe=\\xmlonly<link linkend='stacktrace.theoretical_async_signal_safety'>\\endxmlonly Theoretically async signal safe \\xmlonly</link>\\endxmlonly\" \\
|
||||
"
|
||||
<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;\" \\
|
||||
@@ -39,9 +42,9 @@ boostbook standalone
|
||||
:
|
||||
stacktrace
|
||||
:
|
||||
<xsl:param>boost.root=http://www.boost.org/doc/libs/1_63_0
|
||||
<xsl:param>boost.root=http\://www.boost.org/doc/libs/1_84_0
|
||||
# <xsl:param>boost.root=../../../..
|
||||
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
|
||||
<format>pdf:<xsl:param>boost.url.prefix=http\://www.boost.org/doc/libs/release/doc/html
|
||||
;
|
||||
|
||||
###############################################################################
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
[quickbook 1.6]
|
||||
[version 1.0]
|
||||
[id stacktrace]
|
||||
[copyright 2016-2019 Antony Polukhin]
|
||||
[copyright 2016-2024 Antony Polukhin]
|
||||
[category Language Features Emulation]
|
||||
[license
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
@@ -57,53 +57,6 @@ Code from above will output something like this:
|
||||
[note By default the Stacktrace library is very conservative in methods to decode stacktrace. If your output does not look as fancy as in example from above, see [link stacktrace.configuration_and_build section "Configuration and Build"] for allowing advanced features of the library. ]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Handle terminates, aborts and Segmentation Faults]
|
||||
|
||||
Segmentation Faults and `std::terminate` calls sometimes happen in programs. Programmers usually wish to get as much information as possible on such incidents, so having a stacktrace will significantly improve debugging and fixing.
|
||||
|
||||
`std::terminate` calls `std::abort`, so we need to capture stack traces on Segmentation Faults and Abort signals.
|
||||
|
||||
[warning Writing a signal handler requires high attention! Only a few system calls allowed in signal handlers, so there's no cross platform way to print a stacktrace without a risk of deadlocking. The only way to deal with the problem - [*dump raw stacktrace into file/socket and parse it on program restart].]
|
||||
|
||||
[warning Not all the platforms provide means for even getting stacktrace in async signal safe way. No stack trace will be saved on such platforms. ]
|
||||
|
||||
Let's write a handler to safely dump stacktrace:
|
||||
|
||||
[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]
|
||||
@@ -139,10 +92,114 @@ Now we do know the steps that led to the assertion and can find the error withou
|
||||
|
||||
[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*.
|
||||
|
||||
See [link stacktrace.theoretical_async_signal_safety "Theoretical async signal safety"] for more info.
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Stacktrace from arbitrary exception]
|
||||
|
||||
[warning At the moment the functionality is only available for some of the
|
||||
popular C++ runtimes for POSIX systems with *libbacktrace* and for Windows.
|
||||
Make sure that your platform is supported by running some tests.
|
||||
]
|
||||
|
||||
The library provides a way to get stacktrace from an exception as if the
|
||||
stacktrace was captured at the point the exception was thrown. Works even if
|
||||
the exception was thrown from a third party binary library.
|
||||
|
||||
Link with
|
||||
`boost_stacktrace_from_exception` library (or just `LD_PRELOAD` it!) and call
|
||||
boost::stacktrace::stacktrace::from_current_exception() to get the trace:
|
||||
|
||||
```
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <boost/stacktrace.hpp>
|
||||
|
||||
void foo(std::string_view key);
|
||||
void bar(std::string_view key);
|
||||
|
||||
int main() {
|
||||
try {
|
||||
foo("test1");
|
||||
bar("test2");
|
||||
} catch (const std::exception& exc) {
|
||||
boost::stacktrace::stacktrace trace = boost::stacktrace::stacktrace::from_current_exception(); // <---
|
||||
std::cerr << "Caught exception: " << exc.what() << ", trace:\n" << trace;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The output of the above sample may be the following:
|
||||
|
||||
```
|
||||
Caught exception: std::map::at, trace:
|
||||
0# get_data_from_config(std::string_view) at /home/axolm/basic.cpp:600
|
||||
1# bar(std::string_view) at /home/axolm/basic.cpp:6
|
||||
2# main at /home/axolm/basic.cpp:17
|
||||
```
|
||||
|
||||
With the above technique a developer can locate the source file and the function
|
||||
that has thrown the exception without a debugger help. it is especially useful
|
||||
for testing in containers (github CI, other CIs), where the developer has no
|
||||
direct access to the testing environment and reproducing the issue is
|
||||
complicated.
|
||||
|
||||
Note that linking with `boost_stacktrace_from_exception` may increase memory
|
||||
consumption of the application, as the exceptions now additionally store traces.
|
||||
|
||||
At runtime switch boost::stacktrace::this_thread::set_capture_stacktraces_at_throw()
|
||||
allows to disable/enable capturing and storing traces in exceptions.
|
||||
|
||||
To disable the `boost_stacktrace_from_exception` library builds the
|
||||
`boost.stacktrace.from_exception=off` option, for example
|
||||
`./b2 boost.stacktrace.from_exception=off`.
|
||||
|
||||
[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:
|
||||
|
||||
@@ -242,43 +299,6 @@ 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 process. Here's another example with signal handlers.
|
||||
|
||||
This example is very close to the [link stacktrace.getting_started.handle_terminates_aborts_and_seg "Handle terminates, aborts and Segmentation Faults"], but this time we are dumping stacktrace into shared memory:
|
||||
|
||||
[getting_started_terminate_handlers_shmem]
|
||||
|
||||
After registering signal handlers and catching a signal, we may print stacktrace dumps on program restart:
|
||||
|
||||
[getting_started_on_program_restart_shmem]
|
||||
|
||||
The program output will be the following:
|
||||
|
||||
```
|
||||
Previous run crashed and left trace in shared memory:
|
||||
0# 0x00007FD51C7218EF
|
||||
1# my_signal_handler2(int) at ../example/terminate_handler.cpp:68
|
||||
2# 0x00007FD51B833CB0
|
||||
3# 0x00007FD51B833C37
|
||||
4# 0x00007FD51B837028
|
||||
5# 0x00007FD51BE44BBD
|
||||
6# 0x00007FD51BE42B96
|
||||
7# 0x00007FD51BE42BE1
|
||||
8# bar(int) at ../example/terminate_handler.cpp:18
|
||||
9# foo(int) at ../example/terminate_handler.cpp:22
|
||||
10# bar(int) at ../example/terminate_handler.cpp:14
|
||||
11# foo(int) at ../example/terminate_handler.cpp:22
|
||||
12# run_3(char const**) at ../example/terminate_handler.cpp:152
|
||||
13# main at ../example/terminate_handler.cpp:207
|
||||
14# 0x00007FD51B81EF45
|
||||
15# 0x0000000000402999
|
||||
```
|
||||
|
||||
[endsect]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -294,11 +314,11 @@ 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, Intel on Windows, MinGW-w64] / *BOOST_STACKTRACE_USE_WINDBG*] [*boost_stacktrace_windbg*] [ Uses COM to show debug info. May require linking with *ole32* and *dbgeng*. ] [MSVC, MinGW-w64, Intel on Windows] [yes] [no]]
|
||||
[[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 `-fvisibility=hidden` or marking functions as exported produce a better stacktraces.]] ]
|
||||
[[['default for MSVC, Intel on Windows, MinGW-w64] / *BOOST_STACKTRACE_USE_WINDBG*] [*boost_stacktrace_windbg*] [ Uses `dbgeng.h` to show debug info, stores the implementation internals in a static varaible protected with mutex. May require linking with *ole32* and *dbgeng*. ] [MSVC, MinGW-w64, Intel on Windows] [yes] [no]]
|
||||
[[['default for other platforms]] [*boost_stacktrace_basic*] [Uses compiler intrinsics to collect stacktrace and if possible `::dladdr` to show information about the symbol. Requires linking with *libdl* library on POSIX platforms.] [Any compiler on POSIX or MinGW] [no] [yes]]
|
||||
[[*BOOST_STACKTRACE_USE_WINDBG_CACHED*] [*boost_stacktrace_windbg_cached*] [ Uses COM to show debug info and caches COM instances in TLS for better performance. Useful only for cases when traces are gathered very often. [footnote This may affect other components of your program that use COM, because this mode calls the `CoInitializeEx(0, COINIT_MULTITHREADED)` on first use and does not call `::CoUninitialize();` until the current thread is destroyed. ] May require linking with *ole32* and *dbgeng*. ] [MSVC, Intel on Windows] [yes] [no]]
|
||||
[[*BOOST_STACKTRACE_USE_BACKTRACE*] [*boost_stacktrace_backtrace*] [Requires linking with *libdl* on POSIX and *libbacktrace* libraries. *libbacktrace* is probably already installed in your system[footnote If you are using Clang with libstdc++ you could get into troubles of including `<backtrace.h>`, because on some platforms Clang does not search for headers in the GCC's include paths and any attempt to add GCC's include path leads to linker errors. To explicitly specify a path to the `<backtrace.h>` header you could define the *BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE* to a full path to the header. For example on Ubuntu Xenial use the command line option *-DBOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE=</usr/lib/gcc/x86_64-linux-gnu/5/include/backtrace.h>* while building with Clang. ], or built into your compiler.
|
||||
[[*BOOST_STACKTRACE_USE_WINDBG_CACHED*] [*boost_stacktrace_windbg_cached*] [ Uses `dbgeng.h` to show debug info and caches implementation 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, unfortunately 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]]
|
||||
@@ -330,9 +350,46 @@ Let's assume that you've installed MinGW into C:\MinGW and downloaded [@https://
|
||||
|
||||
[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]
|
||||
|
||||
[section Acknowledgements]
|
||||
[endsect]
|
||||
|
||||
[section Theoretical async signal safety]
|
||||
|
||||
In theory, walking the stack without decoding and demangling should be async signal safe.
|
||||
|
||||
In practice, it is not:
|
||||
|
||||
* Looks like a page fault while dumping the trace on a containerized/virtualized
|
||||
Windows system has a chance to deadlock. Page fault could happen easily
|
||||
as we have to write the dump either to memory or to a file.
|
||||
* On POSIX systems a deadlock could happen if a signal is received when throwing
|
||||
an exception [@https://github.com/boostorg/stacktrace/issues/131 #131].
|
||||
Theoretically this could be worked around by bypassing the mutex locking
|
||||
in C++-runtime at exception throw
|
||||
([@https://github.com/userver-framework/userver/blob/4246909c99506d3ab34bd130a5154b4acc8e87de/core/src/engine/task/exception_hacks.cpp#L241-L244 sample implementation]
|
||||
in the 🐙 userver framework), or by using a very modern runtime
|
||||
(glibc-2.35+ with [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71744#c32 modern]
|
||||
libgcc or [@https://reviews.llvm.org/D130668 modern] LLVM's libunwind).
|
||||
* `-fomit-frame-pointer` like flags add additional complexity to the stack
|
||||
walking implementation, which may also negatively affect the signal safety.
|
||||
|
||||
As a rule of thumb: do *not* capture stack traces in signal handlers unless you
|
||||
are absolutely sure in your environment and inspected all of its source codes.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Acknowledgments]
|
||||
|
||||
In order of helping and advising:
|
||||
|
||||
@@ -340,6 +397,8 @@ In order of helping and advising:
|
||||
* Great thanks to Nat Goodspeed for requesting [classref boost::stacktrace::frame] like class.
|
||||
* Great thanks to Niall Douglas for making an initial review, helping with some platforms and giving great hints on library design.
|
||||
* Great thanks to all the library reviewers.
|
||||
* Great thanks to Andrei Nekrashevich for prototyping the idea of stacktraces
|
||||
from arbitrary exception in `libsfe`.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// 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
|
||||
@@ -38,7 +35,8 @@ namespace boost {
|
||||
inline void assertion_failed_msg(char const* expr, char const* msg, char const* function, char const* /*file*/, long /*line*/) {
|
||||
std::cerr << "Expression '" << expr << "' is false in function '" << function << "': " << (msg ? msg : "<...>") << ".\n"
|
||||
<< "Backtrace:\n" << boost::stacktrace::stacktrace() << '\n';
|
||||
std::abort();
|
||||
/*<-*/ 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -23,59 +23,57 @@ BOOST_NOINLINE void foo(int i) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//[getting_started_terminate_handlers
|
||||
//[getting_started_signal_handlers
|
||||
|
||||
#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");
|
||||
|
||||
::raise(SIGABRT);
|
||||
}
|
||||
//]
|
||||
|
||||
void setup_handlers() {
|
||||
//[getting_started_setup_handlers
|
||||
//[getting_started_setup_signel_handlers
|
||||
::signal(SIGSEGV, &my_signal_handler);
|
||||
::signal(SIGABRT, &my_signal_handler);
|
||||
//]
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t shared_memory_size = 4096 * 8;
|
||||
//[getting_started_terminate_handlers
|
||||
#include <cstdlib> // std::abort
|
||||
#include <exception> // std::set_terminate
|
||||
#include <iostream> // std::cerr
|
||||
|
||||
//[getting_started_terminate_handlers_shmem
|
||||
#include <boost/stacktrace.hpp>
|
||||
#include <boost/interprocess/shared_memory_object.hpp>
|
||||
#include <boost/interprocess/mapped_region.hpp>
|
||||
|
||||
boost::interprocess::shared_memory_object g_shm; // inited at program start
|
||||
boost::interprocess::mapped_region g_region; // inited at program start
|
||||
|
||||
|
||||
void my_signal_handler2(int signum) {
|
||||
::signal(signum, SIG_DFL);
|
||||
void** f = static_cast<void**>(g_region.get_address());
|
||||
*f = reinterpret_cast<void*>(1); // Setting flag that shared memory now constains stacktrace.
|
||||
boost::stacktrace::safe_dump_to(f + 1, g_region.get_size() - sizeof(void*));
|
||||
|
||||
::raise(SIGABRT);
|
||||
void my_terminate_handler() {
|
||||
try {
|
||||
std::cerr << boost::stacktrace::stacktrace();
|
||||
} catch (...) {}
|
||||
std::abort();
|
||||
}
|
||||
//]
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <iostream> // std::cerr
|
||||
#include <fstream> // std::ifstream
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
|
||||
#ifndef BOOST_WINDOWS
|
||||
inline void copy_and_run(const char* exec_name, char param, bool not_null) {
|
||||
std::cout << "Running with param " << param << std::endl;
|
||||
boost::filesystem::path command = exec_name;
|
||||
command = command.parent_path() / (command.stem().string() + param + command.extension().string());
|
||||
boost::filesystem::copy_file(exec_name, command, boost::filesystem::copy_option::overwrite_if_exists);
|
||||
boost::filesystem::copy_file(exec_name, command, boost::filesystem::copy_options::overwrite_existing);
|
||||
|
||||
boost::filesystem::path command_args = command;
|
||||
command_args += ' ';
|
||||
@@ -91,6 +89,16 @@ inline void copy_and_run(const char* exec_name, char param, bool not_null) {
|
||||
std::exit(ret);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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();
|
||||
@@ -132,67 +140,6 @@ int run_2(const char* argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int run_3(const char* /*argv*/[]) {
|
||||
using namespace boost::interprocess;
|
||||
{
|
||||
shared_memory_object shm_obj(open_or_create, "shared_memory", read_write);
|
||||
shm_obj.swap(g_shm);
|
||||
}
|
||||
g_shm.truncate(shared_memory_size);
|
||||
|
||||
{
|
||||
mapped_region m(g_shm, read_write, 0, shared_memory_size);
|
||||
m.swap(g_region);
|
||||
}
|
||||
void** f = static_cast<void**>(g_region.get_address());
|
||||
*f = 0;
|
||||
|
||||
::signal(SIGSEGV, &my_signal_handler2);
|
||||
::signal(SIGABRT, &my_signal_handler2);
|
||||
foo(5);
|
||||
return 31;
|
||||
}
|
||||
|
||||
int run_4(const char* argv[]) {
|
||||
using namespace boost::interprocess;
|
||||
{
|
||||
shared_memory_object shm_obj(open_only, "shared_memory", read_write);
|
||||
shm_obj.swap(g_shm);
|
||||
}
|
||||
|
||||
{
|
||||
mapped_region m(g_shm, read_write, 0, shared_memory_size);
|
||||
m.swap(g_region);
|
||||
}
|
||||
|
||||
//[getting_started_on_program_restart_shmem
|
||||
void** f = static_cast<void**>(g_region.get_address());
|
||||
if (*f) { // Checking if memory constains stacktrace.
|
||||
boost::stacktrace::stacktrace st
|
||||
= boost::stacktrace::stacktrace::from_dump(f + 1, g_region.get_size() - sizeof(bool));
|
||||
|
||||
std::cout << "Previous run crashed and left trace in shared memory:\n" << st << std::endl;
|
||||
*f = 0; /*<-*/
|
||||
shared_memory_object::remove("shared_memory");
|
||||
if (std::string(argv[0]).find("noop") == std::string::npos) {
|
||||
if (!st) {
|
||||
return 43;
|
||||
}
|
||||
} else {
|
||||
if (st) {
|
||||
return 44;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 42; /*->*/
|
||||
}
|
||||
//]
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <sstream>
|
||||
|
||||
int test_inplace() {
|
||||
@@ -300,24 +247,21 @@ 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);
|
||||
case '4': return run_4(argv);
|
||||
}
|
||||
|
||||
return 404;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_USER_CONFIG <libs/stacktrace/example/user_config.hpp>
|
||||
#define BOOST_USER_CONFIG <example/user_config.hpp>
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <exception> // std::set_terminate, std::abort
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -15,5 +15,6 @@
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
#include <boost/stacktrace/stacktrace.hpp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
#include <boost/stacktrace/this_thread.hpp>
|
||||
|
||||
#endif // BOOST_STACKTRACE_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -12,11 +12,13 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/addr_base.hpp>
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
||||
#include <boost/stacktrace/detail/try_dec_convert.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -28,7 +30,7 @@ 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 {
|
||||
constexpr bool is_abs_path(const char* path) noexcept {
|
||||
return *path != '\0' && (
|
||||
*path == ':' || *path == '/' || is_abs_path(path + 1)
|
||||
);
|
||||
@@ -41,7 +43,7 @@ class addr2line_pipe {
|
||||
::pid_t pid;
|
||||
|
||||
public:
|
||||
explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) BOOST_NOEXCEPT
|
||||
explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) noexcept
|
||||
: p(0)
|
||||
, pid(0)
|
||||
{
|
||||
@@ -97,11 +99,11 @@ public:
|
||||
::close(pdes[1]);
|
||||
}
|
||||
|
||||
operator ::FILE*() const BOOST_NOEXCEPT {
|
||||
operator ::FILE*() const noexcept {
|
||||
return p;
|
||||
}
|
||||
|
||||
~addr2line_pipe() BOOST_NOEXCEPT {
|
||||
~addr2line_pipe() noexcept {
|
||||
if (p) {
|
||||
::fclose(p);
|
||||
int pstat = 0;
|
||||
@@ -115,12 +117,14 @@ inline std::string addr2line(const char* flag, const void* addr) {
|
||||
std::string res;
|
||||
|
||||
boost::stacktrace::detail::location_from_symbol loc(addr);
|
||||
if (!loc.empty()) {
|
||||
// For programs started through $PATH loc.name() is not absolute and
|
||||
// addr2line will fail.
|
||||
if (!loc.empty() && std::strchr(loc.name(), '/') != nullptr) {
|
||||
res = loc.name();
|
||||
} else {
|
||||
res.resize(16);
|
||||
int rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
|
||||
while (rlin_size == static_cast<int>(res.size() - 1)) {
|
||||
ssize_t rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
|
||||
while (rlin_size == static_cast<ssize_t>(res.size() - 1)) {
|
||||
res.resize(res.size() * 4);
|
||||
rlin_size = ::readlink("/proc/self/exe", &res[0], res.size() - 1);
|
||||
}
|
||||
@@ -128,7 +132,7 @@ inline std::string addr2line(const char* flag, const void* addr) {
|
||||
res.clear();
|
||||
return res;
|
||||
}
|
||||
res.resize(rlin_size);
|
||||
res.resize(static_cast<std::size_t>(rlin_size));
|
||||
}
|
||||
|
||||
addr2line_pipe p(flag, res.c_str(), to_hex_array(addr).data());
|
||||
@@ -155,6 +159,19 @@ inline std::string addr2line(const char* flag, const void* addr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
inline std::string source_location(const void* addr, bool position_independent) {
|
||||
uintptr_t addr_base = 0;
|
||||
if (position_independent) {
|
||||
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
|
||||
}
|
||||
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
|
||||
std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", reinterpret_cast<const void*>(offset));
|
||||
if (source_line.empty() || source_line[0] == '?') {
|
||||
return "";
|
||||
}
|
||||
|
||||
return source_line;
|
||||
}
|
||||
|
||||
struct to_string_using_addr2line {
|
||||
std::string res;
|
||||
@@ -163,9 +180,20 @@ struct to_string_using_addr2line {
|
||||
}
|
||||
|
||||
bool prepare_source_location(const void* addr) {
|
||||
//return addr2line("-Cfipe", addr); // Does not seem to work in all cases
|
||||
std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", addr);
|
||||
if (!source_line.empty() && source_line[0] != '?') {
|
||||
// general idea in all addr2line uses:
|
||||
// in each case:
|
||||
// - try to resolve whole address as if it was a non-pie binary
|
||||
// - if that didn't work, try to resolve just an offset from binary base address
|
||||
// this is needed because:
|
||||
// - in pie binaries just passing an address to addr2line won't work (it needs an offset in this case)
|
||||
// - in non-pie binaries whole address is needed (offset won't work)
|
||||
// - there is no easy way to test if binary is position independent (that I know of)
|
||||
std::string source_line = boost::stacktrace::detail::source_location(addr, false);
|
||||
if(source_line.empty()) {
|
||||
source_line = boost::stacktrace::detail::source_location(addr, true);
|
||||
}
|
||||
|
||||
if (!source_line.empty()) {
|
||||
res += " at ";
|
||||
res += source_line;
|
||||
return true;
|
||||
@@ -178,8 +206,13 @@ struct to_string_using_addr2line {
|
||||
template <class Base> class to_string_impl_base;
|
||||
typedef to_string_impl_base<to_string_using_addr2line> to_string_impl;
|
||||
|
||||
inline std::string name_impl(const void* addr) {
|
||||
std::string res = boost::stacktrace::detail::addr2line("-fe", addr);
|
||||
inline std::string name(const void* addr, bool position_independent) {
|
||||
uintptr_t addr_base = 0;
|
||||
if(position_independent){
|
||||
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
|
||||
}
|
||||
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
|
||||
std::string res = boost::stacktrace::detail::addr2line("-fe", offset);
|
||||
res = res.substr(0, res.find_last_of('\n'));
|
||||
res = boost::core::demangle(res.c_str());
|
||||
|
||||
@@ -190,11 +223,23 @@ inline std::string name_impl(const void* addr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
inline std::string name_impl(const void* addr) {
|
||||
std::string res = boost::stacktrace::detail::name(addr, false);
|
||||
if (res.empty()) {
|
||||
res = boost::stacktrace::detail::name(addr, true);
|
||||
}
|
||||
|
||||
std::string frame::source_file() const {
|
||||
return res;
|
||||
}
|
||||
|
||||
inline std::string source_file(const void* addr, bool position_independent) {
|
||||
std::string res;
|
||||
res = boost::stacktrace::detail::addr2line("-e", addr_);
|
||||
uintptr_t addr_base = 0;
|
||||
if(position_independent){
|
||||
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
|
||||
}
|
||||
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
|
||||
res = boost::stacktrace::detail::addr2line("-e", offset);
|
||||
res = res.substr(0, res.find_last_of(':'));
|
||||
if (res == "??") {
|
||||
res.clear();
|
||||
@@ -203,10 +248,14 @@ std::string frame::source_file() const {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
inline std::size_t source_line(const void* addr, bool position_independent) {
|
||||
std::size_t line_num = 0;
|
||||
std::string res = boost::stacktrace::detail::addr2line("-e", addr_);
|
||||
uintptr_t addr_base = 0;
|
||||
if(position_independent){
|
||||
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
|
||||
}
|
||||
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
|
||||
std::string res = boost::stacktrace::detail::addr2line("-e", offset);
|
||||
const std::size_t last = res.find_last_of(':');
|
||||
if (last == std::string::npos) {
|
||||
return 0;
|
||||
@@ -220,6 +269,27 @@ std::size_t frame::source_line() const {
|
||||
return line_num;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
std::string frame::source_file() const {
|
||||
std::string res = boost::stacktrace::detail::source_file(addr_, false);
|
||||
if (res.empty()) {
|
||||
res = boost::stacktrace::detail::source_file(addr_, true);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
std::size_t line_num = boost::stacktrace::detail::source_line(addr_, false);
|
||||
if (line_num == 0) {
|
||||
line_num = boost::stacktrace::detail::source_line(addr_, true);
|
||||
}
|
||||
|
||||
return line_num;
|
||||
}
|
||||
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
|
||||
89
include/boost/stacktrace/detail/addr_base.hpp
Normal file
89
include/boost/stacktrace/detail/addr_base.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// 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_ADDR_BASE_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_ADDR_BASE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct mapping_entry_t {
|
||||
uintptr_t start = 0;
|
||||
uintptr_t end = 0;
|
||||
uintptr_t offset_from_base = 0;
|
||||
|
||||
inline bool contains_addr(const void* addr) const {
|
||||
uintptr_t addr_uint = reinterpret_cast<uintptr_t>(addr);
|
||||
return addr_uint >= start && addr_uint < end;
|
||||
}
|
||||
};
|
||||
|
||||
inline uintptr_t hex_str_to_int(const std::string& str) {
|
||||
uintptr_t out;
|
||||
std::stringstream ss;
|
||||
ss << std::hex << str;
|
||||
ss >> out;
|
||||
if(ss.eof() && !ss.fail()) { // whole stream read, with no errors
|
||||
return out;
|
||||
} else {
|
||||
throw std::invalid_argument(std::string("can't convert '") + str + "' to hex");
|
||||
}
|
||||
}
|
||||
|
||||
// parse line from /proc/<id>/maps
|
||||
// format:
|
||||
// 7fb60d1ea000-7fb60d20c000 r--p 00000000 103:02 120327460 /usr/lib/libc.so.6
|
||||
// only parts 0 and 2 are interesting, these are:
|
||||
// 0. mapping address range
|
||||
// 2. mapping offset from base
|
||||
inline mapping_entry_t parse_proc_maps_line(const std::string& line) {
|
||||
std::string mapping_range_str, permissions_str, offset_from_base_str;
|
||||
std::istringstream line_stream(line);
|
||||
if(!std::getline(line_stream, mapping_range_str, ' ') ||
|
||||
!std::getline(line_stream, permissions_str, ' ') ||
|
||||
!std::getline(line_stream, offset_from_base_str, ' ')) {
|
||||
return mapping_entry_t{};
|
||||
}
|
||||
std::string mapping_start_str, mapping_end_str;
|
||||
std::istringstream mapping_range_stream(mapping_range_str);
|
||||
if(!std::getline(mapping_range_stream, mapping_start_str, '-') ||
|
||||
!std::getline(mapping_range_stream, mapping_end_str)) {
|
||||
return mapping_entry_t{};
|
||||
}
|
||||
mapping_entry_t mapping{};
|
||||
try {
|
||||
mapping.start = hex_str_to_int(mapping_start_str);
|
||||
mapping.end = hex_str_to_int(mapping_end_str);
|
||||
mapping.offset_from_base = hex_str_to_int(offset_from_base_str);
|
||||
return mapping;
|
||||
} catch(std::invalid_argument& e) {
|
||||
return mapping_entry_t{};
|
||||
}
|
||||
}
|
||||
|
||||
inline uintptr_t get_own_proc_addr_base(const void* addr) {
|
||||
std::ifstream maps_file("/proc/self/maps");
|
||||
for (std::string line; std::getline(maps_file, line); ) {
|
||||
const mapping_entry_t mapping = parse_proc_maps_line(line);
|
||||
if (mapping.contains_addr(addr)) {
|
||||
return mapping.start - mapping.offset_from_base;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_ADDR_BASE_HPP
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
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 {
|
||||
std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) noexcept {
|
||||
return boost::winapi::RtlCaptureStackBackTrace(
|
||||
static_cast<boost::winapi::ULONG_>(skip),
|
||||
static_cast<boost::winapi::ULONG_>(max_frames_count),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
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 {
|
||||
std::size_t this_thread_frames::collect(native_frame_ptr_t* /*out_frames*/, std::size_t /*max_frames_count*/, std::size_t /*skip*/) noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -63,7 +63,7 @@ inline _Unwind_Reason_Code unwind_callback(::_Unwind_Context* context, void* arg
|
||||
}
|
||||
#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 this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) noexcept {
|
||||
std::size_t frames_count = 0;
|
||||
if (!max_frames_count) {
|
||||
return frames_count;
|
||||
@@ -78,17 +78,17 @@ std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::siz
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
frames_count = static_cast<std::size_t>(state.current - out_frames);
|
||||
#endif //defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
|
||||
|
||||
if (frames_count && out_frames[frames_count - 1] == 0) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -15,8 +15,6 @@
|
||||
#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>
|
||||
|
||||
@@ -47,7 +45,7 @@ public:
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
BOOST_CONSTEXPR frame() BOOST_NOEXCEPT
|
||||
constexpr frame() noexcept
|
||||
: addr_(0)
|
||||
{}
|
||||
|
||||
@@ -75,7 +73,7 @@ public:
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
BOOST_CONSTEXPR explicit frame(native_frame_ptr_t addr) BOOST_NOEXCEPT
|
||||
constexpr explicit frame(native_frame_ptr_t addr) noexcept
|
||||
: addr_(addr)
|
||||
{}
|
||||
|
||||
@@ -86,7 +84,7 @@ public:
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
template <class T>
|
||||
explicit frame(T* function_addr) BOOST_NOEXCEPT
|
||||
explicit frame(T* function_addr) noexcept
|
||||
: addr_(boost::stacktrace::detail::void_ptr_cast<native_frame_ptr_t>(function_addr))
|
||||
{}
|
||||
|
||||
@@ -104,7 +102,7 @@ public:
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
BOOST_CONSTEXPR native_frame_ptr_t address() const BOOST_NOEXCEPT {
|
||||
constexpr native_frame_ptr_t address() const noexcept {
|
||||
return addr_;
|
||||
}
|
||||
|
||||
@@ -131,7 +129,7 @@ public:
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL()
|
||||
constexpr explicit operator bool () const noexcept { return !empty(); }
|
||||
|
||||
/// @brief Checks that frame references NULL address.
|
||||
/// @returns `true` if `this->address() == 0`
|
||||
@@ -139,11 +137,7 @@ public:
|
||||
/// @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
|
||||
constexpr bool empty() const noexcept { return !address(); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -18,19 +18,35 @@
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
|
||||
#ifdef WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
// Prevent inclusion of extra Windows SDK headers which can cause conflict
|
||||
// with other code using Windows SDK
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include "dbgeng.h"
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#include <mutex>
|
||||
|
||||
#if defined(__clang__) || defined(BOOST_MSVC)
|
||||
# pragma comment(lib, "ole32.lib")
|
||||
# pragma comment(lib, "Dbgeng.lib")
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __CRT_UUID_DECL // for __MINGW32__
|
||||
#if !defined(__MINGW32__) || \
|
||||
(!defined(__clang__) && __GNUC__ < 12) || \
|
||||
(defined(__clang__) && __clang_major__ < 16)
|
||||
__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)
|
||||
#endif
|
||||
#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);
|
||||
@@ -44,53 +60,28 @@
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
class com_global_initer: boost::noncopyable {
|
||||
bool ok_;
|
||||
|
||||
public:
|
||||
com_global_initer() BOOST_NOEXCEPT
|
||||
: ok_(false)
|
||||
{
|
||||
// COINIT_MULTITHREADED means that we must serialize access to the objects manually.
|
||||
// This is the fastest way to work. If user calls CoInitializeEx before us - we
|
||||
// can end up with other mode (which is OK for us).
|
||||
//
|
||||
// If we call CoInitializeEx befire user - user may end up with different mode, which is a problem.
|
||||
// So we need to call that initialization function as late as possible.
|
||||
const DWORD res = ::CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
ok_ = (res == S_OK || res == S_FALSE);
|
||||
}
|
||||
|
||||
~com_global_initer() BOOST_NOEXCEPT {
|
||||
if (ok_) {
|
||||
::CoUninitialize();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class com_holder: boost::noncopyable {
|
||||
T* holder_;
|
||||
|
||||
public:
|
||||
com_holder(const com_global_initer&) BOOST_NOEXCEPT
|
||||
com_holder() noexcept
|
||||
: holder_(0)
|
||||
{}
|
||||
|
||||
T* operator->() const BOOST_NOEXCEPT {
|
||||
T* operator->() const noexcept {
|
||||
return holder_;
|
||||
}
|
||||
|
||||
void** to_void_ptr_ptr() BOOST_NOEXCEPT {
|
||||
void** to_void_ptr_ptr() noexcept {
|
||||
return reinterpret_cast<void**>(&holder_);
|
||||
}
|
||||
|
||||
bool is_inited() const BOOST_NOEXCEPT {
|
||||
bool is_inited() const noexcept {
|
||||
return !!holder_;
|
||||
}
|
||||
|
||||
~com_holder() BOOST_NOEXCEPT {
|
||||
~com_holder() noexcept {
|
||||
if (holder_) {
|
||||
holder_->Release();
|
||||
}
|
||||
@@ -98,7 +89,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
static std::string mingw_demangling_workaround(const std::string& s) {
|
||||
inline std::string mingw_demangling_workaround(const std::string& s) {
|
||||
#ifdef BOOST_GCC
|
||||
if (s.empty()) {
|
||||
return s;
|
||||
@@ -114,14 +105,25 @@ static std::string mingw_demangling_workaround(const std::string& s) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void trim_right_zeroes(std::string& s) {
|
||||
// MSVC-9 does not have back() and pop_back() functions in std::string
|
||||
while (!s.empty()) {
|
||||
const std::size_t last = static_cast<std::size_t>(s.size() - 1);
|
||||
if (s[last] != '\0') {
|
||||
break;
|
||||
}
|
||||
s.resize(last);
|
||||
}
|
||||
}
|
||||
|
||||
class debugging_symbols: boost::noncopyable {
|
||||
static void try_init_com(com_holder< ::IDebugSymbols>& idebug, const com_global_initer& com) BOOST_NOEXCEPT {
|
||||
com_holder< ::IDebugClient> iclient(com);
|
||||
static void try_init_com(com_holder< ::IDebugSymbols>& idebug) noexcept {
|
||||
com_holder< ::IDebugClient> iclient;
|
||||
if (S_OK != ::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr())) {
|
||||
return;
|
||||
}
|
||||
|
||||
com_holder< ::IDebugControl> icontrol(com);
|
||||
com_holder< ::IDebugControl> icontrol;
|
||||
const bool res0 = (S_OK == iclient->QueryInterface(
|
||||
__uuidof(IDebugControl),
|
||||
icontrol.to_void_ptr_ptr()
|
||||
@@ -143,36 +145,48 @@ class debugging_symbols: boost::noncopyable {
|
||||
return;
|
||||
}
|
||||
|
||||
// No cheking: QueryInterface sets the output parameter to NULL in case of error.
|
||||
// No checking: QueryInterface sets the output parameter to NULL in case of error.
|
||||
iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr());
|
||||
}
|
||||
|
||||
#ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
|
||||
|
||||
boost::stacktrace::detail::com_global_initer com_;
|
||||
com_holder< ::IDebugSymbols> idebug_;
|
||||
public:
|
||||
debugging_symbols() BOOST_NOEXCEPT
|
||||
: com_()
|
||||
, idebug_(com_)
|
||||
{
|
||||
try_init_com(idebug_, com_);
|
||||
static std::mutex& get_mutex_inst() noexcept {
|
||||
static std::mutex m;
|
||||
return m;
|
||||
}
|
||||
|
||||
static com_holder< ::IDebugSymbols>& get_static_debug_inst() 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 com_holder< ::IDebugSymbols> idebug;
|
||||
|
||||
if (!idebug.is_inited()) {
|
||||
try_init_com(idebug);
|
||||
}
|
||||
|
||||
return idebug;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> guard_;
|
||||
com_holder< ::IDebugSymbols>& idebug_;
|
||||
public:
|
||||
debugging_symbols() noexcept
|
||||
: guard_( get_mutex_inst() )
|
||||
, idebug_( get_static_debug_inst() )
|
||||
{}
|
||||
#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 {
|
||||
static com_holder< ::IDebugSymbols>& get_thread_local_debug_inst() noexcept {
|
||||
// [class.mfct]: A static local variable or local type in a member function always refers to the same entity, whether
|
||||
// or not the member function is inline.
|
||||
static thread_local boost::stacktrace::detail::com_global_initer com;
|
||||
static thread_local com_holder< ::IDebugSymbols> idebug(com);
|
||||
static thread_local com_holder< ::IDebugSymbols> idebug;
|
||||
|
||||
if (!idebug.is_inited()) {
|
||||
try_init_com(idebug, com);
|
||||
try_init_com(idebug);
|
||||
}
|
||||
|
||||
return idebug;
|
||||
@@ -180,13 +194,13 @@ public:
|
||||
|
||||
com_holder< ::IDebugSymbols>& idebug_;
|
||||
public:
|
||||
debugging_symbols() BOOST_NOEXCEPT
|
||||
debugging_symbols() noexcept
|
||||
: idebug_( get_thread_local_debug_inst() )
|
||||
{}
|
||||
|
||||
#endif // #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
|
||||
|
||||
bool is_inited() const BOOST_NOEXCEPT {
|
||||
bool is_inited() const noexcept {
|
||||
return idebug_.is_inited();
|
||||
}
|
||||
|
||||
@@ -217,8 +231,12 @@ public:
|
||||
&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 = name;
|
||||
result.assign(name, size - 1);
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
@@ -244,7 +262,7 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
std::size_t get_line_impl(const void* addr) const BOOST_NOEXCEPT {
|
||||
std::size_t get_line_impl(const void* addr) const noexcept {
|
||||
ULONG result = 0;
|
||||
if (!is_inited()) {
|
||||
return result;
|
||||
@@ -301,6 +319,7 @@ public:
|
||||
&size,
|
||||
0
|
||||
));
|
||||
trim_right_zeroes(result.first);
|
||||
result.second = line_num;
|
||||
|
||||
if (!res) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -59,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;
|
||||
@@ -82,9 +85,13 @@ std::string to_string(const frame* frames, std::size_t size) {
|
||||
|
||||
|
||||
std::string frame::name() const {
|
||||
if (!addr_) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
::Dl_info dli;
|
||||
const bool dl_ok = !!::dladdr(const_cast<void*>(addr_), &dli); // `dladdr` on Solaris accepts nonconst addresses
|
||||
boost::stacktrace::detail::Dl_info dli;
|
||||
const bool dl_ok = !!boost::stacktrace::detail::dladdr(addr_, dli);
|
||||
if (dl_ok && dli.dli_sname) {
|
||||
return boost::core::demangle(dli.dli_sname);
|
||||
}
|
||||
@@ -93,6 +100,10 @@ std::string frame::name() const {
|
||||
}
|
||||
|
||||
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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -52,11 +52,11 @@ inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *
|
||||
if (d.function && function) {
|
||||
*d.function = function;
|
||||
}
|
||||
d.line = lineno;
|
||||
d.line = static_cast<std::size_t>(lineno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) BOOST_NOEXCEPT {
|
||||
inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) noexcept {
|
||||
// Do nothing, just return.
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int
|
||||
//
|
||||
// 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 {
|
||||
BOOST_SYMBOL_VISIBLE inline ::backtrace_state* construct_state(const program_location& prog_location) 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:
|
||||
@@ -82,31 +82,35 @@ BOOST_SYMBOL_VISIBLE inline ::backtrace_state* construct_state(const program_loc
|
||||
//
|
||||
//
|
||||
// Unfortunately, that solution segfaults when `construct_state()` function is in .so file
|
||||
// and multiple threads concurrently work with state.
|
||||
// and multiple threads concurrently work with state. I failed to localize the root cause:
|
||||
// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=87653
|
||||
|
||||
#define BOOST_STACKTRACE_DETAIL_IS_MT 1
|
||||
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
static
|
||||
#if !defined(BOOST_HAS_THREADS)
|
||||
# define BOOST_STACKTRACE_DETAIL_STORAGE static
|
||||
# undef BOOST_STACKTRACE_DETAIL_IS_MT
|
||||
# define BOOST_STACKTRACE_DETAIL_IS_MT 0
|
||||
#elif defined(BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC)
|
||||
# define BOOST_STACKTRACE_DETAIL_STORAGE static
|
||||
#elif !defined(BOOST_NO_CXX11_THREAD_LOCAL)
|
||||
# define BOOST_STACKTRACE_DETAIL_STORAGE thread_local
|
||||
#elif defined(__GNUC__) && !defined(__clang__)
|
||||
# define BOOST_STACKTRACE_DETAIL_STORAGE static __thread
|
||||
#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__)
|
||||
static __thread
|
||||
# else
|
||||
/* just a local variable */
|
||||
# endif
|
||||
|
||||
# define BOOST_STACKTRACE_DETAIL_STORAGE /* just a local variable */
|
||||
#endif
|
||||
::backtrace_state* state = ::backtrace_create_state(
|
||||
|
||||
BOOST_STACKTRACE_DETAIL_STORAGE ::backtrace_state* state = ::backtrace_create_state(
|
||||
prog_location.name(),
|
||||
0,
|
||||
BOOST_STACKTRACE_DETAIL_IS_MT,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
0
|
||||
);
|
||||
|
||||
#undef BOOST_STACKTRACE_DETAIL_IS_MT
|
||||
#undef BOOST_STACKTRACE_DETAIL_STORAGE
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -151,7 +155,7 @@ struct to_string_using_backtrace {
|
||||
return true;
|
||||
}
|
||||
|
||||
to_string_using_backtrace() BOOST_NOEXCEPT {
|
||||
to_string_using_backtrace() noexcept {
|
||||
state = boost::stacktrace::detail::construct_state(prog_location);
|
||||
}
|
||||
};
|
||||
@@ -195,6 +199,10 @@ inline std::string name_impl(const void* addr) {
|
||||
std::string frame::source_file() const {
|
||||
std::string res;
|
||||
|
||||
if (!addr_) {
|
||||
return res;
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::program_location prog_location;
|
||||
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
|
||||
|
||||
@@ -213,6 +221,10 @@ std::string frame::source_file() const {
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
if (!addr_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::program_location prog_location;
|
||||
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -18,33 +18,126 @@
|
||||
# include <boost/winapi/dll.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef _AIX
|
||||
/* AIX doesn't provide dladdr syscall.
|
||||
This provides a minimal implementation of dladdr which retrieves
|
||||
only files information.
|
||||
TODO: Implement the symbol name. */
|
||||
|
||||
#include <sys/ldr.h>
|
||||
#include <sys/debug.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct Dl_info {
|
||||
std::string fname_storage{};
|
||||
const char *dli_fname = nullptr;
|
||||
const char *dli_sname = nullptr;
|
||||
};
|
||||
|
||||
int dladdr(const void* address_raw, Dl_info* info) noexcept {
|
||||
static constexpr std::size_t dl_buff_size = 0x1000;
|
||||
|
||||
try {
|
||||
std::vector<struct ld_info> pld_info_storage;
|
||||
pld_info_storage.resize(
|
||||
(dl_buff_size + sizeof(struct ld_info) - 1) / sizeof(struct ld_info)
|
||||
);
|
||||
|
||||
if (loadquery(L_GETINFO, pld_info_storage.data(), dl_buff_size) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto* pld_info = pld_info_storage.data();
|
||||
const char* const address = static_cast<const char*>(address_raw);
|
||||
while (true) {
|
||||
const auto* const dataorg = static_cast<char*>(pld_info->ldinfo_dataorg);
|
||||
const auto* const textorg = static_cast<char*>(pld_info->ldinfo_textorg);
|
||||
if ((address >= dataorg && address < dataorg + pld_info->ldinfo_datasize )
|
||||
|| (address >= textorg && address < textorg + pld_info->ldinfo_textsize )) {
|
||||
|
||||
/* ldinfo_filename is the null-terminated path name followed
|
||||
by null-terminated member name.
|
||||
If the file is not an archive, then member name is null. */
|
||||
const auto size_filename = std::strlen(pld_info->ldinfo_filename);
|
||||
const auto size_member = std::strlen(pld_info->ldinfo_filename + size_filename + 1);
|
||||
|
||||
/* If member is not null, '(' and ')' must be added to create a
|
||||
fname looking like "filename(membername)". */
|
||||
info->fname_storage.reserve(size_filename + (size_member ? size_member + 3 : 1));
|
||||
info->fname_storage = pld_info->ldinfo_filename;
|
||||
if (size_member) {
|
||||
info->fname_storage += "(";
|
||||
info->fname_storage += pld_info->ldinfo_filename + size_filename + 1;
|
||||
info->fname_storage += ")";
|
||||
}
|
||||
|
||||
info->dli_fname = info->fname_storage.c_str();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!pld_info->ldinfo_next) {
|
||||
break;
|
||||
}
|
||||
|
||||
pld_info = reinterpret_cast<const struct ld_info *>(
|
||||
reinterpret_cast<const char*>(pld_info) + pld_info->ldinfo_next
|
||||
);
|
||||
};
|
||||
} catch (...) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#elif !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
using Dl_info = ::Dl_info;
|
||||
|
||||
inline int dladdr(const void* addr, Dl_info& dli) noexcept {
|
||||
// `dladdr` on Solaris accepts nonconst addresses
|
||||
return ::dladdr(const_cast<void*>(addr), &dli);
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
class location_from_symbol {
|
||||
::Dl_info dli_;
|
||||
boost::stacktrace::detail::Dl_info dli_;
|
||||
|
||||
public:
|
||||
explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT
|
||||
explicit location_from_symbol(const void* addr) noexcept
|
||||
: dli_()
|
||||
{
|
||||
if (!::dladdr(const_cast<void*>(addr), &dli_)) { // `dladdr` on Solaris accepts nonconst addresses
|
||||
if (!boost::stacktrace::detail::dladdr(addr, dli_)) {
|
||||
dli_.dli_fname = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const BOOST_NOEXCEPT {
|
||||
bool empty() const noexcept {
|
||||
return !dli_.dli_fname;
|
||||
}
|
||||
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
const char* name() const noexcept {
|
||||
return dli_.dli_fname;
|
||||
}
|
||||
};
|
||||
|
||||
class program_location {
|
||||
public:
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
const char* name() const noexcept {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
@@ -56,7 +149,7 @@ class location_from_symbol {
|
||||
char file_name_[DEFAULT_PATH_SIZE_];
|
||||
|
||||
public:
|
||||
explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT {
|
||||
explicit location_from_symbol(const void* addr) noexcept {
|
||||
file_name_[0] = '\0';
|
||||
|
||||
boost::winapi::MEMORY_BASIC_INFORMATION_ mbi;
|
||||
@@ -71,11 +164,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const BOOST_NOEXCEPT {
|
||||
bool empty() const noexcept {
|
||||
return file_name_[0] == '\0';
|
||||
}
|
||||
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
const char* name() const noexcept {
|
||||
return file_name_;
|
||||
}
|
||||
};
|
||||
@@ -85,7 +178,7 @@ class program_location {
|
||||
char file_name_[DEFAULT_PATH_SIZE_];
|
||||
|
||||
public:
|
||||
program_location() BOOST_NOEXCEPT {
|
||||
program_location() noexcept {
|
||||
file_name_[0] = '\0';
|
||||
|
||||
const boost::winapi::HMODULE_ handle = 0;
|
||||
@@ -94,7 +187,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
const char* name() const BOOST_NOEXCEPT {
|
||||
const char* name() const noexcept {
|
||||
return file_name_[0] ? file_name_ : 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -11,7 +11,11 @@
|
||||
# define BOOST_STACKTRACE_LINK
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_STACKTRACE_LINK) && !defined(BOOST_STACKTRACE_DYN_LINK) && defined(BOOST_ALL_DYN_LINK)
|
||||
#if !defined(BOOST_STACKTRACE_LINK) && defined(BOOST_STACKTRACE_STATIC_LINK)
|
||||
# define BOOST_STACKTRACE_LINK
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_STACKTRACE_LINK) && !defined(BOOST_STACKTRACE_DYN_LINK) && !defined(BOOST_STACKTRACE_STATIC_LINK) && defined(BOOST_ALL_DYN_LINK)
|
||||
# define BOOST_STACKTRACE_DYN_LINK
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -18,17 +18,17 @@ 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 {
|
||||
std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) noexcept {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
std::size_t dump(int /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
std::size_t dump(int /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) noexcept {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
|
||||
std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) 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,
|
||||
@@ -33,7 +33,7 @@ std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_co
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
|
||||
std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) noexcept {
|
||||
const int fd = ::open(
|
||||
file,
|
||||
O_CREAT | O_WRONLY | O_TRUNC,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) 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_>(
|
||||
@@ -38,7 +38,7 @@ std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
|
||||
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) noexcept {
|
||||
#if 0 // This code causing deadlocks on some platforms. Disabled
|
||||
void* const fd = boost::winapi::CreateFileA(
|
||||
file,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -12,13 +12,14 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <array>
|
||||
#include <cstddef> // std::size_t
|
||||
|
||||
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;
|
||||
inline std::array<char, 40> to_dec_array(std::size_t value) noexcept {
|
||||
std::array<char, 40> ret;
|
||||
if (!value) {
|
||||
ret[0] = '0';
|
||||
ret[1] = '\0';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -12,20 +12,18 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/make_unsigned.hpp>
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
BOOST_STATIC_CONSTEXPR char to_hex_array_bytes[] = "0123456789ABCDEF";
|
||||
|
||||
template <class T>
|
||||
inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(T addr) BOOST_NOEXCEPT {
|
||||
boost::array<char, 2 + sizeof(void*) * 2 + 1> ret = {"0x"};
|
||||
inline std::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(T addr) noexcept {
|
||||
std::array<char, 2 + sizeof(void*) * 2 + 1> ret = {"0x"};
|
||||
ret.back() = '\0';
|
||||
BOOST_STATIC_ASSERT_MSG(!boost::is_pointer<T>::value, "");
|
||||
static_assert(!std::is_pointer<T>::value, "");
|
||||
|
||||
const std::size_t s = sizeof(T);
|
||||
|
||||
@@ -43,9 +41,9 @@ inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(T addr) BOOST_
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(const void* addr) BOOST_NOEXCEPT {
|
||||
inline std::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(const void* addr) noexcept {
|
||||
return to_hex_array(
|
||||
reinterpret_cast< boost::make_unsigned<std::ptrdiff_t>::type >(addr)
|
||||
reinterpret_cast< std::make_unsigned<std::ptrdiff_t>::type >(addr)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -17,7 +17,7 @@
|
||||
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 {
|
||||
inline bool try_dec_convert(const char* s, std::size_t& res) noexcept {
|
||||
char* end_ptr = 0;
|
||||
res = std::strtoul(s, &end_ptr, 10);
|
||||
return *end_ptr == '\0';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -23,7 +23,7 @@ struct to_string_using_nothing {
|
||||
res = boost::stacktrace::frame(addr).name();
|
||||
}
|
||||
|
||||
bool prepare_source_location(const void* /*addr*/) const BOOST_NOEXCEPT {
|
||||
bool prepare_source_location(const void* /*addr*/) const noexcept {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
|
||||
// Copyright 2015-2019 Antony Polukhin.
|
||||
// Copyright Antony Polukhin, 2015-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
@@ -13,8 +13,7 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ * 100 + __GNUC_MINOR__ > 301)
|
||||
# pragma GCC system_header
|
||||
@@ -25,13 +24,13 @@ 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,
|
||||
To void_ptr_cast(From* v) noexcept {
|
||||
static_assert(
|
||||
std::is_pointer<To>::value,
|
||||
"`void_ptr_cast` function must be used only for casting to or from void pointers."
|
||||
);
|
||||
|
||||
BOOST_STATIC_ASSERT_MSG(
|
||||
static_assert(
|
||||
sizeof(From*) == sizeof(To),
|
||||
"Pointer to function and pointer to object differ in size on your platform."
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -15,8 +15,6 @@
|
||||
#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/frame_decl.hpp>
|
||||
@@ -25,15 +23,15 @@
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
/// Comparison operators that provide platform dependant ordering and have O(1) complexity; are Async-Handler-Safe.
|
||||
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); }
|
||||
constexpr inline bool operator< (const frame& lhs, const frame& rhs) noexcept { return lhs.address() < rhs.address(); }
|
||||
constexpr inline bool operator> (const frame& lhs, const frame& rhs) noexcept { return rhs < lhs; }
|
||||
constexpr inline bool operator<=(const frame& lhs, const frame& rhs) noexcept { return !(lhs > rhs); }
|
||||
constexpr inline bool operator>=(const frame& lhs, const frame& rhs) noexcept { return !(lhs < rhs); }
|
||||
constexpr inline bool operator==(const frame& lhs, const frame& rhs) noexcept { return lhs.address() == rhs.address(); }
|
||||
constexpr inline bool operator!=(const frame& lhs, const frame& rhs) noexcept { return !(lhs == rhs); }
|
||||
|
||||
/// Fast hashing support, O(1) complexity; Async-Handler-Safe.
|
||||
inline std::size_t hash_value(const frame& f) BOOST_NOEXCEPT {
|
||||
inline std::size_t hash_value(const frame& f) noexcept {
|
||||
return reinterpret_cast<std::size_t>(f.address());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -12,6 +12,8 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(BOOST_WINDOWS)
|
||||
#include <boost/winapi/config.hpp>
|
||||
#endif
|
||||
@@ -23,32 +25,34 @@
|
||||
# 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.
|
||||
/// @file safe_dump_to.hpp \asyncsafe low-level
|
||||
/// functions for dumping call stacks. Dumps are binary serialized arrays of `void*`,
|
||||
/// so you could read them by using 'od -tx8 -An stacktrace_dump_failename'
|
||||
/// Linux command or using boost::stacktrace::stacktrace::from_dump functions.
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
/// @cond
|
||||
namespace detail {
|
||||
|
||||
typedef const void* native_frame_ptr_t; // TODO: change to `typedef void(*native_frame_ptr_t)();`
|
||||
using native_frame_ptr_t = const void*;
|
||||
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;
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) 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;
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(void* fd, const native_frame_ptr_t* frames, std::size_t frames_count) 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;
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) 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 BOOST_STACKTRACE_FUNCTION static std::size_t collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) 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;
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(void* memory, std::size_t size, std::size_t skip) noexcept {
|
||||
using boost::stacktrace::detail::native_frame_ptr_t;
|
||||
|
||||
if (size < sizeof(native_frame_ptr_t)) {
|
||||
return 0;
|
||||
@@ -61,8 +65,8 @@ struct this_thread_frames { // struct is required to avoid warning about usage o
|
||||
}
|
||||
|
||||
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;
|
||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) noexcept {
|
||||
using boost::stacktrace::detail::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) {
|
||||
@@ -82,14 +86,14 @@ struct this_thread_frames { // struct is required to avoid warning about usage o
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
///
|
||||
/// @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 {
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) noexcept {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, 0);
|
||||
}
|
||||
|
||||
@@ -97,7 +101,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
///
|
||||
/// @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)
|
||||
///
|
||||
@@ -106,7 +110,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST
|
||||
/// @param memory Preallocated buffer to store current function call sequence into.
|
||||
///
|
||||
/// @param size Size of the preallocated buffer.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, void* memory, std::size_t size) BOOST_NOEXCEPT {
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, void* memory, std::size_t size) noexcept {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, skip);
|
||||
}
|
||||
|
||||
@@ -115,12 +119,12 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, void* memory, std::
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
///
|
||||
/// @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 {
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) noexcept {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
@@ -128,7 +132,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
///
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
@@ -137,7 +141,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
|
||||
/// @param max_depth Max call sequence depth to collect.
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, const char* file) BOOST_NOEXCEPT {
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, const char* file) noexcept {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, skip, max_depth);
|
||||
}
|
||||
|
||||
@@ -147,18 +151,18 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_dep
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
///
|
||||
/// @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;
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) noexcept;
|
||||
|
||||
/// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
///
|
||||
/// @returns Stored call sequence depth including terminating zero frame.
|
||||
///
|
||||
@@ -167,26 +171,26 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) BOOS
|
||||
/// @param max_depth Max call sequence depth to collect.
|
||||
///
|
||||
/// @param file File to store current function call sequence.
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, platform_specific_descriptor fd) BOOST_NOEXCEPT;
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, platform_specific_descriptor fd) noexcept;
|
||||
|
||||
#elif defined(BOOST_WINDOWS)
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(void* fd) BOOST_NOEXCEPT {
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(void* fd) noexcept {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, void* fd) BOOST_NOEXCEPT {
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, void* fd) noexcept {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// POSIX
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(int fd) BOOST_NOEXCEPT {
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(int fd) noexcept {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, int fd) BOOST_NOEXCEPT {
|
||||
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, int fd) noexcept {
|
||||
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -12,7 +12,7 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
@@ -26,14 +26,57 @@
|
||||
#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>
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
|
||||
extern "C" {
|
||||
|
||||
const char* boost_stacktrace_impl_current_exception_stacktrace();
|
||||
bool* boost_stacktrace_impl_ref_capture_stacktraces_at_throw();
|
||||
|
||||
}
|
||||
|
||||
#ifndef BOOST_STACKTRACE_LINKED_WITH_FROM_EXCEPTION
|
||||
|
||||
extern "C" {
|
||||
BOOST_SYMBOL_EXPORT
|
||||
inline void* boost_stacktrace_impl_return_nullptr() { return nullptr; }
|
||||
}
|
||||
|
||||
#ifdef _M_IX86
|
||||
# pragma comment(linker, "/ALTERNATENAME:_boost_stacktrace_impl_current_exception_stacktrace=_boost_stacktrace_impl_return_nullptr")
|
||||
# pragma comment(linker, "/ALTERNATENAME:_boost_stacktrace_impl_ref_capture_stacktraces_at_throw=_boost_stacktrace_impl_return_nullptr")
|
||||
#else
|
||||
# pragma comment(linker, "/ALTERNATENAME:boost_stacktrace_impl_current_exception_stacktrace=boost_stacktrace_impl_return_nullptr")
|
||||
# pragma comment(linker, "/ALTERNATENAME:boost_stacktrace_impl_ref_capture_stacktraces_at_throw=boost_stacktrace_impl_return_nullptr")
|
||||
#endif
|
||||
|
||||
#endif // #ifndef BOOST_STACKTRACE_LINKED_WITH_FROM_EXCEPTION
|
||||
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
namespace impl {
|
||||
|
||||
#if defined(__GNUC__) && defined(__ELF__)
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE __attribute__((weak))
|
||||
const char* current_exception_stacktrace() noexcept;
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE __attribute__((weak))
|
||||
bool& ref_capture_stacktraces_at_throw() noexcept;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace impl
|
||||
|
||||
/// Class that on construction copies minimal information about call stack into its internals and provides access to that information.
|
||||
/// @tparam Allocator Allocator to use during stack capture.
|
||||
template <class Allocator>
|
||||
@@ -58,18 +101,18 @@ class basic_stacktrace {
|
||||
}
|
||||
}
|
||||
|
||||
static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) BOOST_NOEXCEPT {
|
||||
static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) noexcept {
|
||||
const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0);
|
||||
return (ret > 1024 ? 1024 : ret); // Dealing with suspiciously big sizes
|
||||
}
|
||||
|
||||
BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) {
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t buffer_size = 128;
|
||||
constexpr std::size_t buffer_size = 128;
|
||||
if (!max_depth) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
BOOST_TRY {
|
||||
{ // Fast path without additional allocations
|
||||
native_frame_ptr_t buffer[buffer_size];
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size < max_depth ? buffer_size : max_depth, frames_to_skip + 1);
|
||||
@@ -95,9 +138,10 @@ class basic_stacktrace {
|
||||
|
||||
buf.resize(buf.size() * 2);
|
||||
} while (buf.size() < buf.max_size()); // close to `true`, but suppresses `C4127: conditional expression is constant`.
|
||||
} catch (...) {
|
||||
} BOOST_CATCH (...) {
|
||||
// ignore exception
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
@@ -119,8 +163,8 @@ public:
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
BOOST_FORCEINLINE basic_stacktrace() BOOST_NOEXCEPT
|
||||
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
BOOST_FORCEINLINE basic_stacktrace() noexcept
|
||||
: impl_()
|
||||
{
|
||||
init(0 , static_cast<std::size_t>(-1));
|
||||
@@ -130,10 +174,10 @@ public:
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
///
|
||||
/// @param a Allocator that would be passed to underlying storeage.
|
||||
BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) BOOST_NOEXCEPT
|
||||
/// @param a Allocator that would be passed to underlying storage.
|
||||
BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) noexcept
|
||||
: impl_(a)
|
||||
{
|
||||
init(0 , static_cast<std::size_t>(-1));
|
||||
@@ -143,17 +187,17 @@ public:
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
///
|
||||
/// @param skip How many top calls to skip and do not store in *this.
|
||||
///
|
||||
/// @param max_depth Max call sequence depth to collect.
|
||||
///
|
||||
/// @param a Allocator that would be passed to underlying storeage.
|
||||
/// @param a Allocator that would be passed to underlying storage.
|
||||
///
|
||||
/// @throws Nothing. Note that default construction of allocator may throw, however it is
|
||||
/// performed outside the constructor and exception in `allocator_type()` would not result in calling `std::terminate`.
|
||||
BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) BOOST_NOEXCEPT
|
||||
BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) noexcept
|
||||
: impl_(a)
|
||||
{
|
||||
init(skip , max_depth);
|
||||
@@ -161,14 +205,14 @@ public:
|
||||
|
||||
/// @b Complexity: O(st.size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
basic_stacktrace(const basic_stacktrace& st)
|
||||
: impl_(st.impl_)
|
||||
{}
|
||||
|
||||
/// @b Complexity: O(st.size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
basic_stacktrace& operator=(const basic_stacktrace& st) {
|
||||
impl_ = st.impl_;
|
||||
return *this;
|
||||
@@ -177,26 +221,26 @@ public:
|
||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator::deallocate is async signal safe.
|
||||
~basic_stacktrace() BOOST_NOEXCEPT = default;
|
||||
/// @b Async-Handler-Safety: \asyncsafe if Allocator::deallocate is async signal safe.
|
||||
~basic_stacktrace() noexcept = default;
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
|
||||
basic_stacktrace(basic_stacktrace&& st) BOOST_NOEXCEPT
|
||||
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction and copying are async signal safe.
|
||||
basic_stacktrace(basic_stacktrace&& st) 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.
|
||||
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction and copying are async signal safe.
|
||||
basic_stacktrace& operator=(basic_stacktrace&& st)
|
||||
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
||||
BOOST_NOEXCEPT_IF(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
|
||||
noexcept(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
|
||||
#else
|
||||
BOOST_NOEXCEPT
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
impl_ = std::move(st.impl_);
|
||||
@@ -208,8 +252,8 @@ public:
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
size_type size() const BOOST_NOEXCEPT {
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
size_type size() const noexcept {
|
||||
return impl_.size();
|
||||
}
|
||||
|
||||
@@ -220,44 +264,44 @@ public:
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_reference operator[](std::size_t frame_no) const BOOST_NOEXCEPT {
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
const_reference operator[](std::size_t frame_no) const noexcept {
|
||||
return impl_[frame_no];
|
||||
}
|
||||
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_iterator begin() const BOOST_NOEXCEPT { return impl_.begin(); }
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
const_iterator begin() const noexcept { return impl_.begin(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_iterator cbegin() const BOOST_NOEXCEPT { return impl_.begin(); }
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
const_iterator cbegin() const noexcept { return impl_.begin(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_iterator end() const BOOST_NOEXCEPT { return impl_.end(); }
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
const_iterator end() const noexcept { return impl_.end(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_iterator cend() const BOOST_NOEXCEPT { return impl_.end(); }
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
const_iterator cend() const noexcept { return impl_.end(); }
|
||||
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
const_reverse_iterator rbegin() const noexcept { return impl_.rbegin(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
const_reverse_iterator crbegin() const noexcept { return impl_.rbegin(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_reverse_iterator rend() const BOOST_NOEXCEPT { return impl_.rend(); }
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
const_reverse_iterator rend() const noexcept { return impl_.rend(); }
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
const_reverse_iterator crend() const BOOST_NOEXCEPT { return impl_.rend(); }
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
const_reverse_iterator crend() const noexcept { return impl_.rend(); }
|
||||
|
||||
|
||||
/// @brief Allows to check that stack trace capturing was successful.
|
||||
@@ -265,22 +309,18 @@ public:
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
constexpr explicit operator bool () const noexcept { return !empty(); }
|
||||
|
||||
/// @brief Allows to check that stack trace failed.
|
||||
/// @returns `true` if `this->size() == 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
bool empty() const BOOST_NOEXCEPT { return !size(); }
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
bool empty() const noexcept { return !size(); }
|
||||
|
||||
/// @cond
|
||||
bool operator!() const BOOST_NOEXCEPT { return !size(); }
|
||||
/// @endcond
|
||||
|
||||
const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const BOOST_NOEXCEPT {
|
||||
const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const noexcept {
|
||||
return impl_;
|
||||
}
|
||||
|
||||
@@ -317,7 +357,7 @@ public:
|
||||
|
||||
/// 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 begin Beginning 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
|
||||
///
|
||||
@@ -342,15 +382,55 @@ public:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Returns a basic_stacktrace object containing a stacktrace captured at
|
||||
/// the point where the currently handled exception was thrown by its
|
||||
/// initial throw-expression (i.e. not a rethrow), or an empty
|
||||
/// basic_stacktrace object if:
|
||||
///
|
||||
/// - the `boost_stacktrace_from_exception` library is not linked to the
|
||||
/// current binary, or
|
||||
/// - the initialization of stacktrace failed, or
|
||||
/// - stacktrace captures are not enabled for the throwing thread, or
|
||||
/// - no exception is being handled, or
|
||||
/// - due to implementation-defined reasons.
|
||||
///
|
||||
/// `alloc` is passed to the constructor of the stacktrace object.
|
||||
/// Rethrowing an exception using a throw-expression with no operand does
|
||||
/// not alter the captured stacktrace.
|
||||
///
|
||||
/// Implements https://wg21.link/p2370r1
|
||||
static basic_stacktrace<Allocator> from_current_exception(const allocator_type& alloc = allocator_type()) noexcept {
|
||||
// Matches the constant from implementation
|
||||
constexpr std::size_t kStacktraceDumpSize = 4096;
|
||||
|
||||
const char* trace = nullptr;
|
||||
#if defined(__GNUC__) && defined(__ELF__)
|
||||
if (impl::current_exception_stacktrace) {
|
||||
trace = impl::current_exception_stacktrace();
|
||||
}
|
||||
#elif defined(BOOST_MSVC)
|
||||
trace = boost_stacktrace_impl_current_exception_stacktrace();
|
||||
#endif
|
||||
|
||||
if (trace) {
|
||||
try {
|
||||
return basic_stacktrace<Allocator>::from_dump(trace, kStacktraceDumpSize, alloc);
|
||||
} catch (const std::exception&) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return basic_stacktrace<Allocator>{0, 0, alloc};
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Compares stacktraces for less, order is platform dependent.
|
||||
///
|
||||
/// @b Complexity: Amortized O(1); worst case O(size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
|
||||
return lhs.size() < rhs.size() || (lhs.size() == rhs.size() && lhs.as_vector() < rhs.as_vector());
|
||||
}
|
||||
|
||||
@@ -358,37 +438,37 @@ bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<
|
||||
///
|
||||
/// @b Complexity: Amortized O(1); worst case O(size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @b Async-Handler-Safety: \asyncsafe.
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
|
||||
return lhs.as_vector() == rhs.as_vector();
|
||||
}
|
||||
|
||||
|
||||
/// Comparison operators that provide platform dependant ordering and have amortized O(1) complexity; O(size()) worst case complexity; are Async-Handler-Safe.
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template <class Allocator1, class Allocator2>
|
||||
bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
|
||||
bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
std::size_t hash_value(const basic_stacktrace<Allocator>& st) noexcept {
|
||||
return boost::hash_range(st.as_vector().begin(), st.as_vector().end());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
62
include/boost/stacktrace/this_thread.hpp
Normal file
62
include/boost/stacktrace/this_thread.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright Antony Polukhin, 2023-2024.
|
||||
//
|
||||
// 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_THIS_THREAD_HPP
|
||||
#define BOOST_STACKTRACE_THIS_THREAD_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/stacktrace.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace this_thread {
|
||||
|
||||
/// @brief Invoking the function with the enable parameter equal to `true`
|
||||
/// enables capturing of stacktraces by the current thread of execution at
|
||||
/// exception object construction if the `boost_stacktrace_from_exception`
|
||||
/// library is linked to the current binary; disables otherwise.
|
||||
///
|
||||
/// Implements https://wg21.link/p2370r1
|
||||
inline void set_capture_stacktraces_at_throw(bool enable = true) noexcept {
|
||||
#if defined(__GNUC__) && defined(__ELF__)
|
||||
if (impl::ref_capture_stacktraces_at_throw) {
|
||||
impl::ref_capture_stacktraces_at_throw() = enable;
|
||||
}
|
||||
#elif defined(BOOST_MSVC)
|
||||
if (bool* p = boost_stacktrace_impl_ref_capture_stacktraces_at_throw()) {
|
||||
*p = enable;
|
||||
}
|
||||
#endif
|
||||
(void)enable;
|
||||
}
|
||||
|
||||
/// @return whether the capturing of stacktraces by the current thread of
|
||||
/// execution is enabled and
|
||||
/// boost::stacktrace::basic_stacktrace::from_current_exception may return a
|
||||
/// non empty stacktrace.
|
||||
///
|
||||
/// Returns true if set_capture_stacktraces_at_throw(false) was not called
|
||||
/// and the `boost_stacktrace_from_exception` is linked to the current binary.
|
||||
///
|
||||
/// Implements https://wg21.link/p2370r1
|
||||
inline bool get_capture_stacktraces_at_throw() noexcept {
|
||||
#if defined(__GNUC__) && defined(__ELF__)
|
||||
if (impl::ref_capture_stacktraces_at_throw) {
|
||||
return impl::ref_capture_stacktraces_at_throw();
|
||||
}
|
||||
#elif defined(BOOST_MSVC)
|
||||
if (bool* p = boost_stacktrace_impl_ref_capture_stacktraces_at_throw()) {
|
||||
return *p;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::this_thread
|
||||
|
||||
#endif // BOOST_STACKTRACE_THIS_THREAD_HPP
|
||||
@@ -1,11 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (c) 2014-2019 Antony Polukhin
|
||||
Copyright (c) Antony Polukhin, 2014-2024
|
||||
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)
|
||||
|
||||
boost-no-inspect
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
@@ -29,7 +31,7 @@
|
||||
<a href="../../doc/html/stacktrace.html">../../doc/html/stacktrace.html</a>
|
||||
</p>
|
||||
<p>
|
||||
© 2014-2019 Antony Polukhin
|
||||
© Antony Polukhin, 2014-2024
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
"Antony Polukhin <antoshkka -at- gmail.com>"
|
||||
],
|
||||
"description": "Gather, store, copy and print backtraces.",
|
||||
"std": [ "proposal" ],
|
||||
"std": [ "c++23" ],
|
||||
"category": [
|
||||
"System", "Correctness"
|
||||
]
|
||||
],
|
||||
"cxxstd": "11"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
54
src/exception_headers.h
Normal file
54
src/exception_headers.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright Antony Polukhin, 2023-2024.
|
||||
//
|
||||
// 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 <stddef.h>
|
||||
|
||||
#if defined(__x86_64__) || defined(_M_X64) || defined(__MINGW32__)
|
||||
#define BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING 1
|
||||
#else
|
||||
#define BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING 0
|
||||
#endif
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Developer note: helper to experiment with layouts of different
|
||||
// exception headers https://godbolt.org/z/rrcdPbh1P
|
||||
|
||||
// https://github.com/llvm/llvm-project/blob/b3dd14ce07f2750ae1068fe62abbf2f3bd2cade8/libcxxabi/src/cxa_exception.h
|
||||
struct cxa_exception_begin_llvm {
|
||||
const char* reserve;
|
||||
size_t referenceCount;
|
||||
};
|
||||
|
||||
static cxa_exception_begin_llvm* exception_begin_llvm_ptr(void* ptr) {
|
||||
size_t kExceptionBeginOffset = (
|
||||
sizeof(void*) == 8 ? 128 : 80
|
||||
);
|
||||
return (cxa_exception_begin_llvm*)((char*)ptr - kExceptionBeginOffset);
|
||||
}
|
||||
|
||||
// https://github.com/gcc-mirror/gcc/blob/5d2a360f0a541646abb11efdbabc33c6a04de7ee/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h#L100
|
||||
struct cxa_exception_begin_gcc {
|
||||
size_t referenceCount;
|
||||
const char* reserve;
|
||||
};
|
||||
|
||||
static cxa_exception_begin_gcc* exception_begin_gcc_ptr(void* ptr) {
|
||||
size_t kExceptionBeginOffset = (
|
||||
sizeof(void*) == 8 ? 128 : 96
|
||||
);
|
||||
return (cxa_exception_begin_gcc*)((char*)ptr - kExceptionBeginOffset);
|
||||
}
|
||||
|
||||
static void* get_current_exception_raw_ptr(void* exc_ptr) {
|
||||
// https://github.com/gcc-mirror/gcc/blob/16e2427f50c208dfe07d07f18009969502c25dc8/libstdc%2B%2B-v3/libsupc%2B%2B/eh_ptr.cc#L147
|
||||
return *static_cast<void**>(exc_ptr);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
||||
367
src/from_exception.cpp
Normal file
367
src/from_exception.cpp
Normal file
@@ -0,0 +1,367 @@
|
||||
// Copyright Antony Polukhin, 2023-2024.
|
||||
//
|
||||
// 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)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
extern "C" void** __cdecl __current_exception(); // exported from vcruntime.dll
|
||||
#define _pCurrentException static_cast<PEXCEPTION_RECORD>(*__current_exception())
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::size_t kStacktraceDumpSize = 4096;
|
||||
|
||||
struct thrown_info {
|
||||
ULONG_PTR object;
|
||||
char* dump;
|
||||
};
|
||||
|
||||
struct exception_data {
|
||||
bool capture_stacktraces_at_throw = true;
|
||||
unsigned count = 0;
|
||||
thrown_info* info = nullptr;
|
||||
|
||||
~exception_data() noexcept {
|
||||
HANDLE hHeap = GetProcessHeap();
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
HeapFree(hHeap, 0, info[i].dump);
|
||||
}
|
||||
HeapFree(hHeap, 0, info);
|
||||
}
|
||||
};
|
||||
|
||||
thread_local exception_data data;
|
||||
|
||||
inline bool PER_IS_MSVC_EH(PEXCEPTION_RECORD p) noexcept {
|
||||
const DWORD EH_EXCEPTION_NUMBER = 0xE06D7363;
|
||||
const ULONG_PTR EH_MAGIC_NUMBER1 = 0x19930520;
|
||||
|
||||
return p->ExceptionCode == EH_EXCEPTION_NUMBER &&
|
||||
(p->NumberParameters == 3 || p->NumberParameters == 4) &&
|
||||
p->ExceptionInformation[0] == EH_MAGIC_NUMBER1;
|
||||
}
|
||||
|
||||
inline ULONG_PTR PER_PEXCEPTOBJ(PEXCEPTION_RECORD p) noexcept {
|
||||
return p->ExceptionInformation[1];
|
||||
}
|
||||
|
||||
unsigned current_cxx_exception_index() noexcept {
|
||||
if (PEXCEPTION_RECORD current_cxx_exception = _pCurrentException) {
|
||||
for (unsigned i = data.count; i > 0;) {
|
||||
--i;
|
||||
if (data.info[i].object == PER_PEXCEPTOBJ(current_cxx_exception)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return data.count;
|
||||
}
|
||||
|
||||
bool is_processing_rethrow(PEXCEPTION_RECORD p) noexcept {
|
||||
// Processing flow:
|
||||
// 0. throw;
|
||||
// 1. _CxxThrowException(pExceptionObject = nullptr)
|
||||
// 2. VEH & SEH (may throw new c++ exceptions!)
|
||||
// 3. __RethrowException(_pCurrentException)
|
||||
// 4. VEH
|
||||
if (PER_PEXCEPTOBJ(p) == 0) return true;
|
||||
PEXCEPTION_RECORD current_cxx_exception = _pCurrentException;
|
||||
if (current_cxx_exception == nullptr) return false;
|
||||
return PER_PEXCEPTOBJ(p) == PER_PEXCEPTOBJ(current_cxx_exception);
|
||||
}
|
||||
|
||||
LONG NTAPI veh(PEXCEPTION_POINTERS p) {
|
||||
if (data.capture_stacktraces_at_throw &&
|
||||
PER_IS_MSVC_EH(p->ExceptionRecord) &&
|
||||
!is_processing_rethrow(p->ExceptionRecord)) {
|
||||
HANDLE hHeap = GetProcessHeap();
|
||||
unsigned index = current_cxx_exception_index();
|
||||
unsigned new_count = 1 + (index < data.count ? index + 1 : 0);
|
||||
|
||||
for (unsigned i = new_count; i < data.count; ++i) {
|
||||
HeapFree(hHeap, 0, data.info[i].dump);
|
||||
data.info[i].dump = nullptr;
|
||||
}
|
||||
|
||||
void* new_info;
|
||||
if (data.info) {
|
||||
new_info = HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, data.info, sizeof(thrown_info) * new_count);
|
||||
} else {
|
||||
new_info = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(thrown_info) * new_count);
|
||||
}
|
||||
if (new_info) {
|
||||
data.count = new_count;
|
||||
data.info = static_cast<thrown_info*>(new_info);
|
||||
data.info[data.count - 1].object = PER_PEXCEPTOBJ(p->ExceptionRecord);
|
||||
char*& dump_ptr = data.info[data.count - 1].dump;
|
||||
if (dump_ptr == nullptr) {
|
||||
dump_ptr = static_cast<char*>(HeapAlloc(hHeap, 0, kStacktraceDumpSize));
|
||||
}
|
||||
if (dump_ptr != nullptr) {
|
||||
const std::size_t kSkip = 4;
|
||||
boost::stacktrace::safe_dump_to(kSkip, dump_ptr, kStacktraceDumpSize);
|
||||
}
|
||||
} else if (new_count <= data.count) {
|
||||
data.count = new_count - 1;
|
||||
HeapFree(hHeap, 0, data.info[data.count - 1].dump);
|
||||
data.info[data.count - 1].dump = nullptr;
|
||||
}
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
struct veh_installer {
|
||||
PVOID h;
|
||||
veh_installer() noexcept : h(AddVectoredExceptionHandler(1, veh)) {}
|
||||
~veh_installer() noexcept { RemoveVectoredExceptionHandler(h); }
|
||||
} installer;
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
BOOST_SYMBOL_EXPORT const char* boost_stacktrace_impl_current_exception_stacktrace() {
|
||||
unsigned index = current_cxx_exception_index();
|
||||
return index < data.count ? data.info[index].dump : nullptr;
|
||||
}
|
||||
|
||||
BOOST_SYMBOL_EXPORT bool* boost_stacktrace_impl_ref_capture_stacktraces_at_throw() {
|
||||
return &data.capture_stacktraces_at_throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace boost { namespace stacktrace { namespace impl {
|
||||
|
||||
BOOST_SYMBOL_EXPORT void assert_no_pending_traces() noexcept {
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::impl
|
||||
|
||||
#else
|
||||
|
||||
#include "exception_headers.h"
|
||||
|
||||
// At the moment the file is used only on POSIX. _Unwind_Backtrace may be
|
||||
// available on some platforms only if _GNU_SOURCE is defined.
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifndef BOOST_STACKTRACE_LIBCXX_RUNTIME_MAY_CAUSE_MEMORY_LEAK
|
||||
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
|
||||
#error On this platform memory leaks are possible if capturing stacktrace from \
|
||||
exceptions is enabled and exceptions are thrown concurrently \
|
||||
and libc++ runtime is used. \
|
||||
\
|
||||
Define `BOOST_STACKTRACE_LIBCXX_RUNTIME_MAY_CAUSE_MEMORY_LEAK` to \
|
||||
suppress this error if the library would not be used with libc++ \
|
||||
runtime (for example, it would be only used with GCC runtime). \
|
||||
\
|
||||
Otherwise, disable the boost_stacktrace_from_exception library build \
|
||||
(for example by `./b2 boost.stacktrace.from_exception=off` option).
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::size_t kStacktraceDumpSize = 4096;
|
||||
|
||||
struct decrement_on_destroy {
|
||||
std::size_t& to_decrement;
|
||||
|
||||
~decrement_on_destroy() { --to_decrement; }
|
||||
};
|
||||
|
||||
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
|
||||
// Inspired by the coursework by Andrei Nekrashevich in the `libsfe`
|
||||
/*constinit*/ std::mutex g_mapping_mutex;
|
||||
std::unordered_map<void*, const char*> g_exception_to_dump_mapping;
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace boost { namespace stacktrace { namespace impl {
|
||||
|
||||
BOOST_SYMBOL_EXPORT bool& ref_capture_stacktraces_at_throw() noexcept {
|
||||
/*constinit*/ thread_local bool g_capture_stacktraces_at_throw{true};
|
||||
return g_capture_stacktraces_at_throw;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::impl
|
||||
|
||||
namespace __cxxabiv1 {
|
||||
|
||||
#if defined(__GNUC__) && defined(__ELF__)
|
||||
|
||||
// libc++-runtime specific function
|
||||
extern "C" BOOST_NOINLINE BOOST_SYMBOL_VISIBLE __attribute__((weak))
|
||||
void __cxa_increment_exception_refcount(void *primary_exception) throw();
|
||||
|
||||
static bool is_libcpp_runtime() noexcept {
|
||||
return __cxa_increment_exception_refcount;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static bool is_libcpp_runtime() noexcept { return false; }
|
||||
|
||||
#endif
|
||||
|
||||
static const char*& reference_to_empty_padding(void* ptr) noexcept {
|
||||
if (is_libcpp_runtime()) {
|
||||
// libc++-runtime
|
||||
BOOST_ASSERT_MSG(
|
||||
sizeof(void*) != 4,
|
||||
"32bit platforms are unsupported with libc++ runtime padding reusage. "
|
||||
"Please report this issue to the library maintainters."
|
||||
);
|
||||
return exception_begin_llvm_ptr(ptr)->reserve;
|
||||
}
|
||||
|
||||
return exception_begin_gcc_ptr(ptr)->reserve;
|
||||
}
|
||||
|
||||
extern "C" BOOST_SYMBOL_EXPORT
|
||||
void* __cxa_allocate_exception(size_t thrown_size) throw() {
|
||||
static const auto orig_allocate_exception = []() {
|
||||
void* const ptr = ::dlsym(RTLD_NEXT, "__cxa_allocate_exception");
|
||||
BOOST_ASSERT_MSG(ptr, "Failed to find '__cxa_allocate_exception'");
|
||||
return reinterpret_cast<void*(*)(size_t)>(ptr);
|
||||
}();
|
||||
|
||||
if (!boost::stacktrace::impl::ref_capture_stacktraces_at_throw()) {
|
||||
return orig_allocate_exception(thrown_size);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static thread_local std::size_t in_allocate_exception = 0;
|
||||
BOOST_ASSERT_MSG(in_allocate_exception < 10, "Suspicious recursion");
|
||||
++in_allocate_exception;
|
||||
const decrement_on_destroy guard{in_allocate_exception};
|
||||
#endif
|
||||
|
||||
static constexpr std::size_t kAlign = alignof(std::max_align_t);
|
||||
thrown_size = (thrown_size + kAlign - 1) & (~(kAlign - 1));
|
||||
|
||||
void* const ptr = orig_allocate_exception(thrown_size + kStacktraceDumpSize);
|
||||
char* const dump_ptr = static_cast<char*>(ptr) + thrown_size;
|
||||
|
||||
constexpr size_t kSkip = 1;
|
||||
boost::stacktrace::safe_dump_to(kSkip, dump_ptr, kStacktraceDumpSize);
|
||||
|
||||
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
|
||||
if (is_libcpp_runtime()) {
|
||||
const std::lock_guard<std::mutex> guard{g_mapping_mutex};
|
||||
g_exception_to_dump_mapping[ptr] = dump_ptr;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
BOOST_ASSERT_MSG(
|
||||
reference_to_empty_padding(ptr) == nullptr,
|
||||
"Not zeroed out, unsupported implementation"
|
||||
);
|
||||
reference_to_empty_padding(ptr) = dump_ptr;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
|
||||
|
||||
// __cxa_free_exception is not called in libc++ as the
|
||||
// __cxa_decrement_exception_refcount has an inlined call to
|
||||
// __cxa_free_exception. Overriding libc++ specific function
|
||||
extern "C" BOOST_SYMBOL_EXPORT
|
||||
void __cxa_decrement_exception_refcount(void *thrown_object) throw() {
|
||||
BOOST_ASSERT(is_libcpp_runtime());
|
||||
if (!thrown_object) {
|
||||
return;
|
||||
}
|
||||
|
||||
static const auto orig_decrement_refcount = []() {
|
||||
void* const ptr = ::dlsym(RTLD_NEXT, "__cxa_decrement_exception_refcount");
|
||||
BOOST_ASSERT_MSG(ptr, "Failed to find '__cxa_decrement_exception_refcount'");
|
||||
return reinterpret_cast<void(*)(void*)>(ptr);
|
||||
}();
|
||||
|
||||
const auto* exception_header = exception_begin_llvm_ptr(thrown_object);
|
||||
|
||||
// The following line has a race and could give false positives and false
|
||||
// negatives. In first case we remove the trace earlier, in the second case
|
||||
// we get a memory leak.
|
||||
if (exception_header->referenceCount == 1) {
|
||||
const std::lock_guard<std::mutex> guard{g_mapping_mutex};
|
||||
g_exception_to_dump_mapping.erase(thrown_object);
|
||||
}
|
||||
|
||||
orig_decrement_refcount(thrown_object);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace __cxxabiv1
|
||||
|
||||
namespace boost { namespace stacktrace { namespace impl {
|
||||
|
||||
BOOST_SYMBOL_EXPORT const char* current_exception_stacktrace() noexcept {
|
||||
if (!ref_capture_stacktraces_at_throw()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto exc_ptr = std::current_exception();
|
||||
void* const exc_raw_ptr = get_current_exception_raw_ptr(&exc_ptr);
|
||||
if (!exc_raw_ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
|
||||
if (__cxxabiv1::is_libcpp_runtime()) {
|
||||
const std::lock_guard<std::mutex> guard{g_mapping_mutex};
|
||||
const auto it = g_exception_to_dump_mapping.find(exc_raw_ptr);
|
||||
if (it != g_exception_to_dump_mapping.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return __cxxabiv1::reference_to_empty_padding(exc_raw_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_SYMBOL_EXPORT void assert_no_pending_traces() noexcept {
|
||||
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
|
||||
if (__cxxabiv1::is_libcpp_runtime()) {
|
||||
const std::lock_guard<std::mutex> guard{g_mapping_mutex};
|
||||
BOOST_ASSERT(g_exception_to_dump_mapping.empty());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::impl
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2020.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// 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)
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
|
||||
#define BOOST_STACKTRACE_LINK
|
||||
#include <boost/stacktrace/detail/frame_msvc.ipp>
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// 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)
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS
|
||||
#define BOOST_STACKTRACE_LINK
|
||||
#define BOOST_STACKTRACE_USE_WINDBG_CACHED
|
||||
|
||||
14
test/CMakeLists.txt
Normal file
14
test/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
# Copyright 2018-2020 Peter Dimov
|
||||
# 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(BoostTest OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
|
||||
|
||||
if(NOT HAVE_BOOST_TEST)
|
||||
return()
|
||||
endif()
|
||||
|
||||
boost_test(TYPE run SOURCES test.cpp test_impl.cpp LINK_LIBRARIES Boost::stacktrace Boost::core)
|
||||
boost_test(TYPE run SOURCES test_noop.cpp test_impl.cpp LINK_LIBRARIES Boost::stacktrace_noop Boost::core)
|
||||
|
||||
boost_test(TYPE run SOURCES test_trivial.cpp LINK_LIBRARIES Boost::stacktrace Boost::core)
|
||||
119
test/Jamfile.v2
119
test/Jamfile.v2
@@ -1,10 +1,14 @@
|
||||
# Copyright (C) 2016-2019, Antony Polukhin.
|
||||
# Copyright (C) 2016-2024, 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-search /boost/config/checks ;
|
||||
import config : requires ;
|
||||
import testing ;
|
||||
|
||||
lib dl : : <link>shared ;
|
||||
lib gcc_s ;
|
||||
lib rt ;
|
||||
@@ -22,12 +26,15 @@ lib backtrace
|
||||
|
||||
project
|
||||
: requirements
|
||||
[ requires cxx11_rvalue_references cxx11_template_aliases cxx11_noexcept ]
|
||||
<toolset>msvc:<asynch-exceptions>on
|
||||
<toolset>intel:<cxxflags>-wd2196
|
||||
<target-os>linux:<linkflags>-lpthread
|
||||
<warnings>all
|
||||
<test-info>always_show_run_output
|
||||
<visibility>hidden
|
||||
<include>..
|
||||
<library>/boost/optional//boost_optional
|
||||
;
|
||||
|
||||
local FORCE_SYMBOL_EXPORT = <target-os>freebsd:<linkflags>"-rdynamic" <target-os>solaris:<linkflags>"-Bdynamic" <target-os>aix:<linkflags>"-rdynamic"
|
||||
@@ -37,7 +44,9 @@ local FORCE_SYMBOL_EXPORT = <target-os>freebsd:<linkflags>"-rdynamic" <target-os
|
||||
<define>BOOST_STACKTRACE_TEST_EXPORTS_TABLE_USAGE ;
|
||||
|
||||
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 ] ;
|
||||
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 = ;
|
||||
@@ -77,6 +86,7 @@ test-suite stacktrace_tests
|
||||
|
||||
# Header only tests with debug symbols
|
||||
[ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : backtrace_ho ]
|
||||
[ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_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 ]
|
||||
@@ -84,6 +94,15 @@ test-suite stacktrace_tests
|
||||
[ 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 ]
|
||||
@@ -92,29 +111,36 @@ test-suite stacktrace_tests
|
||||
[ 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)
|
||||
: : : <debug-symbols>on <library>.//test_impl_lib_backtrace $(LINKSHARED_BT)
|
||||
: backtrace_lib_threaded ]
|
||||
[ run thread_safety_checking.cpp
|
||||
: : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg $(LINKSHARED_WIND)
|
||||
: : : <debug-symbols>on <library>.//test_impl_lib_backtrace $(LINKSHARED_BT)
|
||||
<define>BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC
|
||||
<library>/boost/optional//boost_optional
|
||||
: backtrace_lib_threaded_static ]
|
||||
[ run thread_safety_checking.cpp
|
||||
: : : <debug-symbols>on <library>.//test_impl_lib_windbg $(LINKSHARED_WIND)
|
||||
<library>/boost/optional//boost_optional
|
||||
: 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)
|
||||
: : : <debug-symbols>on <library>.//test_impl_lib_windbg_cached $(LINKSHARED_WIND_CACHED)
|
||||
<library>/boost/optional//boost_optional
|
||||
: 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)
|
||||
: : : <debug-symbols>on <library>.//test_impl_lib_basic $(LINKSHARED_BASIC)
|
||||
<library>/boost/optional//boost_optional
|
||||
: basic_lib_threaded ]
|
||||
|
||||
[ run thread_safety_checking.cpp
|
||||
: : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg
|
||||
$(LINKSHARED_WIND) <define>BOOST_STACKTRACE_TEST_COM_PREINIT_MT
|
||||
: windbg_lib_threaded_com_mt ]
|
||||
[ run thread_safety_checking.cpp
|
||||
: : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg_cached
|
||||
$(LINKSHARED_WIND_CACHED) <define>BOOST_STACKTRACE_TEST_COM_PREINIT_ST
|
||||
: windbg_cached_lib_threaded_com_st ]
|
||||
|
||||
##### Tests with disabled debug symbols #####
|
||||
|
||||
# Header only tests without debug symbols
|
||||
@@ -139,62 +165,71 @@ test-suite stacktrace_tests
|
||||
# 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
|
||||
<library>/boost/optional//boost_optional
|
||||
$(LINKSHARED_BT)
|
||||
: backtrace_lib_no_dbg_threaded ]
|
||||
[ run thread_safety_checking.cpp
|
||||
: : : <debug-symbols>off
|
||||
<library>/boost/thread//boost_thread
|
||||
<library>/boost/timer//boost_timer
|
||||
<library>.//test_impl_lib_windbg_no_dbg
|
||||
$(LINKSHARED_WIND)
|
||||
: windbg_lib_no_dbg_threaded ]
|
||||
[ run thread_safety_checking.cpp
|
||||
: : : <debug-symbols>off
|
||||
<library>/boost/thread//boost_thread
|
||||
<library>/boost/timer//boost_timer
|
||||
<library>.//test_impl_lib_windbg_cached_no_dbg
|
||||
$(LINKSHARED_WIND_CACHED)
|
||||
: windbg_cached_lib_no_dbg_threaded ]
|
||||
[ run thread_safety_checking.cpp
|
||||
: : : <debug-symbols>off
|
||||
<library>/boost/thread//boost_thread
|
||||
<library>/boost/timer//boost_timer
|
||||
<library>.//test_impl_lib_basic_no_dbg
|
||||
$(LINKSHARED_BASIC)
|
||||
: basic_lib_no_dbg_threaded ]
|
||||
|
||||
[ run thread_safety_checking.cpp
|
||||
: : : <debug-symbols>off
|
||||
<library>/boost/thread//boost_thread
|
||||
<library>/boost/timer//boost_timer
|
||||
<library>.//test_impl_lib_windbg
|
||||
$(LINKSHARED_WIND)
|
||||
<define>BOOST_STACKTRACE_TEST_COM_PREINIT_MT
|
||||
: windbg_lib_threaded_com_mt ]
|
||||
[ run thread_safety_checking.cpp
|
||||
: : : <debug-symbols>off
|
||||
<library>/boost/thread//boost_thread
|
||||
<library>/boost/timer//boost_timer
|
||||
<library>.//test_impl_lib_windbg_cached
|
||||
$(LINKSHARED_WIND_CACHED)
|
||||
<define>BOOST_STACKTRACE_TEST_COM_PREINIT_ST
|
||||
: windbg_cached_lib_threaded_com_st ]
|
||||
|
||||
[ run test_void_ptr_cast.cpp ]
|
||||
[ run test_num_conv.cpp ]
|
||||
|
||||
[ run test_from_exception_none.cpp : : : $(LINKSHARED_BASIC) <debug-symbols>on : from_exception_none_basic ]
|
||||
[ run test_from_exception_none.cpp : : : $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) <debug-symbols>on : from_exception_none_basic_ho ]
|
||||
[ run test_from_exception_none.cpp : : : $(LINKSHARED_BT) <debug-symbols>on : from_exception_none_bt ]
|
||||
[ run test_from_exception_none.cpp : : : <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) <debug-symbols>on : from_exception_none_bt_ho ]
|
||||
[ run test_from_exception_none.cpp : : : $(LINKSHARED_WIND) <debug-symbols>on : from_exception_none_windbg ]
|
||||
[ run test_from_exception_none.cpp : : : <define>BOOST_STACKTRACE_USE_WINDBG $(WIND_DEPS) <debug-symbols>on : from_exception_none_windbg_ho ]
|
||||
[ run test_from_exception_none.cpp : : : $(LINKSHARED_WIND_CACHED) <debug-symbols>on : from_exception_none_windbg_cached ]
|
||||
[ run test_from_exception_none.cpp : : : <define>BOOST_STACKTRACE_USE_WINDBG_CACHED $(WICA_DEPS) <debug-symbols>on : from_exception_none_windbg_cached_ho ]
|
||||
|
||||
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_BASIC) <debug-symbols>on : from_exception_disabled_basic ]
|
||||
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) <debug-symbols>on : from_exception_disabled_basic_ho ]
|
||||
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_BT) <debug-symbols>on : from_exception_disabled_bt ]
|
||||
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : from_exception_disabled_bt_ho ]
|
||||
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_WIND) <debug-symbols>on : from_exception_disabled_windbg ]
|
||||
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception <define>BOOST_STACKTRACE_USE_WINDBG $(WIND_DEPS) <debug-symbols>on : from_exception_disabled_windbg_ho ]
|
||||
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_WIND_CACHED) <debug-symbols>on : from_exception_disabled_windbg_cached ]
|
||||
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception <define>BOOST_STACKTRACE_USE_WINDBG_CACHED $(WICA_DEPS) <debug-symbols>on : from_exception_disabled_windbg_cached_ho ]
|
||||
|
||||
[ link test_from_exception.cpp : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_BASIC) <debug-symbols>on : from_exception_basic ]
|
||||
[ run test_from_exception.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_BT) <debug-symbols>on : from_exception_bt ]
|
||||
[ run test_from_exception.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_WIND) <debug-symbols>on : from_exception_windbg ]
|
||||
[ run test_from_exception.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_WIND_CACHED) <debug-symbols>on : from_exception_windbg_cached ]
|
||||
|
||||
[ link test_from_exception.cpp : <library>/boost/stacktrace//boost_stacktrace_from_exception $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) <debug-symbols>on : from_exception_basic_ho ]
|
||||
[ run test_from_exception.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) <debug-symbols>on : from_exception_bt_ho ]
|
||||
[ run test_from_exception.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception <define>BOOST_STACKTRACE_USE_WINDBG $(WIND_DEPS) <debug-symbols>on : from_exception_windbg_ho ]
|
||||
[ run test_from_exception.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception <define>BOOST_STACKTRACE_USE_WINDBG_CACHED $(WICA_DEPS) <debug-symbols>on : from_exception_windbg_cached_ho ]
|
||||
;
|
||||
|
||||
# Assuring that examples compile and run. Adding sources from `examples` directory to the `type_index` test suite.
|
||||
for local p in [ glob ../example/*.cpp ]
|
||||
{
|
||||
local target_name = $(p[1]:B) ;
|
||||
local additional_dependency = ;
|
||||
local additional_dependency = <library>/boost/array//boost_array ;
|
||||
if $(target_name) = "terminate_handler"
|
||||
{
|
||||
additional_dependency = <library>/boost/filesystem//boost_filesystem <library>/boost/system//boost_system <target-os>linux:<library>rt ;
|
||||
additional_dependency += <library>/boost/filesystem//boost_filesystem <library>/boost/system//boost_system <target-os>linux:<library>rt ;
|
||||
}
|
||||
|
||||
if $(target_name) = "throwing_st"
|
||||
{
|
||||
additional_dependency += [ requires rtti ] <library>/boost/exception//boost_exception ;
|
||||
}
|
||||
|
||||
stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_BT) $(additional_dependency) : backtrace_$(p2[1]:B) ] ;
|
||||
|
||||
@@ -2,23 +2,26 @@
|
||||
# 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-2019.
|
||||
# Copyright Antony Polukhin, 2016-2024.
|
||||
|
||||
#
|
||||
# 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 #5
|
||||
# File revision #6
|
||||
|
||||
init:
|
||||
- set BRANCH_TO_TEST=%APPVEYOR_REPO_BRANCH% # Change to branch you wish to test. Use %APPVEYOR_REPO_BRANCH% for current branch.
|
||||
- set BOOST_REMOVE=stacktrace # Remove this folder from lib from full clone of Boost. If you are testing `any` repo, write here `any`.
|
||||
# boost-local/libs/ folder to put this library into. This may be useful, if you're for example running Travis
|
||||
# from `Boost.DLL` repo while Boost already has `dll` and with to replace `dll` with content of`Boost.DLL`.
|
||||
#
|
||||
# Otherwise just leave the default value - set BOOST_LIBS_FOLDER=%APPVEYOR_PROJECT_NAME%
|
||||
- set BOOST_LIBS_FOLDER=%APPVEYOR_PROJECT_NAME%
|
||||
|
||||
###############################################################################################################
|
||||
# From this point and below code is same for all the Boost libs
|
||||
###############################################################################################################
|
||||
|
||||
version: 1.64.{build}-{branch}
|
||||
version: 1.84.{build}-{branch}
|
||||
|
||||
# branches to build
|
||||
branches:
|
||||
@@ -27,32 +30,61 @@ branches:
|
||||
|
||||
skip_tags: true
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: msvc-14.1 #,clang-win
|
||||
CXXSTD: 14,17
|
||||
ADDRMD: 64
|
||||
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
# ADDPATH: C:\cygwin\bin;
|
||||
# TOOLSET: gcc
|
||||
# CXXSTD: 03,11,14,1z
|
||||
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
# ADDPATH: C:\cygwin64\bin;
|
||||
# TOOLSET: gcc
|
||||
# CXXSTD: 03,11,14,1z
|
||||
# Waiting for https://github.com/boostorg/system/issues/116
|
||||
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
# ADDPATH: C:\mingw\bin;
|
||||
# TOOLSET: gcc
|
||||
# CXXSTD: 03,11,14,1z
|
||||
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
# ADDPATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin;
|
||||
# TOOLSET: gcc
|
||||
# CXXSTD: 03,11,14,1z
|
||||
|
||||
before_build:
|
||||
- set PATH=%PATH%;C:\\MinGW\\bin
|
||||
- set BOOST_BRANCH=develop
|
||||
- if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master
|
||||
- echo "Testing %APPVEYOR_PROJECT_NAME%"
|
||||
# Cloning Boost libraries (fast nondeep cloning)
|
||||
- set BOOST=C:/boost-local
|
||||
- git init %BOOST%
|
||||
- git clone -b %BOOST_BRANCH% --depth 10 https://github.com/boostorg/boost.git %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 --init --merge --jobs 16
|
||||
- git remote set-branches --add origin %BRANCH_TO_TEST%
|
||||
#- git pull --recurse-submodules # Updaes submodules to most recent version. Not required
|
||||
- rm -rf %BOOST%/libs/%BOOST_REMOVE%
|
||||
- mv %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%APPVEYOR_PROJECT_NAME%
|
||||
- git submodule update --init --depth 10 tools/build tools/boostdep
|
||||
libs/filesystem libs/atomic libs/system libs/interprocess libs/array
|
||||
libs/iterator libs/detail libs/exception libs/smart_ptr libs/mpl
|
||||
libs/align libs/container libs/tuple libs/intrusive libs/scope
|
||||
libs/variant2 libs/preprocessor libs/io
|
||||
|
||||
- rm -rf %BOOST%/libs/%BOOST_LIBS_FOLDER%
|
||||
- mv -f %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%BOOST_LIBS_FOLDER%
|
||||
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" %BOOST_LIBS_FOLDER%
|
||||
|
||||
build_script:
|
||||
- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
|
||||
- bootstrap.bat
|
||||
- cmd /c bootstrap
|
||||
- b2.exe headers
|
||||
- cd %BOOST%/libs/%APPVEYOR_PROJECT_NAME%/test
|
||||
- cd %BOOST%/libs/%BOOST_LIBS_FOLDER%/test
|
||||
|
||||
after_build:
|
||||
before_test:
|
||||
test_script:
|
||||
- ..\..\..\b2.exe address-model=32 architecture=x86 toolset=msvc,gcc cxxflags="-DBOOST_TRAVISCI_BUILD" -sBOOST_BUILD_PATH=.
|
||||
- PATH=%ADDPATH%%PATH%
|
||||
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
|
||||
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
|
||||
- echo "Running command ..\..\..\b2 -j3 toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release"
|
||||
- ..\..\..\b2.exe -j3 toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release cxxflags="-DBOOST_TRAVISCI_BUILD"
|
||||
|
||||
after_test:
|
||||
on_success:
|
||||
|
||||
BIN
test/backtrace.dump
Normal file
BIN
test/backtrace.dump
Normal file
Binary file not shown.
15
test/cmake_install_test/CMakeLists.txt
Normal file
15
test/cmake_install_test/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
# Copyright 2018-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.20)
|
||||
|
||||
project(cmake_install_test LANGUAGES CXX)
|
||||
|
||||
find_package(boost_stacktrace REQUIRED)
|
||||
|
||||
add_executable(main main.cpp)
|
||||
target_link_libraries(main Boost::stacktrace)
|
||||
|
||||
enable_testing()
|
||||
add_test(main main)
|
||||
12
test/cmake_install_test/main.cpp
Normal file
12
test/cmake_install_test/main.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2019 Peter Dimov
|
||||
// Copyright 2022-2024 Antony Polukhin
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/stacktrace/stacktrace.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << boost::stacktrace::stacktrace() << std::endl;
|
||||
}
|
||||
46
test/cmake_subdir_test/CMakeLists.txt
Normal file
46
test/cmake_subdir_test/CMakeLists.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
# Copyright 2018-2021 Peter Dimov
|
||||
# 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
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...3.20)
|
||||
|
||||
project(cmake_subdir_test LANGUAGES CXX)
|
||||
|
||||
# Put boost_stacktrace_*.dll in the same directory as main.exe
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
add_subdirectory(../.. boostorg/stacktrace)
|
||||
|
||||
# boostdep --brief stacktrace
|
||||
|
||||
set(deps
|
||||
|
||||
# Primary dependencies
|
||||
|
||||
assert
|
||||
config
|
||||
container_hash
|
||||
core
|
||||
predef
|
||||
winapi
|
||||
|
||||
# Secondary dependencies
|
||||
|
||||
describe
|
||||
mp11
|
||||
static_assert
|
||||
throw_exception
|
||||
|
||||
)
|
||||
|
||||
foreach(dep IN LISTS deps)
|
||||
|
||||
add_subdirectory(../../../${dep} boostorg/${dep})
|
||||
|
||||
endforeach()
|
||||
|
||||
add_executable(main main.cpp)
|
||||
target_link_libraries(main Boost::stacktrace)
|
||||
|
||||
enable_testing()
|
||||
add_test(main main)
|
||||
12
test/cmake_subdir_test/main.cpp
Normal file
12
test/cmake_subdir_test/main.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2019 Peter Dimov
|
||||
// Copyright 2022-2024 Antony Polukhin
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/stacktrace/stacktrace.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << boost::stacktrace::stacktrace() << std::endl;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
@@ -45,6 +47,25 @@ 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(bool print = true) {
|
||||
@@ -79,8 +100,6 @@ void test_nested(bool print = true) {
|
||||
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>
|
||||
@@ -208,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
|
||||
@@ -238,8 +257,15 @@ void test_empty_basic_stacktrace() {
|
||||
BOOST_TEST(!(st > st_t(0, 0)));
|
||||
}
|
||||
|
||||
void test_stacktrace_limits()
|
||||
{
|
||||
BOOST_TEST_EQ(boost::stacktrace::stacktrace(0, 1).size(), 1);
|
||||
BOOST_TEST_EQ(boost::stacktrace::stacktrace(1, 1).size(), 1);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_deeply_nested_namespaces();
|
||||
test_frames_string_data_validity();
|
||||
test_nested<15>();
|
||||
test_comparisons();
|
||||
test_iterators();
|
||||
@@ -255,8 +281,8 @@ int main() {
|
||||
test_comparisons_base(make_some_stacktrace1(), make_some_stacktrace2());
|
||||
|
||||
test_nested<260>(false);
|
||||
BOOST_TEST(boost::stacktrace::stacktrace(0, 1).size() == 1);
|
||||
BOOST_TEST(boost::stacktrace::stacktrace(1, 1).size() == 1);
|
||||
|
||||
test_stacktrace_limits();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
209
test/test_from_exception.cpp
Normal file
209
test/test_from_exception.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
// Copyright Antony Polukhin, 2023-2024.
|
||||
//
|
||||
// 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 <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace impl {
|
||||
void assert_no_pending_traces() noexcept;
|
||||
}}}
|
||||
|
||||
using boost::stacktrace::stacktrace;
|
||||
|
||||
struct test_no_pending_on_finish {
|
||||
~test_no_pending_on_finish() {
|
||||
boost::stacktrace::impl::assert_no_pending_traces();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void in_test_throw_1(const char* msg) {
|
||||
std::string new_msg{msg};
|
||||
throw std::runtime_error(new_msg);
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void in_test_throw_2(const char* msg) {
|
||||
std::string new_msg{msg};
|
||||
throw std::logic_error(new_msg);
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void in_test_rethrow_1(const char* msg) {
|
||||
try {
|
||||
in_test_throw_1(msg);
|
||||
} catch (const std::exception&) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void in_test_rethrow_2(const char* msg) {
|
||||
try {
|
||||
in_test_throw_2(msg);
|
||||
} catch (const std::exception&) {
|
||||
try {
|
||||
in_test_throw_1(msg);
|
||||
} catch (const std::exception&) {}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_no_exception() {
|
||||
auto trace = stacktrace::from_current_exception();
|
||||
BOOST_TEST(!trace);
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_trace_from_exception() {
|
||||
// const test_no_pending_on_finish guard{}; // something strange
|
||||
try {
|
||||
in_test_throw_1("testing basic");
|
||||
} catch (const std::exception&) {
|
||||
auto trace = stacktrace::from_current_exception();
|
||||
BOOST_TEST(trace);
|
||||
std::cout << "Tarce in test_trace_from_exception(): " << trace << '\n';
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_1") != std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_after_other_exception() {
|
||||
try {
|
||||
in_test_throw_1("test_other_exception_active");
|
||||
} catch (const std::exception&) {
|
||||
try {
|
||||
in_test_throw_2("test_other_exception_active 2");
|
||||
} catch (const std::exception&) {}
|
||||
|
||||
auto trace = stacktrace::from_current_exception();
|
||||
BOOST_TEST(trace);
|
||||
std::cout << "Tarce in test_after_other_exception(): " << trace;
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_1") != std::string::npos);
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_2") == std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_rethrow() {
|
||||
try {
|
||||
in_test_rethrow_1("test rethrow");
|
||||
} catch (const std::exception&) {
|
||||
auto trace = stacktrace::from_current_exception();
|
||||
BOOST_TEST(trace);
|
||||
std::cout << "Tarce in test_rethrow(): " << trace << '\n';
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_1") != std::string::npos);
|
||||
BOOST_TEST(to_string(trace).find("in_test_rethrow_1") != std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_rethrow_after_other_exception() {
|
||||
try {
|
||||
in_test_rethrow_2("test_rethrow_after_other_exception");
|
||||
} catch (const std::exception&) {
|
||||
auto trace = stacktrace::from_current_exception();
|
||||
BOOST_TEST(trace);
|
||||
std::cout << "Tarce in test_rethrow_after_other_exception(): " << trace << '\n';
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_1") == std::string::npos);
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_2") != std::string::npos);
|
||||
BOOST_TEST(to_string(trace).find("in_test_rethrow_2") != std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_nested() {
|
||||
try {
|
||||
in_test_throw_1("test_other_exception_active");
|
||||
} catch (const std::exception&) {
|
||||
try {
|
||||
in_test_throw_2("test_other_exception_active 2");
|
||||
} catch (const std::exception&) {
|
||||
auto trace = stacktrace::from_current_exception();
|
||||
BOOST_TEST(trace);
|
||||
std::cout << "Tarce in test_nested(): " << trace << '\n';
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_1") == std::string::npos);
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_2") != std::string::npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_rethrow_nested() {
|
||||
std::exception_ptr ptr;
|
||||
|
||||
try {
|
||||
in_test_throw_1("test_other_exception_active");
|
||||
} catch (const std::exception&) {
|
||||
try {
|
||||
in_test_throw_2("test_other_exception_active 2");
|
||||
} catch (const std::exception&) {
|
||||
ptr = std::current_exception();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
std::rethrow_exception(ptr);
|
||||
} catch (...) {
|
||||
auto trace = stacktrace::from_current_exception();
|
||||
BOOST_TEST(trace);
|
||||
std::cout << "Tarce in test_rethrow_nested(): " << trace << '\n';
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_1") == std::string::npos);
|
||||
#if defined(BOOST_MSVC)
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_2") == std::string::npos);
|
||||
#else
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_2") != std::string::npos);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_from_other_thread() {
|
||||
|
||||
// MinGW error: 'thread' is not a member of 'std'
|
||||
#ifndef __MINGW32__
|
||||
std::exception_ptr ptr;
|
||||
|
||||
std::thread t([&ptr]{
|
||||
try {
|
||||
in_test_throw_1("test_other_exception_active");
|
||||
} catch (const std::exception&) {
|
||||
try {
|
||||
in_test_throw_2("test_other_exception_active 2");
|
||||
} catch (const std::exception&) {
|
||||
ptr = std::current_exception();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.join();
|
||||
|
||||
try {
|
||||
std::rethrow_exception(ptr);
|
||||
} catch (...) {
|
||||
auto trace = stacktrace::from_current_exception();
|
||||
BOOST_TEST(trace);
|
||||
std::cout << "Tarce in test_rethrow_nested(): " << trace << '\n';
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_1") == std::string::npos);
|
||||
#if defined(BOOST_MSVC)
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_2") == std::string::npos);
|
||||
#else
|
||||
BOOST_TEST(to_string(trace).find("in_test_throw_2") != std::string::npos);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int main() {
|
||||
const test_no_pending_on_finish guard{};
|
||||
|
||||
BOOST_TEST(boost::stacktrace::this_thread::get_capture_stacktraces_at_throw());
|
||||
|
||||
test_no_exception();
|
||||
test_trace_from_exception();
|
||||
test_after_other_exception();
|
||||
test_rethrow();
|
||||
test_rethrow_after_other_exception();
|
||||
test_nested();
|
||||
test_rethrow_nested();
|
||||
test_from_other_thread();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
34
test/test_from_exception_none.cpp
Normal file
34
test/test_from_exception_none.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright Antony Polukhin, 2023-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/stacktrace.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
using boost::stacktrace::stacktrace;
|
||||
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void in_test_throw_1(const char* msg) {
|
||||
std::string new_msg{msg};
|
||||
throw std::runtime_error(new_msg);
|
||||
}
|
||||
|
||||
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_no_trace_from_exception() {
|
||||
try {
|
||||
in_test_throw_1("testing basic");
|
||||
} catch (const std::exception&) {
|
||||
auto trace = stacktrace::from_current_exception();
|
||||
BOOST_TEST(!trace);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
boost::stacktrace::this_thread::set_capture_stacktraces_at_throw(false);
|
||||
BOOST_TEST(!boost::stacktrace::this_thread::get_capture_stacktraces_at_throw());
|
||||
test_no_trace_from_exception();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// 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-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
15
test/test_trivial.cpp
Normal file
15
test/test_trivial.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright Antony Polukhin, 2022-2024.
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2024.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -7,15 +7,14 @@
|
||||
#include "test_impl.hpp"
|
||||
#include <boost/stacktrace/stacktrace_fwd.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
#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;
|
||||
|
||||
|
||||
@@ -41,32 +40,21 @@ void main_test_loop() {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT) || defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST)
|
||||
# include <windows.h>
|
||||
# include "dbgeng.h"
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT)
|
||||
::CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
#elif defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST)
|
||||
::CoInitializeEx(0, COINIT_APARTMENTTHREADED);
|
||||
#endif
|
||||
const auto t = std::chrono::steady_clock::now();
|
||||
|
||||
boost::timer::auto_cpu_timer t;
|
||||
|
||||
boost::thread t1(main_test_loop);
|
||||
boost::thread t2(main_test_loop);
|
||||
boost::thread t3(main_test_loop);
|
||||
std::thread t1(main_test_loop);
|
||||
std::thread t2(main_test_loop);
|
||||
std::thread t3(main_test_loop);
|
||||
main_test_loop();
|
||||
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
|
||||
#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT) || defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST)
|
||||
::CoUninitialize();
|
||||
#endif
|
||||
|
||||
const auto elapsed = t - std::chrono::steady_clock::now();
|
||||
std::cout << "Elapsed: " << std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
elapsed
|
||||
). count() << "ms";
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user