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 for watchfunction(). 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 the CMD 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.