Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:11:33

0001 #!/bin/sh
0002 
0003 # This script is a copy of $ROOTSYS/etc/gdb-backtrace in svn trunk,
0004 # which is by TUnixSystem::StackTrace() on Linux and MacOS X.
0005 
0006 # Script here is used by cmsShow.cc to print stack trace on 
0007 # SIGILL, SIGILL, SIGBUS, and SIGFPE signal actions.
0008 
0009 tempname=`basename $0 .sh`
0010 messfile=""
0011 
0012 OUTFILE=`mktemp -q /tmp/${tempname}.XXXXXX`
0013 if test $? -ne 0; then
0014    OUTFILE=/dev/stdout
0015 fi
0016 
0017 if [ `uname -s` = "Darwin" ]; then
0018 
0019    if test $# -lt 2; then
0020       echo "Usage: ${tempname} <executable> <process-id> [gdb-mess-file]" 1>&2
0021       exit 1
0022    fi
0023    if test $# -eq 3; then
0024       messfile=$3
0025    fi
0026 
0027    if test ! -x $1; then
0028       echo "${tempname}: process $1 not found." 1>&2
0029       exit 1
0030    fi
0031 
0032    TMPFILE=`mktemp -q /tmp/${tempname}.XXXXXX`
0033    if test $? -ne 0; then
0034       echo "${tempname}: can't create temp file, exiting..." 1>&2
0035       exit 1
0036    fi
0037 
0038    backtrace="thread apply all bt"
0039 
0040    echo $backtrace > $TMPFILE
0041 
0042    GDB=${GDB:-gdb}
0043 
0044    # Run GDB, strip out unwanted noise.
0045    $GDB -q -batch -n -x $TMPFILE $1 $2 2>&1 |
0046    /usr/bin/sed -n \
0047     -e 's/^(gdb) //' \
0048     -e '/^#/p' \
0049     -e 's/\(^Thread.*\)/@\1/p' | tr "@" "\n" > $OUTFILE
0050 
0051    rm -f $TMPFILE
0052 
0053 else
0054 
0055    if test $# -lt 1; then
0056       echo "Usage: ${tempname} <process-id> [gdb-mess-file]" 1>&2
0057       exit 1
0058    fi
0059    if test $# -eq 2; then
0060       messfile=$2
0061    fi
0062 
0063    if test ! -r /proc/$1; then
0064       echo "${tempname}: process $1 not found." 1>&2
0065       exit 1
0066    fi
0067 
0068    # GDB doesn't allow "thread apply all bt" when the process isn't
0069    # threaded; need to peek at the process to determine if that or the
0070    # simpler "bt" should be used.
0071    # The leading spaces are needed for have_eval_command's replacement.
0072 
0073    backtrace="bt"
0074    if test -d /proc/$1/task ; then
0075       # Newer kernel; has a task/ directory.
0076       if test `ls /proc/$1/task | wc -l` -gt 1 2>/dev/null ; then
0077          backtrace="thread apply all bt"
0078       fi
0079    elif test -f /proc/$1/maps ; then
0080       # Older kernel; go by it loading libpthread.
0081       if grep -e libpthread /proc/$1/maps > /dev/null 2>&1 ; then
0082          backtrace="thread apply all bt"
0083       fi
0084    fi
0085 
0086    GDB=${GDB:-gdb}
0087 
0088    # Run GDB, strip out unwanted noise.
0089    have_eval_command=`gdb --help 2>&1 |grep eval-command`
0090    if ! test "x$have_eval_command" = "x"; then
0091       $GDB --batch --eval-command="$backtrace" /proc/$1/exe $1 2>&1 |
0092       /bin/sed -n \
0093          -e 's/^(gdb) //' \
0094          -e '/^#/p' \
0095          -e '/^   /p' \
0096          -e 's/\(^Thread.*\)/@\1/p' | tr '@' '\n' > $OUTFILE
0097    else
0098       $GDB -q -n /proc/$1/exe $1 <<EOF 2>&1 |
0099    $backtrace
0100 EOF
0101       /bin/sed -n \
0102          -e 's/^(gdb) //' \
0103          -e '/^#/p' \
0104          -e '/^   /p' \
0105          -e 's/\(^Thread.*\)/@\1/p' | tr '@' '\n' > $OUTFILE
0106    fi
0107 fi
0108 
0109 # Analyze the stack.
0110 # The recommendations are based on the following assumptions:
0111 #   * More often than not, the crash is caused by user code.
0112 #   * The crash can be caused by the user's interpreted code,
0113 #     in which case sighandler() is called from CINT (G__...)
0114 #   * The crash can be called by the user's library code,
0115 #     in which case sighandler() is called from non-CINT and
0116 #     it's worth dumping the stack frames.
0117 #   * The user doesn't call CINT directly, so whenever we reach
0118 #     a stack frame with "G__" we can stop.
0119 #   * The crash is caused by only one thread, the one which
0120 #     invokes sighandler()
0121 
0122 if ! test "x$OUTFILE" = "x/dev/stdout"; then
0123    frames=""
0124    wantthread=""
0125    skip=""
0126    ininterp=""
0127    signal=""
0128    while IFS= read line; do
0129       case $line in
0130          *'<signal handler called>'* )
0131             # this frame doesn't exist
0132             skip="yes"
0133             frames=""
0134             continue
0135             ;;
0136          Thread* )
0137             if test "x$wantthread" = "xyes"; then
0138                break
0139             fi
0140             skip=""
0141             frames=""
0142             ;;
0143          '#'* )
0144             skip=""
0145             ;;
0146       esac
0147       if test "x${skip}" = "x"; then
0148          tag=`echo $line|sed 's,^.*[0-9a-fA-F] in ,,'`
0149          if test "x$ininterp" = "xcheck next"; then
0150             ininterp="check this"
0151          fi
0152          case $tag in
0153             SigHandler* )
0154                signal=`echo $line | sed 's/^.*\(kSig[^)]*\).*$/\1/'`
0155                wantthread="yes"
0156                ininterp="check next"
0157                frames=""
0158                skip="yes"
0159                ;;
0160             sighandler* | TUnixSystem::DispatchSignals* )
0161                wantthread="yes"
0162                ininterp="check next"
0163                frames=""
0164                skip="yes"
0165                ;;
0166             G__* | Cint::G__* )
0167                if test "x$ininterp" = "xcheck this"; then
0168                   ininterp="yes"
0169                   break
0170                elif test "x$ininterp" = "xno"; then
0171                   break
0172                fi
0173                skip="yes"
0174                ;;
0175             *::ProcessLine* | TRint::HandleTermInput* )
0176                # frames to ignore (upper end)
0177                if test "x$ininterp" = "xcheck this"; then
0178                   ininterp="no"
0179                   break
0180                fi
0181                if test "x$wantthread" = "xyes"; then
0182                   break;
0183                fi
0184                skip="yes"
0185                ;;
0186             * )
0187                if test "x${skip}" = "x"; then
0188                   if test "x$frames" = "x"; then
0189                      frames="$line"
0190                   else
0191                      frames="$frames
0192 $line"
0193                   fi
0194                fi
0195                if test "x$ininterp" = "xcheck this"; then
0196                   ininterp="no"
0197                fi
0198                ;;
0199          esac
0200       fi
0201    done < $OUTFILE
0202 
0203    # Only print the informative text if we actually have a crash
0204    # but not when TSystem::Stacktrace() was called.
0205    if ! test "x$ininterp" = "x"; then
0206       if ! test "x$signal" = "x"; then
0207           signal=' ('${signal}')'
0208       fi
0209       echo ""
0210       echo ""
0211       echo ""
0212       echo "==========================================================="
0213       echo "There was a crash${signal}."
0214       echo "This is the entire stack trace of all threads:"
0215       echo "==========================================================="
0216    fi
0217    cat $OUTFILE
0218    if ! test "x$ininterp" = "x"; then
0219       echo "==========================================================="
0220       if test "x$ininterp" = "xyes"; then
0221          echo ""
0222          echo ""
0223          if test -f "$messfile"; then
0224             cat $messfile | tr '%' '\n'
0225          else
0226             echo 'The crash is most likely caused by a problem in your script.'
0227             echo 'Try to compile it (.L myscript.C+g) and fix any errors.'
0228             echo 'If that does not help then please submit a bug report at'
0229             echo 'http://root.cern.ch/bugs. Please post the ENTIRE stack trace'
0230             echo 'from above as an attachment in addition to anything else'
0231             echo 'that might help us fixing this issue.'
0232          fi
0233       elif ! test "x$frames" = "x"; then
0234          echo ""
0235          echo ""
0236          if test -f "$messfile"; then
0237             cat $messfile | tr '%' '\n'
0238          else
0239             echo 'The lines below might hint at the cause of the crash.'
0240             echo 'If they do not help you then please submit a bug report at'
0241             echo 'http://root.cern.ch/bugs. Please post the ENTIRE stack trace'
0242             echo 'from above as an attachment in addition to anything else'
0243             echo 'that might help us fixing this issue.'
0244          fi
0245          echo "==========================================================="
0246          echo "$frames"
0247          echo "==========================================================="
0248       fi
0249       echo ""
0250       echo ""
0251    fi
0252 
0253    rm -f $OUTFILE $messfile
0254 fi