📄 dbg-sig.inc
字号:
# dbg-sig.inc - Bourne Again Shell Debugger Signal handling routines## Copyright (C) 2002, 2003, 2004, 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.# ==================== VARIABLES =======================================# The "set" options in effect ($-) before debugger was invoked.typeset _Dbg_old_setopts# Place to save debugged program's exit handler, if any.typeset _Dbg_old_EXIT_handler='' typeset BASHDB_RESTART_COMMAND=''typeset -i BASHDB_QUIT_ON_QUIT=0# Return code that debugged program reportstypeset -i _Dbg_program_exit_code=0# This is set to 1 if you want to debug debugger routines, i.e. routines# which start _Dbg_. But you better should know what you are doing# if you do this or else you may get into a recursive loop.typeset -i _Dbg_debug_debugger=0############################################################## Signal arrays: These are indexed by the signal number. ############################################################### Should we print that a signal was intercepted? # Each entry is "print" or "noprint" or null.typeset -a _Dbg_sig_print=()# Should we reentry the debugger command loop on receiving the signal? # Each entry is "stop" or "nostop" or null.typeset -a _Dbg_sig_stop=()# Should we show a traceback on receiving the signal? # Each entry is "stack" or "nostack" or null.typeset -a _Dbg_sig_show_stack=()# Should pass the signal to the user program?? # Each entry is the trap handler with some variables substituted.typeset -a _Dbg_sig_passthrough=()# Should pass the signal to the user program?? # Each entry is the trap handler with some variables substituted.typeset -i _Dbg_return_level=0# Place to save values of $1, $2, etc.typeset -a _Dbg_arg=()# ===================== FUNCTIONS =======================================# We come here after before statement is run. This is the function named# in trap SIGDEBUG.# Note: We have to be careful here in naming "local" variables. In contrast# to other places in the debugger, because of the read/eval loop, they are# in fact seen by those using the debugger. So in contrast to other "local"s# in the debugger, we prefer to preface these with _Dbg_._Dbg_debug_trap_handler() { ### The below is also copied below in _Dbg_sig_handler... ### Should put common stuff into a function. # Consider putting the following line(s) in a routine. # Ditto for the restore environment local -i _Dbg_debugged_exit_code=$? _Dbg_old_set_opts=$- shopt -s extdebug # Turn off line and variable trace listing if were not in our own debug # mode, and set our own PS4 for debugging inside the debugger (( !_Dbg_debug_debugger )) && set +x +v +u # If we are in our own routines -- these start with _bashdb -- then # return. if [[ ${FUNCNAME[1]} == _Dbg_* ]] && (( !_Dbg_debug_debugger )); then _Dbg_set_to_return_from_debugger 0 return 0 fi _Dbg_set_debugger_entry local -i _Dbg_rc=0 # Shift off "RETURN"; we do not need that any more. shift _Dbg_bash_command=$1 shift # Save values of $1 $2 $3 when debugged program was stopped # We use the loop below rather than _Dbg_set_args="(@)" because # we want to preserve embedded blanks in the arguments. local -i _Dbg_n=${#@} local -i _Dbg_i local -i _Dbg_arg_max=${#_Dbg_arg[@]} # If there has been a shift since the last time we entered, # it is possible that _Dbg_arg will contain too many values. # So remove those that have disappeared. for (( _Dbg_i=_Dbg_arg_max; _Dbg_i > _Dbg_n ; _Dbg_i-- )) ; do unset _Dbg_arg[$_Dbg_i] done # Populate _Dbg_args with $1, $2, etc. for (( _Dbg_i=1 ; _Dbg_n > 0; _Dbg_n-- )) ; do _Dbg_arg[$_Dbg_i]=$1 ((_Dbg_i++)) shift done unset _Dbg_arg[0] # Get rid of line number; makes array count # correct; also listing all _Dbg_arg works # like $*. # Read in the journal to pick up variable settings that might have # been left from a subshell. _Dbg_source_journal if (( $BASHDB_QUIT_LEVELS > 0 )) ; then _Dbg_do_quit $_Dbg_debugged_exit_code fi # if in step mode, decrement counter if ((_Dbg_steps >= 0)) ; then ((_Dbg_steps--)) _Dbg_write_journal "_Dbg_steps=$_Dbg_steps" fi # look for watchpoints. local -i _Dbg_i for (( _Dbg_i=0; _Dbg_i < _Dbg_watch_max ; _Dbg_i++ )) ; do if [ -n "${_Dbg_watch_exp[$_Dbg_i]}" ] \ && [[ ${_Dbg_watch_enable[_Dbg_i]} != 0 ]] ; then local new_val=`_Dbg_get_watch_exp_eval $_Dbg_i` local old_val=${_Dbg_watch_val[$_Dbg_i]} if [[ $old_val != $new_val ]] ; then ((_Dbg_watch_count[_Dbg_i]++)) _Dbg_msg "Watchpoint $i: ${_Dbg_watch_exp[$_Dbg_i]} changed:" _Dbg_msg " old value: '$old_val'" _Dbg_msg " new value: '$new_val'" _Dbg_print_source_line _Dbg_watch_val[$_Dbg_i]=$new_val _Dbg_cmdloop _Dbg_set_to_return_from_debugger 1 return $_Dbg_rc fi fi done # Run applicable action statement local entries=`_Dbg_get_assoc_array_entry "_Dbg_action_$_cur_filevar" $_curline` if [[ $entries != "" ]] ; then local -i _Dbg_i for _Dbg_i in $entries ; do if [[ ${_Dbg_action_enable[_Dbg_i]} != 0 ]] ; then . ${_Dbg_libdir}/dbg-set-d-vars.inc eval "${_Dbg_action_stmt[$_Dbg_i]}" fi done fi # check if breakpoint reached local -r entries=`_Dbg_get_assoc_array_entry "_Dbg_brkpt_$_cur_filevar" $_curline` if [[ $entries != "" ]] ; then local -i _Dbg_i for _Dbg_i in $entries ; do if [[ ${_Dbg_brkpt_enable[_Dbg_i]:0} != 0 ]] ; then local -i cond . ${_Dbg_libdir}/dbg-set-d-vars.inc eval let cond=${_Dbg_brkpt_cond[$_Dbg_i]:0} if [[ $cond != 0 ]] ; then ((_Dbg_brkpt_count[_Dbg_i]++)) if [[ ${_Dbg_brkpt_onetime[_Dbg_i]:0} == 1 ]] ; then _Dbg_stop_reason='at a breakpoint that has since been deleted' _Dbg_delete_brkpt_entry $_Dbg_i else _Dbg_stop_reason='at breakpoint' _Dbg_currentbp=$_Dbg_i _Dbg_msg \ "Breakpoint $_Dbg_i hit (${_Dbg_brkpt_count[$_Dbg_i]} times)." fi # We're sneaky and check commands_end because start could # legitimately be 0. if (( ${_Dbg_brkpt_commands_end[$_Dbg_i]} )) ; then # Run any commands associated with this breakpoint _Dbg_bp_commands $_Dbg_i fi _Dbg_print_source_line _Dbg_cmdloop # enter debugger _Dbg_set_to_return_from_debugger 1 return $_Dbg_rc fi fi done fi # next, check if step mode and no. of steps is up if ((_Dbg_steps == 0)); then _Dbg_stop_reason='after being stepped' _Dbg_print_source_line # _Dbg_msg "Stopped at line $_curline" _Dbg_cmdloop # enter debugger _Dbg_set_to_return_from_debugger 1 return $_Dbg_rc elif (( ${#FUNCNAME[@]} == _Dbg_return_level )) ; then # here because a trap RETURN _Dbg_stop_reason='on a return' _Dbg_return_level=0 _Dbg_print_source_line _Dbg_cmdloop # enter debugger _Dbg_set_to_return_from_debugger 1 return $_Dbg_rc elif (( -1 == _Dbg_return_level )) ; then # here because we are fielding a signal. _Dbg_stop_reason='on fielding signal' _Dbg_print_source_line _Dbg_cmdloop # enter debugger _Dbg_set_to_return_from_debugger 1 return $_Dbg_rc else if ((_Dbg_linetrace==1)) ; then if ((_Dbg_linetrace_delay)) ; then sleep $_Dbg_linetrace_delay fi _Dbg_print_linetrace fi fi _Dbg_set_to_return_from_debugger 1 return $_Dbg_inside_skip}# Cleanup routine: erase temp files before exiting._Dbg_cleanup() { rm $_Dbg_evalfile 2>/dev/null _Dbg_erase_journals _Dbg_restore_user_vars}# Somehow we can't put this in _Dbg_cleanup and have it work.# I am not sure why._Dbg_cleanup2() { _Dbg_erase_journals trap - EXIT}# The real way to leave this program._Dbg_do_quit() { local -i return_code=${1:-$_Dbg_program_exit_code} local -i desired_quit_levels=${2:-0} if (( desired_quit_levels == 0 \ || desired_quit_levels > BASH_SUBSHELL+1)) ; then ((desired_quit_levels=BASH_SUBSHELL+1)) fi ((BASHDB_QUIT_LEVELS+=desired_quit_levels)) # Reduce the number of recorded levels that we need to leave by # if BASHDB_QUIT_LEVELS is greater than 0. ((BASHDB_QUIT_LEVELS--)) ## write this to the next level up can read it. _Dbg_write_journal "BASHDB_QUIT_LEVELS=$BASHDB_QUIT_LEVELS" # Reset signal handlers to their default but only if # we are not in a subshell. if (( BASH_SUBSHELL == 0 )) ; then # If we were told to restart from deep down, restart instead of quit. if [ -n "$BASHDB_RESTART_COMMAND" ] ; then _Dbg_erase_journals _Dbg_save_state exec $BASHDB_RESTART_COMMAND fi _Dbg_cleanup trap - DEBUG # This is a hack we need. I am not sure why. trap "_Dbg_cleanup2" EXIT fi # And just when you thought we'd never get around to it... exit $return_code}# Save value of handler variable _Dbg_old_$sig_Dbg_save_handler() { local -r sig=$1 local old_handler='#unset#'; if [[ `trap -p $sig` ]] ; then old_handler=`trap -p $sig` fi if [[ $old_handler != '#unset#' ]] ; then local -a old_hand_a old_hand_a=($old_handler) old_handler=`_Dbg_subst_handler_var ${old_hand_a[2]}` local -r decl_cmd="typeset -r _Dbg_old_${sig}_handler='$old_handler'" eval $decl_cmd fi }# Adjust handler variables to take into account the fact that when we# call the handler we will have added another call before the user's# handler.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -