Version 11 of A minimal debugger

Updated 2004-12-18 09:08:52

Richard Suchenwirth 2001-01-16 -- Of course, Tcl's most minimal debugger is puts. But here is a cute little piece of code that offers some more debugging functionality (if you have stdin and stdout available - so not for wish on Windows):

 proc bp {{s {}}} {
        if ![info exists ::bp_skip] {
           set ::bp_skip [list]
        } elseif {[lsearch -exact $::bp_skip $s]>=0} return
        if [catch {info level -1} who] {set who ::}
        while 1 {
                puts -nonewline "$who/$s> "; flush stdout
                gets stdin line
                if {$line=="c"} {puts "continuing.."; break}
                if {$line=="i"} {set line "info locals"}
                catch {uplevel 1 $line} res
                puts $res
        }
 }

The idea is that you insert breakpoints, calls to bp, in critical code with an optional string argument (that may be used for distinguishing), like this:

 proc foo {args} {
        set x 1
        bp 1
        string toupper $args
 }
 foo bar and grill

When execution reaches bp, you get a prompt on stdout, giving the calling context and the bp string, like this:

 foo bar and grill/1> pwd
 /home/suchenwi/src/roi/test/mr
 foo bar and grill/1> i
 args x
 foo bar and grill/1> set args
 bar and grill
 foo bar and grill/1> set args lowercase
 lowercase
 foo bar and grill/1> c

on which you can issue any Tcl command (especially getting or setting variable values in the scope of foo), shorthand commands ("i" for "info locals"; add which others you need), and exit this micro-debugger with "c"(ontinue). Because you modified a local variable, foo's result will be

 LOWERCASE

To turn off all breakpoints for an application, just say (maybe from inside bp):

 proc bp args {}

You can disable single breakpoints labeled e.g. x with the command

 lappend ::bp_skip x

Stepping is made easy with the new execution traces from 8.4 - see Steppin' out, but in some situations a micro-debugger like this is good enough. See also What debugging tools are available to a Tcl programmer


Bits and pieces.. Here's a minimal variable watcher, that logs every change to the specified variables to stdout:

 proc watch {args} {
     foreach arg $args {
        uplevel 1 "trace var $arg w {puts $arg:\[set $arg\] ;#}"
     }
 }

[Incidental remark: Expect builds in lots of interesting debugging capabilities.]


Tkcon has a couple of debugging features like those described above. idebug is like bp above but with a few more bells and whistles, and observe is like watch above. [kpv]


AM It is very easy to extend this minimal debugger to become a mini debugger. To keep the intrusion as small as possible, just handle all debugging commands that you want to implement in a switch statement (rather than the cascading "if") for readability. This way you introduce but a single new command, bp, instead of a handful (but it may be useful to define a few, like watch, as a procedure, so that you can log the variables automatically.

One problem remains (one that I would like to solve or see solved!): how to get this to work under Windows - perhaps a solution via a pipe? The reason I am concerned is that I use (want to use) Tcl in an "embedded" mode. I can not use Tk in there, so a solution via Tkcon or console show becomes difficult... - RS: What is the problem? The little one above works only with stdin and stdout, no Tk required; and I've made good use of it debugging our app where a Tcl interpreter is embedded.


See also An error experiment with an even minimaller debugger...


Category Debugging | Arts and crafts of Tcl-Tk programming [L1 ] [L2 ] [L3 ] [L4 ] [L5 ] [L6 ] [L7 ] [L8 ] [L9 ] [L10 ] [L11 ] [L12 ] [L13 ] [L14 ] [L15 ] [L16 ] [L17 ] [L18 ] [L19 ] [L20 ] [L21 ] [L22 ] [L23 ] [L24 ] [L25 ] [L26 ] [L27 ] [L28 ] [L29 ] [L30 ] [L31 ] [L32 ] [L33 ] [L34 ] [L35 ] [L36 ] [L37 ] [L38 ] [L39 ] [L40 ] [L41 ] [L42 ] [L43 ] [L44 ] [L45 ] [L46 ] [L47 ] [L48 ] [L49 ] [L50 ] [L51 ] [L52 ] [L53 ] [L54 ] [L55 ] [L56 ] [L57 ] [L58 ] [L59 ] [L60 ] [L61 ] [L62 ] [L63 ] [L64 ] [L65 ] [L66 ] [L67 ] [L68 ] [L69 ] [L70 ] [L71 ] [L72 ] [L73 ] [L74 ] [L75 ] [L76 ] [L77 ] [L78 ] [L79 ] [L80 ] [L81 ] [L82 ] [L83 ] [L84 ] [L85 ] [L86 ] [L87 ] [L88 ] [L89 ] [L90 ] [L91 ] [L92 ] [L93 ] [L94 ] [L95 ] [L96 ] [L97 ] [L98 ] [L99 ] [L100 ] [L101 ] [L102 ] [L103 ] [L104 ] [L105 ] [L106 ] [L107 ] [L108 ] [L109 ] [L110 ] [L111 ] [L112 ] [L113 ] [L114 ] [L115 ] [L116 ] [L117 ] [L118 ] [L119 ] [L120 ] [L121 ] [L122 ] [L123 ] [L124 ] [L125 ] [L126 ] [L127 ] [L128 ] [L129 ] [L130 ] [L131 ] [L132 ] [L133 ] [L134 ] [L135 ] [L136 ] [L137 ] [L138 ] [L139 ] [L140 ] [L141 ] [L142 ] [L143 ] [L144 ] [L145 ] [L146 ] [L147 ] [L148 ] [L149 ] [L150 ] [L151 ] [L152 ] [L153 ] [L154 ] [L155 ] [L156 ] [L157 ] [L158 ] [L159 ] [L160 ] [L161 ] [L162 ] [L163 ] [L164 ] [L165 ] [L166 ] [L167 ] [L168 ] [L169 ] [L170 ] [L171 ] [L172 ] [L173 ] [L174 ] [L175 ] [L176 ] [L177 ] [L178 ] [L179 ] [L180 ] [L181 ] [L182 ] [L183 ] [L184 ] [L185 ] [L186 ] [L187 ] [L188 ] [L189 ] [L190 ] [L191 ] [L192 ] [L193 ] [L194 ] [L195 ] [L196 ] [L197 ] [L198 ] [L199 ] [L200 ] [L201 ] [L202 ] [L203 ] [L204 ] [L205 ] [L206 ] [L207 ] [L208 ] [L209 ] [L210 ] [L211 ] [L212 ] [L213 ] [L214 ] [L215 ] [L216 ] [L217 ] [L218 ] [L219 ] [L220 ] [L221 ] [L222 ] [L223 ] [L224 ] [L225 ] [L226 ] [L227 ] [L228 ] [L229 ] [L230 ] [L231 ] [L232 ] [L233 ] [L234 ] [L235 ] [L236 ] [L237 ] [L238 ] [L239 ] [L240 ] [L241 ] [L242 ] [L243 ] [L244 ] [L245 ] [L246 ] [L247 ] [L248 ] [L249 ] [L250 ] [L251 ] [L252 ] [L253 ] [L254 ] [L255 ] [L256 ] [L257 ] [L258 ] [L259 ] [L260 ] [L261 ] [L262 ] [L263 ] [L264 ] [L265 ] [L266 ] [L267 ] [L268 ] [L269 ] [L270 ] [L271 ] [L272 ] [L273 ] [L274 ] [L275 ] [L276 ] [L277 ] [L278 ] [L279 ] [L280 ] [L281 ] [L282 ] [L283 ] [L284 ] [L285 ] [L286 ] [L287 ] [L288 ] [L289 ] [L290 ] [L291 ] [L292 ] [L293 ] [L294 ] [L295 ] [L296 ] [L297 ] [L298 ] [L299 ] [L300 ] [L301 ] [L302 ] [L303 ] [L304 ] [L305 ] [L306 ] [L307 ] [L308 ] [L309 ] [L310 ] [L311 ] [L312 ] [L313 ] [L314 ] [L315 ] [L316 ] [L317 ] [L318 ]