Perl provides special debugging hooks at both compile
time and run time for creating debugging environments such as the
standard debugger. These hooks are not to be confused with the
perl -D options, which are usable only if your
Perl was built with -DDEBUGGING
support.
For example, whenever you call Perl's built-in
caller
function from the package
DB
, the arguments that the corresponding stack
frame was called with are copied to the the
@DB::args
array. When you invoke Perl with the
-d
switch, the following additional features
are enabled:
Perl inserts the contents of
$ENV{PERL5DB}
(or BEGIN {require
'perl5db.pl'}
if not present) before the first line of
your program.
The array @{"_<$filename"}
holds the
lines of $filename
for all files compiled by
Perl. The same for eval
ed strings that contain
subroutines or are currently being executed. The
$filename
for eval
ed strings
looks like (eval 34)
. Code assertions in
regular expressions look like (re_eval
19)
.
The hash %{"_<$filename"}
contains
breakpoints and actions keyed by line number. You can set
individual entries as opposed to the whole hash. Perl only cares
about Boolean truth here, although the values used by
perl5db.pl have the form
"$break_condition $action
". Values in this
hash are magical in numeric context: they are zeros if the line is
not breakable.
The same holds for evaluated strings that contain
subroutines or are currently being executed. The
$filename
for eval
ed strings
looks like (eval 34)
or (re_eval
19)
.
The scalar ${"_<$filename"}
contains
"_<$filename
". This is also the case for
evaluated strings that contain subroutines or are currently being
executed. The $filename
for
eval
ed strings looks like (eval
34)
or (re_eval 19)
.
After each require
d file is compiled, but
before it is executed,
DB::postponed(*{"_<$filename"})
is called if
the subroutine DB::postponed
exists. Here, the
$filename
is the expanded name of the
require
d file, as found in the values of
%INC
.
After each subroutine subname
is
compiled, the existence of
$DB::postponed{
subname
}
is checked. If this key exists,
DB::postponed(
subname
)
is called if the DB::postponed
subroutine also
exists.
A hash %DB::sub
is maintained, whose keys
are subroutine names and whose values have the form
filename
:startline-endline
.
filename
has the form (eval
34)
for subroutines defined inside
eval
s, or (re_eval 19)
for
those within regular expression code assertions.
When the execution of your program reaches a point that
might hold a breakpoint, the DB::DB()
subroutine is called if any of the variables
$DB::trace
, $DB::single
, or
$DB::signal
is true. These variables are not
local
izable. This feature is disabled when
executing inside DB::DB()
, including functions
called from it unless $^D & (1<<30)
holds true.
When execution of the program reaches a subroutine call, a
call to
&DB::sub(
args
)
is made instead, with $DB::sub
holding the name
of the called subroutine. This doesn't happen if the subroutine
was compiled in the DB
package.
Note that if &DB::sub
needs external data
for it to work, no subroutine call is possible until this is done. For
the standard debugger, the $DB::deep
variable (how
many levels of recursion deep into the debugger you can go before a
mandatory break) gives an example of such a dependency.
The minimal working debugger consists of one line:
sub DB::DB {}
which, since it does nothing whatsoever, can easily be defined
via the PERL5DB
environment variable:
% PERL5DB="sub DB::DB {}" perl -d your-program
Another tiny debugger, slightly more useful, could be created like this:
sub DB::DB {print ++$i; scalar <STDIN>}
This little debugger would print the sequential number of each encountered statement and would wait for you to hit a newline before continuing.
The following debugger, small though it may appear, is really quite functional:
{ package DB; sub DB {} sub sub {print ++$i, " $sub "; &$sub} }
It prints the sequential number of the subroutine call and the
name of the called subroutine. Note that
&DB::sub
must be compiled from the package
DB
, as we've done here.
If you base your new debugger on the current debugger, there
are some hooks that can help you customize it. At startup, the
debugger reads your init file from the current directory or your
home directory. After the file is read, the debugger reads the
PERLDB_OPTS
environment variable and parses this
as the remainder of an O …
line such as you might
enter at the debugger prompt.
The debugger also maintains magical internal variables, such
as @DB::dbline
, %DB::dbline
,
which are aliases for
@{":::_<
current_file
"}
%{"::_<
current_file
"}
.
Here current_file
is the currently
selected file, either explicitly chosen with the debugger's
f
command or implicitly by flow of
execution.
Some functions can help with customization.
DB::parse_options(
STRING
)
parses a line like the O
option.
DB::dump_trace(
SKIP
[
,
COUNT
])
skips the
specified number of frames and returns a list containing information
about the calling frames (all of them, if
COUNT
is missing). Each entry is a
reference to a hash with keys "context
" (either
., $
, or @
),
"sub
" (subroutine name, or info about
eval
), "args
"
(undef
or a reference to an array),
"file
", and "line
".
DB::print_trace(
FH
,
SKIP
[
,
COUNT
[
,
SHORT
]])
prints
formatted info about caller frames to the supplied filehandle. The
last two functions may be convenient as arguments to the debugger's
<
and <<
commands.
You don't need to learn all that--most of us haven't. In fact,
when we need to debug a program, we usually just insert a few
print
statements here and there and rerun the
program.
On our better days, we'll even remember to turn on warnings
first. That often spotlights the problem right away, thus saving a
great deal of wear and tear on our hair (what's left of it). But
when that doesn't work, it's nice to know that, waiting for you
patiently behind that -d
switch, there is a
lovely debugger that can do darn near anything
except find your bug for you.
But if you're going to remember one thing about customizing the debugger, perhaps it is this: don't limit your notion of bugs to things that make Perl unhappy. It's also a bug if your program makes you unhappy. Earlier, we showed you a couple of really simple custom debuggers. In the next section, we'll show you an example of a different sort of custom debugger, one that may (or may not) help you debug the bug known as "Is this thing ever gonna finish?"