mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
Moved/merged to scheme-using.texi, as REPL features. (Examples): New. (Intro to Breakpoints): New introductory text here. Removed all subnodes except for Breakpoints Overview. * scheme-using.texi: New. * guile.texi (Programming in Scheme): Include new scheme-using.texi file. * Makefile.am (guile_TEXINFOS): Include new scheme-using.texi file.
513 lines
15 KiB
Text
513 lines
15 KiB
Text
@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)
|
|
#<<break-in> 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))
|
|
#<<break-in> 808b430>
|
|
guile> (do-main 4)
|
|
| 2: [mkmatrix]
|
|
| 3: [define (define yy 23) ((()) #<eval-closure 4028db30>)]
|
|
| 3: [define (define yy 23) ((()) #<eval-closure 4028db30>)]
|
|
| 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{}
|
|
#<<procedure-breakpoint> 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 = #<procedure trace-here ()>
|
|
|
|
(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 = #<procedure trace-subtree ()>
|
|
|
|
(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.
|