The standard Perl distribution comes with a debugger, although it’s really just another Perl program, perl5db.pl. Since it is just a program, I can use it as the basis for writing my own debuggers to suit my needs, or I can use the interface perl5db.pl provides to configure its actions. That’s just the beginning, though. I can write my own debugger or use one of the many debuggers created by other Perl masters.
This chapter isn’t about actually debugging Perl source code to find problems; people have written entire books about that. The more you practice Perl, the better you should get at that.
Before I get started, I’m almost required to remind you that Perl offers two huge debugging aids: strict
and warnings
. I have the most trouble with smaller programs where I don’t think I need strict
that I make the stupid mistakes it would have caught. I spend much more time than I should have tracking down something Perl would have shown me instantly. It’s the common mistakes that seem to be the hardest for me to debug. Learn from the master: don’t discount strict
or warnings
for even small programs.
Now that I’ve said that, you’re going to look for it in the examples in this chapter. Just pretend those lines are there, and the book costs a bit less for the extra half a page that I saved by omitting those lines. Or, if you don’t like that, just imagine that I’m running every program with both strict
and warnings
turned on from the command line:
% perl -Mstrict -Mwarnings program
Along with that, I have another problem that bites me much more than I should be willing to admit. Am I editing the file on the same machine I’m running it on? I have login accounts on several machines, and my favorite terminal program has tabs so I can have many sessions in one window. It’s easy to checkout source from a repository and work just about anywhere, All of these nifty features conspire to get me into a situation where I’m editing a file in one window and trying to run it in another, thinking I’m on the same machine. If I’m making changes but nothing is changing in the output or behavior, it takes me longer than you’d think to figure out that the file I’m running is not the same one I’m editing. It’s stupid, but it happens. Discount nothing while debugging!
That’s a bit of a funny story, but I included it to illustrate a point; when it comes to debugging, Humility is one of the principal virtues of a maintenance programmer.
My best bet in debugging is to think that I’m the problem. That way, I don’t rule out anything or try to blame the problem on something else, such as I often see in various Perl forums under “Possible bug in Perl”. When I suspect myself first, I’m usually right. Appendix B is my guide to solving any Perl problem, which people have found useful for at least figuring out what might be wrong even if they can’t fix it.
No matter how many different debugger applications or integrated development environments I use, I still find that plain ol’ print
is my best debugger. I could load source into a debugger, set some inputs and breakpoints, and watch what happens, but often I can insert a couple of print
statements and simply run the program normally. I put braces around the variable so I can see any leading or trailing whitespace:
print "The value of var before is [$var]\n"; #... operations affecting $var; print "The value of var after is [$var]\n";
I don’t really have to use print
because I can do the same thing with warn
, which sends its output to standard error:
warn "The value of var before is [$var]"; #... operations affecting $var; warn "The value of var after is [$var]";
Since I left off the newline at the end of my warn
message, it gives me the filename and line number of the warn
:
The value of var before is [...] at program.pl line 123.
If I have a complex data structure, I use Data::Dumper
to show it. It handles hash and array references just fine, so I use a different character, the angle brackets in this case, to offset the output that comes from Data::Dumper
:
use Data::Dumper qw(Dumper); warn "The value of the hash is <\n" . Dumper( \%hash ) . "\n>";
Those warn
statements showed the line number of the warn
statement. That’s not very useful; I already know where the warn
is since I put it there! I really want to know where I called that bit of code when it became a problem. Consider a divide
subroutine that returns the quotient of two numbers. For some reason, something in the code calls it in such a way that it tries to divide by zero:
sub divide { my( $numerator, $denominator ) = @_; return $numerator / $denominator; }
I know exactly where in the code it blows up because Perl tells me:
Illegal division by zero at program.pl line 123.
I might put some debugging code in my subroutine. With warn
, I can inspect the arguments:
sub divide { my( $numerator, $denominator ) = @_; warn "N: [$numerator] D: [$denominator]"; return $numerator / $denominator; }
I might divide
in many, many places in the code, so what I really need to know is which call is the problem. That warn
doesn’t do anything more useful than show me the arguments. In Chapter 12, I show the Carp
module which provides a couple of drop-in replacements for warn
that can give me more information.
When I need to debug things in other modules, especially in ones I do not control, I want to add some debugging statements or change the code somehow to see what happens. That never works out well for me, despite all the source control tools and fancy editors available to me.
I don’t want to change the original source files; whenever I do that I tend to make things worse no matter how careful I am to restore them to their original state. Whatever I do, I want to erase any damage I do and I don’t want it to affect anyone else.
I do something simple: I copy the questionable module file to a new location and set up a special directory for the debugging section just to ensure that my mangled versions of the modules won’t infect anything else. Once I do that, I set the PERL5LIB
environment variable so Perl finds my mangled version first. When I’m done debugging, I can clear PERL5LIB
to use the original versions again.
For instance, I recently needed to check the inner workings of Net::SMTP
because I didn’t think it was handling the socket code correctly. I choose a directory to hold my copies, in this case ~/my_debug_lib
, and set PERL5LIB
to that path. I then create the directories I need to store the modified versions, then copy the module into it:
% export PERL5LIB=~/my_debug_lib
% mkdir -p ~/my_debug_lib/Net/
% cp `perldoc -l Net::SMTP` ~/my_debug_lib/Net/.
Now, I can edit ~/my_debug_lib/Net/SMTP.pm
, run my code to see what happens, and work toward a solution. None of this has affected anyone else. I can do all the things I’ve already showed in this chapter, including inserting confess
statements at the right places to get a quick dump of the call stack. Every time I wanted to investigate a new module, I copied it into my temporary debugging library directory.
I don’t have to copy a module file to change its behavior. I can override parts of it directly in my code. Damian Conway wrote a wonderful module, Hook::LexWrap
, to wrap a subroutine around another subroutine. That means that my wrapper subroutine can see the arguments coming in and the return values going out. I can inspect the values, or even change them if I like.
I’ll start with my simple example program that adds a couple of numbers. As before, it has some problems because I’m passing it the wrong arguments since I can’t tell the difference between $n
and $m
, and have used $n
twice in my call to add
. Just running the program gives me the wrong answer, but I don’t know where the problem is:
#!/usr/bin/perl # @ARGV = qw( 5 6 ); my $n = shift @ARGV; my $m = $ARGV[0]; print "The sum of $n and $m is " . add( $n, $n ) . "\n"; sub add { my( $n, $m ) = @_; my $sum = $n + $m; return $sum; }
I don’t want to change anything in the code, or, I should say, I want to look at what’s happening without affecting the statements that are already there. As before, I want everything back to normal when I’m finished debugging. Not editing the subroutine makes that easier.
The Hook::LexWrap
gives me a chance to do something right after I make a subroutine call and right before the subroutine returns. As the name suggests, it wraps the subroutine with another one to provide the magic. The Hook::LexWrap::wrap
function takes the name of the subroutine it will wrap, add
in this case, and then anonymous subroutines as pre- and posthandlers:
#!/usr/bin/perl use Hook::LexWrap qw(wrap); my $n = shift @ARGV; my $m = $ARGV[0]; wrap add, pre => sub { print "I got the arguments: [@_]\n" }, post => sub { print "The return value is going to be $_[-1]\n" } ; # this line has the error print "The sum of $n and $m is " . add( $n, $n ) . "\n"; sub add { my( $n, $m ) = @_; my $sum = $n + $m; return $sum; }
The prehandler see the same argument list as my call to add
. In this case I just output the list so I can see what it is. The posthandler gets the same arguments, but Hook::LexWrap
adds another element, the return value, on the end of @_
. In the posthandler, $_[-1]
is always the return value. My program now outputs some useful debugging output and I see that I’m passing the same argument twice:
% perl add_numbers.pl 5 6
I got the arguments: [5 5 ]
The return value is going to be 10
The sum of 5 and 6 is 10
In that output, notice the space after the last 5
. Since wrap
added an element to @_
, even though it’s undef
, I get a space between it and the preceding 5
when I interpolate the array in the double-quoted string.
Hook::LexWrap
has the magic to handle all the calling contexts too. It’s smart enough to handle scalar, list, and void contexts. In list context, that last element of @_
in the posthandler will be an array reference. In void context, it won’t be anything.
It gets even better than that, though. Hook::LexWrap
actually adds that extra element to @_
before it does anything. Look at the last output carefully. After the second argument, there’s a space between the second 5
and the closing square bracket. That’s the space between 5
and the undef
value of the extra element in @_
.
In the prehandler, I can assign to that element, signaling to Hook::LexWrap
that it should assume that it already has the return value, so it doesn’t need to actually run the original subroutine. If the subroutine isn’t doing what I need, I can force it to return the right value:
#!/usr/bin/perl use Hook::LexWrap; my $n = shift @ARGV; my $m = $ARGV[0]; { wrap add, pre => sub { rint "I got the arguments: [@_]\n"; _[-1] = "11"; , post => sub { print "The return value is going to be $_[-1]\n" } ; print "The sum of $n and $m is " . add( $n, $m ) . "\n"; } sub add { my( $n, $m ) = @_; my $sum = $n + $m; return $sum; }
Now that I’ve assigned to $_[-1]
in my prehandler, the output is different. It doesn’t run the subroutine or the posthandler, and I get back 11
:
% perl add_numbers.pl 5 6
I got the arguments: [5 6 ]
The sum of 5 and 6 is 11
With my fake return value, I can give myself the right answer and get on with the right program, and do it without changing the subroutine I want to investigate. This can be especially handy if I’m working on a big problem where other things are broken too. I know what I need to return from the subroutine so I make it do that until I fix the other parts, or at least investigate the rest of the program while the subroutine returns what it should. Sometimes eliminating a source of error, even temporarily, makes it easier to fix other things.
We introduced the standard Perl debugger in Intermediate Perl so we could examine complex data structures. It’s well documented in the perldebug, and Richard Foley devoted an entire book, Pro Perl Debugging, to it, so I will only cover enough of the basics here so I can move on to the fancier debuggers.
I invoke the Perl debugger with Perl’s -d
switch:
perl -d add_number.pl 5 6
Perl compiles the program, but stops before running the statements, giving me a prompt. The debugger shows me the program name, line number, and the next statement it will execute:
Loading DB routines from perl5db.pl version 1.25
Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
main::(Scripts/debugging/add_numbers.pl:3):
3: my $n = shift @ARGV;
D1
From there I can do the usual debugging things, such as single-stepping through code, setting breakpoints, and examining the program state.
I can also run the debugger on a program I specify on the command line with the -e
. I still get the debugger prompt, but it’s not very useful for debugging a program. Instead, I have access to the debugger prompt where I can try Perl statements:
% perl -d -e 0
Loading DB routines from perl5db.pl version 1.25 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(-e:1): 0 D1
$n = 1 + 2; D2
x $n 0 3 D3
We showed this debugger in Intermediate Perl, and it’s well documented in perldebug and many other tutorials, so I won’t spend time on it here. Check the references in the “Further Reading” section for sources of more information.
Besides the standard perl5db.pl, there are several other sorts of debuggers that I can use, and there are several code analysis tools which use the debugging infrastructure. There’s a long list of Devel::
modules on CPAN, and one of them probably suits your needs.
I can use an alternative debugger by giving the -d
switch an argument. In this case, I want to run my program under the Devel::Trace
module. The -d
switch implies the Devel::
, so I leave that off. I’ll cover profilers in depth in Chapter 5:
% perl -d:Trace program.pl
This is a wonderful little module the outputs each line as perl executes it. Where perl5db.pl pauses, this one just keeps going with no interaction. I sometimes find this handy to discover the path something took to get to the point where there is a problem.
If I write my own debugging module, I can pass arguments to the module just like I can with the -M
switch. I add the arguments as a comma-separated list after the module name and an equal sign. In this example, I load the Devel::MyDebugger
with the arguments foo
and bar
:
% perl -d:MyDebugger=foo,bar
As normal Perl code, this is the same as loading Devel::MyDebugger
with use
.
use Devel::MyDebugger qw( foo bar );
I can use a Tk-based debugger that provides a graphical interface to the same features I have from perl5db.pl. The Devel::ptkdb
module does not come with Perl, so I have to install it myself. I start ptkdb by specifying it as the debugger I want to use with the -d
switch:
% perl -d:ptkdb program.pl
It starts by creating an application window. In the left pane, I see the program lines around the current line, along with their line numbers. Buttons along the code pane allow me to search through the code. In the right pane, I have tabs to examine expressions, subroutines, and the list of current breakpoints.
![]() |
The “Subs” tab gives me a hierarchal list of package names and the subroutines defined in them. These are all of the loaded modules, and I can immediately display the code for any of those functions by selecting the one I want to see. I can select one either by double-clicking or navigating with the arrow keys and hitting <RETURN>
when I get to the one I want. It doesn’t change the state of my program, and I can use the “Subs” tab to decide to step into a subroutine to watch its execution, or step over it and continue with the execution of the program.
![]() |
The “Exprs” tab is especially useful. It has two text entries at the top. “Quick Expr” allows me to enter a Perl expression, which it then replaces with its result, and affects the state of the program if my quick expression sets or changes variables. This is the equivalent of trying a one-off expression in the terminal debugger. That’s nice, but the “Enter Expr” is even better. I enter a Perl expression and it adds it to the list of expressions in the pane below the tab. As I run my code, these expressions update their results based on the current state of the program. I can add the variables I want to track, for instance, and watch their values update.
I start with a simple program where I want to add two numbers. It’s not something that I need to debug (I hope), but I can use it to show the expressions tab doing its thing. At the start of the program, I’m at the start of the program and nothing has run yet. I single-step over the first line of code and can see the values for $m
and $n
, which I had previously entered as expressions. I could enter much more complex expressions too, and ptkdb will update them as I move through the code.
![]() |
The Devel::ebug
module by Léon Brocard provides an object-oriented interface to Perl’s debugger facility. It comes with its own terminal-based debugger named ebug
. It’s a bit of an odd name until you realize how you call it. The missing d
in the name comes from Perl’s -d
switch:
% perl -d:ebug program.pl
I don’t need to use the -d
switch, though, since I can call it directly with the ebug program, but I have to call it by quoting the entire command line:
% ebug "add_numbers.pl 5 6"
* Welcome to Devel::ebug 0.46
main(add_numbers.pl#3):
my $n = shift @ARGV;
ebug: x @ARGV
--- 5
--- 6
main(add_numbers.pl#3):
my $n = shift @ARGV;
ebug: s
main(add_numbers.pl#4):
my $m = $ARGV[0];
ebug: x $n
--- 5
The ebug program is really just a wrapper around Devel::ebug::Console
, and I can call Devel::ebug
in many different ways. At the core of its design is a detached process. The back-end runs the program under the debugger, and the frontend communicates with it over TCP. This means, for instance, I can debug the program on a different machine than on the one it’s running.
The Devel::ebug
module provides the backend so you can do anything that you like above that. If I need a specific debugger interface that you can’t find elsewhere, I might start here.
The Devel::hdb
starts the debugger and lets you interact with it through a mini-webserver. Through its web interface you can step through code, set watch expressions, and do many of the other basic debugger things. I find this handy when I want to start a program on one machine but debug on another.
![]() |
An “Integrated Development Environment” (IDE) combines several tools into one. These typically include an editor, documentation reader, and debugger. New programmers typically ask which IDE they should use, but I don’t like to answer that question. These tools are a matter of personal preference. When programmers work for or with me, I don’t care what they use as long as their choice doesn’t affect other programmers. I shouldn’t have to use the same tool because it does special things to the file or the module layouts.
Eclipse[3] is an open source development environment that runs on a variety of platforms. It’s a Java application, but don’t let that scare you off. It has a modular design so people can extend it to meet their needs. EPIC[4] is the Perl plug-in for Eclipse.
Eclipse is not just a debugger though, and that’s probably not even its most interesting features. From the source code of my Perl program I can inspect classes, call up parts of the Perl documentation, and do quite a bit more.
ActiveState’s Komodo started off as an integrated development environment for Perl on Microsoft Windows, although it’s now available on Solaris, Linux, and Mac OS X. It handles Perl as well as several other languages, including Tcl, Ruby, PHP, and Python.
![]() |
I can debug my Perl program at almost any level I want, from inserting debugging code around that part I want to inspect, or tweaking it from the outside with an integrated development environment. I can even debug the program on a machine other than the one I run it on. I don’t have to stick with one approach, and might use many of them at the same time. If I’m not satisfied with the existing debuggers, I can even create my own and tailor it for my particular task.
See Appendix B for my guide to debugging any Perl problem. You can also find it Perlmonks, where I first posted it.
Perl Debugged by Peter Scott and Ed Wright is one of the best books about actually programming with Perl. Not only do they show you how to effectively debug a Perl program, but they also show you how to not get yourself into some of the common traps that force you to debug a program. Sadly, this book appears to be out of print, but don’t let the $0.01 price for a used version on Amazon.com color your notion of its usefulness. You might also check out Perl Medic.
Pro Perl Debugging by Richard Foley tells you everything you need to know about the perl5db.pl debugger, which comes with Perl. If you like Perl’s default debugger, this book will tell you everything you want to know about it. He also wrote the Perl Debugger Pocket Reference if you want the short story.
My first ever piece of Perl writing was a little piece for The Perl Journal #9 called “Die-ing on the Web”. It’s available at my personal website: http://www.pair.com/comdog/Articles/Die_and_the_Web.txt.
I talk more about Hook::LexWrap
in “Wrapping Subroutines” in the July 2005 issue of The Perl Journal. It originally appeared in The Perl Journal and now appears in the “Lightweight Languages” section on Dr. Dobbs Journal Online: http://www.ddj.com/dept/lightlang/184416218
The Practice of Programming by Brian W. Kernighan and Rob Pike discusses their approach to debugging. Although this isn’t a Perl book, it really doesn’t need to be about any language. It’s practical advice for any sort of programming.
The Perl Debugging Tools site lists various Perl debugger tools.
[3] The Eclipse Foundation http://www.eclipse.org/
[4] Eclipse Perl Integration http://www.epic-ide.org