diff --git a/doc/ref/ChangeLog b/doc/ref/ChangeLog index aea2b0f1b..9a4e3be5e 100644 --- a/doc/ref/ChangeLog +++ b/doc/ref/ChangeLog @@ -1,3 +1,36 @@ +2008-03-19 Neil Jerram + + * api-debug.texi (Low Level Trap Calls): Removed (material + duplicated elsewhere); doc for with-traps and debug-object? moved + to section on evaluator trap options. + (High Level Traps): Renamed just `Traps'. Add references to + evaluator trap options and debug options. Make language + appropriate for core Guile (as opposed to previously separate + package). + (Location Traps): Corrected to reflect that location traps now + specify a specific position, not a range of positions. + (Debugging Examples): New (content moved here from + scheme-debugging.texi, and updated to use traps instead of + breakpoints). + + * api-modules.texi (Included Guile Modules): Change `Debugging + Features' reference to `Tracing'. + + * api-options.texi (Evaluator trap options): Doc for with-traps + and debug-object? is now here. + + * guile.texi, scheme-debugging.texi: Move the `Tracing' content of + scheme-debugging.texi to the Modules section. + + * scheme-using.texi (Using Guile in Emacs, GDS Getting Started): + Minor edits. + + * scheme-debugging.texi (Debugging Features, Intro to + Breakpoints): Removed. + (Examples): Moved to api-debug.texi. + (Tracing, Old Tracing): Promoted one level. + (New Tracing, Tracing Compared): Removed. + 2008-03-08 Julian Graham * api-scheduling.texi (Threads): Add documentation for new diff --git a/doc/ref/api-debug.texi b/doc/ref/api-debug.texi index 68c202266..0e8c6909f 100644 --- a/doc/ref/api-debug.texi +++ b/doc/ref/api-debug.texi @@ -17,9 +17,9 @@ infrastructure that builds on top of those calls. @menu * Evaluation Model:: Evaluation and the Scheme stack. * Debug on Error:: Debugging when an error occurs. -* Low Level Trap Calls:: -* High Level Traps:: +* Traps:: * Breakpoints:: +* Debugging Examples:: @end menu @node Evaluation Model @@ -610,65 +610,8 @@ Invoke the Guile debugger to explore the context of the last error. @end deffn -@node Low Level Trap Calls -@subsection Low Level Trap Calls - -@cindex Low level trap calls -@cindex Evaluator trap calls -Guile's evaluator can be configured to call the following four user-specified -procedures at various points in its operation. - -@table @dfn -@item apply-frame-handler -@item enter-frame-handler -@item exit-frame-handler -@item memoize-symbol-handler -@end table - -These procedures, and the circumstances under which the evaluator -calls them, are configured by the ``evaluator trap options'' interface -(@pxref{Evaluator trap options}), and by the @code{trace} and -@code{breakpoints} fields of the ``debug options'' interface -(@pxref{Debugger options}). - -It is not necessary to understand the fine details of these low level -calls, and of the options which configure them, in order to use the -class-based trap interface effectively. @code{guile-debugging} takes -care of setting these options as required for whatever set of -installed trap objects the user specifies.@footnote{And consequently, -when using the class-based trap interface, users/applications should -@emph{not} modify these options themselves, to avoid interfering with -@code{guile-debugging}'s option settings.} It is useful, though, to -have a overall idea of how the evaluator works and when these low -level calls can happen, as follows. - -@cindex Frame entry -@cindex Frame exit -On the basis of this description, we can now specify the points where -low level trap calls may occur (subject to configuration). Namely, -whenever a new frame is added to the stack, because the evaluator is -about to begin a new evaluation or to perform a new application, and -whenever a frame is being removed from the stack because the -computation that it refers to has completed and is returning its -value@footnote{If this raises the question of how expressions with -no return value are handled, the answer is that all computations in -Guile return a value. Those that appear to have no return value do so -by using the special @code{*unspecified*} value, which the Guile REPL -avoids displaying to the user.} to its caller. - -@deffn {Scheme Procedure} with-traps thunk -@deffnx {C Function} scm_with_traps (thunk) -Call @var{thunk} with traps enabled. -@end deffn - -@deffn {Scheme Procedure} debug-object? obj -@deffnx {C Function} scm_debug_object_p (obj) -Return @code{#t} if @var{obj} is a debug object. -@end deffn - - -@node High Level Traps -@subsection High Level Traps +@node Traps +@subsection Traps @cindex Traps @cindex Evaluator trap calls @@ -678,29 +621,33 @@ Return @code{#t} if @var{obj} is a debug object. @cindex Code coverage @cindex Profiling The low level C code of Guile's evaluator can be configured to call -out at key points to arbitrary user-specified code. In principle this -allows Scheme code to implement any model it chooses for examining the -evaluation stack as program execution proceeds, and for suspending -execution to be resumed later. Possible applications of this feature -include breakpoints, runtime tracing, code coverage, and profiling. +out at key points to arbitrary user-specified procedures. These +procedures, and the circumstances under which the evaluator calls +them, are configured by the ``evaluator trap options'' interface +(@pxref{Evaluator trap options}), and by the @code{trace} and +@code{breakpoints} fields of the ``debug options'' interface +(@pxref{Debugger options}). In principle this allows Scheme code to +implement any model it chooses for examining the evaluation stack as +program execution proceeds, and for suspending execution to be resumed +later. Possible applications of this feature include breakpoints, +runtime tracing, code coverage, and profiling. @cindex Trap classes @cindex Trap objects -Based on these low level trap calls, the enhancements described here -provide a much higher level, object-oriented interface for the -manipulation of traps. Different kinds of trap are represented as -GOOPS classes; for example, the @code{} class -describes traps that are triggered by invocation of a specified -procedure. A particular instance of a trap class --- or @dfn{trap -object} --- describes the condition under which a single trap will be -triggered, and what will happen then; for example, an instance of -@code{} whose @code{procedure} and @code{behaviour} -slots contain @code{my-factorial} and @code{debug-trap} would be a -trap that enters the command line debugger when the -@code{my-factorial} procedure is invoked. +Based on these low level trap calls, Guile provides a higher level, +object-oriented interface for the manipulation of traps. Different +kinds of trap are represented as GOOPS classes; for example, the +@code{} class describes traps that are triggered by +invocation of a specified procedure. A particular instance of a trap +class --- or @dfn{trap object} --- describes the condition under which +a single trap will be triggered, and what will happen then; for +example, an instance of @code{} whose @code{procedure} +and @code{behaviour} slots contain @code{my-factorial} and +@code{debug-trap} would be a trap that enters the command line +debugger when the @code{my-factorial} procedure is invoked. -The following subsubsections describe all this in greater detail, for both -the user wanting to use traps, and the developer interested in +The following subsections describe all this in detail, for both the +user wanting to use traps, and the developer interested in understanding how the interface hangs together. @@ -813,8 +760,8 @@ shorthands for setting common kinds of traps. @xref{Trap Shorthands}, for some examples. The ability to install, uninstall and reinstall a trap without losing -its definition is @code{guile-debugging}'s equivalent of the -disable/enable commands provided by debuggers like GDB. +its definition is Guile's equivalent of the disable/enable commands +provided by debuggers like GDB. @deffn {Generic Function} install-trap trap Install the trap object @var{trap}, so that its behaviour will be @@ -832,9 +779,9 @@ met. @subsubsection Specifying Trap Behaviour @cindex Trap behaviour -@code{guile-debugging} provides several ``out-of-the-box'' behaviours -for common needs. All of the following can be used directly as the -value of the @code{#:behaviour} option when creating a trap object. +Guile provides several ``out-of-the-box'' behaviours for common needs. +All of the following can be used directly as the value of the +@code{#:behaviour} option when creating a trap object. @deffn {Procedure} debug-trap trap-context Enter Guile's command line debugger to explore the stack at @@ -1179,9 +1126,9 @@ guile> (rev '(a b c)) @node Tracing and (ice-9 debug) @subsubsection Tracing and (ice-9 debug) -The @code{(ice-9 debug)} module of the core Guile distribution -provides a tracing facility that is roughly similar to that described -here, but there are important differences. +The @code{(ice-9 debug)} module provides a tracing facility +(@pxref{Tracing}) that is roughly similar to that described here, but +there are important differences. @itemize @bullet @item @@ -1202,35 +1149,30 @@ in stack depth, by using indentation like this: @end lisp However its output can @emph{only} show the information seen here, -which corresponds to @code{guile-debugging}'s @code{trace/info} -procedure; it cannot be configured to show other pieces of information -about the trap context in the way that @code{guile-debugging}'s trace -feature can. +which corresponds to @code{(ice-9 debugging trace)}'s +@code{trace/info} procedure; it cannot be configured to show other +pieces of information about the trap context in the way that the +@code{(ice-9 debugging trace)} implementation can. @item The @code{(ice-9 debug)} trace only allows the tracing of procedure -applications and their return values, whereas @code{guile-debugging}'s -trace allows any kind of trap to be traced. +applications and their return values, whereas the @code{(ice-9 debugging +trace)} implementation allows any kind of trap to be traced. It's interesting to note that @code{(ice-9 debug)}'s restriction here, which might initially appear to be just a straightforward consequence of its implementation, is also somewhat dictated by its pictorial display. The use of indentation in the output relies on hooking into the low level trap calls in such a way that the trapped application -entries and exits exactly balance each other. -@code{guile-debugging}'s more general traps interface allows traps to -be installed such that entry and exit traps don't necessarily balance, -which means that, in general, indentation diagrams like the one above -don't work. +entries and exits exactly balance each other. The @code{ice-9 +debugging trace} implementation allows traps to be installed such that +entry and exit traps don't necessarily balance, which means that, in +general, indentation diagrams like the one above don't work. @end itemize It isn't currently possible to use both @code{(ice-9 debug)} trace and -@code{guile-debugging} in the same Guile session, because their settings -of the low level trap options conflict with each other. (It should be -possible to fix this, by modifying @code{(ice-9 debug)} to use -@code{guile-debugging}'s trap installation interface, but only if and -when @code{guile-debugging} is integrated into the core Guile -distribution.) +@code{(ice-9 debugging trace)} in the same Guile session, because +their settings of the low level trap options conflict with each other. @node Traps Installing More Traps @@ -1456,9 +1398,9 @@ user would intuitively think of as single-stepping through their code, either through code in general (roughly corresponding to GDB's @code{step} command, for example), or through code from a particular source file (roughly corresponding to GDB's @code{next}). Therefore -if you are using @code{guile-debugging} to single-step through code -and finding its behaviour counter-intuitive, please let me know so -that I can improve it. +if you are using a step trap to single-step through code and finding +its behaviour counter-intuitive, please report that so we can improve +it. The implementation and options of the @code{} class are complicated by the fact that it is unreliable to determine whether a @@ -1620,16 +1562,16 @@ following subsubsection. @subsubsection Location Traps The @code{} class implements traps that are triggered -by evaluation of code at a specific source location or within a -specified range of source locations. When compared with source traps, -they are easier to set, and do not become irrelevant when the relevant -code is reloaded; but unfortunately they are considerably less -efficient, as they require running some ``are we in the right place -for a trap'' code on every low level frame entry trap call. +by evaluation of code at a specific source location. When compared +with source traps, they are easier to set, and do not become +irrelevant when the relevant code is reloaded; but unfortunately they +are a lot less efficient, as they require running some ``are we in the +right place for a trap'' code on every low level frame entry trap +call. @deffn {Class} Class for traps triggered by evaluation of code at a specific source -location or in a specified range of source locations. +location. @end deffn @deffn {Trap Option} #:file-regexp regexp @@ -1637,31 +1579,27 @@ A regular expression specifying the filenames that will match this trap. This option must be specified when creating a location trap. @end deffn -@deffn {Trap Option} #:line line-spec -If specified, @var{line-spec} describes either a single line, in which -case it is a single integer, or a range of lines, in which case it is -a pair of the form @code{(@var{min-line} . @var{max-line})}. All line -numbers are 0-based, and the range form is inclusive-inclusive. If -@code{#f} or not specified, the trap is not restricted by line number. -(Default value @code{#f}.) +@deffn {Trap Option} #:line line +The line number (0-based) of the source location at which the trap +should be triggered. This option must be specified when creating a +location trap. @end deffn -@deffn {Trap Option} #:column column-spec -If specified, @var{column-spec} describes either a single column, in -which case it is a single integer, or a range of columns, in which -case it is a pair of the form @code{(@var{min-column} -. @var{max-column})}. All column numbers are 0-based, and the range -form is inclusive-inclusive. If @code{#f} or not specified, the trap -is not restricted by column number. (Default value @code{#f}.) +@deffn {Trap Option} #:column column +The column number (0-based) of the source location at which the trap +should be triggered. This option must be specified when creating a +location trap. @end deffn @noindent -Example: +Here is an example, which matches the @code{(facti (- n 1) (* a n))} +expression in @file{ice-9/debugging/example-fns.scm}: @lisp (install-trap (make #:file-regexp "example-fns.scm" - #:line '(11 . 13) + #:line 11 + #:column 6 #:behaviour gds-debug-trap)) @end lisp @@ -1672,8 +1610,7 @@ Example: If the code described in the preceding subsubsections for creating and manipulating traps seems a little long-winded, it is of course possible to define more convenient shorthand forms for typical usage -patterns. For example, my own @file{.guile} file contains the -following definitions for setting breakpoints and for tracing. +patterns. Here are some examples. @lisp (define (break! proc) @@ -1694,11 +1631,11 @@ following definitions for setting breakpoints and for tracing. trace-until-exit)))) @end lisp -Definitions like these are not provided out-of-the-box by -@code{guile-debugging}, because different users will have different -ideas about what their default debugger should be, or, for example, -which of the common trap options (@pxref{Common Trap Options}) it -might be useful to expose through such shorthand procedures. +Definitions like these are not provided out-of-the-box by Guile, +because different users will have different ideas about what their +default debugger should be, or, for example, which of the common trap +options (@pxref{Common Trap Options}) it might be useful to expose +through such shorthand procedures. @node Trap Utilities @@ -1760,12 +1697,11 @@ While they are an important piece of infrastructure, and directly usable in some scenarios, traps are still too low level to meet some of the requirements of interactive development. -For example, in my experience a common scenario is that a newly -written procedure is not working properly, and so you'd like to be -able to step or trace through its code to find out why. Ideally this -should be possible from the IDE and without having to modify the -source code. There are two problems with using traps directly in this -scenario. +A common scenario is that a newly written procedure is not working +properly, and so you'd like to be able to step or trace through its +code to find out why. Ideally this should be possible from the IDE +and without having to modify the source code. There are two problems +with using traps directly in this scenario. @enumerate @item @@ -1885,6 +1821,216 @@ be managed through GDS. For the details of GDS's breakpoints interface, see @ref{Setting and Managing Breakpoints}. +@node Debugging Examples +@subsection Debugging Examples + +Here we present some examples of what you can do with the debugging +facilities just described. + +@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 trap on it and then single step through what it does. To do this, +make and install a @code{} 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 traps)) +guile> (load "matrix.scm") +guile> (install-trap (make + #:procedure mkmatrix + #:behaviour debug-trap)) +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'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? For this requirement you +can install a trap on the procedure, as in the previous example, but +instead of @code{debug-trap} or @code{gds-debug-trap}, 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 traps) (ice-9 debugging trace)) +guile> (load "matrix.scm") +guile> (install-trap (make + #:procedure mkmatrix + #:behaviour (list trace-trap trace-until-exit))) +guile> (do-main 4) +| 2: [mkmatrix] +| 3: [# # define #f] +| 3: [# # define #f] +| 4: (and (memq sym bindings) (let ...)) +| 5: (memq sym bindings) +| 5: [memq define (debug)] +| 5: =>#f +| 3: [# # define #f] +| 3: [# # define #f] +| 4: (and (memq sym bindings) (let ...)) +| 5: (memq sym bindings) +| 5: [memq define (debug)] +| 5: =>#f +| 3: [# # let #f] +| 3: [# # let #f] +| 4: (and (memq sym bindings) (let ...)) +| 5: (memq sym bindings) +| 5: [memq let (debug)] +| 5: =>#f +| 3: [# # let #f] +| 3: [# # let #f] +| 4: (and (memq sym bindings) (let ...)) +| 5: (memq sym bindings) +| 5: [memq let (debug)] +| 5: =>#f +| 3: [# # let #f] +| 3: [# # let #f] +| 4: (and (memq sym bindings) (let ...)) +| 5: (memq sym bindings) +| 5: [memq let (debug)] +| 5: =>#f +| 2: (letrec ((yy 23)) (let ((x 1)) (quote this-is-a-matric))) +| 3: [# # let #f] +| 3: [# # let #f] +| 4: (and (memq sym bindings) (let ...)) +| 5: (memq sym bindings) +| 5: [memq let (debug)] +| 5: =>#f +| 3: [# # let #f] +| 3: [# # let #f] +| 4: (and (memq sym bindings) (let ...)) +| 5: (memq sym bindings) +| 5: [memq let (debug)] +| 5: =>#f +| 3: [# # let #f] +| 3: [# # let #f] +| 4: (and (memq sym bindings) (let ...)) +| 5: (memq sym bindings) +| 5: [memq let (debug)] +| 5: =>#f +| 2: (let ((x 1)) (quote this-is-a-matric)) +| 3: [# # let #f] +| 3: [# # let #f] +| 4: (and (memq sym bindings) (let ...)) +| 5: (memq sym bindings) +| 5: [memq let (debug)] +| 5: =>#f +| 2: [let (let # #) (# # #)] +| 2: [let (let # #) (# # #)] +| 2: =>(#@@let* (x 1) #@@let (quote 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:4: (quote this-is-a-matric) +| matrix.scm:4:4: =>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.) + + @c Local Variables: @c TeX-master: "guile.texi" @c End: diff --git a/doc/ref/api-modules.texi b/doc/ref/api-modules.texi index 415c9cba6..94b93bdc1 100644 --- a/doc/ref/api-modules.texi +++ b/doc/ref/api-modules.texi @@ -679,7 +679,7 @@ Guile starts up. @item (ice-9 debug) Mikael Djurfeldt's source-level debugging support for Guile -(@pxref{Debugging Features}). +(@pxref{Tracing}). @item (ice-9 expect) Actions based on matching input from a port (@pxref{Expect}). diff --git a/doc/ref/api-options.texi b/doc/ref/api-options.texi index 493e2385d..c44de8c59 100644 --- a/doc/ref/api-options.texi +++ b/doc/ref/api-options.texi @@ -613,7 +613,6 @@ way. @var{retval} is the return value. @end deffn - @deffn memoize-symbol-handler key cont expression env Called when the evaluator memoizes the value of a procedure symbol @@ -626,6 +625,16 @@ way. @var{retval} is the return value. @end deffn +@deffn {Scheme Procedure} with-traps thunk +@deffnx {C Function} scm_with_traps (thunk) +Call @var{thunk} with traps enabled. +@end deffn + +@deffn {Scheme Procedure} debug-object? obj +@deffnx {C Function} scm_debug_object_p (obj) +Return @code{#t} if @var{obj} is a debug object. +@end deffn + @node Debugger options @subsubsection Debugger options diff --git a/doc/ref/guile.texi b/doc/ref/guile.texi index 109a50b7f..2023c6e96 100644 --- a/doc/ref/guile.texi +++ b/doc/ref/guile.texi @@ -138,7 +138,7 @@ x @comment The title is printed in a large font. @title Guile Reference Manual @subtitle Edition @value{MANUAL-EDITION}, for use with Guile @value{VERSION} -@c @subtitle $Id: guile.texi,v 1.48 2006-11-18 18:14:55 civodul Exp $ +@c @subtitle $Id: guile.texi,v 1.49 2008-03-19 22:51:23 ossau Exp $ @c See preface.texi for the list of authors @author The Guile Developers @@ -222,7 +222,6 @@ etc. that make up Guile's application programming interface (API), * Guile Scripting:: How to write Guile scripts. * Using Guile Interactively:: Guile's REPL features. * Using Guile in Emacs:: Guile and Emacs. -* Debugging Features:: Features for finding errors. * Further Reading:: Where to find out more about Scheme. @end menu @@ -230,7 +229,6 @@ etc. that make up Guile's application programming interface (API), @include scheme-intro.texi @include scheme-scripts.texi @include scheme-using.texi -@include scheme-debugging.texi @include scheme-reading.texi @node Programming in C @@ -351,6 +349,7 @@ available through both Scheme and C interfaces. * Buffered Input:: Ports made from a reader function. * Expect:: Controlling interactive programs with Guile. * The Scheme shell (scsh):: Using scsh interfaces in Guile. +* Tracing:: Tracing program execution. @end menu @include slib.texi @@ -361,6 +360,7 @@ available through both Scheme and C interfaces. @include misc-modules.texi @include expect.texi @include scsh.texi +@include scheme-debugging.texi @include data-rep.texi @include fdl.texi 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) -#< 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)} +@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{} -#< 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. - - @c Local Variables: @c TeX-master: "guile.texi" @c End: diff --git a/doc/ref/scheme-using.texi b/doc/ref/scheme-using.texi index 93d0949f8..986252eac 100644 --- a/doc/ref/scheme-using.texi +++ b/doc/ref/scheme-using.texi @@ -163,10 +163,10 @@ The interactive debugger is documented further in the following section. @node Interactive Debugger @subsection Using the Interactive Debugger -Guile's interactive debugger is a command line application that accepts -commands from you for examining the stack and, if at a breakpoint, for -continuing program execution in various ways. Unlike in the normal -Guile REPL, commands are typed mostly without parentheses. +Guile's interactive debugger is a command line application that +accepts commands from you for examining the stack and, if stopped at a +trap, for continuing program execution in various ways. Unlike in the +normal Guile REPL, commands are typed mostly without parentheses. When you first enter the debugger, it introduces itself with a message like this: @@ -359,15 +359,15 @@ debugger to continue.) @node Using Guile in Emacs @section Using Guile in Emacs -There are quite a few options for working on Guile Scheme code in -Emacs. The simplest options are to use Emacs's standard -@code{scheme-mode} for editing code, and to run the interpreter when you -need it by typing ``guile'' at the prompt of a @code{*shell*} buffer, -but there are Emacs libraries available which add various bells and -whistles to this. The following diagram shows these libraries and how -they relate to each other, with the arrows indicating ``builds on'' or -``extends''. For example, the Quack library builds on cmuscheme, which -in turn builds on the standard scheme mode. +There are several options for working on Guile Scheme code in Emacs. +The simplest are to use Emacs's standard @code{scheme-mode} for +editing code, and to run the interpreter when you need it by typing +``guile'' at the prompt of a @code{*shell*} buffer, but there are +Emacs libraries available which add various bells and whistles to +this. The following diagram shows these libraries and how they relate +to each other, with the arrows indicating ``builds on'' or +``extends''. For example, the Quack library builds on cmuscheme, +which in turn builds on the standard scheme mode. @example scheme @@ -408,25 +408,24 @@ interpreters and remembers which one you used last time; and so on. Quack is available from @uref{http://www.neilvandyke.org/quack}. @dfn{GDS}, written by Neil Jerram, also builds on the scheme/cmuscheme -combination, but with a fundamental change to the way that Scheme code -fragments are sent to the interpreter for evaluation. cmuscheme and -Quack send code fragments to the interpreter's standard input, on the -assumption that the interpreter is expecting to read Scheme expressions -there, and then monitor the interpreter's standard output to infer what -the result of the evaluation is. GDS doesn't use standard input and +combination, but with a change to the way that Scheme code fragments +are sent to the interpreter for evaluation. cmuscheme and Quack send +code fragments to the interpreter's standard input, on the assumption +that the interpreter is expecting to read Scheme expressions there, +and then monitor the interpreter's standard output to infer what the +result of the evaluation is. GDS doesn't use standard input and output like this. Instead, it sets up a socket connection between the Scheme interpreter and Emacs, and sends and receives messages using a simple protocol through this socket. The messages include requests to evaluate Scheme code, and responses conveying the results of an -evaluation, thus providing similar function to cmuscheme or Quack. They -also include requests for setting breakpoints, stack exploration and -debugging, which go beyond what cmuscheme or Quack can do. The price of -this extra power, however, is that GDS is Guile-specific. GDS requires -the Scheme interpreter, or any program that GDS is debugging, to run -some GDS-specific library code; currently this code is written as a -Guile module and uses a lot of debugging-related features that are +evaluation, thus providing similar function to cmuscheme or Quack. +They also include requests for stack exploration and debugging, which +go beyond what cmuscheme or Quack can do. The price of this extra +power, however, is that GDS is Guile-specific. GDS requires the +Scheme interpreter to run some GDS-specific library code; currently +this code is written as a Guile module and uses features that are specific to Guile. GDS is now included in the Guile distribution; for -previous Guile releases (1.8.x and earlier) it can be obtained as part +previous Guile releases (1.8.4 and earlier) it can be obtained as part of the @code{guile-debugging} package from @uref{http://www.ossau.uklinux.net/guile}. @@ -540,7 +539,7 @@ Emacs. This code, consisting of the installed files @file{gds.el} and @file{gds-server.el}, is responsible for displaying information from Guile in Emacs windows, and for responding to Emacs commands and keystrokes by sending instructions back to the Guile program being -debugged. +worked on. @item The GDS @dfn{server} code is written in Scheme and runs as an Emacs @@ -584,12 +583,12 @@ The data exchanged between client and server components, and between server and interface, is a sequence of sexps (parenthesised expressions) that are designed so as to be directly readable by both Scheme and Emacs Lisp. The use of a TCP connection means that the server and Emacs -interface can theoretically be on a different computer from the programs -being debugged, but in practice there are currently two problems with +interface can theoretically be on a different computer from the client +programs, but in practice there are currently two problems with this. Firstly the GDS API doesn't provide any way of specifying a non-local server to connect to, and secondly there is no security or authentication mechanism in the GDS protocol. These are issues that -should be addressed in the near future. +should be addressed in the future. @node GDS Getting Started @@ -620,7 +619,7 @@ and the @code{gds-debug} buffer will contain a Scheme backtrace ending with the message: @lisp -no code for module (ossau gds-server) +no code for module (ice-9 gds-server) @end lisp @noindent @@ -645,10 +644,10 @@ Emacs to open the file @file{gds-tutorial.txt} (which should have been installed as part of Guile, perhaps under @file{/usr/share/doc/guile}), and then follow the steps in that file. -When you want to use GDS to explore or debug an independent Guile +When you want to use GDS to work on an independent Guile application, you need to add something to that application's Scheme code to cause it to connect to and interact with GDS at the right times. The -following subsections describe the various ways of doing this. +following subsections describe the ways of doing this. @subsubsection Setting Specific Breakpoints @@ -667,10 +666,10 @@ the following. @end lisp @noindent -The @code{#:behaviour gds-debug-trap} clauses mean to use GDS to display -the stack when one of these breakpoints is hit. For more on -breakpoints, @code{break-in} and @code{break-at}, see @ref{Intro to -Breakpoints}. +The @code{#:behaviour gds-debug-trap} clauses mean to use GDS to +display the stack when one of these breakpoints is hit. For more on +breakpoints, @code{break-in} and @code{break-at}, see +@ref{Breakpoints}. @subsubsection Setting GDS-managed Breakpoints @@ -723,7 +722,7 @@ is pre-1.8) around the code of interest like this: (gds-debug-trap (throw->trap-context key args)))) @end lisp -In all cases you will need to use the @code{(ice-9 gds-client)} and +Either way, you will need to use the @code{(ice-9 gds-client)} and @code{(ice-9 debugging traps)} modules. Two special cases of this are the lazy-catch that the Guile REPL code @@ -738,7 +737,6 @@ procedure as follows. @lisp (use-modules (ice-9 gds-client) (ice-9 debugging traps)) - (on-lazy-handler-dispatch gds-debug-trap) @end lisp @@ -787,16 +785,12 @@ This approach is not yet implemented, though. @subsubsection Utility Guile Implementation -We conclude this subsection with an aside, by noting that the -``utility'' Guile client described above is nothing more than a -combination of the previous options. - -To be precise, the code for the utility Guile client is essentially just -this: +The ``utility'' Guile client mentioned above is a simple combination +of the mechanisms that we have just described. In fact the code for +the utility Guile client is essentially just this: @lisp (use-modules (ice-9 gds-client)) - (set-gds-breakpoints) (named-module-use! '(guile-user) '(ice-9 session)) (gds-accept-input #f)) @@ -805,17 +799,22 @@ this: @code{set-gds-breakpoints} works as already described. The @code{named-module-use!} line ensures that the client can process @code{help} and @code{apropos} expressions, to implement lookups in -Guile's online help. The @code{#f} parameter to @code{gds-accept-input} -means that the @code{continue} instruction will not cause the -instruction loop to exit, which makes sense here because the utility -client has nothing to do except to process GDS instructions. +Guile's online help. The @code{#f} parameter to +@code{gds-accept-input} means that the @code{continue} instruction +will not cause the instruction loop to exit, which makes sense here +because the utility client has nothing to do except to process GDS +instructions. -(The utility client does not use @code{on-lazy-handler-dispatch}, -because it has its own mechanism for catching and reporting exceptions -in the code that it is asked to evaluate. This mechanism summarizes the -exception and gives the user a button they can click to see the full -stack, so the end result is very similar to what -@code{on-lazy-handler-dispatch} provides.) +The utility client does not use @code{on-lazy-handler-dispatch} at its +top level, because it has its own mechanism for catching and reporting +exceptions in the code that it is asked to evaluate. This mechanism +summarizes the exception and gives the user a button they can click to +see the full stack, so the end result is very similar to what +@code{on-lazy-handler-dispatch} provides. Deep inside +@code{gds-accept-input}, in the part that handles evaluating +expressions from Emacs, the GDS client code uses +@code{throw->trap-context} and @code{gds-debug-trap} to implement +this. @node Working with GDS in Scheme Buffers @@ -850,7 +849,7 @@ or before the cursor but can also be entered or edited in the minibuffer. The available help is popped up in a temporary Emacs window. -@item C-h C-g +@item C-h G @findex gds-apropos List all accessible Guile symbols matching a given regular expression, with the same results as if you had typed @code{(apropos REGEXP)} into @@ -1211,35 +1210,9 @@ display in action. To do this add @noindent to your @file{testgds.scm} buffer and type @kbd{C-x C-e} (which -evaluates the expression that the cursor is just after the end of). The -result is: - -@lisp -(fact1 4) - -;;; Evaluating in current module (guile-user) - @result{} 24 - ---:** *Guile Evaluation* (Scheme:ready)--All------------ -@end lisp - -@noindent -which is correct, but indicates that we forgot the step needed to enable -the trap mechanism. To do this, type @kbd{C-c C-e} and then enter - -@lisp -(trap-enable 'traps) -@end lisp - -@noindent -into the minibuffer. (You could equally have typed this into your test -file and evaluated it from there; we use @kbd{C-c C-e} here to -demonstrate the minibuffer option and because you typically wouldn't -want to leave this kind of global setting in the source code that you -are working on.) - -If you now type @kbd{C-x C-e} to evaluate @code{(fact1 4)} again, a GDS -stack window like the following appears: +evaluates the expression that the cursor is just after the end of). +The result should be that a GDS stack window like the following +appears: @lisp Calling procedure: @@ -1250,19 +1223,10 @@ Calling procedure: --:** PID 28729 (Guile-Debug)--All------------ @end lisp -GDS's most compelling feature is its single-stepping. To get an -immediate feel for what this is like, make sure your Emacs is prepared -as described in @ref{GDS Getting Started}, then type the following code -into an interactive Guile session. - -@lisp -(fact1 4) -@end lisp - -@noindent -This will cause the GDS Guile-Debug window to pop up in Emacs, where -you can then press @kbd{i} once and @kbd{@key{SPC}} repeatedly to -single-step through the code from the point of the initial trap. +This stack tells you that Guile is about to call the @code{fact1} +procedure, with argument 4, and you can step through this call in +detail by pressing @kbd{i} once and then @kbd{@key{SPC}} +(@pxref{Continuing Execution}). (@kbd{i} is needed as the first keystroke rather than @kbd{@key{SPC}}, because the aim here is to step through code in the @code{(ice-9