Version 15 of Favorite debugging techniques applicable to Tcl

Updated 2007-09-26 20:09:17 by JH

Frank Pilhofer's Reload, Refresh, ..., David Welton's endless reloads, Jeffrey Hobbs' use of "fresh" tkcon tabs [L1 ], as well as Keith Vetter's console resets [L2 ] ...

A minimal debugger ...


RS routinely puts into Tk-provided scripts under development these two lines:

 bind . <Escape> {exec wish $argv0 &; exit}
 bind . <F1> {console show} ;# Windows only

With an interactive console, the following shortcut is often helpful:

 interp alias {} ? {} set errorInfo

Another little helper to display canvas x/y coordinates in the title bar:

 bind .c <Motion> {wm title . %x/%y}

LES: Hmm... I have this:

 frame $::w.wframe
 text $::w.wframe.textw
 scrollbar $::w.wframe.sbar

Then I bind it:

 bind $::w.wframe.textw <Motion> {wm title $::w "Position:  %x/%y" }

It works, but only so far as I move the mouse around the text widget. It won't work when I move it over the scroll or title bar. Certainly because I made a binding for the text widget only. Instead, I should bind the mouse movement to the frame, because it contains everything, right?

 bind $::w.wframe <Motion> {wm title $::w "Position:  %x/%y" }

Wrong. Now it only works when I move the mouse over the scroll bar. But isn't the text widget contained in the frame too? What is wrong with my assumption?

And I guess it is impossible to detect mouse movement over the title bar?


Robert Heller and tclguy explain how to use gdb constructively with Tcl-based applications in a clt thread [L3 ].


LV 2007 Sep 25 Okay, here's a debugging situation that needs a technique. Hopefully it is obvious to readers that the small coherent example I provide here is merely to allow illustration of the type of problem, and that the real world examples of this are not so trivial. Thus, responses such as just read the code and look for the bug, while certainly a valid approach, may involve reading tens of thousands of lines of code, extensions, etc. and thus the location of this sort of problem could use a bit of help.

Assume this small coherent example of tcl code:

 $ tclsh
 % proc novar {} {
 return $abc
 }
 % proc a {} {
        return [novar]
 }
 % proc b {} {
        return [a]
 }
 % b
 can't read "abc": no such variable

What would be useful here is some coding technique or trick that would change that simple error message into a stack trace that would get the developer looking into the appropriate proc.

In an ideal situation, Tcl would just generate that stack trace by default.

Lars H: I usually just type

  set errorInfo

when I encounter this situation. That outputs the information you're asking for, does it not?

LV I either didn't know that, or had forgotten that in my old age. Indeed, what I get if I remember is:

 % b
 can't read "abc": no such variable
 % set errorInfo
 can't read "abc": no such variable
    while executing
 "return $abc"
    (procedure "novar" line 2)
    invoked from within
 "novar"
    (procedure "a" line 2)
    invoked from within
 "a"
    (procedure "b" line 2)
    invoked from within
 "b"

Thanks!

JH: As noted on the tkcon page, tkcon's hot errors functionality handles this for you graphically, going all the way to show you the source of the proc in a dig-down style.


Lars H: A useful procedure for use with trace is

  proc putslist {args} {puts $args}

since you can then go

  trace add execution someProc {enter enterstep leave leavestep} putslist

(or some subset of those operations) and get a raw dump of what someProc does. Unless the amount of trace data is large, it's more troublesome to format the trace data than it is to interpret this raw trace. It's also a bit troublesome for more ambitious tracing that the enter* and leave* operations have different syntaxes for the tracing command, hence the use of a catch-all args argument.


Category Debugging