Chapter 21

The Perl Debugger


CONTENTS

Today's lesson describes the Perl debugging facility. You'll learn the following:

Entering and Exiting the Perl Debugger

The following sections describe how to start the Perl debugger and how to exit.

Entering the Debugger

To debug a Perl program, specify the -d option when you run the program. For example, to debug a program named debugtest, specify the following command:


$ perl -d debugtest

You can supply other options along with -d if you want to.

When the Perl interpreter sees the -d option, it starts the Perl debugger. The debugger begins by displaying a message similar to the following one on your screen:


Loading DB routines from $RCSfile: perldb.pl,v  $$Revision: 4.0.1.3

$$Date: 92/06/08 13:43:57 $

Emacs support available.



Enter h for help.



main::(debugtest:3):        $dircount = 0;

  DB<1>

The first few lines display the date on which this version of the debugger was created. The only lines of interest are the last two.

The second-to-last line in this display lists the line that the debugger is about to execute. When the debugger starts, the first executable line of the program is displayed.

When the debugger displays a line that it is about to execute, it also provides the following information about the line:

The last line of the display prompts you for a debugging command. The number enclosed in angle brackets indicates the command number; in this case, the number is 1, because you are about to specify the first debugging command.

Later today you will learn how to use the debugging command number to re-enter debugging commands you have previously executed.

NOTE
To enter the debugger without supplying a program, supply the -e option with the -d option:
$ perl -d -e "1;"
This line starts the debugger with a "program" consisting of the single statement
1;
(which is an expression that doesn't do anything meaningful).
Starting the debugger without a program enables you to examine the predefined system variables or supply statements to be executed. You will learn how to perform both of these tasks later in today's lesson

Exiting the Debugger

To exit the debugger, enter the debugging command q:


DB<1> q

This command halts program execution immediately and returns you to the command shell.

Listing Your Program

You can list any part of your program from within the debugger. The following sections describe debugging commands that perform the display operations.

The l command

The simplest way to list part of your program is with the l command, which lists the next few statements in your program:


  DB<1> l

3:      $dircount = 0;

4:      $curdir = "";

5:      while (1) {

6:              # if we don't have a current directory, get one

7:              if ($curdir eq "") {

8:                      print ("Enter directory to list:\n");

9:                      $curdir = <STDIN>;

10:                     $curdir =~ s/^\s+|\s+$//g;

11:                     $curdir = &followlink($curdir);

12:                     &readsubdirs($curdir);

The l command lists a window of executable statements, which is a group of statements small enough to be easily displayed on your screen. A window usually consists of about ten statements. The line number of each statement is displayed at the beginning of its line.

NOTE
The statements displayed in today's lesson are taken from the program presented in "Week 2 in Review."

Entering the l command again displays the window of statements immediately following the last displayed line, which in this example is line 12:


  DB<1> l

13:             }

14:             $curdir = &menudir($curdir);

15:     }

16:

17:

18:     # Find all subdirectories of the given directory,

19:     # and store them in an associative array.

20:     #

21:     # The associative array subscripts and values are:

22:     # <directory name>:       1

You can specify the lines displayed by the l command. If you specify a single line number with the l command, it displays that line:


  DB<1> l 10

10:                      $curdir =~ s/^\s+|\s+$//g;

To display a range of lines, specify the first and last line number, and separate them with a hyphen:


  DB<1> l 10-15

10:                      $curdir =~ s/^\s+|\s+$//g;

11:                      $curdir = &followlink($curdir);

12:                      &readsubdirs($curdir);

13:             }

14:             $curdir = &menudir($curdir);

15:     }

To display a specified number of lines starting at a certain point, supply the starting line number, a + character, and a number of additional lines to display:


  DB<1> l 10+5

10:                      $curdir =~ s/^\s+|\s+$//g;

11:                      $curdir = &followlink($curdir);

12:                      &readsubdirs($curdir);

13:             }

14:             $curdir = &menudir($curdir);

15:     }

You also can use the l command to specify a subroutine to display. To do this, provide the name of the subroutine to display:


  DB<1> l readsubdirs

26:     sub readsubdirs {

27:             local ($dirname) = @_;

28:             local ($dirvar, $subdircount, $name, $index);

29:

30:             # open the current directory;

31:             # $dircount ensures that each file variable is unique

32:             $dirvar = "DIR" . ++$dircount;

33:             if (!opendir ($dirvar, $dirname)) {

34:                     warn ("Can't open $dirname\n");

35:                     return;

This command lists the statements in the subroutine. If the subroutine is too large to fit in a single window, only the first few statements are listed; you can list subsequent statements by entering l with no arguments.

The - Command

You can display the lines immediately preceding the last displayed line by entering the - command. For example, the following - command lists the window of lines immediately preceding the subroutine readsubdirs.


  DB<1> -

16:

17:

18:     # Find all subdirectories of the given directory,

19:     # and store them in an associative array.

20:     #

21:     # The associative array subscripts and values are:

22:     # <directory name>:       1

23:     #       (indicates that directory has been read)

24:     # <directory name>.<num>  the <num>th subdirectory

25:

Subsequent - commands go back further in the file.

The w Command

To list a window of lines containinga specified line, use the w command, and specify the number of the line to be included:


  DB<1> w 7

4:      $curdir = "";

5:      while (1) {

6:              # if we don't have a current directory, get one

7:              if ($curdir eq "") {

8:                      print ("Enter directory to list:\n");

9:                      $curdir = <STDIN>;

10:                     $curdir =~ s/^\s+|\s+$//g;

11:                     $curdir = &followlink($curdir);

12:                     &readsubdirs($curdir);

13:             }

The w command displays the three lines before the specified line and fills the window with the lines following it.

The // and ?? Commands

You can search for a line containing a particular pattern by enclosing the pattern in slashes:


  DB<1> /Find/

18:     # Find all subdirectories of the given directory,

The debugger searches forward from the last displayed line for a line matching the specified pattern. If it finds such a line, the line is displayed.

To search backward for a particular pattern, enclose the pattern in question marks:


  DB<1> ?readsubdirs?

12:                      &readsubdirs($curdir);

This command starts with the last displayed line and searches backward until it finds a line matching the specified pattern.

NOTE
Patterns specified by // and ?? can contain any special character understood by the Perl interpreter.
You optionally can omit the final / or ? character when you match a pattern.

The S Command

The S command lists all the subroutines in the current file, one subroutine per line:


  DB<> S

main::display

main::followlink

main::menudir

main::readsubdirs

Each subroutine name is preceded by the package name and a single quotation mark.

Stepping Through Programs

One of the most useful features of the Perl debugger is the capability to execute a program one statement at a time. The following sections describe the statements that carry out this action.

The s Command

To execute a single statement of your program, use the s command:


  DB<2> s

main::(debugtest:4):        $curdir = "";

This command executes one statement of your program and then displays the next statement to be executed. If the statement executed needs to read from the standard input file, the debugger waits until the input is provided before displaying the next line to execute.

TIP
If you have forgotten which line is the next line to execute (because, for example, you have displayed lines using the l command), you can list the next line to execute using the L command:
DB<2> L
3: $dircount = 0;
The L command lists the last lines executed by the program. It also lists any breakpoints and line actions that have been defined for particular lines. Breakpoints and line actions are discussed later today.

If the statement executed by the s command calls a subroutine, the Perl debugger enters the subroutine but does not execute any statements in it. Instead, it stops at the first executable statement in the subroutine and displays it. For example, if the following is the current line:


main::(debugtest:12):                      &readsubdirs($curdir);

specifying the s command tells the Perl debugger to enter readsubdirs and display the following, which is the first executable line of readsubdirs:


main::readsubdirs(debugtest:27):      local ($dirname) = @_;

The s command assumes that you want to debug the subroutine you have entered. If you know that a particular subroutine works properly and you don't want to step through it one statement at a time, use the n command, described in the following section.

The n Command

The n command, like the s command, executes one line of your program and displays the next line to be executed:


  DB<2> n

main::(debugtest:5):        while (1) {

The n statement, however, does not enter any subroutines. If the statement executed by n contains a subroutine call, the subroutine is executed in its entirety. After the subroutine is executed, the debugger displays the line immediately following the call.

For example, if the current line is


main::(debugtest:12):                      &readsubdirs($curdir);

the n command tells the debugger to execute readsubdirs and then display the next line in the program, which is


main::(debugtest:13:):             }

Combining the use of s and n ensures that the debugger examines only the subroutines you want to see.

NOTE
The Perl debugger does not enable you to enter any library functions. You can enter only subroutines that you have created yourself or that have been created previously and added to a subroutine library

The f command

The f command tells the Perl debugger to execute the remainder of the statements in the current subroutine and then display the line immediately after the subroutine call. This is useful when you are looking for a bug and have determined that the current subroutine does not contain the problem.

The Carriage-Return Command

If you are stepping through a program using s or n, you can save yourself some typing by just pressing Enter when you want to execute another statement. When you press Enter, the debugger repeats the last s or n command executed.

For example, to step from line 5 to line 7, you can use the s command as usual:


  DB<3> s

main::(debugtest:7):              if ($curdir eq "") {

(Line 6 is skipped because it contains no executable statements.) To execute line 7, you can now just press Enter:


  DB<2>

main::(debugtest:8):              print ("Enter directory to list:\n");


NOTE
Pressing Enter has no effect if you have not specified any s or n commands.

The r Command

If you are inside a subroutine and decide that you no longer need to step through it, you can tell the Perl debugger to finish executing the subroutine and return to the statement after the subroutine call. To do this, use the r command:


  DB<4> r

main::(debugtest:13:):             }

The statement displayed by the debugger is the first statement following the call to the subroutine.

Displaying Variable Values

Another powerful feature of the Perl debugger is the capability to display the value of any variable at any time. The following sections describe the commands that perform this action.

The X Command

The X command displays variables in the current package (which is main if no other package has been specified). If the X command is specified by itself, it lists all the variables in the current package, including the system-defined variables and the variables used by the Perl interpreter itself. Usually, you won't want to use the X command by itself, because there are a lot of system-defined and internal variables known to the Perl interpreter.

To print the value of a particular variable or variables, specify the variable name or names with the X command:


  DB<5> X dircount

$dircount = '0'

This capability often is useful when you are checking for errors in your program.

You must not supply the $ character with the variable name when you use the X command. If you supply the $ character (or the @ or % characters for arrays), the debugger displays nothing.

You can use X to display the values of array variables and associative array variables.


  DB<6> X regarray

@regarray = (

  0     14

  1     'hello'

  2     36

)

  DB<7> X assocarray

%assoc_array = (

  'hi'  1

  'there' 2

)

Each command prints the subscripts of the array and their values. Regular arrays are printed in order of subscript; associative arrays are printed in no particular order.

NOTE
If you have an array variable and a scalar variable with the same name, the X command prints both variables:
DB<8> X var
$var = '0'
@var = (
0 'test1'
1 'test2'
)
There is no way to use X to display one variable but not the other.

The V Command

The V command is identical to the X command except that it prints the values of variables in any package. If you specify just a package name, as in the following, this command displays the values of all variables in the package (including system-defined and internal variables):


DB<9> V mypack

If you specify a package name and one or more variable names, as in the following, the debugger prints the values of the variables (if they are defined in that package):


  DB<10> V main dircount

$dircount = '0'

Breakpoints

As you have seen, you can tell the Perl debugger to execute one statement at a time. Another way of controlling program execution is to tell the debugger to execute up to a certain specified point in the program, called a breakpoint.

The following sections describe the commands that create breakpoints, and the command that executes until a breakpoint is detected.

The b Command

To set a breakpoint in your program, use the b command. This command tells the debugger to halt program execution whenever it is about to execute the specified line. For example, the following command tells the debugger to halt when it is about to execute line 10:


DB<11> b 10

(If the line is not breakable, the debugger will return Line 10 is not breakable.)

NOTE
You can have as many breakpoints in your program as you want. The debugger will halt program execution if it is about to execute any of the statements at which a breakpoint has been defined.

The b command also accepts subroutine names:


DB<12> b menudir

This sets a breakpoint at the first executable statement of the subroutine menudir.

You can use the b command to tell the program to halt only when a specified condition is true. For example, the following command tells the debugger to halt if it is about to execute line 10 and the variable $curdir is equal to the null string:


DB<12> b 10 ($curdir eq "")

The condition specified with the b statement can be any legal Perl conditional expression.

If a statement is longer than a single line, you can set a breakpoint only at the first line of the statement:
71: print ("Test",
72: " here is more output");
Here, you can set a breakpoint at line 71, but not line 72.

The c Command

After you have set a breakpoint, you can tell the debugger to execute until it reaches either the breakpoint or the end of the program. To do this, use the c command:


  DB<13> c

main::(debugtest:10):                  $curdir =~ s/^\s+|\s+$//g;

  DB<14>

When the debugger detects that it is about to execute line 10-the line at which the breakpoint was set-it halts and displays the line. (Recall that the debugger always displays the line it is about to execute.)

The debugger now prompts you for another debugging command. This action enables you to start executing one statement at a time using n or s, continue execution using c, set more breakpoints using b, or perform any other debugging operation.

You can specify a temporary (one-time-only) breakpoint with the c command by supplying a line number:


  DB<15> c 12

main::(debugtest:12):                      &readsubdirs($curdir);

The argument 12 supplied with the c command tells the debugger to define a temporary breakpoint at line 12 and then resume execution. When the debugger reaches line 12, it halts execution, displays the line, and deletes the breakpoint. (The line itself still exists, of course.)

Using c to define a temporary breakpoint is useful if you want to skip a few lines without wasting your time executing the program one statement at a time. Using c also means that you don't have to bother defining a breakpoint using b and deleting it using d (described in the following section).

TIP
If you intend to define breakpoints using c or b, it is a good idea to ensure that each line of your program contains at most one statement. If you are in the habit of writing lines that contain more than one statement, such as
$x++; $y++;
you won't get as much use out of the debugger, because it can't stop in the middle of a line

The L Command and Breakpoints

To list all of your breakpoints, use the L command. This command lists the last few lines executed, the current line, the breakpoints you have defined, and the conditions under which the breakpoints go into effect.


  DB<16> L

3:      $dircount = 0;

4:      $curdir = "";

5:      while (1) {

7:              if ($curdir eq "") {

10:                      $curdir =~ s/^\s+|\s+$//g;

  break if (1)

Here, the program has executed lines 3-7, and a breakpoint is defined for line 10. (Line 6 is not listed because it is a comment.) You can distinguish breakpoints from executed lines by looking for the breakpoint conditional expression, which immediately follows the breakpoint. Here, the conditional expression is (1), which indicates that the breakpoint is always in effect.

The d and D Commands

When you are finished with a breakpoint, you can delete it using the d command.


DB<16> d 10

This command tells the debugger to delete the breakpoint at line 10. The line itself remains in the program.

If you do not specify a breakpoint to delete, the debugger assumes that a breakpoint is defined for the next line to be executed, and deletes it.


main::(debugtest:12):                      &readsubdirs($curdir);

  DB<17> d

Here, line 12 is the next line to be executed, so the debugger deletes the breakpoint at line 12.

To delete all your breakpoints, use the D command.


DB<18> D

This command deletes all the breakpoints you have defined with the b command.

Tracing Program Execution

When you run a program using the Perl debugger, you can tell it to display each line as it is executed. When the debugger is doing this, it is said to be in trace mode.

To turn on trace mode, use the T command.


  DB<18> t

Trace = on

When a statement is executed in trace mode, the statement is displayed. For example, if the current line is line 5 and the command c 10 (which executes up to line 10) is entered, the following is displayed:


  DB<18> c 10

main::(debugtest:5):      while (1) {

main::(debugtest:7):              if ($curdir eq "") {

main::(debugtest:10):                      $curdir =~ s/^\s+|\s+$//g;

  DB<19>

The debugger prints and executes line 5 and line 7, then displays line 10 and waits for further instructions.

To turn off trace mode, specify the t command again.


  DB<19> t

Trace = off

At this point, trace mode is turned off until another t command is entered.

Line Actions

The Perl debugger enables you to specify one or more statements to be executed whenever the program reaches a specified line. Such statements are known as line actions. The most common line actions are printing the value of a variable and resetting a variable containing an erroneous value to the value you want.

The following sections describe the debugging commands that define line actions.

The a Command

To specify a line action for a particular line, use the a command.


DB<19> a 10 print ("curdir is $curdir\n");

This command tells the debugger to execute the statement


print ("curdir is $curdir\n");

whenever it is about to execute line 10 of the program. The debugger performs the action just after it displays the current line and before it asks for the next debugging command.

To create a line action containing more than one statement, just string the statements together. If you need more than one line for the statements, put a backslash at the end of the first line.


  DB<20> a 10 print ("curdir is $curdir\n"); print \

("this is a long line action\n");

In this case, when the debugger reaches line 10, it executes the following statements:


print ("curdir is $curdir\n");

print ("this is a long line action\n");

The A Command

To delete the line actions defined using the a command, use the A command.


DB<21> A

This command deletes all line actions currently defined.

NOTE
The A command does not affect the < and > commands, described in the following section.

The < and > Commands

To define a line action that is to be executed before the debugger executes any further statements, use the > command.


DB<21> > print ("curdir before execution is $curdir\n");

This command tells the debugger to print the value of $curdir before continuing.

Similarly, the < command defines a line action that is to be performed after the debugger has finished executing statements and before it asks for another debugging command:


DB<22> < print ("curdir after execution is $curdir\n");

This command tells the debugger to print the value of $curdir before halting execution again.

The < and > commands are useful when you know that one of your variables has the wrong value, but you don't know which statement assigned the wrong value to the variable. By single-stepping through the program using s or n, and printing the variable either before or after executing each statement, you can determine where the variable was given its incorrect value.

NOTE
To delete a line action defined by the < command, enter another < command with no line action defined.
DB<23> <
Similarly, the following command undoes the effects of a > command:
DB<24> >

Displaying Line Actions Using the L Command

The L command prints any line actions you have defined using the a command (as well as breakpoints and executed lines). For example, suppose that you have defined a line action using the following command:


DB<25> a 10 print ("curdir is $curdir\n");

The L command then displays this line action as shown here:


main::(debugtest:10):                      $curdir =~ s/^\s+|\s+$//g;

  action:  print ("curdir is $curdir\n");

The line action is always displayed immediately after the line for which it is defined. This method of display enables you to distinguish lines containing line actions from other lines displayed by the L command.

Other Debugging Commands

The following sections describe the debugging commands not previously covered.

Executing Other Perl Statements

In the debugger, anything that is not a debugging command is assumed to be a Perl statement and is performed right away. For example:


DB<4> @array = (1, 2, 3);

You can use statements such as this to alter values in your program as it is being executed. This capability is useful when you are testing your code.

NOTE
If you wish, you can omit the semicolon at the end of the statement.

The H Command: Listing Preceding Commands

The H (for "history") command lists the preceding few commands you have entered.


  DB<4> H

3: b 7

2: b 14

1: b 13

The commands are listed in reverse order, with the most recently executed command listed first. Each command is preceded by its command number, which is used by the ! command (described in the following section).

NOTE
The debugger saves only the commands that actually affect the debugging environment. Commands such as l and s, which perform useful work but do not change how the debugger behaves, are not listed by the H command.
This is not a significant limitation because you can enter the letter again if needed.

The ! Command: Executing Previous Commands

Each command that is saved by the debugger and can be listed by the H command has a command number. You can use this command number to repeat a previously executed command. For example, to repeat command number 5, make the following entry:


  DB <11> !5

b 8

  DB <12>

The debugger displays command number 5-in this case, the command b 8- and then executes it.

If you omit the number, the debugger repeats the last command executed.


  DB <12> $foo += $bar + 1

  DB <13> !

$foo += $bar + 1

  DB <14>

If you specify a negative number with !, the debugger skips back that many commands:


  DB <14> $foo += $bar + 1

  DB <15> $foo *= 2

  DB <16> ! -2

$foo += $bar + 1

  DB <17>

Here, the ! -2 command refers to the command $foo += $bar + 1.

You can use ! only to repeat commands that are actually repeatable. Use the H command to list the commands that the debugger has saved and that can be repeated

The T Command: Stack Tracing

The T command enables you to display a stack trace, which is a collection of all the subroutines that have been called, listed in reverse order. Here is an example:


  DB <16> T

$ = &main::sub2('hi') from file debug1 line 7

$ = &main::sub1('hi') from file debug1 line 3

Here, the T command indicates that the program is currently inside subroutine sub2, which was called from line 7 of your program; this subroutine is part of the main package. The call to sub2 is passed the argument 'hi'.

The $ = preceding the subroutine name indicates that the subroutine call is expecting a scalar return value. If the call is expecting a list to be returned, the characters @ = appear in front of the subroutine name.

The next line of the displayed output tells you that sub2 was called by another subroutine, sub1. This subroutine was also passed the argument 'hi', and it was called by line 3 of the program. Because the stack trace lists no more subroutines, line 3 is part of your main program.

NOTE
The list of arguments passed to a subroutine that is displayed by the stack trace is the list of actual values after variable substitution and expression evaluation are performed. This procedure enables you to use the stack trace to check whether your subroutines are being passed the values you expect.

The p Command: Printing an Expression

An easy way to print the value of an expression from inside the debugger is to use the p command.


  DB <17> p $curdir + 1

1

The p command evaluates the expression and displays the result.

NOTE
The p command writes to the screen even when the program has redirected STDOUT to a file.

The = Command: Defining Aliases

If you find yourself repeatedly entering a long debugging command and you want to save yourself some typing, you can define an alias for the long command by using the = command. For example:


  DB <15> = pc print ("curdir is $curdir\n");

= pc print ("curdir is $curdir\n");

The = command prints the alias you have just defined and then stores it in the associative array %DB'alias (package DB, array name alias) for future reference. From here on, the command


DB <16> pc

is equivalent to the command


DB <16> print ("curdir is $curdir\n");

To list the aliases you have defined so far, enter the = command by itself:


  DB <17> =

pc =  print ("curdir is $curdir\n")

This command displays your defined aliases and their equivalent values.

Predefining Aliases

You can define aliases that are to be created every time you enter the Perl debugger.

When the debugger starts, it first searches for a file named .perldb in your home directory. If the debugger finds this file, it executes the statements contained there.

To create an alias, add it to the .perldb file. For example, to add the alias


= pc print ("curdir is $curdir\n");

add the following statement to your .perldb file:


$DB'alias{"pc"} = 's/^pc/print ("curdir is $curdir\n");/';

Here's how this works: when the Perl debugger creates an alias, it adds an element to the $DB'alias associative array. The subscript for this element is the alias you are defining, and the value is a substitution command that replaces the alias with the actual command you want to use. In the preceding example, the substitution takes any command starting with pc and replaces it with


print ("curdir is $curdir\n");

Be careful when you define aliases in this way. For example, your substitution should match only the beginning of a command, as in /^pc/. Otherwise, the alias will replace any occurrence of the letters pc with your print command, which is not what you want.

The h Command: Debugger Help

The h (for help) command provides a list of each of the debugger commands listed in today's lesson, along with a one-line explanation of each. This is handy if you are in the middle of debugging a program and forget the syntax of a particular command.

Summary

Today, you have learned about the Perl debugger. This debugger enables you to perform the following tasks, among others:

Q&A

Q:Is it possible to enter more than one debugging command at a time?
A:No; however, there's no real need to do so. If you want to perform several single steps at once, use the c command to skip ahead to a specified point. If you want to both step ahead and print the value of a variable, use the < or > command.
Q:Is it possible to examine variables in one package while inside another?
A:Yes. Use the V command or the standard Perl package/variable syntax.
Q:If I discover that my program works and I want to turn off debugging, what do I do?
A:You cannot exit the debugger in the middle of a program. However, if you delete all breakpoints and line actions and then enter the c command, the program begins executing normally and is no longer under control of the debugger.
Q:How can I convert to a reusable breakpoint a one-time breakpoint created using c?
A:By default, the b command sets a breakpoint at the line that is about to be executed. This is the line at which c has set its one-time breakpoint.
Q:How can I execute other UNIX commands from inside the debugger?
A:Enter a statement containing a call to the Perl system function. For example, to display the contents of the current directory, enter the following command:
DB <11> system ("ls");
To temporarily escape from the debugger to a UNIX shell, enter the following command:
DB <12> system ("sh");
When you are finished with the shell, enter the command exit, and you will return to the debugger.
Q:What special built-in variables can be accessed from inside the debugger?
A:All of them.

Workshop

The Workshop provides quiz questions to help you solidify your understanding of the material covered.

Quiz

  1. Define the following terms:
    1. trace mode
    2. stack trace
    3. breakpoint
    4. line action
  1. Explain the differences between the X and V commands.
  2. Explain the differences between the // and ?? commands.
  3. Explain the differences between the < and > commands.
  4. Explain the differences between the s and n commands.
  5. What do the following commands do?
    1. l
    2. l 26
    3. l 5-7
    4. l 5+7
    5. w