=head1 NAME perl5db.pl - the perl debugger =head1 SYNOPSIS perl -d your_Perl_script =head1 DESCRIPTION After this routine is over, we don't have user code executing in the debugger's context, so we can use C freely. =cut ############################################## Begin lexical danger zone # 'my' variables used here could leak into (that is, be visible in) # the context that the code being evaluated is executing in. This means that # the code could modify the debugger's variables. # # Fiddling with the debugger's context could be Bad. We insulate things as # much as we can. sub eval { # 'my' would make it visible from user code # but so does local! --tchrist # Remember: this localizes @DB::res, not @main::res. local @res; { # Try to keep the user code from messing with us. Save these so that # even if the eval'ed code changes them, we can put them back again. # Needed because the user could refer directly to the debugger's # package globals (and any 'my' variables in this containing scope) # inside the eval(), and we want to try to stay safe. local $otrace = $trace; local $osingle = $single; local $od = $^D; # Untaint the incoming eval() argument. { ($evalarg) = $evalarg =~ /(.*)/s; } # $usercontext built in DB::DB near the comment # "set up the context for DB::eval ..." # Evaluate and save any results. @res = eval "$usercontext $evalarg;\n"; # '\n' for nice recursive debug # Restore those old values. $trace = $otrace; $single = $osingle; $^D = $od; } # Save the current value of $@, and preserve it in the debugger's copy # of the saved precious globals. my $at = $@; # Since we're only saving $@, we only have to localize the array element # that it will be stored in. local $saved[0]; # Preserve the old value of $@ eval { &DB::save }; # Now see whether we need to report an error back to the user. if ($at) { local $\ = ''; print $OUT $at; } # Display as required by the caller. $onetimeDump and $onetimedumpDepth # are package globals. elsif ($onetimeDump) { if ( $onetimeDump eq 'dump' ) { local $option{dumpDepth} = $onetimedumpDepth if defined $onetimedumpDepth; dumpit( $OUT, \@res ); } elsif ( $onetimeDump eq 'methods' ) { methods( $res[0] ); } } ## end elsif ($onetimeDump) @res; } ## end sub eval ############################################## End lexical danger zone # After this point it is safe to introduce lexicals. # The code being debugged will be executing in its own context, and # can't see the inside of the debugger. # # However, one should not overdo it: leave as much control from outside as # possible. If you make something a lexical, it's not going to be addressable # from outside the debugger even if you know its name. # This file is automatically included if you do perl -d. # It's probably not useful to include this yourself. # # Before venturing further into these twisty passages, it is # wise to read the perldebguts man page or risk the ire of dragons. # # (It should be noted that perldebguts will tell you a lot about # the underlying mechanics of how the debugger interfaces into the # Perl interpreter, but not a lot about the debugger itself. The new # comments in this code try to address this problem.) # Note that no subroutine call is possible until &DB::sub is defined # (for subroutines defined outside of the package DB). In fact the same is # true if $deep is not defined. # Enhanced by ilya@math.ohio-state.edu (Ilya Zakharevich) # modified Perl debugger, to be run from Emacs in perldb-mode # Ray Lischner (uunet!mntgfx!lisch) as of 5 Nov 1990 # Johan Vromans -- upgrade to 4.0 pl 10 # Ilya Zakharevich -- patches after 5.001 (and some before ;-) # (We have made efforts to clarify the comments in the change log # in other places; some of them may seem somewhat obscure as they # were originally written, and explaining them away from the code # in question seems conterproductive.. -JM) =head1 DEBUGGER INITIALIZATION The debugger starts up in phases. =head2 BASIC SETUP First, it initializes the environment it wants to run in: turning off warnings during its own compilation, defining variables which it will need to avoid warnings later, setting itself up to not exit when the program terminates, and defaulting to printing return values for the C command. =cut # Needed for the statement after exec(): # # This BEGIN block is simply used to switch off warnings during debugger # compiliation. Probably it would be better practice to fix the warnings, # but this is how it's done at the moment. BEGIN { $ini_warn = $^W; $^W = 0; } # Switch compilation warnings off until another BEGIN. # test if assertions are supported and actived: BEGIN { $ini_assertion = eval "sub asserting_test : assertion {1}; 1"; # $ini_assertion = undef => assertions unsupported, # " = 1 => assertions supported # print "\$ini_assertion=$ini_assertion\n"; } local ($^W) = 0; # Switch run-time warnings off during init. =head2 THREADS SUPPORT If we are running under a threaded Perl, we require threads and threads::shared if the environment variable C is set, to enable proper threaded debugger control. C<-dt> can also be used to set this. Each new thread will be announced and the debugger prompt will always inform you of each new thread created. It will also indicate the thread id in which we are currently running within the prompt like this: [tid] DB<$i> Where C<[tid]> is an integer thread id and C<$i> is the familiar debugger command prompt. The prompt will show: C<[0]> when running under threads, but not actually in a thread. C<[tid]> is consistent with C usage. While running under threads, when you set or delete a breakpoint (etc.), this will apply to all threads, not just the currently running one. When you are in a currently executing thread, you will stay there until it completes. With the current implementation it is not currently possible to hop from one thread to another. The C and C commands are currently fairly minimal - see C and C. Note that threading support was built into the debugger as of Perl version C<5.8.6> and debugger version C<1.2.8>. =cut BEGIN { # ensure we can share our non-threaded variables or no-op if ($ENV{PERL5DB_THREADED}) { require threads; require threads::shared; import threads::shared qw(share); $DBGR; share(\$DBGR); lock($DBGR); print "Threads support enabled\n"; } else { *lock = sub(*) {}; *share = sub(*) {}; } } # This would probably be better done with "use vars", but that wasn't around # when this code was originally written. (Neither was "use strict".) And on # the principle of not fiddling with something that was working, this was # left alone. warn( # Do not ;-) # These variables control the execution of 'dumpvar.pl'. $dumpvar::hashDepth, $dumpvar::arrayDepth, $dumpvar::dumpDBFiles, $dumpvar::dumpPackages, $dumpvar::quoteHighBit, $dumpvar::printUndef, $dumpvar::globPrint, $dumpvar::usageOnly, # used to save @ARGV and extract any debugger-related flags. @ARGS, # used to control die() reporting in diesignal() $Carp::CarpLevel, # used to prevent multiple entries to diesignal() # (if for instance diesignal() itself dies) $panic, # used to prevent the debugger from running nonstop # after a restart $second_time, ) if 0; foreach my $k (keys (%INC)) { &share(\$main::{'_<'.$filename}); }; # Command-line + PERLLIB: # Save the contents of @INC before they are modified elsewhere. @ini_INC = @INC; # This was an attempt to clear out the previous values of various # trapped errors. Apparently it didn't help. XXX More info needed! # $prevwarn = $prevdie = $prevbus = $prevsegv = ''; # Does not help?! # We set these variables to safe values. We don't want to blindly turn # off warnings, because other packages may still want them. $trace = $signal = $single = 0; # Uninitialized warning suppression # (local $^W cannot help - other packages!). # Default to not exiting when program finishes; print the return # value when the 'r' command is used to return from a subroutine. $inhibit_exit = $option{PrintRet} = 1; =head1 OPTION PROCESSING The debugger's options are actually spread out over the debugger itself and C; some of these are variables to be set, while others are subs to be called with a value. To try to make this a little easier to manage, the debugger uses a few data structures to define what options are legal and how they are to be processed. First, the C<@options> array defines the I of all the options that are to be accepted. =cut @options = qw( CommandSet hashDepth arrayDepth dumpDepth DumpDBFiles DumpPackages DumpReused compactDump veryCompact quote HighBit undefPrint globPrint PrintRet UsageOnly frame AutoTrace TTY noTTY ReadLine NonStop LineInfo maxTraceLen recallCommand ShellBang pager tkRunning ornaments signalLevel warnLevel dieLevel inhibit_exit ImmediateStop bareStringify CreateTTY RemotePort windowSize DollarCaretP OnlyAssertions WarnAssertions ); @RememberOnROptions = qw(DollarCaretP OnlyAssertions); =pod Second, C lists the variables that each option uses to save its state. =cut %optionVars = ( hashDepth => \$dumpvar::hashDepth, arrayDepth => \$dumpvar::arrayDepth, CommandSet => \$CommandSet, DumpDBFiles => \$dumpvar::dumpDBFiles, DumpPackages => \$dumpvar::dumpPackages, DumpReused => \$dumpvar::dumpReused, HighBit => \$dumpvar::quoteHighBit, undefPrint => \$dumpvar::printUndef, globPrint => \$dumpvar::globPrint, UsageOnly => \$dumpvar::usageOnly, CreateTTY => \$CreateTTY, bareStringify => \$dumpvar::bareStringify, frame => \$frame, AutoTrace => \$trace, inhibit_exit => \$inhibit_exit, maxTraceLen => \$maxtrace, ImmediateStop => \$ImmediateStop, RemotePort => \$remoteport, windowSize => \$window, WarnAssertions => \$warnassertions, ); =pod Third, C<%optionAction> defines the subroutine to be called to process each option. =cut %optionAction = ( compactDump => \&dumpvar::compactDump, veryCompact => \&dumpvar::veryCompact, quote => \&dumpvar::quote, TTY => \&TTY, noTTY => \&noTTY, ReadLine => \&ReadLine, NonStop => \&NonStop, LineInfo => \&LineInfo, recallCommand => \&recallCommand, ShellBang => \&shellBang, pager => \&pager, signalLevel => \&signalLevel, warnLevel => \&warnLevel, dieLevel => \&dieLevel, tkRunning => \&tkRunning, ornaments => \&ornaments, RemotePort => \&RemotePort, DollarCaretP => \&DollarCaretP, OnlyAssertions=> \&OnlyAssertions, ); =pod Last, the C<%optionRequire> notes modules that must be Cd if an option is used. =cut # Note that this list is not complete: several options not listed here # actually require that dumpvar.pl be loaded for them to work, but are # not in the table. A subsequent patch will correct this problem; for # the moment, we're just recommenting, and we are NOT going to change # function. %optionRequire = ( compactDump => 'dumpvar.pl', veryCompact => 'dumpvar.pl', quote => 'dumpvar.pl', ); =pod There are a number of initialization-related variables which can be set by putting code to set them in a BEGIN block in the C environment variable. These are: =over 4 =item C<$rl> - readline control XXX needs more explanation =item C<$warnLevel> - whether or not debugger takes over warning handling =item C<$dieLevel> - whether or not debugger takes over die handling =item C<$signalLevel> - whether or not debugger takes over signal handling =item C<$pre> - preprompt actions (array reference) =item C<$post> - postprompt actions (array reference) =item C<$pretype> =item C<$CreateTTY> - whether or not to create a new TTY for this debugger =item C<$CommandSet> - which command set to use (defaults to new, documented set) =back =cut # These guys may be defined in $ENV{PERL5DB} : $rl = 1 unless defined $rl; $warnLevel = 1 unless defined $warnLevel; $dieLevel = 1 unless defined $dieLevel; $signalLevel = 1 unless defined $signalLevel; $pre = [] unless defined $pre; $post = [] unless defined $post; $pretype = [] unless defined $pretype; $CreateTTY = 3 unless defined $CreateTTY; $CommandSet = '580' unless defined $CommandSet; share($rl); share($warnLevel); share($dieLevel); share($signalLevel); share($pre); share($post); share($pretype); share($rl); share($CreateTTY); share($CommandSet); =pod The default C, C, and C handlers are set up. =cut warnLevel($warnLevel); dieLevel($dieLevel); signalLevel($signalLevel); =pod The pager to be used is needed next. We try to get it from the environment first. if it's not defined there, we try to find it in the Perl C. If it's not there, we default to C. We then call the C function to save the pager name. =cut # This routine makes sure $pager is set up so that '|' can use it. pager( # If PAGER is defined in the environment, use it. defined $ENV{PAGER} ? $ENV{PAGER} # If not, see if Config.pm defines it. : eval { require Config } && defined $Config::Config{pager} ? $Config::Config{pager} # If not, fall back to 'more'. : 'more' ) unless defined $pager; =pod We set up the command to be used to access the man pages, the command recall character (C unless otherwise defined) and the shell escape character (C unless otherwise defined). Yes, these do conflict, and neither works in the debugger at the moment. =cut setman(); # Set up defaults for command recall and shell escape (note: # these currently don't work in linemode debugging). &recallCommand("!") unless defined $prc; &shellBang("!") unless defined $psh; =pod We then set up the gigantic string containing the debugger help. We also set the limit on the number of arguments we'll display during a trace. =cut sethelp(); # If we didn't get a default for the length of eval/stack trace args, # set it here. $maxtrace = 400 unless defined $maxtrace; =head2 SETTING UP THE DEBUGGER GREETING The debugger I helps to inform the user how many debuggers are running, and whether the current debugger is the primary or a child. If we are the primary, we just hang onto our pid so we'll have it when or if we start a child debugger. If we are a child, we'll set things up so we'll have a unique greeting and so the parent will give us our own TTY later. We save the current contents of the C environment variable because we mess around with it. We'll also need to hang onto it because we'll need it if we restart. Child debuggers make a label out of the current PID structure recorded in PERLDB_PIDS plus the new PID. They also mark themselves as not having a TTY yet so the parent will give them one later via C. =cut # Save the current contents of the environment; we're about to # much with it. We'll need this if we have to restart. $ini_pids = $ENV{PERLDB_PIDS}; if ( defined $ENV{PERLDB_PIDS} ) { # We're a child. Make us a label out of the current PID structure # recorded in PERLDB_PIDS plus our (new) PID. Mark us as not having # a term yet so the parent will give us one later via resetterm(). $pids = "[$ENV{PERLDB_PIDS}]"; $ENV{PERLDB_PIDS} .= "->$$"; $term_pid = -1; } ## end if (defined $ENV{PERLDB_PIDS... else { # We're the parent PID. Initialize PERLDB_PID in case we end up with a # child debugger, and mark us as the parent, so we'll know to set up # more TTY's is we have to. $ENV{PERLDB_PIDS} = "$$"; $pids = "{pid=$$}"; $term_pid = $$; } $pidprompt = ''; # Sets up $emacs as a synonym for $slave_editor. *emacs = $slave_editor if $slave_editor; # May be used in afterinit()... =head2 READING THE RC FILE The debugger will read a file of initialization options if supplied. If running interactively, this is C<.perldb>; if not, it's C. =cut # As noted, this test really doesn't check accurately that the debugger # is running at a terminal or not. if ( -e "/dev/tty" ) { # this is the wrong metric! $rcfile = ".perldb"; } else { $rcfile = "perldb.ini"; } =pod The debugger does a safety test of the file to be read. It must be owned either by the current user or root, and must only be writable by the owner. =cut # This wraps a safety test around "do" to read and evaluate the init file. # # This isn't really safe, because there's a race # between checking and opening. The solution is to # open and fstat the handle, but then you have to read and # eval the contents. But then the silly thing gets # your lexical scope, which is unfortunate at best. sub safe_do { my $file = shift; # Just exactly what part of the word "CORE::" don't you understand? local $SIG{__WARN__}; local $SIG{__DIE__}; unless ( is_safe_file($file) ) { CORE::warn < command is invoked, it tries to capture all of the state it can into environment variables, and then sets C. When we start executing again, we check to see if C is there; if so, we reload all the information that the R command stuffed into the environment variables. PERLDB_RESTART - flag only, contains no restart data itself. PERLDB_HIST - command history, if it's available PERLDB_ON_LOAD - breakpoints set by the rc file PERLDB_POSTPONE - subs that have been loaded/not executed, and have actions PERLDB_VISITED - files that had breakpoints PERLDB_FILE_... - breakpoints for a file PERLDB_OPT - active options PERLDB_INC - the original @INC PERLDB_PRETYPE - preprompt debugger actions PERLDB_PRE - preprompt Perl code PERLDB_POST - post-prompt Perl code PERLDB_TYPEAHEAD - typeahead captured by readline() We chug through all these variables and plug the values saved in them back into the appropriate spots in the debugger. =cut if ( exists $ENV{PERLDB_RESTART} ) { # We're restarting, so we don't need the flag that says to restart anymore. delete $ENV{PERLDB_RESTART}; # $restart = 1; @hist = get_list('PERLDB_HIST'); %break_on_load = get_list("PERLDB_ON_LOAD"); %postponed = get_list("PERLDB_POSTPONE"); share(@hist); share(@truehist); share(%break_on_load); share(%postponed); # restore breakpoints/actions my @had_breakpoints = get_list("PERLDB_VISITED"); for ( 0 .. $#had_breakpoints ) { my %pf = get_list("PERLDB_FILE_$_"); $postponed_file{ $had_breakpoints[$_] } = \%pf if %pf; } # restore options my %opt = get_list("PERLDB_OPT"); my ( $opt, $val ); while ( ( $opt, $val ) = each %opt ) { $val =~ s/[\\\']/\\$1/g; parse_options("$opt'$val'"); } # restore original @INC @INC = get_list("PERLDB_INC"); @ini_INC = @INC; # return pre/postprompt actions and typeahead buffer $pretype = [ get_list("PERLDB_PRETYPE") ]; $pre = [ get_list("PERLDB_PRE") ]; $post = [ get_list("PERLDB_POST") ]; @typeahead = get_list( "PERLDB_TYPEAHEAD", @typeahead ); } ## end if (exists $ENV{PERLDB_RESTART... =head2 SETTING UP THE TERMINAL Now, we'll decide how the debugger is going to interact with the user. If there's no TTY, we set the debugger to run non-stop; there's not going to be anyone there to enter commands. =cut if ($notty) { $runnonstop = 1; share($runnonstop); } =pod If there is a TTY, we have to determine who it belongs to before we can proceed. If this is a slave editor or graphical debugger (denoted by the first command-line switch being '-emacs'), we shift this off and set C<$rl> to 0 (XXX ostensibly to do straight reads). =cut else { # Is Perl being run from a slave editor or graphical debugger? # If so, don't use readline, and set $slave_editor = 1. $slave_editor = ( ( defined $main::ARGV[0] ) and ( $main::ARGV[0] eq '-emacs' ) ); $rl = 0, shift(@main::ARGV) if $slave_editor; #require Term::ReadLine; =pod We then determine what the console should be on various systems: =over 4 =item * Cygwin - We use C instead of a separate device. =cut if ( $^O eq 'cygwin' ) { # /dev/tty is binary. use stdin for textmode undef $console; } =item * Unix - use C. =cut elsif ( -e "/dev/tty" ) { $console = "/dev/tty"; } =item * Windows or MSDOS - use C. =cut elsif ( $^O eq 'dos' or -e "con" or $^O eq 'MSWin32' ) { $console = "con"; } =item * MacOS - use C if this is the MPW version; C if not. Note that Mac OS X returns C, not C. Also note that the debugger doesn't do anything special for C. Maybe it should. =cut elsif ( $^O eq 'MacOS' ) { if ( $MacPerl::Version !~ /MPW/ ) { $console = "Dev:Console:Perl Debug"; # Separate window for application } else { $console = "Dev:Console"; } } ## end elsif ($^O eq 'MacOS') =item * VMS - use C. =cut else { # everything else is ... $console = "sys\$command"; } =pod =back Several other systems don't use a specific console. We C for those (Windows using a slave editor/graphical debugger, NetWare, OS/2 with a slave editor, Epoc). =cut if ( ( $^O eq 'MSWin32' ) and ( $slave_editor or defined $ENV{EMACS} ) ) { # /dev/tty is binary. use stdin for textmode $console = undef; } if ( $^O eq 'NetWare' ) { # /dev/tty is binary. use stdin for textmode $console = undef; } # In OS/2, we need to use STDIN to get textmode too, even though # it pretty much looks like Unix otherwise. if ( defined $ENV{OS2_SHELL} and ( $slave_editor or $ENV{WINDOWID} ) ) { # In OS/2 $console = undef; } # EPOC also falls into the 'got to use STDIN' camp. if ( $^O eq 'epoc' ) { $console = undef; } =pod If there is a TTY hanging around from a parent, we use that as the console. =cut $console = $tty if defined $tty; =head2 SOCKET HANDLING The debugger is capable of opening a socket and carrying out a debugging session over the socket. If C was defined in the options, the debugger assumes that it should try to start a debugging session on that port. It builds the socket and then tries to connect the input and output filehandles to it. =cut # Handle socket stuff. if ( defined $remoteport ) { # If RemotePort was defined in the options, connect input and output # to the socket. require IO::Socket; $OUT = new IO::Socket::INET( Timeout => '10', PeerAddr => $remoteport, Proto => 'tcp', ); if ( !$OUT ) { die "Unable to connect to remote host: $remoteport\n"; } $IN = $OUT; } ## end if (defined $remoteport) =pod If no C was defined, and we want to create a TTY on startup, this is probably a situation where multiple debuggers are running (for example, a backticked command that starts up another debugger). We create a new IN and OUT filehandle, and do the necessary mojo to create a new TTY if we know how and if we can. =cut # Non-socket. else { # Two debuggers running (probably a system or a backtick that invokes # the debugger itself under the running one). create a new IN and OUT # filehandle, and do the necessary mojo to create a new tty if we # know how, and we can. create_IN_OUT(4) if $CreateTTY & 4; if ($console) { # If we have a console, check to see if there are separate ins and # outs to open. (They are assumed identiical if not.) my ( $i, $o ) = split /,/, $console; $o = $i unless defined $o; # read/write on in, or just read, or read on STDIN. open( IN, "+<$i" ) || open( IN, "<$i" ) || open( IN, "<&STDIN" ); # read/write/create/clobber out, or write/create/clobber out, # or merge with STDERR, or merge with STDOUT. open( OUT, "+>$o" ) || open( OUT, ">$o" ) || open( OUT, ">&STDERR" ) || open( OUT, ">&STDOUT" ); # so we don't dongle stdout } ## end if ($console) elsif ( not defined $console ) { # No console. Open STDIN. open( IN, "<&STDIN" ); # merge with STDERR, or with STDOUT. open( OUT, ">&STDERR" ) || open( OUT, ">&STDOUT" ); # so we don't dongle stdout $console = 'STDIN/OUT'; } ## end elsif (not defined $console) # Keep copies of the filehandles so that when the pager runs, it # can close standard input without clobbering ours. $IN = \*IN, $OUT = \*OUT if $console or not defined $console; } ## end elsif (from if(defined $remoteport)) # Unbuffer DB::OUT. We need to see responses right away. my $previous = select($OUT); $| = 1; # for DB::OUT select($previous); # Line info goes to debugger output unless pointed elsewhere. # Pointing elsewhere makes it possible for slave editors to # keep track of file and position. We have both a filehandle # and a I/O description to keep track of. $LINEINFO = $OUT unless defined $LINEINFO; $lineinfo = $console unless defined $lineinfo; # share($LINEINFO); # <- unable to share globs share($lineinfo); # =pod To finish initialization, we show the debugger greeting, and then call the C subroutine if there is one. =cut # Show the debugger greeting. $header =~ s/.Header: ([^,]+),v(\s+\S+\s+\S+).*$/$1$2/; unless ($runnonstop) { local $\ = ''; local $, = ''; if ( $term_pid eq '-1' ) { print $OUT "\nDaughter DB session started...\n"; } else { print $OUT "\nLoading DB routines from $header\n"; print $OUT ( "Editor support ", $slave_editor ? "enabled" : "available", ".\n" ); print $OUT "\nEnter h or `h h' for help, or `$doccmd perldebug' for more help.\n\n"; } ## end else [ if ($term_pid eq '-1') } ## end unless ($runnonstop) } ## end else [ if ($notty) # XXX This looks like a bug to me. # Why copy to @ARGS and then futz with @args? @ARGS = @ARGV; for (@args) { # Make sure backslashes before single quotes are stripped out, and # keep args unless they are numeric (XXX why?) # s/\'/\\\'/g; # removed while not justified understandably # s/(.*)/'$1'/ unless /^-?[\d.]+$/; # ditto } # If there was an afterinit() sub defined, call it. It will get # executed in our scope, so it can fiddle with debugger globals. if ( defined &afterinit ) { # May be defined in $rcfile &afterinit(); } # Inform us about "Stack dump during die enabled ..." in dieLevel(). $I_m_init = 1;