# -*- shell-script -*- # gdb-like "backtrace" debugger command # # Copyright (C) 2002, 2003, 2004, 2005, 2006, 2008, 2010, 2011 # Rocky Bernstein # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to # the Free Software Foundation, 59 Temple Place, Suite 330, Boston, # MA 02111 USA. # Print a stack backtrace. # $1 is an additional offset correction - this routine is called from two # different places and one routine has one more additional call on top. # $2 is the maximum number of entries to include. # $3 is which entry we start from; the "up", "down" and the "frame" # commands may shift this. # This code assumes the version of bash where FUNCNAME is an array, # not a variable. _Dbg_help_add backtrace \ "**backtrace** [*n*] Print a backtrace of calling functions and sourced files. files. If *n* is given, list only *n* calls. Examples: --------- backtrace # Print a full stack trace backtrace 2 # Print only the top two entries " 1 _Dbg_complete_backtrace # Command completion for a frame command _Dbg_complete_backtrace() { typeset -i start=0 typeset -i end; ((end=_Dbg_stack_size-1)) _Dbg_complete_num_range $start $end } # FIXME: $1 is a hidden parameter not shown in help. $2 is COUNT. # $3 is FRAME-INDEX. function _Dbg_do_backtrace { _Dbg_not_running && return 3 typeset -i count=${1:-$_Dbg_stack_size} $(_Dbg_is_int $count) || { _Dbg_errmsg "Bad integer COUNT parameter: $count" return 1 } typeset -i frame_start=${2:-0} $(_Dbg_is_int $frame_start) || { _Dbg_errmsg "Bad integer parameter: $ignore_count" return 1 } # i is the logical frame value - 0 most recent frame. typeset -i i=frame_start typeset -li adjusted_pos ## DEBUG ## typeset -p pos ## typeset -p BASH_LINENO ## typeset -p BASH_SOURCE ## typeset -p FUNCNAME typeset filename typeset -i adjusted_pos # Position 0 is special in that get the line number not from the # stack but ultimately from LINENO which was saved in the hook call. if (( frame_start == 0 )) ; then ((count--)) ; adjusted_pos=$(_Dbg_frame_adjusted_pos 0) filename=$(_Dbg_file_canonic "${BASH_SOURCE[$adjusted_pos]}") _Dbg_frame_print $(_Dbg_frame_prefix 0) '0' '' "$filename" "$_Dbg_frame_last_lineno" '' fi typeset -i skip_fns ((skip_fns=${#FUNCNAME[@]} - _Dbg_stack_size + 1)) _Dbg_frame_set_fn_param $skip_fns # Loop which dumps out stack trace. ## DEBUG ## typeset -p BASH_ARGC ## typeset -p BASH_ARGV ## typeset -p FUNCNAME ## typeset -p _Dbg_next_argc ## typeset -p _Dbg_next_argv ## echo "Adjusted pos $(_Dbg_frame_adjusted_pos 0)" for (( i=frame_start+1 ; i <= _Dbg_stack_size && count > 0 ; i++ )) ; do typeset -i arg_count=${BASH_ARGC[$_Dbg_next_argc]} adjusted_pos=$(_Dbg_frame_adjusted_pos $i) _Dbg_msg_nocr $(_Dbg_frame_prefix $i)$i ${FUNCNAME[$adjusted_pos-1]} typeset parms='' # Print out parameter list. if (( 0 != ${#BASH_ARGC[@]} )) ; then _Dbg_frame_fn_param_str if [[ ${FUNCNAME[$adjusted_pos-1]} == "source" ]] ; then _Dbg_parm_str=\"$(_Dbg_file_canonic "${BASH_ARGV[$_Dbg_next_argv-1]}")\" fi fi typeset -l lineno if (( adjusted_pos == ${#BASH_SOURCE[@]} )) ; then lineno=0 ((adjusted_pos--)) else lineno=${BASH_LINENO[$adjusted_pos-1]} fi filename=$(_Dbg_file_canonic "${BASH_SOURCE[$adjusted_pos]}") _Dbg_msg "($_Dbg_parm_str) called from file \`$filename'" "at line $lineno" ((count--)) done return 0 } _Dbg_alias_add bt backtrace _Dbg_alias_add T backtrace _Dbg_alias_add where backtrace