mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
* 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.
This commit is contained in:
parent
cc7e01cedd
commit
24dbb5ed10
7 changed files with 402 additions and 644 deletions
|
@ -1,3 +1,36 @@
|
|||
2008-03-19 Neil Jerram <neil@ossau.uklinux.net>
|
||||
|
||||
* 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 <joolean@gmail.com>
|
||||
|
||||
* api-scheduling.texi (Threads): Add documentation for new
|
||||
|
|
|
@ -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{<procedure-trap>} 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{<procedure-trap>} 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{<procedure-trap>} 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{<procedure-trap>} 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{<step-trap>} 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{<location-trap>} 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} <location-trap>
|
||||
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 <location-trap>
|
||||
#: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{<procedure-trap>} 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-trap>
|
||||
#: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-trap>
|
||||
#:procedure mkmatrix
|
||||
#:behaviour (list trace-trap trace-until-exit)))
|
||||
guile> (do-main 4)
|
||||
| 2: [mkmatrix]
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> define #f]
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> define #f]
|
||||
| 4: (and (memq sym bindings) (let ...))
|
||||
| 5: (memq sym bindings)
|
||||
| 5: [memq define (debug)]
|
||||
| 5: =>#f
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> define #f]
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> define #f]
|
||||
| 4: (and (memq sym bindings) (let ...))
|
||||
| 5: (memq sym bindings)
|
||||
| 5: [memq define (debug)]
|
||||
| 5: =>#f
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
|
||||
| 4: (and (memq sym bindings) (let ...))
|
||||
| 5: (memq sym bindings)
|
||||
| 5: [memq let (debug)]
|
||||
| 5: =>#f
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
|
||||
| 4: (and (memq sym bindings) (let ...))
|
||||
| 5: (memq sym bindings)
|
||||
| 5: [memq let (debug)]
|
||||
| 5: =>#f
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> 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: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
|
||||
| 4: (and (memq sym bindings) (let ...))
|
||||
| 5: (memq sym bindings)
|
||||
| 5: [memq let (debug)]
|
||||
| 5: =>#f
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
|
||||
| 4: (and (memq sym bindings) (let ...))
|
||||
| 5: (memq sym bindings)
|
||||
| 5: [memq let (debug)]
|
||||
| 5: =>#f
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> 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: [#<procedure #f (a sym definep)> #<autoload # b7c93870> let #f]
|
||||
| 3: [#<procedure #f (a sym definep)> #<autoload # b7c93870> 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:
|
||||
|
|
|
@ -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}).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue