mirror of
https://github.com/boostorg/stacktrace.git
synced 2026-01-28 19:52:08 +00:00
Compare commits
44 Commits
boost-1.84
...
feature/bo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
342
.github/workflows/ci.yml
vendored
342
.github/workflows/ci.yml
vendored
@@ -27,8 +27,7 @@ jobs:
|
|||||||
- toolset: gcc-9
|
- toolset: gcc-9
|
||||||
cxxstd: "03,11,14,17,2a"
|
cxxstd: "03,11,14,17,2a"
|
||||||
os: ubuntu-22.04
|
os: ubuntu-22.04
|
||||||
- toolset: clang
|
- toolset: clang-15
|
||||||
compiler: clang++-14
|
|
||||||
cxxstd: "03,11,14,17,2a"
|
cxxstd: "03,11,14,17,2a"
|
||||||
os: ubuntu-22.04
|
os: ubuntu-22.04
|
||||||
# TODO: fix and uncomment
|
# TODO: fix and uncomment
|
||||||
@@ -41,7 +40,7 @@ jobs:
|
|||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
if: matrix.install
|
if: matrix.install
|
||||||
@@ -127,7 +126,7 @@ jobs:
|
|||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Boost
|
- name: Setup Boost
|
||||||
shell: cmd
|
shell: cmd
|
||||||
@@ -166,3 +165,338 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.github_token }}
|
github-token: ${{ secrets.github_token }}
|
||||||
parallel-finished: true
|
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: [ ON ] # https://github.com/boostorg/stacktrace/issues/169
|
||||||
|
|
||||||
|
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: [ ON ] # https://github.com/boostorg/stacktrace/issues/169
|
||||||
|
|
||||||
|
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: [ ON ] # https://github.com/boostorg/stacktrace/issues/169
|
||||||
|
|
||||||
|
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: [ ON ] # https://github.com/boostorg/stacktrace/issues/169
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -90,12 +90,43 @@ message(STATUS "Boost.Stacktrace: "
|
|||||||
)
|
)
|
||||||
|
|
||||||
stacktrace_add_library(noop ${BOOST_STACKTRACE_ENABLE_NOOP} "" "")
|
stacktrace_add_library(noop ${BOOST_STACKTRACE_ENABLE_NOOP} "" "")
|
||||||
stacktrace_add_library(backtrace ${BOOST_STACKTRACE_ENABLE_BACKTRACE} "backtrace" "")
|
stacktrace_add_library(backtrace ${BOOST_STACKTRACE_ENABLE_BACKTRACE} "backtrace;${CMAKE_DL_LIBS}" "")
|
||||||
stacktrace_add_library(addr2line ${BOOST_STACKTRACE_ENABLE_ADDR2LINE} "" "")
|
stacktrace_add_library(addr2line ${BOOST_STACKTRACE_ENABLE_ADDR2LINE} "${CMAKE_DL_LIBS}" "")
|
||||||
stacktrace_add_library(basic ${BOOST_STACKTRACE_ENABLE_BASIC} "" "")
|
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 ${BOOST_STACKTRACE_ENABLE_WINDBG} "dbgeng;ole32" "_GNU_SOURCE=1")
|
||||||
stacktrace_add_library(windbg_cached ${BOOST_STACKTRACE_ENABLE_WINDBG_CACHED} "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")
|
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||||
|
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
# Copyright (C) 2016-2023, Antony Polukhin.
|
# Copyright (C) 2016-2024, Antony Polukhin.
|
||||||
#
|
#
|
||||||
# Use, modification and distribution is subject to the Boost Software License,
|
# Use, modification and distribution is subject to the Boost Software License,
|
||||||
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import feature ;
|
||||||
|
import property ;
|
||||||
import ../../config/checks/config : requires ;
|
import ../../config/checks/config : requires ;
|
||||||
|
|
||||||
project
|
project
|
||||||
: source-location .
|
: source-location .
|
||||||
: requirements
|
: requirements
|
||||||
[ requires cxx11_rvalue_references ]
|
[ requires cxx11_rvalue_references ]
|
||||||
|
: default-build
|
||||||
<visibility>hidden
|
<visibility>hidden
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -19,6 +22,7 @@ lib gcc_s ;
|
|||||||
lib Dbgeng ;
|
lib Dbgeng ;
|
||||||
lib ole32 ;
|
lib ole32 ;
|
||||||
|
|
||||||
|
feature.feature boost.stacktrace.from_exception : on off : optional propagated ;
|
||||||
|
|
||||||
local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ;
|
local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ;
|
||||||
lib backtrace
|
lib backtrace
|
||||||
@@ -131,4 +135,37 @@ lib boost_stacktrace_windbg_cached
|
|||||||
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||||
;
|
;
|
||||||
|
|
||||||
boost-install boost_stacktrace_noop boost_stacktrace_backtrace boost_stacktrace_addr2line boost_stacktrace_basic boost_stacktrace_windbg boost_stacktrace_windbg_cached ;
|
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 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ../build//libbacktrace : : <build>no ]
|
||||||
|
: # default build
|
||||||
|
: # usage-requirements
|
||||||
|
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
|
||||||
|
;
|
||||||
|
|
||||||
|
boost-install boost_stacktrace_noop boost_stacktrace_backtrace boost_stacktrace_addr2line boost_stacktrace_basic boost_stacktrace_windbg boost_stacktrace_windbg_cached boost_stacktrace_from_exception ;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright Antony Polukhin, 2016-2023.
|
# Copyright Antony Polukhin, 2016-2024.
|
||||||
# Use, modification, and distribution are
|
# Use, modification, and distribution are
|
||||||
# subject to the Boost Software License, Version 1.0. (See accompanying
|
# 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)
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -22,6 +22,9 @@ doxygen autodoc
|
|||||||
<doxygen:param>SEARCH_INCLUDES=YES
|
<doxygen:param>SEARCH_INCLUDES=YES
|
||||||
<doxygen:param>SHORT_NAMES=NO
|
<doxygen:param>SHORT_NAMES=NO
|
||||||
<doxygen:param>INCLUDE_PATH=../../../
|
<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\" \\
|
<doxygen:param>"PREDEFINED=\"stl_type_info=std::type_info\" \\
|
||||||
\"BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()=explicit operator bool() const noexcept;\" \\
|
\"BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()=explicit operator bool() const noexcept;\" \\
|
||||||
\"BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()=explicit constexpr operator bool() const noexcept;\" \\
|
\"BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()=explicit constexpr operator bool() const noexcept;\" \\
|
||||||
@@ -39,9 +42,9 @@ boostbook standalone
|
|||||||
:
|
:
|
||||||
stacktrace
|
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=../../../..
|
# <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]
|
[quickbook 1.6]
|
||||||
[version 1.0]
|
[version 1.0]
|
||||||
[id stacktrace]
|
[id stacktrace]
|
||||||
[copyright 2016-2023 Antony Polukhin]
|
[copyright 2016-2024 Antony Polukhin]
|
||||||
[category Language Features Emulation]
|
[category Language Features Emulation]
|
||||||
[license
|
[license
|
||||||
Distributed under the Boost Software License, Version 1.0.
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
@@ -120,14 +120,80 @@ Previous run crashed:
|
|||||||
9# 0x0000000000402209
|
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.
|
[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!
|
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*.
|
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::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]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
@@ -233,43 +299,6 @@ Terminate called:
|
|||||||
|
|
||||||
[endsect]
|
[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]
|
[endsect]
|
||||||
|
|
||||||
@@ -286,9 +315,9 @@ 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:
|
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
|
[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 `-fvisibility=hidden` or marking functions as exported produce a better stacktraces.]] ]
|
[[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. May require linking with *ole32* and *dbgeng*. ] [MSVC, MinGW-w64, Intel on Windows] [yes] [no]]
|
[[['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]]
|
[[['default for other platforms]] [*boost_stacktrace_basic*] [Uses compiler intrinsics to collect stacktrace and if possible `::dladdr` to show information about the symbol. Requires linking with *libdl* library on POSIX platforms.] [Any compiler on POSIX or MinGW] [no] [yes]]
|
||||||
[[*BOOST_STACKTRACE_USE_WINDBG_CACHED*] [*boost_stacktrace_windbg_cached*] [ Uses `dbgeng.h` to show debug info and caches internals in TLS for better performance. Useful only for cases when traces are gathered very often. May require linking with *ole32* and *dbgeng*. ] [MSVC, Intel on Windows] [yes] [no]]
|
[[*BOOST_STACKTRACE_USE_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.
|
[[*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]]
|
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]]
|
||||||
@@ -334,7 +363,33 @@ There are multiple ways to deal with that issue if you distribute PDB files alon
|
|||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Acknowledgements]
|
[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:
|
In order of helping and advising:
|
||||||
|
|
||||||
@@ -342,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 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 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 all the library reviewers.
|
||||||
|
* Great thanks to Andrei Nekrashevich for prototyping the idea of stacktraces
|
||||||
|
from arbitrary exception in `libsfe`.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -63,38 +63,17 @@ void my_terminate_handler() {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
BOOST_CONSTEXPR_OR_CONST std::size_t shared_memory_size = 4096 * 8;
|
|
||||||
|
|
||||||
//[getting_started_terminate_handlers_shmem
|
|
||||||
#include <boost/stacktrace.hpp>
|
|
||||||
#include <boost/interprocess/shared_memory_object.hpp>
|
|
||||||
#include <boost/interprocess/mapped_region.hpp>
|
|
||||||
|
|
||||||
boost::interprocess::shared_memory_object g_shm; // inited at program start
|
|
||||||
boost::interprocess::mapped_region g_region; // inited at program start
|
|
||||||
|
|
||||||
|
|
||||||
void my_signal_handler2(int signum) {
|
|
||||||
::signal(signum, SIG_DFL);
|
|
||||||
void** f = static_cast<void**>(g_region.get_address());
|
|
||||||
*f = reinterpret_cast<void*>(1); // Setting flag that shared memory now contains stacktrace.
|
|
||||||
boost::stacktrace::safe_dump_to(f + 1, g_region.get_size() - sizeof(void*));
|
|
||||||
|
|
||||||
::raise(SIGABRT);
|
|
||||||
}
|
|
||||||
//]
|
|
||||||
|
|
||||||
#include <iostream> // std::cerr
|
#include <iostream> // std::cerr
|
||||||
#include <fstream> // std::ifstream
|
#include <fstream> // std::ifstream
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
|
|
||||||
|
#ifndef BOOST_WINDOWS
|
||||||
inline void copy_and_run(const char* exec_name, char param, bool not_null) {
|
inline void copy_and_run(const char* exec_name, char param, bool not_null) {
|
||||||
std::cout << "Running with param " << param << std::endl;
|
std::cout << "Running with param " << param << std::endl;
|
||||||
boost::filesystem::path command = exec_name;
|
boost::filesystem::path command = exec_name;
|
||||||
command = command.parent_path() / (command.stem().string() + param + command.extension().string());
|
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;
|
boost::filesystem::path command_args = command;
|
||||||
command_args += ' ';
|
command_args += ' ';
|
||||||
@@ -110,6 +89,7 @@ inline void copy_and_run(const char* exec_name, char param, bool not_null) {
|
|||||||
std::exit(ret);
|
std::exit(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int run_0(const char* /*argv*/[]) {
|
int run_0(const char* /*argv*/[]) {
|
||||||
//[getting_started_setup_terminate_handlers
|
//[getting_started_setup_terminate_handlers
|
||||||
@@ -160,67 +140,6 @@ int run_2(const char* argv[]) {
|
|||||||
return 0;
|
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 contains 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>
|
#include <sstream>
|
||||||
|
|
||||||
int test_inplace() {
|
int test_inplace() {
|
||||||
@@ -335,10 +254,6 @@ int main(int argc, const char* argv[]) {
|
|||||||
// We are copying files to make sure that stacktrace printing works independently from executable name
|
// 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], '1', true);
|
||||||
copy_and_run(argv[0], '2', false);
|
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
|
#endif
|
||||||
|
|
||||||
return test_inplace();
|
return test_inplace();
|
||||||
@@ -347,9 +262,6 @@ int main(int argc, const char* argv[]) {
|
|||||||
switch (argv[1][0]) {
|
switch (argv[1][0]) {
|
||||||
case '0': return run_0(argv);
|
case '0': return run_0(argv);
|
||||||
case '1': return run_1(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;
|
return 404;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -13,7 +13,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/stacktrace/frame.hpp>
|
#include <boost/stacktrace/frame.hpp>
|
||||||
#include <boost/stacktrace/stacktrace.hpp> // Actually already includes all the headers
|
#include <boost/stacktrace/stacktrace.hpp>
|
||||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||||
|
#include <boost/stacktrace/this_thread.hpp>
|
||||||
|
|
||||||
#endif // BOOST_STACKTRACE_HPP
|
#endif // BOOST_STACKTRACE_HPP
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -18,9 +18,21 @@
|
|||||||
#include <boost/core/noncopyable.hpp>
|
#include <boost/core/noncopyable.hpp>
|
||||||
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
||||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||||
|
|
||||||
|
#ifdef WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#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"
|
#include "dbgeng.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#ifdef BOOST_MSVC
|
#ifdef BOOST_MSVC
|
||||||
# pragma comment(lib, "ole32.lib")
|
# pragma comment(lib, "ole32.lib")
|
||||||
# pragma comment(lib, "Dbgeng.lib")
|
# pragma comment(lib, "Dbgeng.lib")
|
||||||
@@ -138,14 +150,30 @@ class debugging_symbols: boost::noncopyable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
|
#ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
|
||||||
|
static std::mutex& get_mutex_inst() noexcept {
|
||||||
com_holder< ::IDebugSymbols> idebug_;
|
static std::mutex m;
|
||||||
public:
|
return m;
|
||||||
debugging_symbols() noexcept
|
|
||||||
{
|
|
||||||
try_init_com(idebug_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
#else
|
||||||
|
|
||||||
#ifdef BOOST_NO_CXX11_THREAD_LOCAL
|
#ifdef BOOST_NO_CXX11_THREAD_LOCAL
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -90,8 +90,8 @@ std::string frame::name() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||||
::Dl_info dli;
|
boost::stacktrace::detail::Dl_info dli;
|
||||||
const bool dl_ok = !!::dladdr(const_cast<void*>(addr_), &dli); // `dladdr` on Solaris accepts nonconst addresses
|
const bool dl_ok = !!boost::stacktrace::detail::dladdr(addr_, dli);
|
||||||
if (dl_ok && dli.dli_sname) {
|
if (dl_ok && dli.dli_sname) {
|
||||||
return boost::core::demangle(dli.dli_sname);
|
return boost::core::demangle(dli.dli_sname);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -18,17 +18,110 @@
|
|||||||
# include <boost/winapi/dll.hpp>
|
# include <boost/winapi/dll.hpp>
|
||||||
#endif
|
#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 {
|
namespace boost { namespace stacktrace { namespace detail {
|
||||||
|
|
||||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||||
class location_from_symbol {
|
class location_from_symbol {
|
||||||
::Dl_info dli_;
|
boost::stacktrace::detail::Dl_info dli_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit location_from_symbol(const void* addr) noexcept
|
explicit location_from_symbol(const void* addr) noexcept
|
||||||
: dli_()
|
: 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;
|
dli_.dli_fname = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
|
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
|
||||||
// Copyright Antony Polukhin, 2015-2023.
|
// Copyright Antony Polukhin, 2015-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
// (See accompanying file LICENSE_1_0.txt
|
// (See accompanying file LICENSE_1_0.txt
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -12,6 +12,8 @@
|
|||||||
# pragma once
|
# pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
#if defined(BOOST_WINDOWS)
|
#if defined(BOOST_WINDOWS)
|
||||||
#include <boost/winapi/config.hpp>
|
#include <boost/winapi/config.hpp>
|
||||||
#endif
|
#endif
|
||||||
@@ -23,15 +25,17 @@
|
|||||||
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
|
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
|
||||||
#endif
|
#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*`,
|
/// @file safe_dump_to.hpp \asyncsafe low-level
|
||||||
/// so you could read them by using 'od -tx8 -An stacktrace_dump_failename' Linux command or using boost::stacktrace::stacktrace::from_dump functions.
|
/// 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 {
|
namespace boost { namespace stacktrace {
|
||||||
|
|
||||||
/// @cond
|
/// @cond
|
||||||
namespace detail {
|
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 };
|
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 from_dump(const char* filename, native_frame_ptr_t* out_frames);
|
||||||
@@ -48,7 +52,7 @@ struct this_thread_frames { // struct is required to avoid warning about usage o
|
|||||||
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 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) noexcept {
|
BOOST_NOINLINE static std::size_t safe_dump_to_impl(void* memory, std::size_t size, std::size_t skip) noexcept {
|
||||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
using boost::stacktrace::detail::native_frame_ptr_t;
|
||||||
|
|
||||||
if (size < sizeof(native_frame_ptr_t)) {
|
if (size < sizeof(native_frame_ptr_t)) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -62,7 +66,7 @@ struct this_thread_frames { // struct is required to avoid warning about usage o
|
|||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) noexcept {
|
BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) noexcept {
|
||||||
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
|
using boost::stacktrace::detail::native_frame_ptr_t;
|
||||||
|
|
||||||
native_frame_ptr_t buffer[boost::stacktrace::detail::max_frames_dump + 1];
|
native_frame_ptr_t buffer[boost::stacktrace::detail::max_frames_dump + 1];
|
||||||
if (max_depth > boost::stacktrace::detail::max_frames_dump) {
|
if (max_depth > boost::stacktrace::detail::max_frames_dump) {
|
||||||
@@ -82,7 +86,7 @@ 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 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)
|
/// @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)
|
||||||
///
|
///
|
||||||
@@ -97,7 +101,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) noexc
|
|||||||
///
|
///
|
||||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
/// @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)
|
/// @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)
|
||||||
///
|
///
|
||||||
@@ -115,7 +119,7 @@ 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 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.
|
/// @returns Stored call sequence depth including terminating zero frame.
|
||||||
///
|
///
|
||||||
@@ -128,7 +132,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) noexcept {
|
|||||||
///
|
///
|
||||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
/// @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.
|
/// @returns Stored call sequence depth including terminating zero frame.
|
||||||
///
|
///
|
||||||
@@ -147,7 +151,7 @@ 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 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.
|
/// @returns Stored call sequence depth including terminating zero frame.
|
||||||
///
|
///
|
||||||
@@ -158,7 +162,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) noex
|
|||||||
///
|
///
|
||||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
/// @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.
|
/// @returns Stored call sequence depth including terminating zero frame.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -33,8 +33,42 @@
|
|||||||
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
|
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
BOOST_SYMBOL_EXPORT inline void* boost_stacktrace_impl_return_nullptr() { return nullptr; }
|
||||||
|
const char* boost_stacktrace_impl_current_exception_stacktrace();
|
||||||
|
bool* boost_stacktrace_impl_ref_capture_stacktraces_at_throw();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
namespace boost { namespace stacktrace {
|
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.
|
/// 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.
|
/// @tparam Allocator Allocator to use during stack capture.
|
||||||
template <class Allocator>
|
template <class Allocator>
|
||||||
@@ -65,7 +99,7 @@ class basic_stacktrace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) {
|
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) {
|
if (!max_depth) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -121,7 +155,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
/// @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.
|
||||||
BOOST_FORCEINLINE basic_stacktrace() noexcept
|
BOOST_FORCEINLINE basic_stacktrace() noexcept
|
||||||
: impl_()
|
: impl_()
|
||||||
{
|
{
|
||||||
@@ -132,7 +166,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
/// @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 storage.
|
/// @param a Allocator that would be passed to underlying storage.
|
||||||
BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) noexcept
|
BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) noexcept
|
||||||
@@ -145,7 +179,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
|
/// @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 skip How many top calls to skip and do not store in *this.
|
||||||
///
|
///
|
||||||
@@ -163,14 +197,14 @@ public:
|
|||||||
|
|
||||||
/// @b Complexity: O(st.size())
|
/// @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)
|
basic_stacktrace(const basic_stacktrace& st)
|
||||||
: impl_(st.impl_)
|
: impl_(st.impl_)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/// @b Complexity: O(st.size())
|
/// @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) {
|
basic_stacktrace& operator=(const basic_stacktrace& st) {
|
||||||
impl_ = st.impl_;
|
impl_ = st.impl_;
|
||||||
return *this;
|
return *this;
|
||||||
@@ -179,21 +213,21 @@ public:
|
|||||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe if Allocator::deallocate is async signal safe.
|
/// @b Async-Handler-Safety: \asyncsafe if Allocator::deallocate is async signal safe.
|
||||||
~basic_stacktrace() noexcept = default;
|
~basic_stacktrace() noexcept = default;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @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(basic_stacktrace&& st) noexcept
|
basic_stacktrace(basic_stacktrace&& st) noexcept
|
||||||
: impl_(std::move(st.impl_))
|
: impl_(std::move(st.impl_))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/// @b Complexity: O(st.size())
|
/// @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)
|
basic_stacktrace& operator=(basic_stacktrace&& st)
|
||||||
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
||||||
noexcept(( 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 ))
|
||||||
@@ -210,7 +244,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
size_type size() const noexcept {
|
size_type size() const noexcept {
|
||||||
return impl_.size();
|
return impl_.size();
|
||||||
}
|
}
|
||||||
@@ -222,43 +256,43 @@ public:
|
|||||||
///
|
///
|
||||||
/// @b Complexity: O(1).
|
/// @b Complexity: O(1).
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
const_reference operator[](std::size_t frame_no) const noexcept {
|
const_reference operator[](std::size_t frame_no) const noexcept {
|
||||||
return impl_[frame_no];
|
return impl_[frame_no];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
const_iterator begin() const noexcept { return impl_.begin(); }
|
const_iterator begin() const noexcept { return impl_.begin(); }
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
const_iterator cbegin() const noexcept { return impl_.begin(); }
|
const_iterator cbegin() const noexcept { return impl_.begin(); }
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
const_iterator end() const noexcept { return impl_.end(); }
|
const_iterator end() const noexcept { return impl_.end(); }
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
const_iterator cend() const noexcept { return impl_.end(); }
|
const_iterator cend() const noexcept { return impl_.end(); }
|
||||||
|
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
const_reverse_iterator rbegin() const noexcept { return impl_.rbegin(); }
|
const_reverse_iterator rbegin() const noexcept { return impl_.rbegin(); }
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
const_reverse_iterator crbegin() const noexcept { return impl_.rbegin(); }
|
const_reverse_iterator crbegin() const noexcept { return impl_.rbegin(); }
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
const_reverse_iterator rend() const noexcept { return impl_.rend(); }
|
const_reverse_iterator rend() const noexcept { return impl_.rend(); }
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
const_reverse_iterator crend() const noexcept { return impl_.rend(); }
|
const_reverse_iterator crend() const noexcept { return impl_.rend(); }
|
||||||
|
|
||||||
|
|
||||||
@@ -267,7 +301,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
constexpr explicit operator bool () const noexcept { return !empty(); }
|
constexpr explicit operator bool () const noexcept { return !empty(); }
|
||||||
|
|
||||||
/// @brief Allows to check that stack trace failed.
|
/// @brief Allows to check that stack trace failed.
|
||||||
@@ -275,7 +309,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// @b Complexity: O(1)
|
/// @b Complexity: O(1)
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
bool empty() const noexcept { return !size(); }
|
bool empty() const noexcept { return !size(); }
|
||||||
|
|
||||||
const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const noexcept {
|
const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const noexcept {
|
||||||
@@ -340,13 +374,53 @@ public:
|
|||||||
|
|
||||||
return ret;
|
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.
|
/// @brief Compares stacktraces for less, order is platform dependent.
|
||||||
///
|
///
|
||||||
/// @b Complexity: Amortized O(1); worst case O(size())
|
/// @b Complexity: Amortized O(1); worst case O(size())
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
template <class Allocator1, class Allocator2>
|
template <class Allocator1, class Allocator2>
|
||||||
bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) 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());
|
return lhs.size() < rhs.size() || (lhs.size() == rhs.size() && lhs.as_vector() < rhs.as_vector());
|
||||||
@@ -356,7 +430,7 @@ bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<
|
|||||||
///
|
///
|
||||||
/// @b Complexity: Amortized O(1); worst case O(size())
|
/// @b Complexity: Amortized O(1); worst case O(size())
|
||||||
///
|
///
|
||||||
/// @b Async-Handler-Safety: Safe.
|
/// @b Async-Handler-Safety: \asyncsafe.
|
||||||
template <class Allocator1, class Allocator2>
|
template <class Allocator1, class Allocator2>
|
||||||
bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
|
bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
|
||||||
return lhs.as_vector() == rhs.as_vector();
|
return lhs.as_vector() == rhs.as_vector();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// 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,6 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<!--
|
<!--
|
||||||
Copyright (c) Antony Polukhin, 2014-2023
|
Copyright (c) Antony Polukhin, 2014-2024
|
||||||
antoshkka at gmail dot com
|
antoshkka at gmail dot com
|
||||||
|
|
||||||
Distributed under the Boost Software License,
|
Distributed under the Boost Software License,
|
||||||
@@ -31,7 +31,7 @@ boost-no-inspect
|
|||||||
<a href="../../doc/html/stacktrace.html">../../doc/html/stacktrace.html</a>
|
<a href="../../doc/html/stacktrace.html">../../doc/html/stacktrace.html</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
© Antony Polukhin, 2014-2023
|
© Antony Polukhin, 2014-2024
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
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"
|
||||||
|
|
||||||
|
|
||||||
366
src/from_exception.cpp
Normal file
366
src/from_exception.cpp
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
// 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 <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
|
||||||
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)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (C) 2016-2023, Antony Polukhin.
|
# Copyright (C) 2016-2024, Antony Polukhin.
|
||||||
#
|
#
|
||||||
# Use, modification and distribution is subject to the Boost Software License,
|
# Use, modification and distribution is subject to the Boost Software License,
|
||||||
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -24,7 +24,7 @@ lib backtrace
|
|||||||
|
|
||||||
project
|
project
|
||||||
: requirements
|
: requirements
|
||||||
[ requires cxx11_rvalue_references ]
|
[ requires cxx11_rvalue_references cxx11_template_aliases cxx11_noexcept ]
|
||||||
<toolset>msvc:<asynch-exceptions>on
|
<toolset>msvc:<asynch-exceptions>on
|
||||||
<toolset>intel:<cxxflags>-wd2196
|
<toolset>intel:<cxxflags>-wd2196
|
||||||
<target-os>linux:<linkflags>-lpthread
|
<target-os>linux:<linkflags>-lpthread
|
||||||
@@ -117,20 +117,20 @@ test-suite stacktrace_tests
|
|||||||
|
|
||||||
# Thread safety with debug symbols
|
# Thread safety with debug symbols
|
||||||
[ run thread_safety_checking.cpp
|
[ 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 ]
|
: backtrace_lib_threaded ]
|
||||||
[ run thread_safety_checking.cpp
|
[ 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)
|
||||||
<define>BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC
|
<define>BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC
|
||||||
: backtrace_lib_threaded_static ]
|
: backtrace_lib_threaded_static ]
|
||||||
[ run thread_safety_checking.cpp
|
[ 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_windbg $(LINKSHARED_WIND)
|
||||||
: windbg_lib_threaded ]
|
: windbg_lib_threaded ]
|
||||||
[ run thread_safety_checking.cpp
|
[ 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)
|
||||||
: windbg_cached_lib_threaded ]
|
: windbg_cached_lib_threaded ]
|
||||||
[ run thread_safety_checking.cpp
|
[ 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)
|
||||||
: basic_lib_threaded ]
|
: basic_lib_threaded ]
|
||||||
|
|
||||||
##### Tests with disabled debug symbols #####
|
##### Tests with disabled debug symbols #####
|
||||||
@@ -157,35 +157,55 @@ test-suite stacktrace_tests
|
|||||||
# Thread safety without debug symbols
|
# Thread safety without debug symbols
|
||||||
[ run thread_safety_checking.cpp
|
[ run thread_safety_checking.cpp
|
||||||
: : : <debug-symbols>off
|
: : : <debug-symbols>off
|
||||||
<library>/boost/thread//boost_thread
|
|
||||||
<library>/boost/timer//boost_timer
|
|
||||||
<library>.//test_impl_lib_backtrace_no_dbg
|
<library>.//test_impl_lib_backtrace_no_dbg
|
||||||
$(LINKSHARED_BT)
|
$(LINKSHARED_BT)
|
||||||
: backtrace_lib_no_dbg_threaded ]
|
: backtrace_lib_no_dbg_threaded ]
|
||||||
[ run thread_safety_checking.cpp
|
[ run thread_safety_checking.cpp
|
||||||
: : : <debug-symbols>off
|
: : : <debug-symbols>off
|
||||||
<library>/boost/thread//boost_thread
|
|
||||||
<library>/boost/timer//boost_timer
|
|
||||||
<library>.//test_impl_lib_windbg_no_dbg
|
<library>.//test_impl_lib_windbg_no_dbg
|
||||||
$(LINKSHARED_WIND)
|
$(LINKSHARED_WIND)
|
||||||
: windbg_lib_no_dbg_threaded ]
|
: windbg_lib_no_dbg_threaded ]
|
||||||
[ run thread_safety_checking.cpp
|
[ run thread_safety_checking.cpp
|
||||||
: : : <debug-symbols>off
|
: : : <debug-symbols>off
|
||||||
<library>/boost/thread//boost_thread
|
|
||||||
<library>/boost/timer//boost_timer
|
|
||||||
<library>.//test_impl_lib_windbg_cached_no_dbg
|
<library>.//test_impl_lib_windbg_cached_no_dbg
|
||||||
$(LINKSHARED_WIND_CACHED)
|
$(LINKSHARED_WIND_CACHED)
|
||||||
: windbg_cached_lib_no_dbg_threaded ]
|
: windbg_cached_lib_no_dbg_threaded ]
|
||||||
[ run thread_safety_checking.cpp
|
[ run thread_safety_checking.cpp
|
||||||
: : : <debug-symbols>off
|
: : : <debug-symbols>off
|
||||||
<library>/boost/thread//boost_thread
|
|
||||||
<library>/boost/timer//boost_timer
|
|
||||||
<library>.//test_impl_lib_basic_no_dbg
|
<library>.//test_impl_lib_basic_no_dbg
|
||||||
$(LINKSHARED_BASIC)
|
$(LINKSHARED_BASIC)
|
||||||
: basic_lib_no_dbg_threaded ]
|
: basic_lib_no_dbg_threaded ]
|
||||||
|
|
||||||
[ run test_void_ptr_cast.cpp ]
|
[ run test_void_ptr_cast.cpp ]
|
||||||
[ run test_num_conv.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.
|
# Assuring that examples compile and run. Adding sources from `examples` directory to the `type_index` test suite.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# subject to the Boost Software License, Version 1.0. (See accompanying
|
# 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)
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
#
|
#
|
||||||
# Copyright Antony Polukhin, 2016-2023.
|
# Copyright Antony Polukhin, 2016-2024.
|
||||||
|
|
||||||
#
|
#
|
||||||
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
|
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
|
||||||
@@ -33,7 +33,7 @@ skip_tags: true
|
|||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
TOOLSET: msvc-14.1 # ,clang-win
|
TOOLSET: msvc-14.1 #,clang-win
|
||||||
CXXSTD: 14,17
|
CXXSTD: 14,17
|
||||||
ADDRMD: 64
|
ADDRMD: 64
|
||||||
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||||
@@ -44,10 +44,11 @@ environment:
|
|||||||
# ADDPATH: C:\cygwin64\bin;
|
# ADDPATH: C:\cygwin64\bin;
|
||||||
# TOOLSET: gcc
|
# TOOLSET: gcc
|
||||||
# CXXSTD: 03,11,14,1z
|
# CXXSTD: 03,11,14,1z
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
# Waiting for https://github.com/boostorg/system/issues/116
|
||||||
ADDPATH: C:\mingw\bin;
|
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||||
TOOLSET: gcc
|
# ADDPATH: C:\mingw\bin;
|
||||||
CXXSTD: 03,11,14,1z
|
# TOOLSET: gcc
|
||||||
|
# CXXSTD: 03,11,14,1z
|
||||||
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||||
# ADDPATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin;
|
# ADDPATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin;
|
||||||
# TOOLSET: gcc
|
# TOOLSET: gcc
|
||||||
@@ -61,7 +62,10 @@ before_build:
|
|||||||
- set BOOST=C:/boost-local
|
- set BOOST=C:/boost-local
|
||||||
- git clone -b %BOOST_BRANCH% --depth 10 https://github.com/boostorg/boost.git %BOOST%
|
- git clone -b %BOOST_BRANCH% --depth 10 https://github.com/boostorg/boost.git %BOOST%
|
||||||
- cd %BOOST%
|
- cd %BOOST%
|
||||||
- git submodule update --init --depth 10 tools/build tools/boostdep libs/filesystem libs/interprocess
|
- 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
|
||||||
|
|
||||||
- rm -rf %BOOST%/libs/%BOOST_LIBS_FOLDER%
|
- rm -rf %BOOST%/libs/%BOOST_LIBS_FOLDER%
|
||||||
- mv -f %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%BOOST_LIBS_FOLDER%
|
- mv -f %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%BOOST_LIBS_FOLDER%
|
||||||
|
|||||||
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-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -257,6 +257,12 @@ void test_empty_basic_stacktrace() {
|
|||||||
BOOST_TEST(!(st > st_t(0, 0)));
|
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() {
|
int main() {
|
||||||
test_deeply_nested_namespaces();
|
test_deeply_nested_namespaces();
|
||||||
test_frames_string_data_validity();
|
test_frames_string_data_validity();
|
||||||
@@ -275,8 +281,8 @@ int main() {
|
|||||||
test_comparisons_base(make_some_stacktrace1(), make_some_stacktrace2());
|
test_comparisons_base(make_some_stacktrace1(), make_some_stacktrace2());
|
||||||
|
|
||||||
test_nested<260>(false);
|
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();
|
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-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2022-2023.
|
// Copyright Antony Polukhin, 2022-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright Antony Polukhin, 2016-2023.
|
// Copyright Antony Polukhin, 2016-2024.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -7,15 +7,14 @@
|
|||||||
#include "test_impl.hpp"
|
#include "test_impl.hpp"
|
||||||
#include <boost/stacktrace/stacktrace_fwd.hpp>
|
#include <boost/stacktrace/stacktrace_fwd.hpp>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <boost/stacktrace.hpp>
|
#include <boost/stacktrace.hpp>
|
||||||
#include <boost/thread.hpp>
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <boost/core/lightweight_test.hpp>
|
#include <boost/core/lightweight_test.hpp>
|
||||||
|
|
||||||
#include <boost/timer/timer.hpp>
|
|
||||||
|
|
||||||
using boost::stacktrace::stacktrace;
|
using boost::stacktrace::stacktrace;
|
||||||
|
|
||||||
|
|
||||||
@@ -42,16 +41,20 @@ void main_test_loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
boost::timer::auto_cpu_timer t;
|
const auto t = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
boost::thread t1(main_test_loop);
|
std::thread t1(main_test_loop);
|
||||||
boost::thread t2(main_test_loop);
|
std::thread t2(main_test_loop);
|
||||||
boost::thread t3(main_test_loop);
|
std::thread t3(main_test_loop);
|
||||||
main_test_loop();
|
main_test_loop();
|
||||||
|
|
||||||
t1.join();
|
t1.join();
|
||||||
t2.join();
|
t2.join();
|
||||||
t3.join();
|
t3.join();
|
||||||
|
|
||||||
|
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();
|
return boost::report_errors();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user