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# $FreeBSD$
33
34usage()
35{
36	echo "usage: crashinfo [-b] [-d crashdir] [-n dumpnr]" \
37		"[-k kernel] [core]"
38	exit 1
39}
40
41# Remove an uncompressed copy of a dump
42cleanup()
43{
44
45	[ -e $VMCORE ] && rm -f $VMCORE
46}
47
48# Find a gdb binary to use and save the value in GDB.
49find_gdb()
50{
51	local binary
52
53	for binary in /usr/local/bin/gdb /usr/libexec/gdb; do
54		if [ -x ${binary} ]; then
55			GDB=${binary}
56			return
57		fi
58	done
59}
60
61# Run a single gdb command against a kernel file in batch mode.
62# The kernel file is specified as the first argument and the command
63# is given in the remaining arguments.
64gdb_command()
65{
66	local k
67
68	k=$1 ; shift
69
70	if [ ${GDB} = /usr/local/bin/gdb ]; then
71		${GDB} -batch -ex "$@" $k
72	else
73		echo -e "$@" | ${GDB} -x /dev/stdin -batch $k
74	fi
75}
76
77find_kernel()
78{
79	local ivers k kvers
80
81	ivers=$(awk '
82	/Version String/ {
83		print
84		nextline=1
85		next
86	}
87	nextline==1 {
88		if ($0 ~ "^  [A-Za-z ]+: ") {
89			nextline=0
90		} else {
91			print
92		}
93	}' $INFO)
94
95	# Look for a matching kernel version, handling possible truncation
96	# of the version string recovered from the dump.
97	for k in `sysctl -n kern.bootfile` $(ls -t /boot/*/kernel); do
98		kvers=$(gdb_command $k 'printf "  Version String: %s", version' | \
99		    awk "{line=line\$0\"\n\"} END{print substr(line,1,${#ivers})}" \
100		    2>/dev/null)
101		if [ "$ivers" = "$kvers" ]; then
102			KERNEL=$k
103			break
104		fi
105	done
106}
107
108BATCH=false
109CRASHDIR=/var/crash
110DUMPNR=
111KERNEL=
112
113while getopts "bd:n:k:" opt; do
114	case "$opt" in
115	b)
116		BATCH=true
117		;;
118	d)
119		CRASHDIR=$OPTARG
120		;;
121	n)
122		DUMPNR=$OPTARG
123		;;
124	k)
125		KERNEL=$OPTARG
126		;;
127	\?)
128		usage
129		;;
130	esac
131done
132
133shift $((OPTIND - 1))
134
135if [ $# -eq 1 ]; then
136	if [ -n "$DUMPNR" ]; then
137		echo "-n and an explicit vmcore are mutually exclusive"
138		usage
139	fi
140
141	# Figure out the crash directory and number from the vmcore name.
142	CRASHDIR=`dirname $1`
143	DUMPNR=$(expr $(basename $1) : 'vmcore\.\([0-9]*\)')
144	if [ -z "$DUMPNR" ]; then
145		echo "Unable to determine dump number from vmcore file $1."
146		exit 1
147	fi
148elif [ $# -gt 1 ]; then
149	usage
150else
151	# If we don't have an explicit dump number, operate on the most
152	# recent dump.
153	if [ -z "$DUMPNR" ]; then
154		if ! [ -r $CRASHDIR/bounds ]; then
155			echo "No crash dumps in $CRASHDIR."
156			exit 1
157		fi			
158		next=`cat $CRASHDIR/bounds`
159		if [ -z "$next" ] || [ "$next" -eq 0 ]; then
160			echo "No crash dumps in $CRASHDIR."
161			exit 1
162		fi
163		DUMPNR=$(($next - 1))
164	fi
165fi
166
167VMCORE=$CRASHDIR/vmcore.$DUMPNR
168INFO=$CRASHDIR/info.$DUMPNR
169FILE=$CRASHDIR/core.txt.$DUMPNR
170HOSTNAME=`hostname`
171
172if $BATCH; then
173	echo "Writing crash summary to $FILE."
174	exec > $FILE 2>&1
175fi
176
177find_gdb
178if [ -z "$GDB" ]; then
179	echo "Unable to find a kernel debugger."
180	echo "Please install the devel/gdb port or gdb package."
181	exit 1
182fi
183
184if [ ! -e $VMCORE ]; then
185    	if [ -e $VMCORE.gz ]; then
186		trap cleanup EXIT HUP INT QUIT TERM
187		gzcat $VMCORE.gz > $VMCORE
188	elif [ -e $VMCORE.zst ]; then
189		trap cleanup EXIT HUP INT QUIT TERM
190		zstdcat $VMCORE.zst > $VMCORE
191	else
192		echo "$VMCORE not found"
193		exit 1
194	fi
195fi
196
197if [ ! -e $INFO ]; then
198	echo "$INFO not found"
199	exit 1
200fi
201
202# If the user didn't specify a kernel, then try to find one.
203if [ -z "$KERNEL" ]; then
204	find_kernel
205	if [ -z "$KERNEL" ]; then
206		echo "Unable to find matching kernel for $VMCORE"
207		exit 1
208	fi
209elif [ ! -e $KERNEL ]; then
210	echo "$KERNEL not found"
211	exit 1
212fi
213
214umask 077
215
216# Simulate uname
217ostype=$(gdb_command $KERNEL 'printf "%s", ostype')
218osrelease=$(gdb_command $KERNEL 'printf "%s", osrelease')
219version=$(gdb_command $KERNEL 'printf "%s", version' | tr '\t\n' '  ')
220machine=$(gdb_command $KERNEL 'printf "%s", machine')
221
222if ! $BATCH; then
223	echo "Writing crash summary to $FILE."
224	exec > $FILE 2>&1
225fi
226
227echo "$HOSTNAME dumped core - see $VMCORE"
228echo
229date
230echo
231echo "$ostype $HOSTNAME $osrelease $version $machine"
232echo
233sed -ne '/^  Panic String: /{s//panic: /;p;}' $INFO
234echo
235
236# XXX: /bin/sh on 7.0+ is broken so we can't simply pipe the commands to
237# kgdb via stdin and have to use a temporary file instead.
238file=`mktemp /tmp/crashinfo.XXXXXX`
239if [ $? -eq 0 ]; then
240	echo "bt" >> $file
241	echo "quit" >> $file
242	${GDB%gdb}kgdb $KERNEL $VMCORE < $file
243	rm -f $file
244	echo
245fi
246echo
247
248echo "------------------------------------------------------------------------"
249echo "ps -axlww"
250echo
251ps -M $VMCORE -N $KERNEL -axlww
252echo
253
254echo "------------------------------------------------------------------------"
255echo "vmstat -s"
256echo
257vmstat -M $VMCORE -N $KERNEL -s
258echo
259
260echo "------------------------------------------------------------------------"
261echo "vmstat -m"
262echo
263vmstat -M $VMCORE -N $KERNEL -m
264echo
265
266echo "------------------------------------------------------------------------"
267echo "vmstat -z"
268echo
269vmstat -M $VMCORE -N $KERNEL -z
270echo
271
272echo "------------------------------------------------------------------------"
273echo "vmstat -i"
274echo
275vmstat -M $VMCORE -N $KERNEL -i
276echo
277
278echo "------------------------------------------------------------------------"
279echo "pstat -T"
280echo
281pstat -M $VMCORE -N $KERNEL -T
282echo
283
284echo "------------------------------------------------------------------------"
285echo "pstat -s"
286echo
287pstat -M $VMCORE -N $KERNEL -s
288echo
289
290echo "------------------------------------------------------------------------"
291echo "iostat"
292echo
293iostat -M $VMCORE -N $KERNEL
294echo
295
296echo "------------------------------------------------------------------------"
297echo "ipcs -a"
298echo
299ipcs -C $VMCORE -N $KERNEL -a
300echo
301
302echo "------------------------------------------------------------------------"
303echo "ipcs -T"
304echo
305ipcs -C $VMCORE -N $KERNEL -T
306echo
307
308# XXX: This doesn't actually work in 5.x+
309if false; then
310echo "------------------------------------------------------------------------"
311echo "w -dn"
312echo
313w -M $VMCORE -N $KERNEL -dn
314echo
315fi
316
317echo "------------------------------------------------------------------------"
318echo "netstat -s"
319echo
320netstat -M $VMCORE -N $KERNEL -s
321echo
322
323echo "------------------------------------------------------------------------"
324echo "netstat -m"
325echo
326netstat -M $VMCORE -N $KERNEL -m
327echo
328
329echo "------------------------------------------------------------------------"
330echo "netstat -anA"
331echo
332netstat -M $VMCORE -N $KERNEL -anA
333echo
334
335echo "------------------------------------------------------------------------"
336echo "netstat -aL"
337echo
338netstat -M $VMCORE -N $KERNEL -aL
339echo
340
341echo "------------------------------------------------------------------------"
342echo "fstat"
343echo
344fstat -M $VMCORE -N $KERNEL
345echo
346
347echo "------------------------------------------------------------------------"
348echo "dmesg"
349echo
350dmesg -a -M $VMCORE -N $KERNEL
351echo
352
353echo "------------------------------------------------------------------------"
354echo "kernel config"
355echo
356config -x $KERNEL
357
358echo
359echo "------------------------------------------------------------------------"
360echo "ddb capture buffer"
361echo
362
363ddb capture -M $VMCORE -N $KERNEL print
364