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