@c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. @c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004 @c Free Software Foundation, Inc. @c See the file guile.texi for copying conditions. @page @node Debugging Features @section Debugging Features Guile includes debugging tools to help you work out what is going wrong when a program signals an error or behaves differently to how you would expect. This chapter describes how to use these tools. Broadly speaking, Guile's debugging support allows you to do two things: @itemize @bullet @item specify @dfn{breakpoints} --- points in the execution of a program where execution should pause so you can see what is going on @item examine in detail the ``scene of the crime'' --- in other words, the execution context at a breakpoint, or when the last error occurred. @end itemize @noindent The details are more complex and more powerful @dots{} @menu * Examples:: * Intro to Breakpoints:: Setting and manipulating them. * Tracing:: Tracing program execution. @end menu @node Examples @subsection Examples Before we dive into the details and reference documentation of guile-debugging's features, this chapter sets the scene by presenting a few examples of what you can do with guile-debugging. @menu * Single Stepping through a Procedure's Code:: * Profiling or Tracing a Procedure's Code:: @end menu @node Single Stepping through a Procedure's Code @subsubsection Single Stepping through a Procedure's Code A good way to explore in detail what a Scheme procedure does is to set a breakpoint on it and then single step through what it does. To do this, use the @code{break-in} procedure from the @code{(ice-9 debugging breakpoints)} module with the @code{debug-trap} behaviour from @code{(ice-9 debugging ice-9-debugger-extensions)}. The following sample session illustrates this. It assumes that the file @file{matrix.scm} defines a procedure @code{mkmatrix}, which is the one we want to explore, and another procedure @code{do-main} which calls @code{mkmatrix}. @lisp $ /usr/bin/guile -q guile> (use-modules (ice-9 debugger) (ice-9 debugging ice-9-debugger-extensions) (ice-9 debugging breakpoints)) guile> (load "matrix.scm") guile> (break-in 'mkmatrix #:behaviour debug-trap) #< 808cb70> guile> (do-main 4) This is the Guile debugger -- for help, type `help'. There are 3 frames on the stack. Frame 2 at matrix.scm:8:3 [mkmatrix] debug> next Frame 3 at matrix.scm:4:3 (let ((x 1)) (quote this-is-a-matric)) debug> info frame Stack frame: 3 This frame is an evaluation. The expression being evaluated is: matrix.scm:4:3: (let ((x 1)) (quote this-is-a-matric)) debug> next Frame 3 at matrix.scm:5:21 (quote this-is-a-matric) debug> bt In unknown file: ?: 0* [primitive-eval (do-main 4)] In standard input: 4: 1* [do-main 4] In matrix.scm: 8: 2 [mkmatrix] ... 5: 3 (quote this-is-a-matric) debug> quit this-is-a-matric guile> @end lisp Or you can use guile-debugging's Emacs interface (GDS), by using the module @code{(ice-9 gds-client)} instead of @code{(ice-9 debugger)} and @code{(ice-9 debugging ice-9-debugger-extensions)}, and changing @code{debug-trap} to @code{gds-debug-trap}. Then the stack and corresponding source locations are displayed in Emacs instead of on the Guile command line. @node Profiling or Tracing a Procedure's Code @subsubsection Profiling or Tracing a Procedure's Code What if you wanted to get a trace of everything that the Guile evaluator does within a given procedure, but without Guile stopping and waiting for your input at every step? In this case you set a breakpoint on the procedure using @code{break-in} (the same as in the previous example), but use the @code{trace-trap} and @code{trace-until-exit} behaviours provided by the @code{(ice-9 debugging trace)} module. @lisp guile> (use-modules (ice-9 debugging breakpoints) (ice-9 debugging trace)) guile> (load "matrix.scm") guile> (break-in 'mkmatrix #:behaviour (list trace-trap trace-until-exit)) #< 808b430> guile> (do-main 4) | 2: [mkmatrix] | 3: [define (define yy 23) ((()) #)] | 3: [define (define yy 23) ((()) #)] | 3: =>(#@@define yy 23) | 3: [let (let # #) (# #)] | 3: [let (let # #) (# #)] | 3: =>(#@@let* (x 1) #@@let (quote this-is-a-matric)) | 2: (letrec ((yy 23)) (let ((x 1)) (quote this-is-a-matric))) | 3: [let (let # #) (# # #)] | 3: [let (let # #) (# # #)] | 3: =>(#@@let* (x 1) #@@let (quote this-is-a-matric)) | 2: (let ((x 1)) (quote this-is-a-matric)) | 3: [quote (quote this-is-a-matric) ((x . 1) ((yy) 23) (()) ...)] | 3: [quote (quote this-is-a-matric) ((x . 1) ((yy) 23) (()) ...)] | 3: =>(#@@quote this-is-a-matric) | 2: (quote this-is-a-matric) | 2: =>this-is-a-matric this-is-a-matric guile> (do-main 4) | 2: [mkmatrix] | 2: (letrec ((yy 23)) (let ((x 1)) (quote this-is-a-matric))) | 2: (let ((x 1)) (quote this-is-a-matric)) | 2: (quote this-is-a-matric) | 2: =>this-is-a-matric this-is-a-matric guile> @end lisp This example shows the default configuration for how each line of trace output is formatted, which is: @itemize @item the character @code{|}, a visual clue that the line is a line of trace output, followed by @item a number indicating the real evaluator stack depth (where ``real'' means not counting tail-calls), followed by @item a summary of the expression being evaluated (@code{(@dots{})}), the procedure being called (@code{[@dots{}]}), or the value being returned from an evaluation or procedure call (@code{=>@dots{}}). @end itemize @noindent You can customize @code{(ice-9 debugging trace)} to show different information in each trace line using the @code{set-trace-layout} procedure. The next example shows how to get the source location in each trace line instead of the stack depth. @lisp guile> (set-trace-layout "|~16@@a: ~a\n" trace/source trace/info) guile> (do-main 4) | matrix.scm:7:2: [mkmatrix] | : (letrec ((yy 23)) (let ((x 1)) (quote this-is-a-matric))) | matrix.scm:3:2: (let ((x 1)) (quote this-is-a-matric)) | matrix.scm:4:20: (quote this-is-a-matric) | matrix.scm:4:20: =>this-is-a-matric this-is-a-matric guile> @end lisp (For anyone wondering why the first @code{(do-main 4)} call above generates lots more trace lines than the subsequent calls: these examples also demonstrate how the Guile evaluator ``memoizes'' code. When Guile evaluates a source code expression for the first time, it changes some parts of the expression so that they will be quicker to evaluate when that expression is evaluated again; this is called memoization. The trace output from the first @code{(do-main 4)} call shows memoization steps, such as an internal define being transformed to a letrec.) @node Intro to Breakpoints @subsection Intro to Breakpoints Sometimes a piece of Scheme code isn't working and you'd like to go through it step by step. You can do this in Guile by setting a breakpoint at the start of the relevant code, and then using the command line or Emacs interface to step through it. A breakpoint can be specified by procedure name or by location -- the relevant code's file name, line number and column number. For details please see the full documentation for @code{break-in} and @code{break-at} in @ref{Intro to Breakpoints}. When you set a breakpoint, you can specify any ``behaviour'' you like for what should happen when the breakpoint is hit; a breakpoint ``behaviour'' is just a Scheme procedure with the right signature. @menu * Breakpoints Overview:: @end menu @node Breakpoints Overview @subsubsection How Breakpoints Work and Why They Are Useful Often, debugging the last error is not enough to tell you what went wrong. For example, the root cause of the error may have arisen a long time before the error was signalled, in which case the execution context of the error is too late to be useful. Or your program might not signal an error at all, just return an unexpected result or have some incorrect side effect. In many such cases, it's useful to pause the program at or before the point where you suspect the problem arises. Then you can explore the stack, display the values of key variables, and generally check that the state of the program is as you expect. If all is well, you can let the program continue running normally, or step more slowly through each expression that the Scheme interpreter evaluates. Single-stepping may reveal that the program is going through blocks of code that you didn't intend --- a useful data point for understanding what the underlying problem is. Telling Guile where or when to pause a program is called @dfn{setting a breakpoint}. When a breakpoint is hit, Guile's default behaviour is to enter the interactive debugger, where there are now two sets of commands available: @itemize @bullet @item all the commands as described for last error debugging (@pxref{Interactive Debugger}), which allow you to explore the stack and so on @item additional commands for continuing program execution in various ways: @code{next}, @code{step}, @code{finish}, @code{trace-finish} and @code{continue}. @end itemize Use of the interactive debugger is described in @ref{Interactive Debugger}. @node Tracing @subsection Tracing Tracing has already been described as a breakpoint behaviour, but we mention it again here because it is so useful, and because Guile actually now has @emph{two} mechanisms for tracing, and its worth clarifying the differences between them. @menu * Old Tracing:: Tracing provided by (ice-9 debug). * New Tracing:: Breakpoint-based tracing. * Tracing Compared:: Differences between old and new. @end menu @node Old Tracing @subsubsection Tracing Provided by @code{(ice-9 debug)} The @code{(ice-9 debug)} module implements tracing of procedure applications. When a procedure is @dfn{traced}, it means that every call to that procedure is reported to the user during a program run. The idea is that you can mark a collection of procedures for tracing, and Guile will subsequently print out a line of the form @smalllisp | | [@var{procedure} @var{args} @dots{}] @end smalllisp whenever a marked procedure is about to be applied to its arguments. This can help a programmer determine whether a function is being called at the wrong time or with the wrong set of arguments. In addition, the indentation of the output is useful for demonstrating how the traced applications are or are not tail recursive with respect to each other. Thus, a trace of a non-tail recursive factorial implementation looks like this: @smalllisp [fact1 4] | [fact1 3] | | [fact1 2] | | | [fact1 1] | | | | [fact1 0] | | | | 1 | | | 1 | | 2 | 6 24 @end smalllisp While a typical tail recursive implementation would look more like this: @smalllisp [fact2 4] [facti 1 4] [facti 4 3] [facti 12 2] [facti 24 1] [facti 24 0] 24 @end smalllisp @deffn {Scheme Procedure} trace procedure Enable tracing for @code{procedure}. While a program is being run, Guile will print a brief report at each call to a traced procedure, advising the user which procedure was called and the arguments that were passed to it. @end deffn @deffn {Scheme Procedure} untrace procedure Disable tracing for @code{procedure}. @end deffn Here is another example: @lisp (define (rev ls) (if (null? ls) '() (append (rev (cdr ls)) (cons (car ls) '())))) @result{} rev (trace rev) @result{} (rev) (rev '(a b c d e)) @result{} [rev (a b c d e)] | [rev (b c d e)] | | [rev (c d e)] | | | [rev (d e)] | | | | [rev (e)] | | | | | [rev ()] | | | | | () | | | | (e) | | | (e d) | | (e d c) | (e d c b) (e d c b a) (e d c b a) @end lisp Note the way Guile indents the output, illustrating the depth of execution at each procedure call. This can be used to demonstrate, for example, that Guile implements self-tail-recursion properly: @lisp (define (rev ls sl) (if (null? ls) sl (rev (cdr ls) (cons (car ls) sl)))) @result{} rev (trace rev) @result{} (rev) (rev '(a b c d e) '()) @result{} [rev (a b c d e) ()] [rev (b c d e) (a)] [rev (c d e) (b a)] [rev (d e) (c b a)] [rev (e) (d c b a)] [rev () (e d c b a)] (e d c b a) (e d c b a) @end lisp Since the tail call is effectively optimized to a @code{goto} statement, there is no need for Guile to create a new stack frame for each iteration. Tracing reveals this optimization in operation. @node New Tracing @subsubsection Breakpoint-based Tracing Guile's newer mechanism implements tracing as an optional behaviour for any kind of breakpoint. To trace a procedure (in the same kind of way as the older tracing), use the @code{trace!} procedure to set a procedure breakpoint with @code{trace-here} behaviour: @lisp (trace! fact1) @print{} Set breakpoint 1: [fact1] @result{} #< 40337bf0> (fact1 4) @print{} | [fact1 4] | | [fact1 3] | | | [fact1 2] | | | | [fact1 1] | | | | | [fact1 0] | | | | | 1 | | | | 2 | | | 6 | | 24 | 24 @result{} 24 @end lisp To trace evaluation of a source expression, evaluate code containing a breakpoint marker @code{##} in the appropriate place, then use @code{set-breakpoint} to change the behaviour of the new breakpoint to @code{trace-here}: @lisp (define (fact1 n) (if ##(= n 0) 1 (* n (fact1 (- n 1))))) @print{} Set breakpoint 4: standard input:13:9: (= n 0) (use-modules (ice-9 debugger behaviour)) (set-breakpoint! trace-here 4) @print{} Breakpoint 4: standard input:13:9: (= n 0) enabled? = #t behaviour = # (fact1 4) @print{} | (= n 0) | #f | (= n 0) | #f | (= n 0) | #f | (= n 0) | #f | (= n 0) | #t @result{} 24 @end lisp @noindent (Note --- this example reveals a bug: each occurrence of @code{(= n 0)} should be shown indented with respect to the one before it, as @code{fact1} does not call itself tail-recursively.) You can also give a breakpoint the @code{trace-subtree} behaviour, which means to trace the breakpoint location itself plus any evaluations and applications that occur below it in the call stack. In the following example, this allows us to see the evaluated arguments that are being compared by the @code{=} procedure: @lisp (set-breakpoint! trace-subtree 4) @print{} Breakpoint 4: standard input:13:9: (= n 0) enabled? = #t behaviour = # (fact1 4) @print{} | (= n 0) | [= 4 0] | #f | (= n 0) | [= 3 0] | #f | (= n 0) | [= 2 0] | #f | (= n 0) | [= 1 0] | #f | (= n 0) | [= 0 0] | #t @result{} 24 @end lisp @node Tracing Compared @subsubsection Differences Between Old and New Tracing Mechanisms The newer tracing mechanism is more general and so more powerful than the older one: it works for expressions as well as procedure applications, and it implements the useful @code{trace-subtree} behaviour as well as the more traditional @code{trace-here}. The older mechanism will probably become obsolete eventually, but it's worth keeping it around for a while until we are sure that the new mechanism is correct and does what programmers need.