pdb.py - why is this debugger different from all other debuggers?
rocky at panix.com
Mon Jan 2 08:04:35 EST 2006
Okay, a bit of an exaggeration.
Recently, I've been using Python more seriously, and in using the
debugger I think one of the first things I noticed was that there is
no "restart" ("R" in perldb) or "run" (gdb) command.
I was pleasantly pleased discover how easy though it was patch pdb.py
and pdb.doc; my patch for this is here:
Encouraged, the next thing I noticed lacking from my usual debugging
repertoire was gdb's "frame" command which is the absolute-position
version of "up" and "down". Clearly since "up" and "down" are there,
adding a "frame" command is also pretty simple.
Perhaps I should explain that I noticed the lack of and wanted a
"frame" command because I had noticed that prior to adding "restart"
that when the program was restarted through a post-mortem dump, the
first line number in the post-mortem dump was not getting reported. So
Emacs was showing a weird position in the source; it was confusing and
not clear that a restart had actually taken place. When Emacs and the
debugger are out of sync, my usual way of fixing this is by issuing
"frame 0", which usually means go to the top (or is it bottom?) of the
stack which has a side effect of forcing emacs to update the display.
Well, so now we get to the second issue. Python's stack numbering is
different from the way most (all?) other languages. And "up" and
"down" in pdb.py follow the Python notion of direction rather than
what is common among debuggers. Yes, I realize Python's stack
numbering is the one true the right way; I have no doubt that Python
programmers draw their trees with the root at the bottom. So at least
for now I hacked in "frame -1" to mean what is generally called "frame
0" in other debuggers. And "frame 0" in my private hacked pdb.py goes
to the most least-recently encountered entry or the grand-daddy place
which calls all of the others.
Finally, we come to listing breakpoints. Showing my gdb orientation,
the first thing tried and looked for was "info break". Nope, not
there. For a while I just thought one just couldn't list breakpoints
and lived with that. Then when I decided I'll hack in an "info break"
I realized that if you type "break" without any arguments it lists the
breakpoints. (And yes, I see that the behavior is documented.)
In fact the breakpoint-listing output looks similar to what gdb
uses. That's nice, but in both gdb and Perl's debugger a "break"
without an argument *sets* a breakpoint at the current the line, it
doesn't list it.
Here I'm in a little quandary as to what to do. My take would be to
just change the behavior of break so it works like the other debuggers
mentioned. In contrast to say the "frame" command, I fail to see how
pdb.py's lingo for "list breakpoints" superior. In fact it seems
inferior. If one wanted to extend the debugger command set to include
a "list information about breakpoint number n" (which gdb does by
"info break n"), I'm not sure this would fit in with the existing
My guess is that pdb.py started as a small undertaking and grew
without all that much thought or concern as to what a full debugger
command set should or would be.
So what I am suggesting is that it would be helpful to just follow an
existing debugger paradigm (or follow more closely) so folks don't
have to learn yet another interface.
Let me close with a rather pleasant experience when I tried something
like that in my debugger for Bash (http://bashdb.sourceforge.net). In
doing that I decided that I'd just try follow the gdb command set. Not
that I think gdb's is the most wonderful, orthogonal or well-designed
command set, but just that it is commonly used and rather
complete. For example, whereas pdb.py has "up" and "down", gdb's
version also allows a numeric argument to indicate how many places up
or down - again something pretty easy to hack in. No doubt someone at
some point found this useful, so it was added. And no doubt there are
programmers who use this. Might that not also apply to people
debugging Python programs? At any rate I wanted to reduce the learning
curve of folks using my debugger.
At some point someone asked for a GUI interface. I thought okay, and
found this GUI front-end called ddd. Naturally it handled gdb and Perl
as back ends. So to add in my bash debugger support, basically all I
had do do was tell ddd that handling this construct (say
"breakpoints") is like gdb. There were a few places where I told ddd
not to follow gdb but Perl instead because the paradigm needed had to
be more like a scripting language than a compiled language. But in the
end, adding support for bash inside ddd was much more straightforward
and required much less thought than if I had invented my own debugger
Well after this was done and I fire up ddd, I notice that when my
cursor is hovering over some of the buttons I see short descriptions
for what that command does. And there is this button called "customize
bash" and in that there are all these setting variables. But I don't
remember adding a box widget for customization or remember any code
that I modified using tool tips. How did it do this? I was very
curious and had to find out.
You see, because I even copied the output format of gdb's "info",
"set" and "show" commands, what ddd is doing is running these commands
on its own and parsing the output; it then uses that output to form
tool tips and create a customization boxes.
So of course when I recently added a debugger for GNU Make
(http://bashdb.soruceforge.net/remake) I've again followed this
principle. And again it's been helpful.
In sum, I think copying or following an existing command set might
also be a good thing to do in pdb.py.
More information about the Python-list