📄 dbg-brk.inc
字号:
# dbg-brk.inc - Bourne Again Shell Debugger Break/Watch/Action routines# Copyright (C) 2002, 2003, 2006, 2007 Rocky Bernstein # rockyb@users.sourceforge.net## Bash 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.## Bash 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 Bash; see the file COPYING. If not, write to the Free Software# Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.#================ VARIABLE INITIALIZATIONS ====================#declare -r _Dbg_brk_ver=\'$Id: dbg-brk.inc,v 1.15 2007/03/02 07:56:34 rockyb Exp $'typeset -ar _Dbg_yn=("n" "y") typeset -ar _Dbg_keep=('keep' 'del') # action data structurestypeset -ai _Dbg_action_line=() # Line number of breakpointtypeset -a _Dbg_action_file=() # filename of breakpointtypeset -ai _Dbg_action_enable=() # 1/0 if enabled or nottypeset -a _Dbg_action_stmt=() # Statement to eval when line is hit.typeset -i _Dbg_action_max=0 # Needed because we can't figure # out what the max index is and arrays # can be sparse# Note: we loop over possibly sparse arrays with _Dbg_brkpt_max by adding one# and testing for an entry. Could add yet another array to list only # used indices. Bash is kind of primitive.# Breakpoint data structurestypeset -ai _Dbg_brkpt_line=() # Line number of breakpointtypeset -a _Dbg_brkpt_file=() # filename of breakpointtypeset -a _Dbg_brkpt_enable=() # 1/0 if enabled or nottypeset -ai _Dbg_brkpt_count=() # Number of times hittypeset -ai _Dbg_brkpt_onetime=() # Is this a onetime break?typeset -a _Dbg_brkpt_cond=() # Condition to eval true in order to stop.typeset -i _Dbg_brkpt_max=0 # Needed because we can't figure out what # the max index is and arrays can be sparse# Note: we loop over possibly sparse arrays with _Dbg_brkpt_max by adding one# and testing for an entry. Could add yet another array to list only # used indices. Bash is kind of primitive.# Watchpoint data structurestypeset -a _Dbg_watch_exp=() # Watchpoint expressionstypeset -a _Dbg_watch_val=() # values of watchpoint expressionstypeset -ai _Dbg_watch_arith=() # 1 if arithmetic expression or not.typeset -ai _Dbg_watch_count=() # Number of times hittypeset -ai _Dbg_watch_enable=() # 1/0 if enabled or nottypeset -i _Dbg_watch_max=0 # Needed because we can't figure out what # the max index is and arrays can be sparsetypeset -r _watch_pat="${int_pat}[wW]"# Display data structurestypeset -a _Dbg_disp_exp=() # Watchpoint expressionstypeset -ai _Dbg_disp_enable=() # 1/0 if enabled or nottypeset -i _Dbg_disp_max=0 # Needed because we can't figure out what # the max index is and arrays can be sparse#========================= FUNCTIONS ============================## Error message for file not read in_Dbg_file_not_read_in() { local -r filename=$(_Dbg_adjust_filename "$1") _Dbg_msg "File $filename not found in read-in files." _Dbg_msg "See 'info files' for a list of known files and" _Dbg_msg "'load' to read in a file."}# Common routine for setup of commands that take a single# linespec argument. We assume the following variables # which we store into:# filename, line_number, full_filename_Dbg_linespec_setup() { local linespec=${1:-''} if [[ -z $linespec ]] ; then _Dbg_msg "Invalid line specification, null given" fi local -a word=($(_Dbg_parse_linespec "$linespec")) if [[ ${#word[@]} == 0 ]] ; then _Dbg_msg "Invalid line specification: $linespec" return fi filename=${word[2]} local -ir is_function=${word[1]} line_number=${word[0]} full_filename=`_Dbg_is_file $filename` if (( is_function )) ; then if [[ -z $full_filename ]] ; then _Dbg_readin "$filename" full_filename=`_Dbg_is_file $filename` fi fi}# Error message for file not read in_Dbg_file_not_read_in() { local -r filename=$(_Dbg_adjust_filename ${1:-""}) _Dbg_msg "File $filename not found in read-in files." _Dbg_msg "See 'info files' for a list of known files and" _Dbg_msg "'load' to read in a file."}_Dbg_save_breakpoints() { local file for file in ${_Dbg_filenames[@]} ; do local filevar="`_Dbg_file2var $file`" declare -p _Dbg_brkpt_$filevar >> $_Dbg_statefile 2>/dev/null done declare -p _Dbg_brkpt_line >> $_Dbg_statefile declare -p _Dbg_brkpt_file >> $_Dbg_statefile declare -p _Dbg_brkpt_cond >> $_Dbg_statefile declare -p _Dbg_brkpt_count >> $_Dbg_statefile declare -p _Dbg_brkpt_enable >> $_Dbg_statefile declare -p _Dbg_brkpt_onetime >> $_Dbg_statefile declare -p _Dbg_brkpt_max >> $_Dbg_statefile}_Dbg_save_actions() { for file in ${_Dbg_filenames[@]} ; do local filevar="`_Dbg_file2var $file`" declare -p _Dbg_action_$filevar >> $_Dbg_statefile 2>/dev/null done declare -p _Dbg_action_line >> $_Dbg_statefile declare -p _Dbg_action_file >> $_Dbg_statefile declare -p _Dbg_action_enable >> $_Dbg_statefile declare -p _Dbg_action_stmt >> $_Dbg_statefile declare -p _Dbg_action_max >> $_Dbg_statefile}_Dbg_save_watchpoints() { declare -p _Dbg_watch_exp >> $_Dbg_statefile declare -p _Dbg_watch_val >> $_Dbg_statefile declare -p _Dbg_watch_arith >> $_Dbg_statefile declare -p _Dbg_watch_count >> $_Dbg_statefile declare -p _Dbg_watch_enable >> $_Dbg_statefile declare -p _Dbg_watch_max >> $_Dbg_statefile}_Dbg_save_display() { declare -p _Dbg_disp_exp >> $_Dbg_statefile declare -p _Dbg_disp_enable >> $_Dbg_statefile declare -p _Dbg_disp_max >> $_Dbg_statefile}# Start out with general break/watchpoint functions first...# Routine to a delete breakpoint/watchpoint by entry numbers._Dbg_do_delete() { local -r to_go=$@ local -i i local -i found=0 # set -xv eval "$_seteglob" for del in $to_go ; do case $del in $_watch_pat ) _Dbg_delete_watch_entry ${del:0:${#del}-1} ;; $int_pat ) _Dbg_delete_brkpt_entry $del ((found += $?)) ;; * ) _Dbg_msg "Invalid entry number skipped: $del" esac done eval "$_resteglob" [[ $found != 0 ]] && _Dbg_msg "Removed $found breakpoint(s)." return $found # set +xv}# Enable/disable breakpoint or watchpoint by entry numbers._Dbg_enable_disable() { if [ -z "$1" ] ; then _Dbg_msg "Expecting a list of breakpoint/watchpoint numbers. Got none." return 1 fi local -i on=$1 local en_dis=$2 shift; shift if [[ $1 = 'display' ]] ; then shift local to_go="$@" local i eval "$_seteglob" for i in $to_go ; do case $i in $int_pat ) _Dbg_enable_disable_display $on $en_dis $i ;; * ) _Dbg_msg "Invalid entry number skipped: $i" esac done eval "$_resteglob" return 0 elif [[ $1 = 'action' ]] ; then shift local to_go="$@" local i eval "$_seteglob" for i in $to_go ; do case $i in $int_pat ) _Dbg_enable_disable_action $on $en_dis $i ;; * ) _Dbg_msg "Invalid entry number skipped: $i" esac done eval "$_resteglob" return 0 fi local to_go="$@" local i eval "$_seteglob" for i in $to_go ; do case $i in $_watch_pat ) _Dbg_enable_disable_watch $on $en_dis ${del:0:${#del}-1} ;; $int_pat ) _Dbg_enable_disable_brkpt $on $en_dis $i ;; * ) _Dbg_msg "Invalid entry number skipped: $i" esac done eval "$_resteglob" return 0}_Dbg_do_continue() { # set -xv if (( ! _Dbg_running )) ; then _Dbg_msg "The program is not being run." return fi [[ -z "$1" ]] && return 0 local filename local -i line_number local full_filename _Dbg_linespec_setup $1 if [[ -n $full_filename ]] ; then if (( $line_number == 0 )) ; then _Dbg_msg "There is no line 0 to continue at." else _Dbg_check_line $line_number "$full_filename" (( $? == 0 )) && \ _Dbg_set_brkpt "$full_filename" "$line_number" 1 1 return 0 fi else _Dbg_file_not_read_in $filename fi return 1}# Enable breakpoint(s)/watchpoint(s) by entry number(s)._Dbg_do_enable() { _Dbg_enable_disable 1 "enabled" $@}# Disable breakpoint(s)/watchpoint(s) by entry number(s)._Dbg_do_disable() { _Dbg_enable_disable 0 "disabled" $@}_Dbg_print_brkpt_count() { local -ir i=$1 if (( _Dbg_brkpt_count[$i] != 0 )) ; then if (( _Dbg_brkpt_count[$i] == 1 )) ; then _Dbg_printf "\tbreakpoint already hit 1 time" else _Dbg_printf "\tbreakpoint already hit %d times" ${_Dbg_brkpt_count[$i]} fi fi}#======================== BREAKPOINTS ============================## Add breakpoint(s) at given line number of the current file. $1 is# the line number or _curline if omitted. $2 is a condition to test# for whether to stop._Dbg_do_break() { local -i is_temp=$1 shift local n=${1:-$_curline} shift local condition=${1:-''}; if [[ "$n" == 'if' ]]; then n=$_curline elif [[ -z $condition ]] ; then condition=1 elif [[ $condition == 'if' ]] ; then shift fi if [[ -z $condition ]] ; then condition=1 else condition="$*" fi local filename local -i line_number local full_filename _Dbg_linespec_setup $n if [[ -n $full_filename ]] ; then if (( $line_number == 0 )) ; then _Dbg_msg "There is no line 0 to break at." else _Dbg_check_line $line_number "$full_filename" (( $? == 0 )) && \ _Dbg_set_brkpt "$full_filename" "$line_number" $is_temp "$condition" fi else _Dbg_file_not_read_in $filename fi}# Set a condition for a given breakpoint $1 is a breakpoint number# $2 is a condition. If not given, set "unconditional" or 1.# returns 0 if success or 1 if fail._Dbg_do_condition() { # set -x local -r n=$1 shift local condition="$@" # set -xv if [[ -z $n ]]; then _Dbg_msg "Argument required (breakpoint number)." return 1 fi eval "$_seteglob" if [[ $n != $int_pat ]]; then eval "$_resteglob" _Dbg_msg "Bad breakpoint number: $n" return 1 fi eval "$_resteglob" if [[ -z ${_Dbg_brkpt_file[$n]} ]] ; then _Dbg_msg "Breakpoint entry $n is not set. Condition not changed." return 1 fi if [[ -z $condition ]] ; then condition=1 _Dbg_msg "Breakpoint $n now unconditional." fi _Dbg_brkpt_cond[$n]="$condition" return 0}# delete brkpt(s) at given file:line numbers. If no file is given# use the current file._Dbg_do_clear_brkpt() { # set -x local -r n=${1:-$_curline} local filename local -i line_number local full_filename _Dbg_linespec_setup $n if [[ -n $full_filename ]] ; then if (( $line_number == 0 )) ; then _Dbg_msg "There is no line 0 to clear." else _Dbg_check_line $line_number "$full_filename" if (( $? == 0 )) ; then _Dbg_unset_brkpt "$full_filename" "$line_number" local -r found=$? if [[ $found != 0 ]] ; then _Dbg_msg "Removed $found breakpoint(s)." else _Dbg_msg "Didn't find any breakpoints to remove at $n." fi fi fi else _Dbg_file_not_read_in $filename fi}# list breakpoints and break condition.# If $1 is given just list those associated for that line._Dbg_do_list_brkpt() { local brkpt_num=${1:-''} eval "$_seteglob" if [[ -n $brkpt_num ]] ; then if [[ $brkpt_num != $int_pat ]]; then _Dbg_msg "Bad breakpoint number $brkpt_num." elif [[ -z ${_Dbg_brkpt_file[$brkpt_num]} ]] ; then _Dbg_msg "Breakpoint entry $brkpt_num is not set." else local -r -i i=$brkpt_num local source_file=${_Dbg_brkpt_file[$i]} source_file=$(_Dbg_adjust_filename "$source_file") _Dbg_msg "Num Type Disp Enb What" _Dbg_printf "%-3d breakpoint %-4s %-3s %s:%s" $i \ ${_Dbg_keep[${_Dbg_brkpt_onetime[$i]}]} \ ${_Dbg_yn[${_Dbg_brkpt_enable[$i]}]} \ $source_file ${_Dbg_brkpt_line[$i]} if [[ ${_Dbg_brkpt_cond[$i]} != '1' ]] ; then _Dbg_printf "\tstop only if %s" "${_Dbg_brkpt_cond[$i]}" fi _Dbg_print_brkpt_count ${_Dbg_brkpt_count[$i]} fi eval "$_resteglob" return fi if [ ${#_Dbg_brkpt_line[@]} != 0 ]; then local -i i _Dbg_msg "Num Type Disp Enb What" for (( i=1; (( i <= _Dbg_brkpt_max )) ; i++ )) ; do local source_file=${_Dbg_brkpt_file[$i]} if [[ -n ${_Dbg_brkpt_line[$i]} ]] ; then source_file=$(_Dbg_adjust_filename "$source_file") _Dbg_printf "%-3d breakpoint %-4s %-3s %s:%s" $i \ ${_Dbg_keep[${_Dbg_brkpt_onetime[$i]}]} \ ${_Dbg_yn[${_Dbg_brkpt_enable[$i]}]} \ $source_file ${_Dbg_brkpt_line[$i]} if [[ ${_Dbg_brkpt_cond[$i]} != '1' ]] ; then _Dbg_printf "\tstop only if %s" "${_Dbg_brkpt_cond[$i]}" fi if (( _Dbg_brkpt_count[$i] != 0 )) ; then _Dbg_print_brkpt_count ${_Dbg_brkpt_count[$i]} fi fi done else _Dbg_msg "No breakpoints have been set." fi}# clear all brkpts_Dbg_clear_all_brkpt() { local -i k for (( k=0; (( k < ${#_Dbg_filenames[@]} )) ; k++ )) ; do local filename=${_filename[$k]} local filevar="`_Dbg_file2var $filename`" local brkpt_a="_Dbg_brkpt_${filevar}" _Dbg_write_journal_eval "unset ${brkpt_a}[$k]" done _Dbg_write_journal_eval "_Dbg_brkpt_line=()" _Dbg_write_journal_eval "_Dbg_brkpt_cond=()" _Dbg_write_journal_eval "_Dbg_brkpt_file=()" _Dbg_write_journal_eval "_Dbg_brkpt_enable=()" _Dbg_write_journal_eval "_Dbg_brkpt_count=()" _Dbg_write_journal_eval "_Dbg_brkpt_onetime=()"}# Internal routine to a set breakpoint unconditonally. _Dbg_set_brkpt() { local source_file=$1 local -ir line=$2 local -ir is_temp=$3 local -r condition=${4:-1} local -r filevar="`_Dbg_file2var $source_file`" local val_str=`_Dbg_get_assoc_array_entry "_Dbg_brkpt_$filevar" $line` # Increment brkpt_max here because we are 1-origin ((_Dbg_brkpt_max++)) if [ -z "$val_str" ] ; then val_str=$_Dbg_brkpt_max else val_str="$val_str $_Dbg_brkpt_max" fi _Dbg_brkpt_line[$_Dbg_brkpt_max]=$line _Dbg_brkpt_file[$_Dbg_brkpt_max]="$source_file" _Dbg_brkpt_cond[$_Dbg_brkpt_max]="$condition" _Dbg_brkpt_onetime[$_Dbg_brkpt_max]=$is_temp _Dbg_brkpt_count[$_Dbg_brkpt_max]=0 _Dbg_brkpt_enable[$_Dbg_brkpt_max]=1 local dq_source_file=$(_Dbg_esc_dq "$source_file") local dq_condition=$(_Dbg_esc_dq "$condition") _Dbg_write_journal "_Dbg_brkpt_line[$_Dbg_brkpt_max]=$line" _Dbg_write_journal "_Dbg_brkpt_file[$_Dbg_brkpt_max]=\"$dq_source_file\"" _Dbg_write_journal "_Dbg_brkpt_cond[$_Dbg_brkpt_max]=\"$dq_condition\"" _Dbg_write_journal "_Dbg_brkpt_onetime[$_Dbg_brkpt_max]=$is_temp"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -