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