Why am I here?

  • I offered to do this talk quite a long time ago when I thought that I had more time on my hands than was actually the case. Things didn't improve at all in the meantime and so I sat down on Saturday with my trusty iBook to write a presentation about debugging.
  • There's one thing to know about my trusty iBook, you can trust it to breakdown. Sure enough as I cruised on to slide number six the iBook blew logic board number six.
  • Apple Support are not keen exponents of hardware debugging and so each time my iBook's video fails they put in a new logic board. Six months later it fails again. Maybe they just like talking to me.

Plan B

  • Unsurprisingly, I still had a presentation to write before Monday evening if I didn't want to make a fool of myself, so I came up with a new plan.
  • I hope that at the end of this you'll know at least a little bit more about the perl debugger (or perhaps learn that there is one), maybe a tiny bit about debugging, and that preparing your presentation the day before you deliver it isn't a great idea.

What is debugging?

  • Dijkstra is no fan of the term debugging, "Debugging suggests that the programmer is not to blame for the error. It's as if the bug crept into the code while the programmer was looking the other way."
  • Usually your job as a programmer isn't finished until the code works right and even if it did work right when you finished it that doesn't mean that it'll go well in the real world. In the real world people and things happen to your code in uncontrollable and unexpected ways. "Right" in this case has more to do with the customer's expectations than anything else.
  • Generally the task of debugging comes down to finding out what the system was supposed to do (if you're lucky, you already know this), finding out what it actually is doing (and why) and then making it do the right thing. Once you've done that it's vitally important that you make sure that everything else that is was doing hasn't been affected by your fix, otherwise you're back to square on.

Introducing the perl debugger

  • Fortunately perl has an excellent, if often overlooked, support tool for helping you to find your code's little problems: the perl debugger.
  • There are various theories on why the perl debugger isn't used as much as it mihgt be, one of these is that the documentation has been scattered and also a bit thin. I think that the situation has improved a lot over the years and there's now some good documentation in the standard perl distribution.
  • If you don't get anywhere with the perldebug and debug tutorial manpages, then let me recommend O'Reilly's Perl Debugger Pocket Reference by Richard Foley. It sets out with the goal of fixing the perl debuggers documentation problems.

Starting the debugger

  • Let's take a look at how you can get started with the perl debugger. My most frequent use of the debugger - as I am guilty of not using it as much as I should - is to try things out. The first technique here simply evaluates a zero (which turns out to be false) and drops you into the debugger command line.
  • If you're familiar with other debuggers, for example GDB, you'll find that the perl debugger doesn't hold many surprises for you. However, because the perl debugger is implemented in perl, as the DB package, there are a few neat things that you can do which you wouldn't be able to do if you were debugging C code in GDB.

First steps

  • Having entered our minimal program - 0 - we can rerun it to our heart's content by entering the R command.
  • R
  • And view the code listing:
  • l
  • All very interesting. You can also remind yourself of the debugger commands with the h option.

First steps [contd.]

  • You can also set up some code to look at something else:
  • @t = localtime
  • $min = $t[1]
  • p $min
  • x @t
  • It's good for testing out regexes too:
  • $s = "the cat jumped over the sky blue fox"
  • @m = $s =~ m/(the)/g
  • p @m
  • x @m
  • p scalar @m

Debugging a program

  • Here, by way of a short example program to demonstrate some of the features of the perl debugger, is a debugging session with a slightly quirky program for checking the Earth's approximate volume.

My program

  • (run broken.pl)
  • Obviously there's nothing wrong with this. I've used strict and turned on warnings. So I just have to run it and I can see that my friend is wrong and the earth is, in fact, approximately the same volume as the estimated remaining oil supply.
  • Or, my program has a bug.

The volume of a sphere...

  • (run broken2.pl)
  • Okay, so my code has some really obvious errors which shouldn't have been there in the first place, but now it's fixed I should get the right answer. Hmm, let's take a look at it in the debugger.

List, break, action, step

  • First let's have a look at what the debugger has loaded for us:
  • l 1-19
  • Obviously this would be more interesting with a less trivial broken program. l 1-19 shows us the source code for lines 1-19, coincidentally the whole of my small program.
  • There's an arrow that tells us which line will be executed next in our program, and some other information. A colon after a line number tells us that we can set a breakpoint or an action on that line:
  • b 7
  • l 1-19
  • Our listing now shows that there's a breakpoint set on line 7, c continues execution until the next breakpoint is reached (you can also tell it to continue to a specific line or until a particular subroutine is called).
  • Stepping through code can be done with n (which executes the next executable statement in the current scope), or s which is similar but also allows you to step into subroutines rather than right over them. I haven't done any subroutines, so both will behave the same for me. When you're tired of stepping you can just use r, to run your program, or c to continue up to a given line.
  • If you get the end and your debugging isn't done, type R to restart.
  • R
  • l 1-19
  • a 12 if ($qr > 7000) { print "bad radius: $qr\n"; $qr = 6356; print "corrected: $qr\n"; }
  • l 1-19
  • Complex actions like this are possible because the debugger is in perl. You can also set breakpoints with conditions. For example:
  • perl -d broken2.pl
  • b 12 $qr > 7000
  • c
  • You can list the various breakpoints, actions, etc., in your debugger session by using the L command. L on its own will show you everything or you can use L b, for example, to show all the breakpoints.
  • L a
  • b 15
  • L b
  • L
  • c
  • You can delete breakpoints and actions simply:
  • l 1-19
  • B *
  • A *
  • c
  • But the program is still wrong.

Watching

  • In a less trivial program you might not know where your variable value was coming from, or you might want to watch for a particular value to arise. This is what watchpoints are good for.
  • Now that's suspicious for a start. How can the mean radius be approximately twice either of the individual radiuses? The debugger can't really help me here, it's back to the old method of having a look and realising that I've got the algorithm wrong. But the debugger did help me to track down the problem (in a less trivial program it might even have been important).
  • You can even set watchpoints for elements in an array or hash and watch for changes in these only.
  • Here I have got my parentheses wrong, fixing that up I can check for a sane value of the quadratic mean radius.
  • It's still not quite right, hmmm, what can be wrong. Let's check the value we have for Pi...
  • Not the best approximation ever
  • p atan2(1,1) * 4
  • Now that's better. Shame it's a constant, but at least we know what to fix now.
  • And there you have it, fully debugged and it turns out that my friend was right after all.

Other stuff

  • Setting $DB::single to 1 (it's usually 0) tells the debugger that you want to step through the code from this point. A breakpoint.
  • It might be that you know roughly where your code fails and you want to keep looking in that area. It's safe to add calls and changes to the DB:: package since none of that code will get invoked unless you run the program under the debugger.

Setting up your session

  • Once you've got to grips with using the debugger and you're using it every day to support your total quality coding practices, you might find that there's a few things you change every time you start a debugging session, or annoyances that you can't quite get past.
  • You can set up various parameters in your environment to control the workings of the debugger. You can even put perl code into your .perldb file to control the debugger commands. For example, you might make an alias of "stop at" for b, if that happened to mean more to you.

GUI

  • DDD, though a little bit ugly, provides a nice GUI interface to GDB, the perl debugger, and a number of other popular debuggers. It has a good graphical mode for examining data structures and if GUIs work for you it's well worth learning.

Tracing

  • Tracing allows you to see the call tree for your program. You can turn it on and off from within your code or when working in the debugger.