xref: /freebsd/usr.sbin/crashinfo/crashinfo.sh (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1#!/bin/sh
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5# Copyright (c) 2008 Yahoo!, Inc.
6# All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16# 3. Neither the name of the author nor the names of any co-contributors
17#    may be used to endorse or promote products derived from this software
18#    without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30# SUCH DAMAGE.
31#
32
33usage()
34{
35	echo "usage: crashinfo [-b] [-d crashdir] [-n dumpnr]" \
36		"[-k kernel] [core]"
37	exit 1
38}
39
40# Remove an uncompressed copy of a dump
41cleanup()
42{
43
44	[ -e $VMCORE ] && rm -f $VMCORE
45}
46
47# Find a gdb binary to use and save the value in GDB.
48find_gdb()
49{
50	local binary
51
52	for binary in /usr/local/bin/gdb /usr/libexec/gdb; do
53		if [ -x ${binary} ]; then
54			GDB=${binary}
55			return
56		fi
57	done
58}
59
60# Run a single gdb command against a kernel file in batch mode.
61# The kernel file is specified as the first argument and the command
62# is given in the remaining arguments.
63gdb_command()
64{
65	local k
66
67	k=$1 ; shift
68
69	if [ ${GDB} = /usr/local/bin/gdb ]; then
70		${GDB} -batch -ex "$@" $k
71	else
72		echo -e "$@" | ${GDB} -x /dev/stdin -batch $k
73	fi
74}
75
76find_kernel()
77{
78	local ivers k kvers
79
80	ivers=$(awk '
81	/Version String/ {
82		print
83		nextline=1
84		next
85	}
86	nextline==1 {
87		if ($0 ~ "^  [A-Za-z ]+: ") {
88			nextline=0
89		} else {
90			print
91		}
92	}' $INFO)
93
94	# Look for a matching kernel version, handling possible truncation
95	# of the version string recovered from the dump.
96	for k in `sysctl -n kern.bootfile` $(ls -t /boot/*/kernel); do
97		kvers=$(gdb_command $k 'printf "  Version String: %s", version' | \
98		    awk "{line=line\$0\"\n\"} END{print substr(line,1,${#ivers})}" \
99		    2>/dev/null)
100		if [ "$ivers" = "$kvers" ]; then
101			KERNEL=$k
102			break
103		fi
104	done
105}
106
107BATCH=false
108CRASHDIR=/var/crash
109DUMPNR=
110KERNEL=
111
112while getopts "bd:n:k:" opt; do
113	case "$opt" in
114	b)
115		BATCH=true
116		;;
117	d)
118		CRASHDIR=$OPTARG
119		;;
120	n)
121		DUMPNR=$OPTARG
122		;;
123	k)
124		KERNEL=$OPTARG
125		;;
126	\?)
127		usage
128		;;
129	esac
130done
131
132shift $((OPTIND - 1))
133
134if [ $# -eq 1 ]; then
135	if [ -n "$DUMPNR" ]; then
136		echo "-n and an explicit vmcore are mutually exclusive"
137		usage
138	fi
139
140	# Figure out the crash directory and number from the vmcore name.
141	CRASHDIR=`dirname $1`
142	DUMPNR=$(expr $(basename $1) : 'vmcore\.\([0-9]*\)')
143	if [ -z "$DUMPNR" ]; then
144		echo "Unable to determine dump number from vmcore file $1."
145		exit 1
146	fi
147elif [ $# -gt 1 ]; then
148	usage
149else
150	# If we don't have an explicit dump number, operate on the most
151	# recent dump.
152	if [ -z "$DUMPNR" ]; then
153		if ! [ -r $CRASHDIR/bounds ]; then
154			echo "No crash dumps in $CRASHDIR."
155			exit 1
156		fi
157		next=`cat $CRASHDIR/bounds`
158		if [ -z "$next" ] || [ "$next" -eq 0 ]; then
159			echo "No crash dumps in $CRASHDIR."
160			exit 1
161		fi
162		DUMPNR=$(($next - 1))
163	fi
164fi
165
166VMCORE=$CRASHDIR/vmcore.$DUMPNR
167INFO=$CRASHDIR/info.$DUMPNR
168FILE=$CRASHDIR/core.txt.$DUMPNR
169HOSTNAME=`hostname`
170
171if $BATCH; then
172	echo "Writing crash summary to $FILE."
173	exec > $FILE 2>&1
174fi
175
176find_gdb
177if [ -z "$GDB" ]; then
178	echo "Unable to find a kernel debugger."
179	echo "Please install the devel/gdb port or gdb package."
180	exit 1
181fi
182
183if [ ! -e $VMCORE ]; then
184    	if [ -e $VMCORE.gz ]; then
185		trap cleanup EXIT HUP INT QUIT TERM
186		gzcat $VMCORE.gz > $VMCORE
187	elif [ -e $VMCORE.zst ]; then
188		trap cleanup EXIT HUP INT QUIT TERM
189		zstdcat $VMCORE.zst > $VMCORE
190	else
191		echo "$VMCORE not found"
192		exit 1
193	fi
194fi
195
196if [ ! -e $INFO ]; then
197	echo "$INFO not found"
198	exit 1
199fi
200
201# If the user didn't specify a kernel, then try to find one.
202if [ -z "$KERNEL" ]; then
203	find_kernel
204	if [ -z "$KERNEL" ]; then
205		echo "Unable to find matching kernel for $VMCORE"
206		exit 1
207	fi
208elif [ ! -e $KERNEL ]; then
209	echo "$KERNEL not found"
210	exit 1
211fi
212
213umask 077
214
215# Simulate uname
216ostype=$(gdb_command $KERNEL 'printf "%s", ostype')
217osrelease=$(gdb_command $KERNEL 'printf "%s", osrelease')
218version=$(gdb_command $KERNEL 'printf "%s", version' | tr '\t\n' '  ')
219machine=$(gdb_command $KERNEL 'printf "%s", machine')
220
221if ! $BATCH; then
222	echo "Writing crash summary to $FILE."
223	exec > $FILE 2>&1
224fi
225
226echo "$HOSTNAME dumped core - see $VMCORE"
227echo
228date
229echo
230echo "$ostype $HOSTNAME $osrelease $version $machine"
231echo
232sed -ne '/^  Panic String: /{s//panic: /;p;}' $INFO
233echo
234
235# XXX: /bin/sh on 7.0+ is broken so we can't simply pipe the commands to
236# kgdb via stdin and have to use a temporary file instead.
237file=`mktemp /tmp/crashinfo.XXXXXX`
238if [ $? -eq 0 ]; then
239	echo "bt" >> $file
240	echo "quit" >> $file
241	${GDB%gdb}kgdb $KERNEL $VMCORE < $file
242	rm -f $file
243	echo
244fi
245echo
246
247echo "------------------------------------------------------------------------"
248echo "ps -axlww"
249echo
250ps -M $VMCORE -N $KERNEL -axlww
251echo
252
253echo "------------------------------------------------------------------------"
254echo "vmstat -s"
255echo
256vmstat -M $VMCORE -N $KERNEL -s
257echo
258
259echo "------------------------------------------------------------------------"
260echo "vmstat -m"
261echo
262vmstat -M $VMCORE -N $KERNEL -m
263echo
264
265echo "------------------------------------------------------------------------"
266echo "vmstat -z"
267echo
268vmstat -M $VMCORE -N $KERNEL -z
269echo
270
271echo "------------------------------------------------------------------------"
272echo "vmstat -i"
273echo
274vmstat -M $VMCORE -N $KERNEL -i
275echo
276
277echo "------------------------------------------------------------------------"
278echo "pstat -T"
279echo
280pstat -M $VMCORE -N $KERNEL -T
281echo
282
283echo "------------------------------------------------------------------------"
284echo "pstat -s"
285echo
286pstat -M $VMCORE -N $KERNEL -s
287echo
288
289echo "------------------------------------------------------------------------"
290echo "iostat"
291echo
292iostat -M $VMCORE -N $KERNEL
293echo
294
295echo "------------------------------------------------------------------------"
296echo "ipcs -a"
297echo
298ipcs -C $VMCORE -N $KERNEL -a
299echo
300
301echo "------------------------------------------------------------------------"
302echo "ipcs -T"
303echo
304ipcs -C $VMCORE -N $KERNEL -T
305echo
306
307# XXX: This doesn't actually work in 5.x+
308if false; then
309echo "------------------------------------------------------------------------"
310echo "w -dn"
311echo
312w -M $VMCORE -N $KERNEL -dn
313echo
314fi
315
316echo "------------------------------------------------------------------------"
317echo "netstat -s"
318echo
319netstat -M $VMCORE -N $KERNEL -s
320echo
321
322echo "------------------------------------------------------------------------"
323echo "netstat -m"
324echo
325netstat -M $VMCORE -N $KERNEL -m
326echo
327
328echo "------------------------------------------------------------------------"
329echo "netstat -anA"
330echo
331netstat -M $VMCORE -N $KERNEL -anA
332echo
333
334echo "------------------------------------------------------------------------"
335echo "netstat -aL"
336echo
337netstat -M $VMCORE -N $KERNEL -aL
338echo
339
340echo "------------------------------------------------------------------------"
341echo "fstat"
342echo
343fstat -M $VMCORE -N $KERNEL
344echo
345
346echo "------------------------------------------------------------------------"
347echo "dmesg"
348echo
349dmesg -a -M $VMCORE -N $KERNEL
350echo
351
352echo "------------------------------------------------------------------------"
353echo "kernel config"
354echo
355config -x $KERNEL
356
357echo
358echo "------------------------------------------------------------------------"
359echo "ddb capture buffer"
360echo
361
362ddb capture -M $VMCORE -N $KERNEL print
363