Skip to content
R. Bernstein edited this page May 27, 2015 · 13 revisions

As a long-time user of gdb and the debuggers of that ilk, the first thing that kept tripping me up is that debugger commands are given as valid JavaScript. While it is an intriguing idea, it is nonetheless different.

For example, to list a source text starting at line 5, you would type:

list(5)

not:

list 5

Note: the parameter 5 in trepanjs means the first line to list as would be the case in gdb; it isn't involved in the calculation of how many lines to list as it is in node's debugger.

Part of the motivation for doing this, I suspect, is debugger coding simplicity: the debugger reads in what you type and evaluates the line. If the line is a debugger command, great! If it is some other valid JavaScript, well, that's okay too. But in "node debug" (and in contrast to trepanjs), evaluation is not the debugged program's context, but rather some blank-slate context which contains mostly just the debugger commands.

I suppose one could argue that issuing the debugger commands using JavaScript syntax is more natural than a shell-type command syntax. And because it's an intriguing idea, I'm going with it for now. But I'd be curious to learn how others feel.

However working this way is not without some drawbacks. The most notable hidden consequence is that some common gdb command names can't be used because they are JavaScript reserved words. Most notably: continue, and break.

Huh? If you've used this debugger, you'll notice that the corresponding gdb command is run when you type those commands at a prompt. So let me explain...

I've implemented an alias command. And the way that works, is that I do some string munging on the line entered before evaluation. So I can catch a leading "continue" string, and convert that to the official debugger command name: "cont". Likewise, a leading "break" with a space or parenthesis is converted to the underlying command name "setBreakpoint".

Here is another feature of the string preprocessing that is done. Originally in node's debugger, the user of the debugger had to keep in mind whether a command took arguments or not. If the command didn't take an argument, you'd give that without parenthesis. For example, step, next, finish, and quit worked this way.

Of course, as user of gdb-like debuggers, user I prefer not having to give parenthesis, especially empty parenthesis. So this is great. But now what happens if one day, if I would like to add parameters to some of those commands. Actually, this did happen when I wanted to extend quit so that it took an optional exitcode parameter. And note that in gdb, all of those commands cited before do take an optional number parameters. I think it would be horrible to now force users of the debugger to change syntax.

So what I've done is in that string-munging phase before evaluation add a set of parenthesis when I see that the first word is a valid debugger command but the first word isn't followed by anything. In other words, I turn quit into quit() before evaluation. Of course, if you typed quit(5), I leave that alone.

And I've extended this string-munging to include the most common case of two words without parenthesis. So in the example first cited above list 5 is accepted and turned into list(5). But note string parameters still have to be marked as strings. So you still need help '*' or help('*') rather than help *. And if the command takes more than one argument, you also need the parenthesis. For example: set("listsize", 10) rather than set "listsize", 10.

Finally, when the first token is not a debugger command, evaluation is switched to the context of the debugged program. You can still however use eval() which I find more inconvenient since the parameter to it needs to be put in quotes. And you can also go into a node REPL (read-eval-print loop) using the shell command.

There other disadvantages of the current approach for entering debugger commands that have to do with the amount of control over giving errors and confusion of running an evaluation not in the context of the debugged program. But since these are minor, I won't mention here.

Clone this wiki locally