xref: /spdk/scripts/core-collector.sh (revision b30d57cdad6d2bc75cc1e4e2ebbcebcb0d98dcfa)
1#!/usr/bin/env bash
2# We don't want to tell kernel to include %e or %E since these
3# can include whitespaces or other funny characters, and working
4# with those on the cmdline would be a nightmare. Use procfs for
5# the remaining pieces we want to gather:
6# |$rootdir/scripts/core-collector.sh %P %s %t $output_dir
7
8get_rlimit() {
9	local limit
10
11	while read -ra limit; do
12		[[ ${limit[1]} == core ]] && echo "${limit[4]}" # soft
13	done < "/proc/$core_pid/limits"
14}
15
16core_meta() {
17	jq . <<- CORE
18		{
19		  "$exe_comm": {
20		    "ts": "$core_time",
21		    "size": "$core_size bytes",
22		    "PID": $core_pid,
23		    "signal": "$core_sig ($core_sig_name)",
24		    "path": "$exe_path",
25		    "statm": "$statm"
26		  }
27		}
28	CORE
29}
30
31bt() { hash gdb && gdb -batch -ex "thread apply all bt full" "$1" "$2" 2>&1; }
32
33stderr() {
34	exec 2> "$core.stderr.txt"
35	set -x
36}
37
38args+=(core_pid)
39args+=(core_sig)
40args+=(core_ts)
41args+=(output_dir)
42
43read -r "${args[@]}" <<< "$*"
44
45exe_path=$(readlink -f "/proc/$core_pid/exe")
46exe_comm=$(< "/proc/$core_pid/comm")
47statm=$(< "/proc/$core_pid/statm")
48core_time=$(date -d@"$core_ts")
49core_sig_name=$(kill -l "$core_sig")
50
51core=$output_dir/${exe_path##*/}_$core_pid.core
52stderr
53
54# RLIMIT_CORE is not enforced when core is piped to us. To make
55# sure we won't attempt to overload underlying storage, copy
56# only the reasonable amount of bytes (systemd defaults to 2G
57# so let's follow that). But first, check limits of terminating
58# process to see if we need to make any adjustments.
59max_core=$((1024 * 1024 * 1024 * 2))
60
61rlimit=$(get_rlimit)
62if [[ $rlimit == unlimited ]] || ((rlimit > max_core)); then
63	rlimit=$max_core
64fi
65
66# Nothing to do
67((rlimit == 0)) && exit 0
68
69# Clear path for lz
70rm -f "$core"{,.{bin,bt,gz,json}}
71
72# Slurp the core
73head -c "$rlimit" <&0 > "$core"
74core_size=$(wc -c < "$core")
75
76# Compress it
77gzip -c "$core" > "$core.gz"
78
79# Save the binary
80cp "$exe_path" "$core.bin"
81
82# Save the backtrace
83bt "$exe_path" "$core" > "$core.bt.txt"
84
85# Save the metadata of the core
86core_meta > "$core.json"
87
88# Nuke the original core
89rm "$core"
90