watchfunction()
watchfunction()
is a function that can be defined by the user; it is a function which will be run on each entry to DB::DB
; it gets the current package, filename, and line as its parameters.
The watchfunction can do anything it likes; it is executing in the debugger's context, so it has access to all of the debugger's internal data structures and functions.
watchfunction()
can control the debugger's actions. Any of the following will cause the debugger to return control to the user's program after watchfunction()
executes:
Returning a false value from the
watchfunction()
itself.Altering
$single
to a false value.Altering
$signal
to a false value.Turning off the
4
bit in$trace
(this also disables the check forwatchfunction()
. This can be done with$trace &= ~4;
GETTING READY TO EXECUTE COMMANDS
The debugger decides to take control if single-step mode is on, the t
command was entered, or the user generated a signal. If the program has fallen off the end, we set things up so that entering further commands won't cause trouble, and we say that the program is over.
Special check: if we're in package DB::fake
, we've gone through the END
block at least once. We set up everything so that we can continue to enter commands and have a valid context to be in.
If the program hasn't finished executing, we scan forward to the next executable line, print that out, build the prompt from the file and line number information, and print that.
If there's an action to be executed for the line we stopped at, execute it. If there are any preprompt actions, execute those as well.
WHERE ARE WE?
XXX Relocate this section?
The debugger normally shows the line corresponding to the current line of execution. Sometimes, though, we want to see the next line, or to move elsewhere in the file. This is done via the $incr
, $start
, and $max
variables.
$incr
controls by how many lines the current line should move forward after a command is executed. If set to -1, this indicates that the current line shouldn't change.
$start
is the current line. It is used for things like knowing where to move forwards or backwards from when doing an L
or -
command.
$max
tells the debugger where the last line of the current file is. It's used to terminate loops most often.
THE COMMAND LOOP
Most of DB::DB
is actually a command parsing and dispatch loop. It comes in two parts:
The outer part of the loop, starting at the
CMD
label. This loop reads a command and then executes it.The inner part of the loop, starting at the
PIPE
label. This part is wholly contained inside theCMD
block and only executes a command. Used to handle commands running inside a pager.
So why have two labels to restart the loop? Because sometimes, it's easier to have a command generate another command and then re-execute the loop to do the new command. This is faster, but perhaps a bit more convoluted.
The null command
A newline entered by itself means re-execute the last command. We grab the command out of $laststep
(where it was recorded previously), and copy it back into $cmd
to be executed below. If there wasn't any previous command, we'll do nothing below (no command will match). If there was, we also save it in the command history and fall through to allow the command parsing to pick it up.
COMMAND ALIASES
The debugger can create aliases for commands (these are stored in the %alias
hash). Before a command is executed, the command loop looks it up in the alias hash and substitutes the contents of the alias for the command, completely replacing it.
MAIN-LINE COMMANDS
All of these commands work up to and after the program being debugged has terminated.
Extended commands
Define your extended commands in %commands
at the top of the file. This section runs them.
q
- quit
Quit the debugger. This entails setting the $fall_off_end
flag, so we don't try to execute further, cleaning any restart-related stuff out of the environment, and executing with the last value of $?
.
t
- trace
Turn tracing on or off. Inverts the appropriate bit in $trace
(q.v.).
S
- list subroutines matching/not matching a pattern
Walks through %sub
, checking to see whether or not to print the name.
X
- list variables in current package
Since the V
command actually processes this, just change this to the appropriate V
command and fall through.
V
- list variables
Uses dumpvar.pl
to dump out the current values for selected variables.
x
- evaluate and print an expression
Hands the expression off to DB::eval
, setting it up to print the value via dumpvar.pl
instead of just printing it directly.
m
- print methods
Just uses DB::methods
to determine what methods are available.
f
- switch files
.
- return to last-executed line.
We set $incr
to -1 to indicate that the debugger shouldn't move ahead, and then we look up the line in the magical %dbline
hash.
-
- back one window
We change $start
to be one window back; if we go back past the first line, we set it to be the first line. We ser $incr
to put us back at the currently-executing line, and then put a l $start +
(list one window from $start
) in $cmd
to be executed later.
PRE-580 COMMANDS VS. NEW COMMANDS: a, A, b, B, h, l, L, M, o, O, P, v, w, W, <, <<, {, {{
In Perl 5.8.0, a realignment of the commands was done to fix up a number of problems, most notably that the default case of several commands destroying the user's work in setting watchpoints, actions, etc. We wanted, however, to retain the old commands for those who were used to using them or who preferred them. At this point, we check for the new commands and call cmd_wrapper
to deal with them instead of processing them in-line.
y
- List lexicals in higher scope
Uses PadWalker
to find the lexicals supplied as arguments in a scope above the current one and then displays then using dumpvar.pl
.
COMMANDS NOT WORKING AFTER PROGRAM ENDS
All of the commands below this point don't work after the program being debugged has ended. All of them check to see if the program has ended; this allows the commands to be relocated without worrying about a 'line of demarcation' above which commands can be entered anytime, and below which they can't.
n
- single step, but don't trace down into subs
Done by setting $single
to 2, which forces subs to execute straight through when entered (see DB::sub
). We also save the n
command in $laststep
, so a null command knows what to re-execute.
s
- single-step, entering subs
Sets $single
to 1, which causes DB::sub
to continue tracing inside subs. Also saves s
as $lastcmd
.
c
- run continuously, setting an optional breakpoint
Most of the code for this command is taken up with locating the optional breakpoint, which is either a subroutine name or a line number. We set the appropriate one-time-break in @dbline
and then turn off single-stepping in this and all call levels above this one.
r
- return from a subroutine
For r
to work properly, the debugger has to stop execution again immediately after the return is executed. This is done by forcing single-stepping to be on in the call level above the current one. If we are printing return values when a r
is executed, set $doret
appropriately, and force us out of the command loop.
T
- stack trace
Just calls DB::print_trace
.
w
- List window around current line.
Just calls DB::cmd_w
.
W
- watch-expression processing.
Just calls DB::cmd_W
.
/
- search forward for a string in the source
We take the argument and treat it as a pattern. If it turns out to be a bad one, we return the error we got from trying to eval
it and exit. If not, we create some code to do the search and eval
it so it can't mess us up.
?
- search backward for a string in the source
Same as for /
, except the loop runs backwards.
$rc
- Recall command
Manages the commands in @hist
(which is created if Term::ReadLine
reports that the terminal supports history). It find the the command required, puts it into $cmd
, and redoes the loop to execute it.
$sh$sh
- system()
command
Calls the DB::system()
to handle the command. This keeps the STDIN
and STDOUT
from getting messed up.
$rc pattern $rc
- Search command history
Another command to manipulate @hist
: this one searches it with a pattern. If a command is found, it is placed in $cmd
and executed via redo
.
$sh
- Invoke a shell
Uses DB::system
to invoke a shell.
$sh command
- Force execution of a command in a shell
Like the above, but the command is passed to the shell. Again, we use DB::system
to avoid problems with STDIN
and STDOUT
.
H
- display commands in history
Prints the contents of @hist
(if any).
man, doc, perldoc
- look up documentation
Just calls runman()
to print the appropriate document.
p
- print
Builds a print EXPR
expression in the $cmd
; this will get executed at the bottom of the loop.
=
- define command alias
Manipulates %alias
to add or list command aliases.
source
- read commands from a file.
Opens a lexical filehandle and stacks it on @cmdfhs
; DB::readline
will pick it up.
save
- send current history to a file
Takes the complete history, (not the shrunken version you see with H
), and saves it to the given filename, so it can be replayed using source
.
Note that all ^(save|source)
's are commented out with a view to minimise recursion.
R
- restart
Restart the debugger session.
rerun
- rerun the current session
Return to any given position in the true-history list
|, ||
- pipe output through the pager.
For |
, we save OUT
(the debugger's output filehandle) and STDOUT
(the program's standard output). For ||
, we only save OUT
. We open a pipe to the pager (restoring the output filehandles if this fails). If this is the |
command, we also set up a SIGPIPE
handler which will simply set $signal
, sending us back into the debugger.
We then trim off the pipe symbols and redo
the command loop at the PIPE
label, causing us to evaluate the command in $cmd
without reading another.
END OF COMMAND PARSING
Anything left in $cmd
at this point is a Perl expression that we want to evaluate. We'll always evaluate in the user's context, and fully qualify any variables we might want to address in the DB
package.
POST-COMMAND PROCESSING
After each command, we check to see if the command output was piped anywhere. If so, we go through the necessary code to unhook the pipe and go back to our standard filehandles for input and output.
COMMAND LOOP TERMINATION
When commands have finished executing, we come here. If the user closed the input filehandle, we turn on $fall_off_end
to emulate a q
command. We evaluate any post-prompt items. We restore $@
, $!
, $^E
, $,
, $/
, $\
, and $^W
, and return a null list as expected by the Perl interpreter. The interpreter will then execute the next line and then return control to us again.
NAME
Devel::Command - Perl extension to automatically load and register debugger command extensions
SYNOPSIS
# in .perldb:
use Devel::Command;
sub afterinit {
Devel::Command->install;
}
DESCRIPTION
Devel::Command
provides a simple means to extend the Perl debugger with custom commands. It uses Module::Pluggable
to locate the command modules, and installs these into a debugger global (%DB::commands
) where they can be found by a modified version of DB::DB
.
SEE ALSO
perl5db.pl
, notably the documentation for the DB::DB
subroutine.
AUTHOR
Joe McMahon, <mcmahon@ibiblio.org>
COPYRIGHT AND LICENSE
Copyright (C) 2005 by Joe McMahon
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available.