123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 |
- #!/usr/bin/env bash
- # Turn on extended globbing
- shopt -s extglob
- # Bail on any error
- set -e
- prog=$(basename $0)
- print_help() {
- cat <<EOF
- NAME
- $prog - Dump and/or format asterisk coredump files
- SYNOPSIS
- $prog [ --help ] [ --running | --RUNNING ] [ --latest ]
- [ --tarball-coredumps ] [ --delete-coredumps-after ]
- [ --tarball-results ] [ --delete-results-after ]
- [ --tarball-config ] [ --tarball-uniqueid="<uniqueid>" ]
- [ --no-default-search ] [ --append-coredumps ]
- [ --asterisk-bin="path" ]
- [ <coredump> | <pattern> ... ]
- DESCRIPTION
- Extracts backtraces and lock tables from Asterisk coredump files.
- For each coredump found, 4 new result files are created:
- - <coredump>.brief.txt: The output of "thread apply all bt".
- - <coredump>.thread1.txt: The output of "thread apply 1 bt full".
- - <coredump>.full.txt: The output of "thread apply all bt full".
- - <coredump>.locks.txt: If asterisk was compiled with
- "DEBUG_THREADS", this file will contain a dump of the locks
- table similar to doing a "core show locks" from the asterisk
- CLI.
- Optional features:
- - The running asterisk process can be suspended and dumped.
- - The coredumps can be merged into a tarball.
- - The coredumps can be deleted after processing.
- - The results files can be merged into a tarball.
- - The results files can be deleted after processing.
- Options:
- --help
- Print this help.
- --running
- Create a coredump from the running asterisk instance and
- process it along with any other coredumps found (if any).
- WARNING: This WILL interrupt call processing. You will be
- asked to confirm. The coredump will be written to /tmp if
- $OUTPUTDIR is not defined.
- --RUNNING
- Same as --running but without the confirmation prompt.
- DANGEROUS!!
- --latest
- Process only the latest coredump from those specified (based
- on last-modified time). If a dump of the running process was
- requested, it is always included in addition to the latest
- from the existing coredumps.
- --tarball-coredumps
- Creates a gzipped tarball of coredumps processed, their
- results txt files and copies of /etc/os-release,
- /usr/sbin/asterisk, /usr/lib(64)/libasterisk* and
- /usr/lib(64)/asterisk as those files are needed to properly
- examine the coredump. The file will be named
- $OUTPUTDIR/asterisk.<timestamp>.coredumps.tar.gz or
- $OUTPUTDIR/asterisk-<uniqueid>.coredumps.tar.gz if
- --tarball-uniqueid was specified.
- WARNING: This file could 1gb in size!
- Mutually exclusive with --tartball-results
- --delete-coredumps-after
- Deletes all processed coredumps regardless of whether
- a tarball was created.
- --tarball-results
- Creates a gzipped tarball of all result files produced.
- The tarball name will be:
- $OUTPUTDIR/asterisk.<timestamp>.results.tar.gz
- Mutually exclusive with --tartball-coredumps
- --delete-results-after
- Deletes all processed results regardless of whether
- a tarball was created. It probably doesn't make sense
- to use this option unless you have also specified
- --tarball-results.
- --tarball-config
- Adds the contents of /etc/asterisk to the tarball created
- with --tarball-coredumps or --tarball-results.
- --tarball-uniqueid="<uniqueid>"
- Normally DATEFORMAT is used to make the tarballs unique
- but you can use your own unique id in the tarball names
- such as the Jira issue id.
- --no-default-search
- Ignore COREDUMPS from the config files and process only
- coredumps listed on the command line (if any) and/or
- the running asterisk instance (if requested).
- --append-coredumps
- Append any coredumps specified on the command line to the
- config file specified ones instead of overriding them.
- --asterisk-binary
- Path to the asterisk binary. Default: look for asterisk
- in the PATH.
- <coredump> | <pattern>
- A list of coredumps or coredump search patterns. Unless
- --append-coredumps was specified, these entries will override
- those specified in the config files.
- Any resulting file that isn't actually a coredump is silently
- ignored. If your patterns contains spaces be sure to only
- quote the portion of the pattern that DOESN'T contain wildcard
- expressions. If you quote the whole pattern, it won't be
- expanded.
- If --no-default-search is specified and no files are specified
- on the command line, then the only the running asterisk process
- will be dumped (if requested). Otherwise if no files are
- specified on the command line the value of COREDUMPS from
- ast_debug_tools.conf will be used. Failing that, the following
- patterns will be used:
- /tmp/core[-._]asterisk!(*.txt)
- /tmp/core[-._]\$(hostname)!(*.txt)
- NOTES
- You must be root to use $prog.
- $OUTPUTDIR can be read from the current environment or from the
- ast_debug_tools.conf file described below. If not specified,
- work products are placed in the same directory as the core file.
- The script relies on not only bash, but also recent GNU date and
- gdb with python support. *BSD operating systems may require
- installation of the 'coreutils' and 'devel/gdb' packagess and minor
- tweaking of the ast_debug_tools.conf file.
- Any files output will have ':' characters changed to '-'. This is
- to facilitate uploading those files to Jira which doesn't like the
- colons.
- FILES
- /etc/asterisk/ast_debug_tools.conf
- ~/ast_debug_tools.conf
- ./ast_debug_tools.conf
- #
- # This file is used by the Asterisk debug tools.
- # Unlike other Asterisk config files, this one is
- # "sourced" by bash and must adhere to bash semantics.
- #
- # A list of coredumps and/or coredump search patterns.
- # Bash extended globs are enabled and any resulting files
- # that aren't actually coredumps are silently ignored
- # so you can be liberal with the globs.
- #
- # If your patterns contains spaces be sure to only quote
- # the portion of the pattern that DOESN'T contain wildcard
- # expressions. If you quote the whole pattern, it won't
- # be expanded and the glob characters will be treated as
- # literals.
- #
- # The exclusion of files ending ".txt" is just for
- # demonstration purposes as non-coredumps will be ignored
- # anyway.
- COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]\$(hostname)!(*.txt))
- # The directory to contain output files and work directories.
- # For output from existing core files, the default is the
- # directory that the core file is found in. For core files
- # produced from a running process, the default is /tmp.
- OUTPUTDIR=/some/directory
- # Date command for the "running" coredump and tarballs.
- # DATEFORMAT will be executed to get the timestamp.
- # Don't put quotes around the format string or they'll be
- # treated as literal characters. Also be aware of colons
- # in the output as you can't upload files with colons in
- # the name to Jira.
- #
- # Unix timestamp
- #DATEFORMAT='date +%s.%N'
- #
- # *BSD/MacOS doesn't support %N but after installing GNU
- # coreutils...
- #DATEFORMAT='gdate +%s.%N'
- #
- # Readable GMT
- #DATEFORMAT='date -u +%FT%H-%M-%S%z'
- #
- # Readable Local time
- DATEFORMAT='date +%FT%H-%M-%S%z'
- EOF
- exit 1
- }
- if [ $EUID -ne 0 ] ; then
- echo "You must be root to use $prog."
- exit 1
- fi
- running=false
- RUNNING=false
- latest=false
- tarball_coredumps=false
- tarball_config=false
- delete_coredumps_after=false
- tarball_results=false
- delete_results_after=false
- append_coredumps=false
- declare -a COREDUMPS
- declare -a ARGS_COREDUMPS
- # readconf reads a bash-sourceable file and sets variables
- # that havn't already been set. This allows variables set
- # on the command line or that are already in the environment
- # to take precedence over those read from the file.
- #
- # Setting the values can't be done in a subshell so you can't
- # just pipe the output of sed into the while.
- readconf() {
- while read line ; do
- v=${line%%=*}
- [ -z "${!v}" ] && eval $line || :
- done <<EOF
- $( sed -r -e "/\s*#/d" -e "/^\s*$/d" $1 )
- EOF
- }
- # Read config files from most important to least important.
- # Variable set on the command line or environment always take precedence.
- [ -f ./ast_debug_tools.conf ] && readconf ./ast_debug_tools.conf
- [ -f ~/ast_debug_tools.conf ] && readconf ~/ast_debug_tools.conf
- [ -f /etc/asterisk/ast_debug_tools.conf ] && readconf /etc/asterisk/ast_debug_tools.conf
- # For *BSD, the preferred gdb may be in /usr/local/bin so we
- # need to search for one that supports python.
- for g in $(which -a gdb) ; do
- result=$($g --batch --ex "python print('hello')" 2>/dev/null || : )
- if [[ "$result" =~ ^hello$ ]] ; then
- GDB=$g
- break
- fi
- done
- if [ -z "$GDB" ] ; then
- echo "No suitable gdb was found in $PATH"
- exit 1
- fi
- if [ -n "$OUTPUTDIR" ] ; then
- if [ ! -d "$OUTPUTDIR" ] ; then
- echo "OUTPUTDIR $OUTPUTDIR doesn't exists or is not a directory"
- exit 1
- fi
- fi
- if [ ${#COREDUMPS[@]} -eq 0 ] ; then
- COREDUMPS+=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt))
- fi
- DATEFORMAT=${DATEFORMAT:-'date +%FT%H-%M-%S%z'}
- # Use "$@" (with the quotes) so spaces in patterns or
- # file names are preserved.
- # Later on when we have to iterate over COREDUMPS, we always
- # use the indexes rather than trying to expand the values of COREDUMPS
- # just in case.
- for a in "$@" ; do
- case "$a" in
- --running)
- running=true
- ;;
- --RUNNING)
- RUNNING=true
- ;;
- --no-default-search)
- # Clean out COREDUMPS from config files
- COREDUMPS=()
- ;;
- --latest)
- latest=true
- ;;
- --tarball-coredumps)
- tarball_coredumps=true
- ;;
- --tarball-config)
- tarball_config=true
- ;;
- --delete-coredumps-after)
- delete_coredumps_after=true
- ;;
- --tarball-results)
- tarball_results=true
- ;;
- --delete-results-after)
- delete_results_after=true
- ;;
- --append-coredumps)
- append_coredumps=true
- ;;
- --tarball-uniqueid=*)
- tarball_uniqueid=${a#*=}
- ;;
- --asterisk-bin=*)
- asterisk_bin=${a#*=}
- ;;
- --help|-*)
- print_help
- ;;
- *)
- ARGS_COREDUMPS+=("$a")
- # If any files are specified on the command line, ignore those
- # specified in the config files unless append-coredumps was specified.
- if ! $append_coredumps ; then
- COREDUMPS=()
- fi
- esac
- done
- # append coredumps/patterns specified as command line arguments to COREDUMPS.
- for i in ${!ARGS_COREDUMPS[@]} ; do
- COREDUMPS+=("${ARGS_COREDUMPS[$i]}")
- done
- # At this point, all glob entries that match files should be expanded.
- # Any entries that don't exist are probably globs that didn't match anything
- # and need to be pruned. Any non coredumps are also pruned.
- for i in ${!COREDUMPS[@]} ; do
- if [ ! -f "${COREDUMPS[$i]}" ] ; then
- unset COREDUMPS[$i]
- continue
- fi
- # Some versions of 'file' don't allow only the first n bytes of the
- # file to be processed so we use dd to grab just the first 32 bytes.
- mimetype=$(dd if="${COREDUMPS[$i]}" bs=32 count=1 2>/dev/null | file -bi -)
- if [[ ! "$mimetype" =~ coredump ]] ; then
- unset COREDUMPS[$i]
- continue
- fi
- done
- # Sort and weed out any dups
- IFS=$'\x0a'
- readarray -t COREDUMPS < <(echo -n "${COREDUMPS[*]}" | sort -u )
- unset IFS
- # If --latest, get the last modified timestamp of each file,
- # sort them, then return the latest.
- if [ ${#COREDUMPS[@]} -gt 0 ] && $latest ; then
- lf=$(find "${COREDUMPS[@]}" -printf '%T@ %p\n' | sort -n | tail -1)
- COREDUMPS=("${lf#* }")
- fi
- # Timestamp to use for output files
- df=${tarball_uniqueid:-$(${DATEFORMAT})}
- if [ x"$asterisk_bin" = x ]; then
- asterisk_bin=$(which asterisk)
- fi
- if $running || $RUNNING ; then
- # We need to go through some gyrations to find the pid of the running
- # MAIN asterisk process and not someone or something running asterisk -r.
- unset pid
- # Simplest case first...
- pids=$(pgrep -f "$asterisk_bin")
- pidcount=$(echo $pids | wc -w)
- if [ $pidcount -eq 0 ] ; then
- >&2 echo "Asterisk is not running"
- exit 1
- fi
- # Single process, great.
- if [ $pidcount -eq 1 ] ; then
- pid=$pids
- echo "Found a single asterisk instance running as process $pid"
- fi
- # More than 1 asterisk process running
- if [ x"$pid" = x ] ; then
- # More than 1 process running, let's try asking asterisk for it's
- # pidfile
- pidfile=$("$asterisk_bin" -rx "core show settings" 2>/dev/null | sed -n -r -e "s/^\s*pid file:\s+(.*)/\1/gpi")
- # We found it
- if [ x"$pidfile" != x -a -f "$pidfile" ] ; then
- pid=$(cat "$pidfile")
- echo "Found pidfile $pidfile with process $pid"
- fi
- fi
- # It's possible that asterisk was started with the -C option which means the
- # control socket and pidfile might not be where we expect. We're going to
- # have to parse the process arguments to see if -C was specified.
- # The first process that has a -C argument determines which config
- # file to use to find the pidfile of the main process.
- # NOTE: The ps command doesn't quote command line arguments that it
- # displays so we need to look in /proc/<pid>/cmdline.
- if [ x"$pid" = x ] ; then
- # BSDs might not mount /proc by default :(
- mounted_proc=0
- if uname -o | grep -qi "bsd" ; then
- if ! mount | grep -qi "/proc" ; then
- echo "Temporarily mounting /proc"
- mounted_proc=1
- mount -t procfs proc /proc
- fi
- fi
- for p in $pids ; do
- # Fields in cmdline are delimited by NULLs
- astetcconf=$(sed -n -r -e "s/.*\x00-C\x00([^\x00]+).*/\1/gp" /proc/$p/cmdline)
- if [ x"$astetcconf" != x ] ; then
- pidfile=$("$asterisk_bin" -C "$astetcconf" -rx "core show settings" 2>/dev/null | sed -n -r -e "s/^\s*pid file:\s+(.*)/\1/gpi")
- if [ x"$pidfile" != x -a -f "$pidfile" ] ; then
- pid=$(cat "$pidfile")
- echo "Found pidfile $pidfile the hard way with process $pid"
- break
- fi
- fi
- done
- if [ $mounted_proc -eq 1 ] ; then
- echo "Unmounting /proc"
- umount /proc
- fi
- fi
- if [ x"$pid" = x ] ; then
- >&2 echo "Can't determine pid of the running asterisk instance"
- exit 1
- fi
- if $RUNNING ; then
- answer=Y
- else
- read -p "WARNING: Taking a core dump of the running asterisk instance will suspend call processing while the dump is saved. Do you wish to continue? (y/N) " answer
- fi
- if [[ "$answer" =~ ^[Yy] ]] ; then
- cf="${OUTPUTDIR:-/tmp}/core-asterisk-running-$df"
- echo "Dumping running asterisk process to $cf"
- ${GDB} ${asterisk_bin} -p $pid -q --batch --ex "gcore $cf" >/dev/null 2>&1
- COREDUMPS+=("$cf")
- else
- echo "Skipping dump of running process"
- fi
- fi
- if [ "${#COREDUMPS[@]}" -eq 0 ] ; then
- echo "No coredumps found"
- print_help
- fi
- # Extract the gdb scripts from the end of this script
- # and save them to /tmp/.gdbinit
- gdbinit=${OUTPUTDIR:-/tmp}/.ast_coredumper.gdbinit
- trap "rm $gdbinit" EXIT
- ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:`
- tail -n +${ss} $0 >$gdbinit
- # Now iterate over the coredumps and dump the debugging info
- for i in ${!COREDUMPS[@]} ; do
- cf=${COREDUMPS[$i]}
- echo "Processing $cf"
- cfdir=`dirname ${cf}`
- cfname=`basename ${cf}`
- outputdir=${OUTPUTDIR:-${cfdir}}
- ${GDB} -n --batch -q --ex "source $gdbinit" "$asterisk_bin" "$cf" 2>/dev/null | (
- of=/dev/null
- while IFS= read line ; do
- if [[ "$line" =~ !@!@!@!\ ([^\ ]+)\ !@!@!@! ]] ; then
- of=${outputdir}/${cfname}-${BASH_REMATCH[1]}
- of=${of//:/-}
- rm -f "$of"
- echo "Creating $of"
- fi
- echo -e $"$line" >> "$of"
- done
- )
- if $tarball_coredumps ; then
- cfname=${cfname//:/-}
- tf=${outputdir}/${cfname}.tar.gz
- echo "Creating ${tf}"
- dest=${outputdir}/${cfname}.output
- rm -rf ${dest} 2>/dev/null || :
- libdir=usr/lib
- [ -d /usr/lib64 ] && libdir+=64
- mkdir -p ${dest}/tmp ${dest}/${libdir}/asterisk ${dest}/etc ${dest}/usr/sbin
- ln -s ${cf} ${dest}/tmp/${cfname}
- cp ${outputdir}/${cfname}*.txt ${dest}/tmp/
- [ -f /etc/os-release ] && cp /etc/os-release ${dest}/etc/
- if $tarball_config ; then
- cp -a /etc/asterisk ${dest}/etc/
- fi
- cp -a /${libdir}/libasterisk* ${dest}/${libdir}/
- cp -a /${libdir}/asterisk/* ${dest}/${libdir}/asterisk/
- cp -a /usr/sbin/asterisk ${dest}/usr/sbin
- rm -rf ${tf}
- tar -chzf ${tf} --transform="s/^[.]/${cfname}/" -C ${dest} .
- sleep 3
- rm -rf ${dest}
- echo "Created $tf"
- elif $tarball_results ; then
- cfname=${cfname//:/-}
- tf=${outputdir}/${cfname}.tar.gz
- echo "Creating ${tf}"
- dest=${outputdir}/${cfname}.output
- rm -rf ${dest} 2>/dev/null || :
- mkdir -p ${dest}
- cp ${outputdir}/${cfname}*.txt ${dest}/
- if $tarball_config ; then
- mkdir -p ${dest}/etc
- cp -a /etc/asterisk ${dest}/etc/
- fi
- tar -chzf ${tf} --transform="s/^[.]/${cfname}/" -C ${dest} .
- rm -rf ${dest}
- echo "Created $tf"
- fi
- if $delete_coredumps_after ; then
- rm -rf "${cf}"
- fi
- if $delete_results_after ; then
- rm -rf "${cf//:/-}"-{brief,full,thread1,locks}.txt
- fi
- done
- exit
- # Be careful editng the inline scripts.
- # They're space-indented.
- # We need the python bit because lock_infos isn't
- # a valid symbol in asterisk unless DEBUG_THREADS was
- # used during the compile. Also, interrupt and continue
- # are only valid for a running program.
- #@@@SCRIPTSTART@@@
- python
- class DumpAsteriskCommand(gdb.Command):
- def __init__(self):
- super(DumpAsteriskCommand, self).__init__ ("dump-asterisk",
- gdb.COMMAND_OBSCURE, gdb.COMPLETE_COMMAND)
- def invoke(self, arg, from_tty):
- try:
- gdb.execute("interrupt", from_tty)
- except:
- pass
- print("!@!@!@! thread1.txt !@!@!@!\n")
- try:
- gdb.execute("p $_siginfo", from_tty)
- gdb.execute("info signal $_siginfo.si_signo")
- except:
- pass
- try:
- gdb.execute("thread apply 1 bt full", from_tty)
- except:
- pass
- print("!@!@!@! brief.txt !@!@!@!\n")
- try:
- gdb.execute("p $_siginfo", from_tty)
- gdb.execute("info signal $_siginfo.si_signo")
- except:
- pass
- try:
- gdb.execute("thread apply all bt", from_tty)
- except:
- pass
- print("!@!@!@! full.txt !@!@!@!\n")
- try:
- gdb.execute("p $_siginfo", from_tty)
- gdb.execute("info signal $_siginfo.si_signo")
- except:
- pass
- try:
- gdb.execute("thread apply all bt full", from_tty)
- except:
- pass
- print("!@!@!@! locks.txt !@!@!@!\n")
- try:
- gdb.execute("p $_siginfo", from_tty)
- gdb.execute("info signal $_siginfo.si_signo")
- except:
- pass
- try:
- gdb.execute("show_locks", from_tty)
- except:
- pass
- try:
- gdb.execute("continue", from_tty)
- except:
- pass
- DumpAsteriskCommand ()
- end
- define show_locks
- set $n = lock_infos.first
- if $argc == 0
- printf " where_held count-|\n"
- printf " suspended-| |\n"
- printf " type- | times locked-| | |\n"
- printf "thread status file line function lock name | lock addr | | |\n"
- else
- printf "thread,status,file,line,function,lock_name,lock_type,lock_addr,times_locked,suspended,where_held_count,where_held_file,where_held_line,where_held_function,there_held_thread\n"
- end
- while $n
- if $n->num_locks > 0
- set $i = 0
- while $i < $n->num_locks
- if $n->locks[$i]->suspended == 0
- if ((ast_mutex_t *)$n->locks[$i]->lock_addr)->tracking
- if $n->locks[$i]->type > 0
- set $track = ((ast_rwlock_t *)$n->locks[$i]->lock_addr)->track
- else
- set $track = ((ast_mutex_t *)$n->locks[$i]->lock_addr)->track
- end
- end
- set $reentrancy = $track->reentrancy
- set $pending = $n->locks[$i]->pending
- if $argc > 0
- printf "%p,%d,%s,%d,%s,%s,%d,%p,%d,%d,%d",\
- $n->thread_id, $n->locks[$i]->pending, $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
- $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
- $n->locks[$i]->suspended, $track->reentrancy
- if $reentrancy
- if $pending
- printf ",%s,%d,%s,%p", $track->file[0], $track->lineno[0], $track->func[0], $track->thread[0]
- end
- end
- else
- if $n->locks[$i]->pending < 0
- printf "%p failed %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
- $n->thread_id,\
- $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
- $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
- $n->locks[$i]->suspended, $track->reentrancy
- end
- if $n->locks[$i]->pending == 0
- printf "%p holding %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
- $n->thread_id,\
- $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
- $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
- $n->locks[$i]->suspended, $track->reentrancy
- end
- if $n->locks[$i]->pending > 0
- printf "%p waiting %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
- $n->thread_id,\
- $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
- $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
- $n->locks[$i]->suspended, $track->reentrancy
- end
- if $reentrancy
- if $pending
- printf "\n held at: %-20s %6d %-36s by 0x%08lx", $track->file[0], $track->lineno[0], $track->func[0], $track->thread_id[0]
- end
- end
- end
- printf "\n"
- end
- set $i = $i + 1
- end
- end
- set $n = $n->entry->next
- end
- end
- dump-asterisk
|