Skip to content

Commit 437f042

Browse files
committed
ci: try to get stack trace from mptest
1 parent 0fc31ec commit 437f042

File tree

5 files changed

+124
-2
lines changed

5 files changed

+124
-2
lines changed

ci/configs/gnu32.bash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ NIX_ARGS=(
44
--arg minimal true
55
--arg crossPkgs 'import <nixpkgs> { crossSystem = { config = "i686-unknown-linux-gnu"; }; }'
66
)
7-
export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wno-unused-parameter"
7+
export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wno-unused-parameter -ggdb"
88
CMAKE_ARGS=(-G Ninja)
99
BUILD_ARGS=(-k 0)

ci/scripts/ci.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@ else
3434
cmake --build . --target "$t" -- "${BUILD_ARGS[@]+"${BUILD_ARGS[@]}"}"
3535
done
3636
fi
37+
ulimit -c unlimited || true
3738
ctest --output-on-failure

ci/scripts/run.sh

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,119 @@ export LC_ALL=C.UTF-8
88

99
set -o errexit -o nounset -o pipefail -o xtrace
1010

11+
echo "::group::Enable core dumps"
12+
13+
# Try to ensure cores are written as files (not to systemd-coredump/apport).
14+
# This typically requires root; it's okay if it fails — we'll fall back to coredumpctl.
15+
want_pattern='core.%e.%p.%t'
16+
have_sudo=0
17+
if command -v sudo >/dev/null 2>&1; then have_sudo=1; fi
18+
if [[ -r /proc/sys/kernel/core_pattern ]]; then
19+
current="$(cat /proc/sys/kernel/core_pattern || true)"
20+
if [[ "$current" == '|'* ]]; then
21+
# Piped to a handler; try to switch to file-based cores
22+
if (( have_sudo )); then sudo sysctl -w "kernel.core_pattern=$want_pattern" || true; fi
23+
else
24+
# Already file-based; try to make the name more informative
25+
if (( have_sudo )); then sudo sysctl -w "kernel.core_pattern=$want_pattern" || true; fi
26+
fi
27+
fi
28+
29+
echo "core_pattern now: $(cat /proc/sys/kernel/core_pattern 2>/dev/null || echo '?')"
30+
echo "::endgroup::"
31+
1132
[ "${CI_CONFIG+x}" ] && source "$CI_CONFIG"
1233

13-
nix-shell --pure --keep CI_CONFIG --keep CI_CLEAN "${NIX_ARGS[@]+"${NIX_ARGS[@]}"}" --run ci/scripts/ci.sh shell.nix
34+
status=0
35+
if ! nix-shell --pure --keep CI_CONFIG --keep CI_CLEAN "${NIX_ARGS[@]+"${NIX_ARGS[@]}"}" --run ci/scripts/ci.sh shell.nix; then
36+
status=$?
37+
echo "ci.sh failed with status $status"
38+
fi
39+
40+
# --- Collect core files (file-based) -----------------------------------------
41+
echo "::group::Search for core files"
42+
mapfile -t cores < <(find "${GITHUB_WORKSPACE:-$PWD}" -xdev \
43+
\( -type f -name 'core' -o -name 'core.*' \) 2>/dev/null || true)
44+
echo "Found ${#cores[@]} possible core files."
45+
echo "::endgroup::"
46+
47+
# --- If no file-based cores, try systemd-coredump (Ubuntu) -------------------
48+
use_coredumpctl=0
49+
if [[ "${#cores[@]}" -eq 0 ]] && command -v coredumpctl >/dev/null 2>&1; then
50+
# List recent dumps for this workspace's binaries (best-effort heuristic).
51+
# If you know the test binary name(s), set EXE_HINT to narrow it.
52+
EXE_HINT="mptest"
53+
echo "::group::Check systemd-coredump"
54+
if [[ -n "$EXE_HINT" ]]; then
55+
coredumpctl --no-pager list | grep -E "$EXE_HINT" || true
56+
else
57+
coredumpctl --no-pager list | head -n 50 || true
58+
fi
59+
echo "::endgroup::"
60+
use_coredumpctl=1
61+
fi
62+
63+
# --- Print backtraces --------------------------------------------------------
64+
echo "::group::Backtraces"
65+
66+
backtrace_with_gdb () {
67+
local exe="$1" core="$2"
68+
if [[ -n "$exe" && -x "$exe" ]]; then
69+
echo "Core: $core"
70+
echo "Exe: $exe"
71+
gdb -batch "$exe" "$core" \
72+
-ex 'set pagination off' \
73+
-ex 'set print pretty on' \
74+
-ex 'info threads' \
75+
-ex 'thread apply all bt full' \
76+
-ex 'quit' || true
77+
else
78+
echo "Core: $core (exe unknown or not executable; trying core-only mode)"
79+
gdb -batch -c "$core" \
80+
-ex 'set pagination off' \
81+
-ex 'set print pretty on' \
82+
-ex 'info threads' \
83+
-ex 'info files' \
84+
-ex 'thread apply all bt full' \
85+
-ex 'quit' || true
86+
fi
87+
}
88+
if [[ "${#cores[@]}" -gt 0 ]]; then
89+
for core in "${cores[@]}"; do
90+
# Try to extract the executable path that gdb discovers from the core
91+
exe="$(gdb -batch -c "$core" -ex 'info files' 2>/dev/null | sed -n "s/^Core was generated by \`\(.*\)'.*$/\1/p" | head -n1 || true)"
92+
backtrace_with_gdb "$exe" "$core"
93+
done
94+
elif (( use_coredumpctl )); then
95+
# If your tests produce a known binary name, set EXE_HINT to make this precise.
96+
# Otherwise we grab the newest C/C++ dump and use that.
97+
line="$(coredumpctl --no-pager --no-legend list | tail -n 1)"
98+
if [[ -n "$EXE_HINT" ]]; then
99+
line="$(coredumpctl --no-pager --no-legend list | grep -E "$EXE_HINT" | tail -n 1 || true)"
100+
fi
101+
if [[ -n "$line" ]]; then
102+
pid="$(awk '{print $5}' <<<"$line" || true)"
103+
exe_path="$(coredumpctl --no-pager info "$pid" \
104+
| sed -n 's/^ *Executable: //p' \
105+
| head -n1)"
106+
# Dump that core to a file and analyze
107+
out="core.from-coredumpctl.${pid:-unknown}"
108+
if coredumpctl dump "${pid:-}" -o "$out" >/dev/null 2>&1; then
109+
backtrace_with_gdb "$exe_path" "$out"
110+
else
111+
echo "Could not dump core via coredumpctl (pid=$pid)."
112+
# As a last resort, coredumpctl can drive gdb directly, but it's interactive.
113+
# We avoid that in CI.
114+
fi
115+
rm -v "$out"
116+
else
117+
echo "No matching coredumps in systemd-coredump."
118+
fi
119+
else
120+
echo "No core files found."
121+
fi
122+
123+
echo "::endgroup::"
124+
125+
# Preserve the original test result code
126+
exit "$status"

shell.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ in crossPkgs.mkShell {
5555
];
5656
nativeBuildInputs = with pkgs; [
5757
cmakeBuild
58+
gdb
5859
include-what-you-use
5960
ninja
6061
] ++ lib.optionals (!minimal) [

test/mp/test/test.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "mp/util.h"
3030
#include <optional>
3131
#include <set>
32+
#include <signal.h>
3233
#include <stdexcept>
3334
#include <string>
3435
#include <string_view>
@@ -67,6 +68,12 @@ class TestSetup
6768

6869
TestSetup(bool client_owns_connection = true)
6970
: thread{[&] {
71+
// Restore default sigsegv handler to enable core dumps
72+
struct sigaction dfl{};
73+
dfl.sa_handler = SIG_DFL;
74+
sigemptyset(&dfl.sa_mask);
75+
sigaction(SIGSEGV, &dfl, nullptr);
76+
7077
EventLoop loop("mptest", [](mp::LogMessage log_data) {
7178
std::cout << "LOG" << (int)log_data.level << ": " << log_data.message << "\n";
7279
if (log_data.level == mp::Log::Raise) throw std::runtime_error(log_data.message);

0 commit comments

Comments
 (0)