diff options
Diffstat (limited to 'doc/ref/scheme-debugging.texi')
-rw-r--r-- | doc/ref/scheme-debugging.texi | 396 |
1 files changed, 1 insertions, 395 deletions
diff --git a/doc/ref/scheme-debugging.texi b/doc/ref/scheme-debugging.texi index 32a6a46bd..07511263b 100644 --- a/doc/ref/scheme-debugging.texi +++ b/doc/ref/scheme-debugging.texi @@ -5,280 +5,8 @@ @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)} +@section Tracing The @code{(ice-9 debug)} module implements tracing of procedure applications. When a procedure is @dfn{traced}, it means that every @@ -391,128 +119,6 @@ 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. - - @c Local Variables: @c TeX-master: "guile.texi" @c End: |