ast_coredumper 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. #!/usr/bin/env bash
  2. # Turn on extended globbing
  3. shopt -s extglob
  4. # Bail on any error
  5. set -e
  6. prog=$(basename $0)
  7. print_help() {
  8. cat <<EOF
  9. NAME
  10. $prog - Dump and/or format asterisk coredump files
  11. SYNOPSIS
  12. $prog [ --help ] [ --running | --RUNNING ] [ --latest ]
  13. [ --tarball-coredumps ] [ --delete-coredumps-after ]
  14. [ --tarball-results ] [ --delete-results-after ]
  15. [ --tarball-config ] [ --tarball-uniqueid="<uniqueid>" ]
  16. [ --no-default-search ] [ --append-coredumps ]
  17. [ --asterisk-bin="path" ]
  18. [ <coredump> | <pattern> ... ]
  19. DESCRIPTION
  20. Extracts backtraces and lock tables from Asterisk coredump files.
  21. For each coredump found, 4 new result files are created:
  22. - <coredump>.brief.txt: The output of "thread apply all bt".
  23. - <coredump>.thread1.txt: The output of "thread apply 1 bt full".
  24. - <coredump>.full.txt: The output of "thread apply all bt full".
  25. - <coredump>.locks.txt: If asterisk was compiled with
  26. "DEBUG_THREADS", this file will contain a dump of the locks
  27. table similar to doing a "core show locks" from the asterisk
  28. CLI.
  29. Optional features:
  30. - The running asterisk process can be suspended and dumped.
  31. - The coredumps can be merged into a tarball.
  32. - The coredumps can be deleted after processing.
  33. - The results files can be merged into a tarball.
  34. - The results files can be deleted after processing.
  35. Options:
  36. --help
  37. Print this help.
  38. --running
  39. Create a coredump from the running asterisk instance and
  40. process it along with any other coredumps found (if any).
  41. WARNING: This WILL interrupt call processing. You will be
  42. asked to confirm. The coredump will be written to /tmp if
  43. $OUTPUTDIR is not defined.
  44. --RUNNING
  45. Same as --running but without the confirmation prompt.
  46. DANGEROUS!!
  47. --latest
  48. Process only the latest coredump from those specified (based
  49. on last-modified time). If a dump of the running process was
  50. requested, it is always included in addition to the latest
  51. from the existing coredumps.
  52. --tarball-coredumps
  53. Creates a gzipped tarball of coredumps processed, their
  54. results txt files and copies of /etc/os-release,
  55. /usr/sbin/asterisk, /usr/lib(64)/libasterisk* and
  56. /usr/lib(64)/asterisk as those files are needed to properly
  57. examine the coredump. The file will be named
  58. $OUTPUTDIR/asterisk.<timestamp>.coredumps.tar.gz or
  59. $OUTPUTDIR/asterisk-<uniqueid>.coredumps.tar.gz if
  60. --tarball-uniqueid was specified.
  61. WARNING: This file could 1gb in size!
  62. Mutually exclusive with --tartball-results
  63. --delete-coredumps-after
  64. Deletes all processed coredumps regardless of whether
  65. a tarball was created.
  66. --tarball-results
  67. Creates a gzipped tarball of all result files produced.
  68. The tarball name will be:
  69. $OUTPUTDIR/asterisk.<timestamp>.results.tar.gz
  70. Mutually exclusive with --tartball-coredumps
  71. --delete-results-after
  72. Deletes all processed results regardless of whether
  73. a tarball was created. It probably doesn't make sense
  74. to use this option unless you have also specified
  75. --tarball-results.
  76. --tarball-config
  77. Adds the contents of /etc/asterisk to the tarball created
  78. with --tarball-coredumps or --tarball-results.
  79. --tarball-uniqueid="<uniqueid>"
  80. Normally DATEFORMAT is used to make the tarballs unique
  81. but you can use your own unique id in the tarball names
  82. such as the Jira issue id.
  83. --no-default-search
  84. Ignore COREDUMPS from the config files and process only
  85. coredumps listed on the command line (if any) and/or
  86. the running asterisk instance (if requested).
  87. --append-coredumps
  88. Append any coredumps specified on the command line to the
  89. config file specified ones instead of overriding them.
  90. --asterisk-binary
  91. Path to the asterisk binary. Default: look for asterisk
  92. in the PATH.
  93. <coredump> | <pattern>
  94. A list of coredumps or coredump search patterns. Unless
  95. --append-coredumps was specified, these entries will override
  96. those specified in the config files.
  97. Any resulting file that isn't actually a coredump is silently
  98. ignored. If your patterns contains spaces be sure to only
  99. quote the portion of the pattern that DOESN'T contain wildcard
  100. expressions. If you quote the whole pattern, it won't be
  101. expanded.
  102. If --no-default-search is specified and no files are specified
  103. on the command line, then the only the running asterisk process
  104. will be dumped (if requested). Otherwise if no files are
  105. specified on the command line the value of COREDUMPS from
  106. ast_debug_tools.conf will be used. Failing that, the following
  107. patterns will be used:
  108. /tmp/core[-._]asterisk!(*.txt)
  109. /tmp/core[-._]\$(hostname)!(*.txt)
  110. NOTES
  111. You must be root to use $prog.
  112. $OUTPUTDIR can be read from the current environment or from the
  113. ast_debug_tools.conf file described below. If not specified,
  114. work products are placed in the same directory as the core file.
  115. The script relies on not only bash, but also recent GNU date and
  116. gdb with python support. *BSD operating systems may require
  117. installation of the 'coreutils' and 'devel/gdb' packagess and minor
  118. tweaking of the ast_debug_tools.conf file.
  119. Any files output will have ':' characters changed to '-'. This is
  120. to facilitate uploading those files to Jira which doesn't like the
  121. colons.
  122. FILES
  123. /etc/asterisk/ast_debug_tools.conf
  124. ~/ast_debug_tools.conf
  125. ./ast_debug_tools.conf
  126. #
  127. # This file is used by the Asterisk debug tools.
  128. # Unlike other Asterisk config files, this one is
  129. # "sourced" by bash and must adhere to bash semantics.
  130. #
  131. # A list of coredumps and/or coredump search patterns.
  132. # Bash extended globs are enabled and any resulting files
  133. # that aren't actually coredumps are silently ignored
  134. # so you can be liberal with the globs.
  135. #
  136. # If your patterns contains spaces be sure to only quote
  137. # the portion of the pattern that DOESN'T contain wildcard
  138. # expressions. If you quote the whole pattern, it won't
  139. # be expanded and the glob characters will be treated as
  140. # literals.
  141. #
  142. # The exclusion of files ending ".txt" is just for
  143. # demonstration purposes as non-coredumps will be ignored
  144. # anyway.
  145. COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]\$(hostname)!(*.txt))
  146. # The directory to contain output files and work directories.
  147. # For output from existing core files, the default is the
  148. # directory that the core file is found in. For core files
  149. # produced from a running process, the default is /tmp.
  150. OUTPUTDIR=/some/directory
  151. # Date command for the "running" coredump and tarballs.
  152. # DATEFORMAT will be executed to get the timestamp.
  153. # Don't put quotes around the format string or they'll be
  154. # treated as literal characters. Also be aware of colons
  155. # in the output as you can't upload files with colons in
  156. # the name to Jira.
  157. #
  158. # Unix timestamp
  159. #DATEFORMAT='date +%s.%N'
  160. #
  161. # *BSD/MacOS doesn't support %N but after installing GNU
  162. # coreutils...
  163. #DATEFORMAT='gdate +%s.%N'
  164. #
  165. # Readable GMT
  166. #DATEFORMAT='date -u +%FT%H-%M-%S%z'
  167. #
  168. # Readable Local time
  169. DATEFORMAT='date +%FT%H-%M-%S%z'
  170. EOF
  171. exit 1
  172. }
  173. if [ $EUID -ne 0 ] ; then
  174. echo "You must be root to use $prog."
  175. exit 1
  176. fi
  177. running=false
  178. RUNNING=false
  179. latest=false
  180. tarball_coredumps=false
  181. tarball_config=false
  182. delete_coredumps_after=false
  183. tarball_results=false
  184. delete_results_after=false
  185. append_coredumps=false
  186. declare -a COREDUMPS
  187. declare -a ARGS_COREDUMPS
  188. # readconf reads a bash-sourceable file and sets variables
  189. # that havn't already been set. This allows variables set
  190. # on the command line or that are already in the environment
  191. # to take precedence over those read from the file.
  192. #
  193. # Setting the values can't be done in a subshell so you can't
  194. # just pipe the output of sed into the while.
  195. readconf() {
  196. while read line ; do
  197. v=${line%%=*}
  198. [ -z "${!v}" ] && eval $line || :
  199. done <<EOF
  200. $( sed -r -e "/\s*#/d" -e "/^\s*$/d" $1 )
  201. EOF
  202. }
  203. # Read config files from most important to least important.
  204. # Variable set on the command line or environment always take precedence.
  205. [ -f ./ast_debug_tools.conf ] && readconf ./ast_debug_tools.conf
  206. [ -f ~/ast_debug_tools.conf ] && readconf ~/ast_debug_tools.conf
  207. [ -f /etc/asterisk/ast_debug_tools.conf ] && readconf /etc/asterisk/ast_debug_tools.conf
  208. # For *BSD, the preferred gdb may be in /usr/local/bin so we
  209. # need to search for one that supports python.
  210. for g in $(which -a gdb) ; do
  211. result=$($g --batch --ex "python print('hello')" 2>/dev/null || : )
  212. if [[ "$result" =~ ^hello$ ]] ; then
  213. GDB=$g
  214. break
  215. fi
  216. done
  217. if [ -z "$GDB" ] ; then
  218. echo "No suitable gdb was found in $PATH"
  219. exit 1
  220. fi
  221. if [ -n "$OUTPUTDIR" ] ; then
  222. if [ ! -d "$OUTPUTDIR" ] ; then
  223. echo "OUTPUTDIR $OUTPUTDIR doesn't exists or is not a directory"
  224. exit 1
  225. fi
  226. fi
  227. if [ ${#COREDUMPS[@]} -eq 0 ] ; then
  228. COREDUMPS+=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt))
  229. fi
  230. DATEFORMAT=${DATEFORMAT:-'date +%FT%H-%M-%S%z'}
  231. # Use "$@" (with the quotes) so spaces in patterns or
  232. # file names are preserved.
  233. # Later on when we have to iterate over COREDUMPS, we always
  234. # use the indexes rather than trying to expand the values of COREDUMPS
  235. # just in case.
  236. for a in "$@" ; do
  237. case "$a" in
  238. --running)
  239. running=true
  240. ;;
  241. --RUNNING)
  242. RUNNING=true
  243. ;;
  244. --no-default-search)
  245. # Clean out COREDUMPS from config files
  246. COREDUMPS=()
  247. ;;
  248. --latest)
  249. latest=true
  250. ;;
  251. --tarball-coredumps)
  252. tarball_coredumps=true
  253. ;;
  254. --tarball-config)
  255. tarball_config=true
  256. ;;
  257. --delete-coredumps-after)
  258. delete_coredumps_after=true
  259. ;;
  260. --tarball-results)
  261. tarball_results=true
  262. ;;
  263. --delete-results-after)
  264. delete_results_after=true
  265. ;;
  266. --append-coredumps)
  267. append_coredumps=true
  268. ;;
  269. --tarball-uniqueid=*)
  270. tarball_uniqueid=${a#*=}
  271. ;;
  272. --asterisk-bin=*)
  273. asterisk_bin=${a#*=}
  274. ;;
  275. --help|-*)
  276. print_help
  277. ;;
  278. *)
  279. ARGS_COREDUMPS+=("$a")
  280. # If any files are specified on the command line, ignore those
  281. # specified in the config files unless append-coredumps was specified.
  282. if ! $append_coredumps ; then
  283. COREDUMPS=()
  284. fi
  285. esac
  286. done
  287. # append coredumps/patterns specified as command line arguments to COREDUMPS.
  288. for i in ${!ARGS_COREDUMPS[@]} ; do
  289. COREDUMPS+=("${ARGS_COREDUMPS[$i]}")
  290. done
  291. # At this point, all glob entries that match files should be expanded.
  292. # Any entries that don't exist are probably globs that didn't match anything
  293. # and need to be pruned. Any non coredumps are also pruned.
  294. for i in ${!COREDUMPS[@]} ; do
  295. if [ ! -f "${COREDUMPS[$i]}" ] ; then
  296. unset COREDUMPS[$i]
  297. continue
  298. fi
  299. # Some versions of 'file' don't allow only the first n bytes of the
  300. # file to be processed so we use dd to grab just the first 32 bytes.
  301. mimetype=$(dd if="${COREDUMPS[$i]}" bs=32 count=1 2>/dev/null | file -bi -)
  302. if [[ ! "$mimetype" =~ coredump ]] ; then
  303. unset COREDUMPS[$i]
  304. continue
  305. fi
  306. done
  307. # Sort and weed out any dups
  308. IFS=$'\x0a'
  309. readarray -t COREDUMPS < <(echo -n "${COREDUMPS[*]}" | sort -u )
  310. unset IFS
  311. # If --latest, get the last modified timestamp of each file,
  312. # sort them, then return the latest.
  313. if [ ${#COREDUMPS[@]} -gt 0 ] && $latest ; then
  314. lf=$(find "${COREDUMPS[@]}" -printf '%T@ %p\n' | sort -n | tail -1)
  315. COREDUMPS=("${lf#* }")
  316. fi
  317. # Timestamp to use for output files
  318. df=${tarball_uniqueid:-$(${DATEFORMAT})}
  319. if [ x"$asterisk_bin" = x ]; then
  320. asterisk_bin=$(which asterisk)
  321. fi
  322. if $running || $RUNNING ; then
  323. # We need to go through some gyrations to find the pid of the running
  324. # MAIN asterisk process and not someone or something running asterisk -r.
  325. unset pid
  326. # Simplest case first...
  327. pids=$(pgrep -f "$asterisk_bin")
  328. pidcount=$(echo $pids | wc -w)
  329. if [ $pidcount -eq 0 ] ; then
  330. >&2 echo "Asterisk is not running"
  331. exit 1
  332. fi
  333. # Single process, great.
  334. if [ $pidcount -eq 1 ] ; then
  335. pid=$pids
  336. echo "Found a single asterisk instance running as process $pid"
  337. fi
  338. # More than 1 asterisk process running
  339. if [ x"$pid" = x ] ; then
  340. # More than 1 process running, let's try asking asterisk for it's
  341. # pidfile
  342. pidfile=$("$asterisk_bin" -rx "core show settings" 2>/dev/null | sed -n -r -e "s/^\s*pid file:\s+(.*)/\1/gpi")
  343. # We found it
  344. if [ x"$pidfile" != x -a -f "$pidfile" ] ; then
  345. pid=$(cat "$pidfile")
  346. echo "Found pidfile $pidfile with process $pid"
  347. fi
  348. fi
  349. # It's possible that asterisk was started with the -C option which means the
  350. # control socket and pidfile might not be where we expect. We're going to
  351. # have to parse the process arguments to see if -C was specified.
  352. # The first process that has a -C argument determines which config
  353. # file to use to find the pidfile of the main process.
  354. # NOTE: The ps command doesn't quote command line arguments that it
  355. # displays so we need to look in /proc/<pid>/cmdline.
  356. if [ x"$pid" = x ] ; then
  357. # BSDs might not mount /proc by default :(
  358. mounted_proc=0
  359. if uname -o | grep -qi "bsd" ; then
  360. if ! mount | grep -qi "/proc" ; then
  361. echo "Temporarily mounting /proc"
  362. mounted_proc=1
  363. mount -t procfs proc /proc
  364. fi
  365. fi
  366. for p in $pids ; do
  367. # Fields in cmdline are delimited by NULLs
  368. astetcconf=$(sed -n -r -e "s/.*\x00-C\x00([^\x00]+).*/\1/gp" /proc/$p/cmdline)
  369. if [ x"$astetcconf" != x ] ; then
  370. pidfile=$("$asterisk_bin" -C "$astetcconf" -rx "core show settings" 2>/dev/null | sed -n -r -e "s/^\s*pid file:\s+(.*)/\1/gpi")
  371. if [ x"$pidfile" != x -a -f "$pidfile" ] ; then
  372. pid=$(cat "$pidfile")
  373. echo "Found pidfile $pidfile the hard way with process $pid"
  374. break
  375. fi
  376. fi
  377. done
  378. if [ $mounted_proc -eq 1 ] ; then
  379. echo "Unmounting /proc"
  380. umount /proc
  381. fi
  382. fi
  383. if [ x"$pid" = x ] ; then
  384. >&2 echo "Can't determine pid of the running asterisk instance"
  385. exit 1
  386. fi
  387. if $RUNNING ; then
  388. answer=Y
  389. else
  390. 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
  391. fi
  392. if [[ "$answer" =~ ^[Yy] ]] ; then
  393. cf="${OUTPUTDIR:-/tmp}/core-asterisk-running-$df"
  394. echo "Dumping running asterisk process to $cf"
  395. ${GDB} ${asterisk_bin} -p $pid -q --batch --ex "gcore $cf" >/dev/null 2>&1
  396. COREDUMPS+=("$cf")
  397. else
  398. echo "Skipping dump of running process"
  399. fi
  400. fi
  401. if [ "${#COREDUMPS[@]}" -eq 0 ] ; then
  402. echo "No coredumps found"
  403. print_help
  404. fi
  405. # Extract the gdb scripts from the end of this script
  406. # and save them to /tmp/.gdbinit
  407. gdbinit=${OUTPUTDIR:-/tmp}/.ast_coredumper.gdbinit
  408. trap "rm $gdbinit" EXIT
  409. ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:`
  410. tail -n +${ss} $0 >$gdbinit
  411. # Now iterate over the coredumps and dump the debugging info
  412. for i in ${!COREDUMPS[@]} ; do
  413. cf=${COREDUMPS[$i]}
  414. echo "Processing $cf"
  415. cfdir=`dirname ${cf}`
  416. cfname=`basename ${cf}`
  417. outputdir=${OUTPUTDIR:-${cfdir}}
  418. ${GDB} -n --batch -q --ex "source $gdbinit" "$asterisk_bin" "$cf" 2>/dev/null | (
  419. of=/dev/null
  420. while IFS= read line ; do
  421. if [[ "$line" =~ !@!@!@!\ ([^\ ]+)\ !@!@!@! ]] ; then
  422. of=${outputdir}/${cfname}-${BASH_REMATCH[1]}
  423. of=${of//:/-}
  424. rm -f "$of"
  425. echo "Creating $of"
  426. fi
  427. echo -e $"$line" >> "$of"
  428. done
  429. )
  430. if $tarball_coredumps ; then
  431. cfname=${cfname//:/-}
  432. tf=${outputdir}/${cfname}.tar.gz
  433. echo "Creating ${tf}"
  434. dest=${outputdir}/${cfname}.output
  435. rm -rf ${dest} 2>/dev/null || :
  436. libdir=usr/lib
  437. [ -d /usr/lib64 ] && libdir+=64
  438. mkdir -p ${dest}/tmp ${dest}/${libdir}/asterisk ${dest}/etc ${dest}/usr/sbin
  439. ln -s ${cf} ${dest}/tmp/${cfname}
  440. cp ${outputdir}/${cfname}*.txt ${dest}/tmp/
  441. [ -f /etc/os-release ] && cp /etc/os-release ${dest}/etc/
  442. if $tarball_config ; then
  443. cp -a /etc/asterisk ${dest}/etc/
  444. fi
  445. cp -a /${libdir}/libasterisk* ${dest}/${libdir}/
  446. cp -a /${libdir}/asterisk/* ${dest}/${libdir}/asterisk/
  447. cp -a /usr/sbin/asterisk ${dest}/usr/sbin
  448. rm -rf ${tf}
  449. tar -chzf ${tf} --transform="s/^[.]/${cfname}/" -C ${dest} .
  450. sleep 3
  451. rm -rf ${dest}
  452. echo "Created $tf"
  453. elif $tarball_results ; then
  454. cfname=${cfname//:/-}
  455. tf=${outputdir}/${cfname}.tar.gz
  456. echo "Creating ${tf}"
  457. dest=${outputdir}/${cfname}.output
  458. rm -rf ${dest} 2>/dev/null || :
  459. mkdir -p ${dest}
  460. cp ${outputdir}/${cfname}*.txt ${dest}/
  461. if $tarball_config ; then
  462. mkdir -p ${dest}/etc
  463. cp -a /etc/asterisk ${dest}/etc/
  464. fi
  465. tar -chzf ${tf} --transform="s/^[.]/${cfname}/" -C ${dest} .
  466. rm -rf ${dest}
  467. echo "Created $tf"
  468. fi
  469. if $delete_coredumps_after ; then
  470. rm -rf "${cf}"
  471. fi
  472. if $delete_results_after ; then
  473. rm -rf "${cf//:/-}"-{brief,full,thread1,locks}.txt
  474. fi
  475. done
  476. exit
  477. # Be careful editng the inline scripts.
  478. # They're space-indented.
  479. # We need the python bit because lock_infos isn't
  480. # a valid symbol in asterisk unless DEBUG_THREADS was
  481. # used during the compile. Also, interrupt and continue
  482. # are only valid for a running program.
  483. #@@@SCRIPTSTART@@@
  484. python
  485. class DumpAsteriskCommand(gdb.Command):
  486. def __init__(self):
  487. super(DumpAsteriskCommand, self).__init__ ("dump-asterisk",
  488. gdb.COMMAND_OBSCURE, gdb.COMPLETE_COMMAND)
  489. def invoke(self, arg, from_tty):
  490. try:
  491. gdb.execute("interrupt", from_tty)
  492. except:
  493. pass
  494. print("!@!@!@! thread1.txt !@!@!@!\n")
  495. try:
  496. gdb.execute("p $_siginfo", from_tty)
  497. gdb.execute("info signal $_siginfo.si_signo")
  498. except:
  499. pass
  500. try:
  501. gdb.execute("thread apply 1 bt full", from_tty)
  502. except:
  503. pass
  504. print("!@!@!@! brief.txt !@!@!@!\n")
  505. try:
  506. gdb.execute("p $_siginfo", from_tty)
  507. gdb.execute("info signal $_siginfo.si_signo")
  508. except:
  509. pass
  510. try:
  511. gdb.execute("thread apply all bt", from_tty)
  512. except:
  513. pass
  514. print("!@!@!@! full.txt !@!@!@!\n")
  515. try:
  516. gdb.execute("p $_siginfo", from_tty)
  517. gdb.execute("info signal $_siginfo.si_signo")
  518. except:
  519. pass
  520. try:
  521. gdb.execute("thread apply all bt full", from_tty)
  522. except:
  523. pass
  524. print("!@!@!@! locks.txt !@!@!@!\n")
  525. try:
  526. gdb.execute("p $_siginfo", from_tty)
  527. gdb.execute("info signal $_siginfo.si_signo")
  528. except:
  529. pass
  530. try:
  531. gdb.execute("show_locks", from_tty)
  532. except:
  533. pass
  534. try:
  535. gdb.execute("continue", from_tty)
  536. except:
  537. pass
  538. DumpAsteriskCommand ()
  539. end
  540. define show_locks
  541. set $n = lock_infos.first
  542. if $argc == 0
  543. printf " where_held count-|\n"
  544. printf " suspended-| |\n"
  545. printf " type- | times locked-| | |\n"
  546. printf "thread status file line function lock name | lock addr | | |\n"
  547. else
  548. 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"
  549. end
  550. while $n
  551. if $n->num_locks > 0
  552. set $i = 0
  553. while $i < $n->num_locks
  554. if $n->locks[$i]->suspended == 0
  555. if ((ast_mutex_t *)$n->locks[$i]->lock_addr)->tracking
  556. if $n->locks[$i]->type > 0
  557. set $track = ((ast_rwlock_t *)$n->locks[$i]->lock_addr)->track
  558. else
  559. set $track = ((ast_mutex_t *)$n->locks[$i]->lock_addr)->track
  560. end
  561. end
  562. set $reentrancy = $track->reentrancy
  563. set $pending = $n->locks[$i]->pending
  564. if $argc > 0
  565. printf "%p,%d,%s,%d,%s,%s,%d,%p,%d,%d,%d",\
  566. $n->thread_id, $n->locks[$i]->pending, $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
  567. $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
  568. $n->locks[$i]->suspended, $track->reentrancy
  569. if $reentrancy
  570. if $pending
  571. printf ",%s,%d,%s,%p", $track->file[0], $track->lineno[0], $track->func[0], $track->thread[0]
  572. end
  573. end
  574. else
  575. if $n->locks[$i]->pending < 0
  576. printf "%p failed %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
  577. $n->thread_id,\
  578. $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
  579. $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
  580. $n->locks[$i]->suspended, $track->reentrancy
  581. end
  582. if $n->locks[$i]->pending == 0
  583. printf "%p holding %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
  584. $n->thread_id,\
  585. $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
  586. $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
  587. $n->locks[$i]->suspended, $track->reentrancy
  588. end
  589. if $n->locks[$i]->pending > 0
  590. printf "%p waiting %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
  591. $n->thread_id,\
  592. $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
  593. $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
  594. $n->locks[$i]->suspended, $track->reentrancy
  595. end
  596. if $reentrancy
  597. if $pending
  598. printf "\n held at: %-20s %6d %-36s by 0x%08lx", $track->file[0], $track->lineno[0], $track->func[0], $track->thread_id[0]
  599. end
  600. end
  601. end
  602. printf "\n"
  603. end
  604. set $i = $i + 1
  605. end
  606. end
  607. set $n = $n->entry->next
  608. end
  609. end
  610. dump-asterisk