#! /bin/sh 
# This script supersedes all previous versions of "crpt" and
# "kreport" that have been emailed out.
#
# Some minor mods by Dave Olson 12/93 (for IRIX 405x systems).
# mainly to add the time of the crash to the output, and to
# be less 'noisy'.
#
# Mods made by Pete Sullivan 12/93 
#  -Made this versions work with both 4.* and 5.* core files.
#  -crpt will now uncompress core files as needed.
#  -cleaned up the arguments and allowed vmcore.N.comp files
#   to be passed in as args.
#  -workaround for dbx bug #196361 (1-14-94)
#    
#
# Frequently asked questions (FAQ's):
#
# Can I redistribute this script ?
#
# Well, it helps SGI get more detailed reports about crashing systems
# quickly, so the more it's used the better.  Unrestricted distribution.
#
# How do I interpret the results ? 
#
# If you have a support contract or are still under warranty,
# please contact your local support provider.  In North America
# contact the Technical Assistance Center at 1-800-800-4SGI.
# If you are outside North America, contact the Silicon Graphics 
# subsidiary or authorized distributor in your country.
#
# What do I do with the files in /usr/adm/crash (/var/adm/crash) ?
#
# Don't delete the core files after you've generated the crash report.
# Wait until your support provider tells you that this is a "known
# problem".  If the crash requires further investigation, a kernel expert
# will need to examine the core files more closely.  Even if you
# desperately need the disk space, it's always wise to at least back the
# core files up to tape before deleting them.
#
#
#     CRPT(1)                UNIX System V                CPRT(1)
#
#     NAME
#          crpt - Kernel core file report generator
#
#     SYNOPSIS
#          crpt [-n] [N]
#          crpt [-n] [unix.N] [vmcore.N]
#          crpt [-n] [unix.N] [vmcore.N.comp]
#
#     DESCRIPTION
#          crpt generates a report from kernel core files that can aid
#          your support provider in determining the cause of a system
#          crash.  The report is saved in current directory as
#          "Crash_N.rpt" (Where "N" is the number of the dump file as
#          specified by /usr/adm/crash/bounds).
#
#          When a system crashes, it saves the contents of physical
#          memory and a copy of the kernel that was running.  savecore
#          places these files in /usr/adm/crash.  If your system has
#          crashed and you do not have unix.N and vmcore.N in
#          /usr/adm/crash, make sure your primary swap space on your
#          system disk is at least as large as your physical memory and
#          that you have at least that much free space in your /usr
#          partition (see savecore(1M)).  Save unix.N and vmcore.N to
#          tape in case indepth debugging is required.  Usually only a
#          kernel expert with access to the SGI source code can
#          accurately debug these core files.  crpt drives the dbx
#          debugger through the basic steps a kernel expert would start
#          with when debugging a system crash.  The dbx(1) debugger
#          must be installed for crpt to run.  The report can be
#          included in a call logged through electronic services or
#          emailed or faxed to your local support provider.
#
#          crpt provides the following information:
#
#              1) Report System Info:
#
#                 -The full path of the given core files
#                 -Output of the utsname data structure to provide
#                 system information:
#
#                 If the script is run on the crashing system, it
#                 will provide additional hardware and software
#                 information.  The output from "hinv" and
#                 "versions -b" will be incorporated into the
#                 script.
#
#              2) Formatted output from the kernel's error buffer.
#                 This buffer contains errors messages that are
#                 flushed to the system's error log
#                 (/usr/adm/SYSLOG), but this buffer is often not
#                 flushed when the system crashes.
#
#              3) Print the name of the program that was running
#                 at the time of the crash and the process id of
#                 that program.
#
#              4) Print a kernel stack trace on the current
#                 process id with the "print_exception_frame"
#                 variable set.  This will help trace the
#                 functions called which lead up to the crash.
#                 If there was an exception, the contents of the
#                 exception frame (exception context) will be
#                 printed out above the function which trapped
#                 into the kernel.
#
#              5) Disassemble the code surrounding the exception
#                 program counter.  This will output the name of
#                 the routine the system crashed in and the line
#                 number in the source code.
#
#              6) Output for 'netstat -m' can be viewed by the -n
#          	 option.
#
#              7) Output for 'netstat -n' can be viewed by the -n
#          	 option.
#
#     OPTIONS
#          Command line options are described below.
#
#          -n   The -n option turns on netstat -m and -s reports (see
#               netstat(1)).
#
#     SEE ALSO
#          savecore(1M), dbx(1), netstat(1)
#
#


#!/bin/sh 
#
# "crpt: usage: crpt -n [unix.N] [vmcore.N] or N"
#
#############################################################################
#									    #
#			VARIABLES					    #
#									    #
#############################################################################

NETSTAT=n
OSVER=`uname -r | /usr/bin/cut -d"." -f1`

if [ $OSVER = "4" ]
then

    USERSTRUCT="0xffffc000"
    PUTBUF="&putbuf/1000s"

elif [ $OSVER = "5" ]
then

    USERSTRUCT="0xffffd000"
    PUTBUF="putbuf/200s"
    
else
    echo "Unsupported IRIX Operating System"
    exit -1
fi


#############################################################################
#									    #
#			DEFINE FUNCTIONS				    #
#									    #
#############################################################################

usage() 
{    
    echo "usage:"
    echo "crpt -n [N]"
    echo "crpt -n [unix.N] [vmcore.N]"
    echo "crpt -n [unix.N] [vmcore.N.comp]"
    exit -1
}

cleanup()
{
    if test -r /tmp/dbxktmp*;
	    then /bin/rm -f /tmp/dbxktmp*
    fi
}

isreadable()
{
    if [ ! -r $UNIX ]
	then 
	    echo "$UNIX does not exist or no read permission"
	    exit
    fi
    
    if [ ! -r $VMCORE ]
	then 
	    echo "$VMCORE does not exist or no read permission"
	    exit
    fi
}

notename()
{
    if [ -w `pwd` ]
    then
	NOTES=Crash_${X}.rpt
    else
	NOTES=/tmp/Crash_${X}.rpt
    fi
}

dbxcheck()
{ 
    if [  -x /usr/adm/crash/dbx ]
	then 
	DBXPATH="/usr/adm/crash"
    
    elif [  -x /usr/bin/dbx ]
	then 
	DBXPATH="/usr/bin"
    else
	echo "crpt requires dbx(1) for successful"
	echo "operation - see man on crpt(1)"  
	exit -1 
    fi   
}

netstats()
{
    if [ ! -x /usr/etc/netstat ]
    then 
	    echo "-n option requires netstat(1) for successful"
	    echo "operation - see man on crpt"  
	    exit  
    fi
    
    if [ $NETSTAT = "y" ] 
    then /usr/etc/netstat -s $UNIX $VMCORE > /tmp/dbxktmp.netstats
	 /usr/etc/netstat -m $UNIX $VMCORE > /tmp/dbxktmp.netstatm
    fi        
}

uncompress1()
{
    if [ -r ${DUMPDIR}/vmcore.${X}.comp -a ! -r ${DUMPDIR}/vmcore.${X} ]
    then
	/etc/uncompvm ${DUMPDIR}/vmcore.${X}.comp
    fi        
}

uncompress2()
{
    if [ $VMCORE = "vmcore.${X}.comp" ]
    then
	VMCORE="vmcore.${X}"
	if [ ! -r vmcore.${X} ]
	then
	    echo "Uncompressing"
	    /etc/uncompvm vmcore.${X}.comp
	fi
    elif [ $VMCORE = "${DUMPDIR}/vmcore.${X}.comp" ]
    then
	VMCORE="vmcore.${X}"
	if [ ! -r ${DUMPDIR}/vmcore.${X} ]
	then
	    echo "Uncompressing"
	    /etc/uncompvm ${DUMPDIR}/vmcore.${X}.comp
	fi
    fi    
}


#############################################################################
#									    #
#			CHECK INPUT ARG'S & FOR DBX			    #
#									    #
#############################################################################



trap 'cleanup; exit 1' 2 3 15

if [ $# = 1 -a $1 != "=n" ]
then

    X=$1
    DUMPDIR=`pwd`
    UNIX=${DUMPDIR}/unix.${X}
    uncompress1
    VMCORE=${DUMPDIR}/vmcore.${X}		

	
elif [ $# = 2 ]
then	

    if [ $1 = "-n" ] 
    then 

	NETSTAT="y"
	X=$2
	DUMPDIR=`pwd`
	UNIX=${DUMPDIR}/unix.${X}
	uncompress1
	VMCORE=${DUMPDIR}/vmcore.${X}

    else 

	UNIX=$1
	VMCORE=$2
	X=`basename $VMCORE | sed 's/^......\.\([0-9]*\).*/\1/'`
	DUMPDIR=`dirname $UNIX`
	uncompress2
	
    fi	

elif [ $# = 3 -a $1 = "-n" ]
then 

	NETSTAT="y"
	UNIX=$2
	VMCORE=$3	
	X=`basename $VMCORE | sed 's/^......\.\([0-9]*\).*/\1/'`
	DUMPDIR=`dirname $UNIX`
	uncompress2
	
else 
	usage
fi

    isreadable
    dbxcheck
    notename
    cleanup
    netstats

# Next 90 lines create a ksh script that converts kernel 'time' variable
# (seconds since 1 Jan 1970 Midnight GMT) into a date; telling us
# when we crashed.  Based on code written by Tom Murphy.  Olson
cat > /tmp/dbxktmp.hrs << \EOF
#! /bin/ksh
HourDate() {
	typeset -i i dow day year hour min leapday=0
	hours=minutes/60
	min=minutes%60
	day=hours/24
	hour=hours-24*day
	dow=day%7
	case $dow in
	0) weekday="Fri" ;;
	1) weekday="Sat" ;;
	2) weekday="Sun" ;;
	3) weekday="Mon" ;;
	4) weekday="Tue" ;;
	5) weekday="Wed" ;;
	6) weekday="Thu" ;;
	esac
	i=day/1461
	year=1970+4*i
	day=day-1461*i
	#if ((day>1154)); then
	if ((day>1153)); then
		leapday=1
		day=day-1
	fi
	i=day/365
	year=year+i
	day=day-365*i+1
	if ((day<182)); then
		if ((day<91)); then
			if ((day<60)); then
				if ((day<32)); then
					month="Jan"
				else
					month="Feb"
					day=day-31+leapday
				fi
			else
				month="Mar"
				day=day-59
			fi
		elif ((day<152)); then
			if ((day<121)); then
				month="Apr"
				day=day-90
			else
				month="May"
				day=day-120
			fi
		else
			month="Jun"
			day=day-151
		fi
	elif ((day<274)); then
		if ((day<244)); then
			if ((day<213)); then
				month="Jul"
				day=day-181
			else
				month="Aug"
				day=day-212
			fi
		else
			month="Sep"
			day=day-243
		fi
	elif ((day<335)); then
		if ((day<305)); then
			month="Oct"
			day=day-273
		else
			month="Nov"
			day=day-304
		fi
	else
		month="Dec"
		day=day-334
	fi
	if ((min<10)); then
		tim=0$min
	else
		tim=$min
	fi
	if ((hour<10)); then
		tim=0$hour:$tim
	else
		tim=$hour:$tim
	fi
	echo "$weekday $month $day ${tim} GMT $year"
}

# arg is a file whose second line is the time converted to hours
# see point where invoked
minutes=`sed -n '$p' $1 `
HourDate
EOF
chmod 755 /tmp/dbxktmp.hrs
# end of date conversion script

# "Input_to_dbx" magic word starts input to dbx
#----------------------------------------------------------------------------

# no regular output, but show errors
$DBXPATH/dbx  -k $UNIX $VMCORE << Input_to_dbx > /dev/null

/############################################################################
/									    #
/			SET VARIALBES FOR DBX				    #
/									    #
/############################################################################

set \$pager="cat"
set \$prompt=""
set \$pagewindow=1000

/############################################################################
/									    #
/			PRINT THE KERNEL PUTBUF				    #
/									    #
/############################################################################

record output /tmp/dbxktmp.putbuf
    $PUTBUF
unrecord all

/############################################################################
/									    #
/		   PRINT CORE FILE NAME & SYSTEM INFO			    #
/									    #
/############################################################################

record output /tmp/dbxktmp.date
p time div 60
unrecord all

record output /tmp/dbxktmp.utsname
    givenfile ;corefile
    print *(struct utsname *)&utsname
    printf "system crashed at %#x seconds from Jan 1, 1970\nor about: ", time
    sh /tmp/dbxktmp.hrs /tmp/dbxktmp.date >> /tmp/dbxktmp.utsname
unrecord all

/############################################################################
/									    #
/	IF RUNNING ON THE SYSTEM WHICH CRASHED - GET HINV, VERSIONS	    #
/									    #
/############################################################################

sh sh -c 'fgrep nodename /tmp/dbxktmp.utsname| tr -d \" | cut -f7 -d" " \
       > /tmp/dbxktmp.name'

sh sh -c "if test \`uname -n\` = \`cat /tmp/dbxktmp.name\`;then versions -b > \
   /tmp/dbxktmp.versions; hinv > /tmp/dbxktmp.hinv; fi"

/############################################################################
/									    #
/		NAME AND PID OF CURRENTLY RUNNING PROCESS		    #
/									    #
/############################################################################
  
record output /tmp/dbxktmp.psargs
    print ((struct user *) $USERSTRUCT).u_psargs
unrecord all

record output /tmp/dbxktmp.pid
    print \$pid
unrecord all

sh echo "PID:" > /tmp/dbxktmp.pid1
sh cat /tmp/dbxktmp.pid  >> /tmp/dbxktmp.pid1
sh cat /tmp/dbxktmp.pid1 | fgrep -v record | tr -d "\012" >> /tmp/dbxktmp.pid2
sh echo "\n" >> /tmp/dbxktmp.pid2

/############################################################################
/									    #
/	PRINT STACK POINTER, FRAME POINTER AND PROGRAM COUNTER		    #
/		   PRINT A KERNEL STACK TRACE	    			    #
/									    #
/############################################################################

# more or less duplicate the message that dbx prints on startup
# s8 is the frame ptr

record output /tmp/dbxktmp.trace
    printf "SP=%x fp=%x pc=%x\n", \$sp, \$s8, \$pc
    set \$print_exception_frame=1
    t
    set \$print_exception_frame=0
unrecord all


/############################################################################
/									    #
/	    GET THE EXCEPTION FRAME POINTER FROM THE PUTBUF	   	    #
/	         SAVE THE EXCEPTION PROGRAM COUNTER			    #
/									    #
/############################################################################

set \$hexints=1

sh sh -c 'fgrep ep: /tmp/dbxktmp.putbuf | sed -e "s/^.*ep:/ep:/" > \
	  /tmp/dbxktmp.epptr; \
	if grep -s "ep:0x" /tmp/dbxktmp.epptr; \
	then cat /tmp/dbxktmp.epptr | cut -c1-13 | \
	    sed -e "s/ep:/\(\(struct eframe_s \*\)/" | \
	    sed -e "s/$/\)\.ef_epc-0x10\/20i/" > /tmp/dbxktmp.trace0 ;\
	else cat /tmp/dbxktmp.epptr | cut -c1-11 | \
	    sed -e "s/ep:/\(\(struct eframe_s \*\)0x/" | \
	    sed -e "s/$/\)\.ef_epc-0x10\/20i/" > /tmp/dbxktmp.trace0 ;\
       fi'  
	  

/############################################################################
/									    #
/		DISASSEMBLE THE CODE NEAR THE EXCEPTION PC		    #
/									    #
/############################################################################

record output /tmp/dbxktmp.epc_dis
    playback input /tmp/dbxktmp.trace0
unrecord all 

quit
Input_to_dbx

# "Input_to_dbx" magic word ends sending input to dbx
#----------------------------------------------------------------------------


# cleanup and polish.

#############################################################################
#									    #
#		FORMAT A REPORT ON THE KERNEL CORE DUMP			    #
#			SAVE AS "Crash_N.rpt"				    #
#									    #
#############################################################################


if test -s /tmp/dbxktmp.utsname
then
    echo   '____ System Info _______________________________________________________________\n' \
    >  /tmp/dbxktmp.out;fgrep -v "{" /tmp/dbxktmp.utsname |  fgrep -v "}" \
    | fgrep -v \"\" \
    | sed 's/and its processid is 0//' >> /tmp/dbxktmp.out
fi

if test -s /tmp/dbxktmp.hinv 
then
    echo '\n____ Hardware Inventory ________________________________________________________\n' \
    >> /tmp/dbxktmp.out;cat /tmp/dbxktmp.hinv >> /tmp/dbxktmp.out
fi

if test -s /tmp/dbxktmp.versions 
then
    echo '\n____ Versions __________________________________________________________________\n' \
    >> /tmp/dbxktmp.out;cat /tmp/dbxktmp.versions >> /tmp/dbxktmp.out
fi

if test -s /tmp/dbxktmp.putbuf
then
    echo '\n____ Putbuf Dump _______________________________________________________________\n' \
    >> /tmp/dbxktmp.out; fgrep -v \"\" /tmp/dbxktmp.putbuf | sed -e '/^"\.*"$/d' -e 's/\\n/\
/g' | sed 's/\\t/\	/' | tr -d \"| uniq >> /tmp/dbxktmp.out
#^ This is not a formatting error, it's just a cludge to replace literal "\n" with \012
fi

if test -s /tmp/dbxktmp.psargs
then
    echo '\n____ Program Running ___________________________________________________________\n' \
	>> /tmp/dbxktmp.out;cat /tmp/dbxktmp.psargs /tmp/dbxktmp.pid2 >> /tmp/dbxktmp.out
fi

if test -s /tmp/dbxktmp.trace
then
    echo '\n____ Trace & Exception Frame Registers _________________________________________\n' \
    >> /tmp/dbxktmp.out
    cat /tmp/dbxktmp.trace >> /tmp/dbxktmp.out
fi

if test -s /tmp/dbxktmp.epc_dis  
then
EPC=`cat /tmp/dbxktmp.epc_dis | wc -l | tr -d " "`
if [ $EPC -gt  "12" ]     
then
    echo '\n____ Exception PC Disassembled _________________________________________________\n' \
    >> /tmp/dbxktmp.out;cat /tmp/dbxktmp.epc_dis >> /tmp/dbxktmp.out
fi
fi

if test -s /tmp/dbxktmp.netstatm
then
    echo '\n____ Netstat -m ________________________________________________________________\n' \
    >> /tmp/dbxktmp.out
    cat /tmp/dbxktmp.netstatm >> /tmp/dbxktmp.out
fi

if test -s /tmp/dbxktmp.netstats
then
    echo '\n____ Netstat -s ________________________________________________________________\n' \
    >> /tmp/dbxktmp.out
    cat /tmp/dbxktmp.netstats >> /tmp/dbxktmp.out
fi

# Clean up the final report:
if test -r ${NOTES}
    then /bin/mv ${NOTES} ${NOTES}.old
fi

egrep -v 'record|reference data|zero repetition count' /tmp/dbxktmp.out > $NOTES

echo "Generated crash report - $NOTES"

# Remove all tempory files
cleanup
exit 0 # ignore trailing signature stuff
