Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

Cultured Perl: Debugging Perl with ease

Catch the bugs before they bite

Teodor Zlatanov (tzz@bu.edu), Programmer, Gold Software Systems
Author photo
Teodor Zlatanov graduated with an M.S. in computer engineering from Boston University in 1999. He has worked as a programmer since 1992, using Perl, Java, C, and C++. His interests are in open source work on text parsing, 3-tier client-server database architectures, UNIX system administration, CORBA, and project management. He can be contacted at tzz@bu.edu.

Summary:  Teodor Zlatanov walks you through both the built-in Perl debugger and CPAN's Devel::ptkdb. The Perl debugger is powerful but frustrating to navigate. CPAN's Devel::ptkdb, on the other hand, works wonders by simplifying code debugging and thereby saving hours of your precious time. In his discussion Zlatanov concentrates on explaining debugging methods and general concepts rather than looking at specific tools.

Date:  01 Nov 2000
Level:  Intermediate

Comments:  

Bugs are as inevitable as death and taxes. Nevertheless, the following material should help you avoid the pitfalls of bugs. Some of the examples will require Perl 5.6.0 or at least 5.005. If you want to try the Emacs examples, you may also need to install the Emacs editor.

The trouble with bugs

Software developers commonly underestimate the importance of software testing. The fundamental reason for this is simple: dealing with bugs is hard! Occasionally bugs even require developers to re-write major portions of a project from scratch, because bugs are good at revealing fundamental deficiencies of the code.

I think debugging is so important that it should be allocated at least 30% of the project timeline. Extra debugging time will produce a better product. If, on the other hand, you cut debugging time to deliver the software more quickly, you will almost always double the amount of post-production time you spend fixing problems that come to light later.

Bugs come in three basic varieties: coding bugs, documentation bugs, and requirement bugs. Requirement bugs are generally the result of imprecise or missing requirements. Documentation bugs reside in the manuals or online help. Coding bugs result from programmer errors in implementing the requirements. Unfortunately requirement and documentation bugs are outside the scope of what we can do here, so we'll have to limit ourselves to "detecting," "solving," and "fixing" coding bugs.

Debugging terms

Breakpoint: a place in the program where execution will stop and control will return to the debugger.

Debugger: 1) the program in control of the debugging process, with facilities specifically written to support it; 2) the person performing the debugging.

Execution stack: the list of functions entered so far during program execution. If the main program calls function A, for instance, and function A calls function B, the execution stack is: main -> A -> B.

Step in: continuing execution step by stepping inside the currently selected line of code. If the current line of code contains a function, stepping in will go inside that function.

Step over: continuing execution over the currently selected line of code. Execution occurs unconditionally, regardless of the line's contents, and control returns to the debugger upon completion.

Watch: an automatically triggered action when a variable changes value.

See the Resources section below for additional sources of information on debugging.


Basic concepts of debugging

We have defined coding bugs as errors by the programmer in implementing the requirements. Coding bugs cause improper program behavior (behavior deviating from the requirements). So the first thing a programmer should know before writing or debugging a program is the program's requirements.

Debugging is not unlike a hunt. The first step is detecting the bugs (by observing wrong behavior and identifying a pattern). At this stage, bugs are only symptoms.

The second step is solving the bugs. Someone who knows the program well should examine the bugs and understand their root causes, since bugs must be eliminated at their source. If the code becomes easier to understand and you have no more code than there was in the buggy version, you are probably on the right track.

The third and final step is fixing the bugs (note that "fixing" is distinct from "solving"). The debugger places the source code change into "live" production and checks it for correctness. If the code isn't correct, you've either failed to solve the bug or, even worse, you've introduced a new bug. Since solving bugs only to introduce new ones is not fun, make sure to fix every bug once you've solved it!

To make sure that you locate the bugs quickly and understand them well, you should have a clear mental image of the program's actions at every major branch, with every module and class, throughout the debugging process. This of course implies that you have a solid understanding of the language the code is written in (Perl, in our case). Because of all these requirements, good software testers are hard to find.


The Perl debugger

The first recourse for a Perl programmer is the debugger that comes with Perl. As you'll see, it's easy enough to use from the start.

  
 perl -d program.pl

The Perl debugger comes with its own help ('h' or 'h h', for the long and short help screens, respectively). The perldoc perldebug page (type "perldoc perldebug" at your prompt) has a more complete description of the Perl debugger.

So let's start with a buggy program and take a look at how the Perl debugger works. First, it'll attempt to print the first 20 lines in a file.

 #!/usr/bin/perl -w

 use strict;

 foreach (0..20)
 {
  my $line = 
;
  print "$_ : $line";
 }

When run by itself, buggy.pl fails with the message: "Use of uninitialized value in concatenation (.) at ./buggy.pl line 8, line 9." More mysteriously, it prints "9:" on a line by itself and waits for user input.

Now what does that mean? You may already have spotted the bugbear that came along when we fired up the Perl debugger.

First let's simply make sure the bug is repeatable. We'll set an action on line 8 to print $line where the error occurred, and run the program.

 > perl -d ./buggy.pl buggy.pl

 Default die handler restored.

 Loading DB routines from perl5db.pl version 1.07
 Editor support available.

 Enter h or `h h' for help, or `man perldebug' for more help.

 main::(./buggy.pl:5):   foreach (0..20)
 main::(./buggy.pl:6):   {
   DB<1>  use Data::Dumper

   DB<1>  a 8 print 'The line variable is now ', Dumper $line

The Data::Dumper module loads so that the autoaction can use a nice output format. The autoaction is set to do a print statement every time line 8 is reached. Now let's watch the show.

  DB
 c
 The line variable is now $VAR1 = '#!/usr/bin/perl -w
 ';
 0 : #!/usr/bin/perl -w
 The line variable is now $VAR1 = '
 ';
 1 : 
 The line variable is now $VAR1 = 'use strict;
 ';
 2 : use strict;
 The line variable is now $VAR1 = '
 ';
 3 : 
 The line variable is now $VAR1 = 'foreach (0..20)
 ';
 4 : foreach (0..20)
 The line variable is now $VAR1 = '{
 ';
 5 : {
 The line variable is now $VAR1 = ' my $line = 
;
 ';
 6 :  my $line = 
;
 The line variable is now $VAR1 = ' print "$_ : $line";
 ';
 7 :  print "$_ : $line";
 The line variable is now $VAR1 = '}
 ';
 8 : }
 The line variable is now $VAR1 = undef;
 Use of uninitialized value in concatenation (.) at ./buggy.pl line 8, <> line 9.
 9 : 

It's clear now that the problem occurred when the line variable was undefined. Furthermore, the program waited for more input. And pressing the Return key eleven more times created the following output:

The line variable is now $VAR1 = '
';
10 : 
The line variable is now $VAR1 = '
';
11 : 
The line variable is now $VAR1 = '
';
12 : 
The line variable is now $VAR1 = '
';
13 : 
The line variable is now $VAR1 = '
';
14 : 
The line variable is now $VAR1 = '
';
15 : 
The line variable is now $VAR1 = '
';
16 : 
The line variable is now $VAR1 = '
';
17 : 
The line variable is now $VAR1 = '
';
18 : 
The line variable is now $VAR1 = '
';
19 : 
The line variable is now $VAR1 = '
';
20 : 
Debugged program terminated.  Use q to quit or R to restart,
  use O inhibit_exit to avoid stopping after program termination,
  h q, h R or h O to get additional info.  
  DB<3> 

By now it's obvious that the program is buggy because it unconditionally waits for 20 lines of input, even though there are cases in which the lines will not be there. The fix is to test the $line after reading it from the filehandle:

#!/usr/bin/perl -w
use strict;
foreach (0..20)
{
 my $line = 
;
 last unless defined $line;		# exit loop if $line is not defined
 print "$_ : $line";
}

As you see, the fixed program works properly in all cases!


Concluding notes on the Perl debugger

The Emacs editor supports the Perl debugger and makes using it a somewhat better experience. You can read more about the GUD Emacs mode inside Emacs with Info (type M-x info). GUD is a universal debugging mode that works with the Perl debugger (type M-x perldb while editing a Perl program in Emacs).

With a little work, the vi family of editors will also support the Perl debuggers. See the perldoc perldebug page for more information. For other editors, consult each editor's documentation.

The Perl built-in debugger is a powerful tool and can do much more than the simple usage we just looked at. It does, however, require a fair amount of Perl expertise. Which is why we are now going to look at some simpler tools that will better suit beginning and intermediate Perl programmers.


Devel::ptkdb

To use the Devel::ptkdb debugger you first have to download it from CPAN (see Resources below) and install it on your system. (Some of you may also need to install the Tk module, also in CPAN.) On a personal note, Devel::ptkdb works best on UNIX systems like Linux. (Although it's not theoretically limited to UNIX-compatible systems, I have never heard of anyone successfully using Devel::ptkdb on Windows. As the old saying goes, anything is possible except skiing through a revolving door.)

If you can't get your system administrator to perform the installation for you (because, for instance, you are the system administrator), you can try doing the following at your prompt (you may need to run this as root):

perl -MCPAN -e'install Tk'
perl -MCPAN -e'install Devel::ptkdb'

After some initial questions, if this is your first time running the CPAN installation routines, you will download and install the appropriate modules automatically.

You can run a program with the ptkdb debugger as follows (using our old buggy.pl example):

perl -d:ptkdb buggy.pl buggy.pl

To read the documentation for the Devel::ptkdb modules, use the command "perldoc Devel::ptkdb". We are using version 1.1071 here. (Although updated versions may come out at any time, they should not look very different from the one we're using.)

A window will come up with the program's source code on the left and a list of watched expressions (initially empty) on the right. Enter the word "$line" in the "Enter Expr:" box. Then click on the "Step Over" button to watch the program execute.

The "Run" button will run the program until it finishes or hits a breakpoint. Clicking on the line number in the source-listing window sets or deletes breakpoints. If you select the "BrkPts" tab on the right, you can edit the list of breakpoints and make them conditional upon a variable or a function. (This is a very easy way to set up conditional breakpoints.)

Ptkdb also has File, Control, Data, Stack, and Bookmarks menus. These menus are all explained in the perldoc documentation. Because it's so easy to use, Ptkdb is an absolute must for beginner and intermediate Perl programmers. It can even be useful for Perl gurus (as long as they don't tell anyone that they're using those new-fangled graphical interfaces).


Writing your own Perl shell

Sometimes using a debugger is overkill. If, for example, you want to test something simple, in isolation from the rest of a large program, a debugger would be too complex for the task. This is where a Perl shell can come in handy.

While other valid approaches to a Perl shell certainly exist, we're going to look at a general solution that works well for most daily work (and I use it all the time). Once you understand the tool, you should feel free to tailor it to your own needs and preferences.

The following code requires the Term::ReadLine module. You can download it from CPAN and install it almost the same way as you did Devel::ptkdb.

#!/usr/bin/perl -w
use Term::ReadLine;
use Data::Dumper;
my $historyfile = $ENV{HOME} . '/.phistory';
my $term = new Term::ReadLine 'Perl Shell';
sub save_list 
{ 
 my $f = shift; 
 my $l = shift; 
 open F, $f; 
 print F "$_\n" foreach @$l 
}
if (open H, $historyfile)
{
 @h = 
;
 chomp @h;
 close H;
 $h{$_} = 1 foreach @h;
 $term->addhistory($_) foreach keys %h;
}
while ( defined ($_ = $term->readline("My Perl Shell> ")) ) 
{
  my $res = eval($_);
  warn $@ if $@;
  unless ($@)
  {
   open H, ">>$historyfile";
   print H "$_\n";
   close H;
   print "\n", Data::Dumper->Dump([$res], ['Result']);
  }
  $term->addhistory($_) if /\S/;
}

This Perl shell does several things well, and some things decently.

First of all, it keeps a unique history of commands already entered in your home directory in a file called ".phistory". If you enter a command twice, only one copy will remain (see the function that opens $historyfile and reads history lines from it).

With each entry of a new command, the command list is saved to the .phistory file. So if you enter a command that crashes the shell, the history of your last session is not lost.

The Term::ReadLine module makes it easy to enter commands for execution. Because commands are limited to only one line at a time, it's possible to write good old buggy.pl as:

Da Perl Shell> use strict
$Result = undef;
Perl Shell> print "$_: " . 
 foreach (0..20)
0: ...
1: ...

The problem of course is that the input operator ends up eating the shell's own input. So don't use or STDIN in the Perl shell, because they'll make things more difficult. Try this instead:

    Perl Shell> open F, "buggy.pl"
$Result = 1;
Perl Shell> foreach (0..20) { last if eof(F); print "$_: " . 
; }
0: #!/usr/bin/perl -w
1: 
2: use strict;
3: 
4: foreach (0..20)
5: {
6:  my $line = 
;
7:  last unless defined $line;   # exit loop if $line is not defined
8:  print "$_ : $line";
9: }
$Result = undef;

As you can see, the shell works for cases where you can easily condense statements into one line. It's also a surprisingly common solution to isolating bugs and provides a great learning environment. Do a little exercise and see if you can write a Perl shell for debugging on your own, and see how much you learn!


Building an arsenal of tools

We've only covered the very basics here of the built-in Perl debugger, Devel::ptkdb, and related tools. There are many more ways to debug Perl. What's important is that you gain an understanding of the debugging process: how a bug is observed, solved, and then fixed. Of course the single most important thing is to make sure you have a comprehensive understanding of your program's requirements.

The Perl built-in debugger is very powerful, but it's not good for beginner or intermediate Perl programmers. (With the exception of Emacs, where it can be a useful tool even for beginners as long as they understand debugging under Emacs.)

The Devel::ptkdb module and debugger are (because of power and usability) by far the best choice for beginning and intermediate programmers. Perl shells, on the other hand, are personalized debugging solutions for isolated problems with small pieces of code.

Every software tester builds his own arsenal of debugging tools, whether it's the Emacs editor with GUD, or a Perl shell, or print statements throughout the code. Hopefully the tools we've looked at here will make your debugging experience a little easier.


Resources

About the author

Author photo

Teodor Zlatanov graduated with an M.S. in computer engineering from Boston University in 1999. He has worked as a programmer since 1992, using Perl, Java, C, and C++. His interests are in open source work on text parsing, 3-tier client-server database architectures, UNIX system administration, CORBA, and project management. He can be contacted at tzz@bu.edu.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Linux
ArticleID=11057
ArticleTitle=Cultured Perl: Debugging Perl with ease
publish-date=11012000
author1-email=tzz@bu.edu
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).