#!/bin/ksh
#
# License:      Please refer to the license file (license.txt) for license and support information
#
# Purpose:      Dump core information by dbx
#
# Author: Tao Chen (chenttao@cn.ibm.com)
# Last update: 2011/07/21

print_usage()
{
        print "\nUsage:"
        print "\tFor core   : ${0##/*/} [-d depth] [ -p oldpath=newpath:...| pathfile ] ObjectFile CoreFile\n"
}

clean_up()
{
        print -u2 "\nScript is stopped. Partial output is saved $OFILE.\n"
        exit
}

while getopts :p:d:th flag ; do
        case $flag in
                p)      LIBP=$OPTARG;;
                d)      DEPTH=$OPTARG;;
                t)      TFLAG=1;;
                h)      print_usage
                        return 0;;
                \?)     print -u2 "\nInvalid parameter"
                        print_usage
                        return 1;;
        esac
done
shift $(($OPTIND -1))

if [[ ! -f /usr/bin/dbx ]]
then
        print -u2 "/usr/bin/dbx doesn't exist. Please install bos.adt.debug."
        return 1
fi

if [[ $# -ne 2 ]]
then
        print_usage
        return 1
fi

if [[ ! -f $1 ]]
then
        print -u2 "ObjectFile $1 not found"
        return 1
fi
objfile=$1

if [[ ! -f $2 ]]
then
        print -u2 "CoreFile ($2) not found"
        return 1
fi
corefile=$2

OFILE="dbx.${objfile##*/}.${corefile##*/}.out"
DBXCMD="/usr/bin/dbx "

if [[ -n $LIBP ]]
then
        osl=$(oslevel | cut -c1-3)
#       if [[ $osl != "5.2" ]]
#       then
#               print -u2 "'-p' is only supported in AIX version 5.2"
#               return 1
#       fi
        DBXCMD="/usr/bin/dbx -p $LIBP"
fi

if [[ -n $DEPTH ]]; then
        DBXCMD="$DBXCMD -d $DEPTH"
fi

DBXCMD="$DBXCMD $objfile $corefile"

> $OFILE

echo "DBX Files:"       >> $OFILE

/bin/ls -l $objfile     >> $OFILE
/bin/ls -l $corefile    >> $OFILE
lslpp -l bos.adt.debug 2>/dev/null | /usr/bin/awk '/bos/ {printf("\nbos.adt.debug: %s\n", $2)}' >> $OFILE

echo "\n`whoami`@$HOSTNAME:`pwd` $ $DBXCMD\n" >> $OFILE

BRK='p "."'
SECT=">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"

trap clean_up TERM INT

## Get the current thread's output first
echo "Running dbx ..."
echo "\n p '(dbx) where' \n where \
      \n p '(dbx) set \$_dbx' \n set \$_dbx \
      \n p '(dbx) where' \n where \
      \n p '(dbx) x' \n x     \
      \n p '(dbx) (\$stkp)/200' \n (\$stkp)/200 \
      \n p '(dbx) map' \n map   \
      \n p '(dbx) p __n_pthreads' \n p __n_pthreads \
      \n p '(dbx) p __multi_threaded' \n p __multi_threaded \
      \n p '(dbx) mutex' \n mutex \
      \n p '(dbx) condition' \n condition \
      \n p '(dbx) rwlock' \n rwlock \
      \n p '(dbx) dump' \n dump \
      \n p '(dbx) th' \n th \
      \n p '(dbx) malloc' \n malloc \
      \n p '(dbx) malloc allocation' \n malloc allocation \
      \n p '(dbx) malloc freespace' \n malloc freespace \
      \n p '(dbx) q' \n q" | $DBXCMD >> $OFILE 2>&1

/usr/bin/grep "k-tid" $OFILE > /dev/null 2>&1 ## single- or multi-threaded
if [[ $? -eq 0 ]]
then

        ### build a command list

        COMMS="$BRK\n"
        COMMS=$COMMS"p '$SECT thread info'\n$BRK\n thread info\n$BRK\n"

        #### Since thread number is not necessarily continuous,
        #### we have to get the exact thread number.

#       for TPT in `awk '/^.\$t[0-9]/ {print $1}' $OFILE`
        sed -n -e '/(dbx) th/,$p' $OFILE | awk '/^.\$t[0-9]/ {print $1}' | while read TPT
        do
                PT=${TPT#*t}

                echo "Dumping thread $PT ..."
                COMMS=$COMMS"p '$SECT thread current $PT' \n$BRK\n thread current $PT\n"
                COMMS=$COMMS"p '$SECT x $PT' \n$BRK\n x \n$BRK\n"
                COMMS=$COMMS"p '$SECT where $PT' \n$BRK\n where \n$BRK\n"
                COMMS=$COMMS"p '$SECT (\$stkp)/100 $PT' \n$BRK\n (\$stkp)/100 \n$BRK\n"
        done
        COMMS=$COMMS"q"
        echo $COMMS > dbx.CommandFile

        echo "$COMMS" | $DBXCMD 2>/dev/null >> $OFILE
fi

echo x | $DBXCMD | tail -1 | tr '()+' '   ' | awk '{print $1, $2, $3}' | read iar func ioff
echo "\n + Instructions of the failing routine\n" >> $OFILE
echo "\n p '(dbx) listi $iar-$ioff, $iar' \n listi $iar-$ioff, $iar \n p '(dbx) q' \n q" | $DBXCMD 2>&1 | sed -n '/(dbx)/,$p' >> $OFILE 2>&1
print "\nDone. Output file: $OFILE\n"
echo "\n + List of object files: \n" >> $OFILE

for obj in `/usr/bin/awk '/Object name: / { print $NF }' $OFILE | /usr/bin/sort | /usr/bin/uniq`
do
        ## the main program may not locate in the current directly
        ## so ls -l may return error > /dev/null
        realobj=$obj
        /bin/ls -l $realobj >> $OFILE 2>/dev/null
        /bin/ls -l $realobj 2>/dev/null | /usr/bin/grep ^l >/dev/null 2>&1
        while [[ $? -eq 0 ]]
        do
                realobj=`/bin/ls -l $realobj 2>/dev/null | awk '{print $NF}'`
                /bin/ls -l $realobj >> $OFILE  2>/dev/null
                /bin/ls -l $realobj 2>/dev/null | /usr/bin/grep ^lrwx >/dev/null 2>&1
        done
done

# 2009-09-29:
# 2010-05-21: add 'malloc allocation' for " MALLOCDEBUG=log:extended,stack_depth:6 " debug option
# 2011-07-15: add "set $_dbx" with another where command.
# 2012-01-15: add malloc commands (see help malloc)
