mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 11:50:28 +02:00
* scheme-compound.texi: Renamed to api-compound.texi. * scheme-control.texi: Renamed to api-control.texi. * scheme-data.texi: Renamed to api-data.texi. * scheme-debug.texi: Renamed to api-debug.texi. * deprecated.texi: Renamed to api-deprecated.texi. * scheme-evaluation.texi: Renamed to api-evaluation.texi. * ref-init.texi: Renamed to api-init.texi. * scheme-io.texi: Renamed to api-io.texi. * scheme-memory.texi: Renamed to api-memory.texi. * scheme-modules.texi: Renamed to api-modules.texi. * scheme-options.texi: Renamed to api-options.texi. * scm.texi: Renamed to api-overview.texi. * scheme-procedures.texi: Renamed to api-procedures.texi. * scheme-scheduling.texi: Renamed to api-scheduling.texi. * scheme-scm.texi: Renamed to api-scm.texi. * scheme-smobs.texi: Renamed to api-smobs.texi. * scheme-snarf.texi: Renamed to api-snarf.texi. * scheme-translation.texi: Renamed to api-translation.texi. * scheme-utility.texi: Renamed to api-utility.texi. * debugging.texi: Renamed to scheme-debugging.texi. * scripts.texi: Renamed to scheme-scripts.texi. * program.texi: Renamed to libguile-program.texi.
1045 lines
30 KiB
Text
1045 lines
30 KiB
Text
@c -*-texinfo-*-
|
|
@c This is part of the GNU Guile Reference Manual.
|
|
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004
|
|
@c Free Software Foundation, Inc.
|
|
@c See the file guile.texi for copying conditions.
|
|
|
|
@page
|
|
@node Debugging Features
|
|
@section Debugging Features
|
|
|
|
Guile includes debugging tools to help you work out what is going wrong
|
|
when a program signals an error or behaves differently to how you would
|
|
expect. This chapter describes how to use these tools.
|
|
|
|
Broadly speaking, Guile's debugging support allows you to do two things:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
specify @dfn{breakpoints} --- points in the execution of a program where
|
|
execution should pause so you can see what is going on
|
|
|
|
@item
|
|
examine in detail the ``scene of the crime'' --- in other words, the
|
|
execution context at a breakpoint, or when the last error occurred.
|
|
@end itemize
|
|
|
|
@noindent
|
|
The details are more complex and more powerful @dots{}
|
|
|
|
@menu
|
|
* Debug Last Error:: Debugging the most recent error.
|
|
* Intro to Breakpoints:: Setting and manipulating them.
|
|
* Interactive Debugger:: Using the interactive debugger.
|
|
* Tracing:: Tracing program execution.
|
|
@end menu
|
|
|
|
|
|
@node Debug Last Error
|
|
@subsection Debugging the Most Recent Error
|
|
|
|
When an error is signalled, Guile remembers the execution context where
|
|
the error occurred. By default, Guile then displays only the most
|
|
immediate information about where and why the error occurred, for
|
|
example:
|
|
|
|
@lisp
|
|
(make-string (* 4 (+ 3 #\s)) #\space)
|
|
@print{}
|
|
standard input:2:19: In procedure + in expression (+ 3 #\s):
|
|
standard input:2:19: Wrong type argument: #\s
|
|
ABORT: (wrong-type-arg)
|
|
|
|
Type "(backtrace)" to get more information or "(debug)" to enter the debugger.
|
|
@end lisp
|
|
|
|
@noindent
|
|
However, as the message above says, you can obtain much more
|
|
information about the context of the error by typing
|
|
@code{(backtrace)} or @code{(debug)}.
|
|
|
|
@code{(backtrace)} displays the Scheme call stack at the point where the
|
|
error occurred:
|
|
|
|
@lisp
|
|
(backtrace)
|
|
@print{}
|
|
Backtrace:
|
|
In standard input:
|
|
2: 0* [make-string ...
|
|
2: 1* [* 4 ...
|
|
2: 2* [+ 3 #\s]
|
|
|
|
Type "(debug-enable 'backtrace)" if you would like a backtrace
|
|
automatically if an error occurs in the future.
|
|
@end lisp
|
|
|
|
@noindent
|
|
In a more complex scenario than this one, this can be extremely useful
|
|
for understanding where and why the error occurred. For more on the
|
|
format of the displayed backtrace, see the subsection below.
|
|
|
|
@code{(debug)} takes you into Guile's interactive debugger, which
|
|
provides commands that allow you to
|
|
|
|
@itemize @bullet
|
|
@item
|
|
display the Scheme call stack at the point where the error occurred
|
|
(the @code{backtrace} command --- see @ref{Display Backtrace})
|
|
|
|
@item
|
|
move up and down the call stack, to see in detail the expression being
|
|
evaluated, or the procedure being applied, in each @dfn{frame} (the
|
|
@code{up}, @code{down}, @code{frame}, @code{position}, @code{info args}
|
|
and @code{info frame} commands --- see @ref{Frame Selection} and
|
|
@ref{Frame Information})
|
|
|
|
@item
|
|
examine the values of variables and expressions in the context of each
|
|
frame (the @code{evaluate} command --- see @ref{Frame Evaluation}).
|
|
@end itemize
|
|
|
|
Use of the interactive debugger, including these commands, is described
|
|
in @ref{Interactive Debugger}.
|
|
|
|
@menu
|
|
* Backtrace Format:: How to interpret a backtrace.
|
|
@end menu
|
|
|
|
|
|
@node Backtrace Format
|
|
@subsubsection How to Interpret a Backtrace
|
|
|
|
|
|
@node Intro to Breakpoints
|
|
@subsection Intro to Breakpoints
|
|
|
|
If you are not already familiar with the concept of breakpoints, the
|
|
first subsection below explains how they work are why they are useful.
|
|
|
|
Broadly speaking, Guile's breakpoint support consists of
|
|
|
|
@itemize @bullet
|
|
@item
|
|
type-specific features for @emph{creating} breakpoints of various types
|
|
|
|
@item
|
|
relatively generic features for @emph{manipulating} the behaviour of
|
|
breakpoints once they've been created.
|
|
@end itemize
|
|
|
|
Different breakpoint types are implemented as different classes in a
|
|
GOOPS hierarchy with common base class @code{<breakpoint>}. The magic
|
|
of generic functions then allows most of the manipulation functions to
|
|
be generic by default but specializable (by breakpoint class) if the
|
|
need arises.
|
|
|
|
Generic breakpoint support is provided by the @code{(ice-9 debugger
|
|
breakpoints)} module, so you will almost always need to use this module
|
|
in order to access the functionality described here:
|
|
|
|
@smalllisp
|
|
(use-modules (ice-9 debugger breakpoints))
|
|
@end smalllisp
|
|
|
|
@noindent
|
|
You may like to add this to your @file{.guile} file.
|
|
|
|
@menu
|
|
* Breakpoints Overview::
|
|
* Source Breakpoints::
|
|
* Procedural Breakpoints::
|
|
* Setting Breakpoints::
|
|
* break! trace! trace-subtree!::
|
|
* Accessing Breakpoints::
|
|
* Breakpoint Behaviours::
|
|
* Enabling and Disabling::
|
|
* Deleting Breakpoints::
|
|
* Breakpoint Information::
|
|
* Other Breakpoint Types::
|
|
@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{Debug
|
|
Last Error}), 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 Source Breakpoints
|
|
@subsubsection Source Breakpoints
|
|
|
|
A source breakpoint is a breakpoint that triggers whenever program
|
|
execution hits a particular source location. A source breakpoint can be
|
|
conveniently set simply by evaluating code that has @code{##} inserted
|
|
into it at the position where you want the breakpoint to be.
|
|
|
|
For example, to set a breakpoint immediately before evaluation of
|
|
@code{(= n 0)} in the following procedure definition, evaluate:
|
|
|
|
@smalllisp
|
|
(define (fact1 n)
|
|
(if ##(= n 0)
|
|
1
|
|
(* n (fact1 (- n 1)))))
|
|
@print{}
|
|
Set breakpoint 1: standard input:4:9: (= n 0)
|
|
@end smalllisp
|
|
|
|
@noindent
|
|
Note the message confirming that you have set a breakpoint. If you
|
|
don't see this, something isn't working.
|
|
|
|
@code{##} is provided by the @code{(ice-9 debugger breakpoints source)} module,
|
|
so you must use this module before trying to set breakpoints in this
|
|
way:
|
|
|
|
@smalllisp
|
|
(use-modules (ice-9 debugger breakpoints source))
|
|
@end smalllisp
|
|
|
|
@noindent
|
|
You may like to add this to your @file{.guile} file.
|
|
|
|
The default behaviour for source breakpoints is @code{debug-here}
|
|
(@pxref{Breakpoint Behaviours}), which means to enter the command line
|
|
debugger when the breakpoint is hit. So, if you now use @code{fact1},
|
|
that is what happens.
|
|
|
|
@smalllisp
|
|
guile> (fact1 3)
|
|
Hit breakpoint 1: standard input:4:9: (= n 0)
|
|
Frame 3 at standard input:4:9
|
|
(= n 0)
|
|
debug>
|
|
@end smalllisp
|
|
|
|
|
|
@node Procedural Breakpoints
|
|
@subsubsection Procedural Breakpoints
|
|
|
|
A procedural breakpoint is a breakpoint that triggers whenever Guile is
|
|
about to apply a specified procedure to its (already evaluated)
|
|
arguments. To set a procedural breakpoint, call @code{break!} with the
|
|
target procedure as a single argument. For example:
|
|
|
|
@smalllisp
|
|
(define (fact1 n)
|
|
(if (= n 0)
|
|
1
|
|
(* n (fact1 (- n 1)))))
|
|
|
|
(break! fact1)
|
|
@print{}
|
|
Set breakpoint 1: [fact1]
|
|
@result{}
|
|
#<<procedure-breakpoint> 808b0b0>
|
|
@end smalllisp
|
|
|
|
Alternatives to @code{break!} are @code{trace!} and
|
|
@code{trace-subtree!}. The difference is that these three calls create
|
|
a breakpoint in the same place but with three different behaviours,
|
|
respectively @code{debug-here}, @code{trace-here} and
|
|
@code{trace-subtree}. Breakpoint behaviours are documented fully later
|
|
(@pxref{Breakpoint Behaviours}), but to give a quick taste, here's an
|
|
example of running code that includes a procedural breakpoint with the
|
|
@code{trace-here} behaviour.
|
|
|
|
@smalllisp
|
|
(trace! fact1)
|
|
@print{}
|
|
Set breakpoint 1: [fact1]
|
|
@result{}
|
|
#<<procedure-breakpoint> 808b0b0>
|
|
|
|
(fact1 4)
|
|
@print{}
|
|
| [fact1 4]
|
|
| | [fact1 3]
|
|
| | | [fact1 2]
|
|
| | | | [fact1 1]
|
|
| | | | | [fact1 0]
|
|
| | | | | 1
|
|
| | | | 2
|
|
| | | 6
|
|
| | 24
|
|
| 24
|
|
@result{}
|
|
24
|
|
@end smalllisp
|
|
|
|
To set and use procedural breakpoints, you will need to use the
|
|
@code{(ice-9 debugger breakpoints procedural)} module:
|
|
|
|
@smalllisp
|
|
(use-modules (ice-9 debugger breakpoints procedural))
|
|
@end smalllisp
|
|
|
|
@noindent
|
|
You may like to add this to your @file{.guile} file.
|
|
|
|
|
|
@node Setting Breakpoints
|
|
@subsubsection Setting Breakpoints
|
|
|
|
In general, that is. We've already seen how to set source and
|
|
procedural breakpoints conveniently in practice. This section explains
|
|
how those conveniences map onto a more general mechanism.
|
|
|
|
The general mechanism for setting breakpoints is the generic function
|
|
@code{set-breakpoint!}. Different kinds of breakpoints define
|
|
subclasses of the class @code{<breakpoint>} and provide their own
|
|
methods for @code{set-pbreakpoint!}.
|
|
|
|
For example, @code{(ice-9 debugger breakpoints procedural)} implements
|
|
the @code{<procedure-breakpoint>} subclass and provides a
|
|
@code{set-breakpoint!} method that takes a procedure argument:
|
|
|
|
@smalllisp
|
|
(set-breakpoint! @var{behavior} fact1)
|
|
@print{}
|
|
Set breakpoint 1: [fact1]
|
|
@result{}
|
|
#<<procedure-breakpoint> 808b0b0>
|
|
@end smalllisp
|
|
|
|
A non-type-specific @code{set-breakpoint!} method is provided by the
|
|
generic module @code{(ice-9 debugger breakpoints)}. It allows you to
|
|
change the behaviour of an existing breakpoint that is identified by
|
|
its breakpoint number.
|
|
|
|
@smalllisp
|
|
(set-breakpoint! @var{behavior} 1)
|
|
@end smalllisp
|
|
|
|
@node break! trace! trace-subtree!
|
|
@subsubsection break! trace! trace-subtree!
|
|
|
|
We have already talked above about the use of @code{break!},
|
|
@code{trace!} and @code{trace-subtree!} for setting procedural
|
|
breakpoints. Now that @code{set-breakpoint!} has been introduced, we
|
|
can reveal that @code{break!}, @code{trace!} and @code{trace-subtree!}
|
|
are in fact just wrappers for @code{set-breakpoint!} that specify
|
|
particular breakpoint behaviours, respectively @code{debug-here},
|
|
@code{trace-here} and @code{trace-subtree}.
|
|
|
|
@smalllisp
|
|
(break! . @var{args})
|
|
@equiv{} (set-breakpoint! debug-here . @var{args})
|
|
(trace! . @var{args})
|
|
@equiv{} (set-breakpoint! trace-here . @var{args})
|
|
(trace-subtree! . @var{args})
|
|
@equiv{} (set-breakpoint! trace-subtree . @var{args})
|
|
@end smalllisp
|
|
|
|
This means that these three procedures can be used to set the
|
|
corresponding behaviours for any type of breakpoint for which a
|
|
@code{set-breakpoint!} method exists, not just procedural ones.
|
|
|
|
|
|
@node Accessing Breakpoints
|
|
@subsubsection Accessing Breakpoints
|
|
|
|
Information about the state and behaviour of a breakpoint is stored in
|
|
an instance of the appropriate breakpoint class. To access and change
|
|
that information, therefore, you need to get hold of the desired
|
|
breakpoint instance.
|
|
|
|
The generic function @code{get-breakpoint} meets this need: For every
|
|
@code{set-breakpoint!} method there is a corresponding
|
|
@code{get-breakpoint} method. Note especially the useful
|
|
type-independent case:
|
|
|
|
@smalllisp
|
|
(get-breakpoint 1)
|
|
@result{}
|
|
#<<procedure-breakpoint> 808b0b0>
|
|
@end smalllisp
|
|
|
|
|
|
@node Breakpoint Behaviours
|
|
@subsubsection Breakpoint Behaviours
|
|
|
|
A breakpoint's @dfn{behaviour} determines what happens when that
|
|
breakpoint is hit. Several kinds of behaviour are generally useful.
|
|
|
|
@table @code
|
|
@item debug-here
|
|
Enter the command line debugger. This gives the opportunity to explore
|
|
the stack, evaluate expressions in any of the pending stack frames,
|
|
change breakpoint properties or set new breakpoints, and continue
|
|
program execution when you are done.
|
|
|
|
@item trace-here
|
|
Trace the current stack frame. For expressions being evaluated, this
|
|
shows the expression. For procedure applications, it shows the
|
|
procedure name and its arguments @emph{post-evaluation}. For both
|
|
expressions and applications, the indentation of the tracing indicates
|
|
whether the traced items are mutually tail recursive.
|
|
|
|
@item trace-subtree
|
|
Trace the current stack frame, and enable tracing for all future
|
|
evaluations and applications until the current stack frame is exited.
|
|
@code{trace-subtree} is a great preliminary exploration tool when all
|
|
you know is that there is a bug ``somewhere in XXX or in something that
|
|
XXX calls''.
|
|
|
|
@item (at-exit @var{thunk})
|
|
Don't do anything now, but arrange for @var{thunk} to be executed when
|
|
the current stack frame is exited. For example, the operation that most
|
|
debugging tools call ``finish'' is @code{(at-exit debug-here)}.
|
|
|
|
@item (at-next @var{count} @var{thunk})
|
|
@dots{} arrange for @var{thunk} to be executed when beginning the
|
|
@var{count}th next evaluation or application with source location in the
|
|
current file.
|
|
|
|
@item (at-entry @var{count} @var{thunk})
|
|
@dots{} arrange for @var{thunk} to be executed when beginning the
|
|
@var{count}th next evaluation (regardless of source location).
|
|
|
|
@item (at-apply @var{count} @var{thunk})
|
|
@dots{} arrange for @var{thunk} to be executed just before performing
|
|
the @var{count}th next application (regardless of source location).
|
|
|
|
@item (at-step @var{count} @var{thunk})
|
|
Synthesis of @code{at-entry} and @code{at-apply}; counts both
|
|
evaluations and applications.
|
|
@end table
|
|
|
|
Every breakpoint instance has a slot in which its behaviour is stored.
|
|
If you have a breakpoint instance in hand, you can change its behaviour
|
|
using the @code{bp-behaviour} accessor.
|
|
|
|
An @dfn{accessor} supports the setting of a property like this:
|
|
|
|
@smalllisp
|
|
(set! (bp-behaviour @var{breakpoint}) @var{new-behaviour})
|
|
@end smalllisp
|
|
|
|
@noindent
|
|
See the GOOPS manual for further information on accessors.
|
|
|
|
Alternatively, if you know how to specify the @var{location-args} for
|
|
the breakpoint in question, you can change its behaviour using
|
|
@code{set-breakpoint!}. For example:
|
|
|
|
@smalllisp
|
|
;; Change behaviour of breakpoint number 2.
|
|
(set-breakpoint! @var{new-behaviour} 2)
|
|
|
|
;; Change behaviour of procedural breakpoint on [fact1].
|
|
(set-breakpoint! @var{new-behaviour} fact1)
|
|
@end smalllisp
|
|
|
|
In all cases, the behaviour that you specify should be either a single
|
|
thunk, or a list of thunks, to be called when the breakpoint is hit.
|
|
|
|
The most common behaviours above are exported as thunks from the
|
|
@code{(ice-9 debugger behaviour)} module. So, if you use this module, you can
|
|
use those behaviours directly like this:
|
|
|
|
@smalllisp
|
|
(use-modules (ice-9 debugger behaviour))
|
|
(set-breakpoint! trace-subtree 2)
|
|
(set! (bp-behaviour (get-breakpoint 3)) debug-here)
|
|
@end smalllisp
|
|
|
|
@noindent
|
|
You can also use the list option to combine common behaviours:
|
|
|
|
@smalllisp
|
|
(set-breakpoint! (list trace-here debug-here) 2)
|
|
@end smalllisp
|
|
|
|
@noindent
|
|
Or, for more customized behaviour, you could build and use your own
|
|
thunk like this:
|
|
|
|
@smalllisp
|
|
(define (my-behaviour)
|
|
(trace-here)
|
|
(at-exit (lambda ()
|
|
(display "Exiting frame of my-behaviour bp\n")
|
|
... do something unusual ...)))
|
|
|
|
(set-breakpoint my-behaviour 2)
|
|
@end smalllisp
|
|
|
|
|
|
@node Enabling and Disabling
|
|
@subsubsection Enabling and Disabling
|
|
|
|
Independently of its behaviour, each breakpoint also keeps track of
|
|
whether it is currently enabled. This is a straightforward convenience
|
|
to allow breakpoints to be temporarily switched off without losing all
|
|
their carefully constructed properties.
|
|
|
|
If you have a breakpoint instance in hand, you can enable or disable it
|
|
using the @code{bp-enabled?} accessor.
|
|
|
|
Alternatively, you can enable or disable a breakpoint via its location
|
|
args by using @code{enable-breakpoint!} or @code{disable-breakpoint!}.
|
|
|
|
@smalllisp
|
|
(disable-breakpoint! fact1) ; disable the procedural breakpoint on fact1
|
|
(enable-breakpoint! 1) ; enable breakpoint 1
|
|
@end smalllisp
|
|
|
|
@code{enable-breakpoint!} and @code{disable-breakpoint!} are implemented
|
|
using @code{get-breakpoint} and @code{bp-enabled?}, so any
|
|
@var{location-args} that are valid for @code{get-breakpoint} will work
|
|
also for these procedures.
|
|
|
|
|
|
@node Deleting Breakpoints
|
|
@subsubsection Deleting Breakpoints
|
|
|
|
Given a breakpoint instance in hand, you can deactivate it and remove
|
|
it from the global list of current breakpoints by calling
|
|
@code{bp-delete!}.
|
|
|
|
Alternatively, you can delete a breakpoint by its location args:
|
|
|
|
@smalllisp
|
|
(delete-breakpoint! 1) ; delete breakpoint 1
|
|
@end smalllisp
|
|
|
|
@code{delete-breakpoint!} is implemented using @code{get-breakpoint} and
|
|
@code{bp-delete!}, so any @var{location-args} that are valid for
|
|
@code{get-breakpoint} will work also for @code{delete-breakpoint!}.
|
|
|
|
There is no way to reinstate a deleted breakpoint. Final destruction of
|
|
the breakpoint instance is determined by the usual garbage collection
|
|
rules.
|
|
|
|
|
|
@node Breakpoint Information
|
|
@subsubsection Breakpoint Information
|
|
|
|
To get Guile to print a description of a breakpoint instance, use
|
|
@code{bp-describe}:
|
|
|
|
@smalllisp
|
|
(bp-describe (get-breakpoint 1) #t) ; #t specifies standard output
|
|
@print{}
|
|
Breakpoint 1: [fact1]
|
|
enabled? = #t
|
|
behaviour = #<procedure trace-here ()>
|
|
@end smalllisp
|
|
|
|
Following the usual model, @code{describe-breakpoint} is also provided:
|
|
|
|
@smalllisp
|
|
(describe-breakpoint 1)
|
|
@print{}
|
|
Breakpoint 1: [fact1]
|
|
enabled? = #t
|
|
behaviour = #<procedure trace-here ()>
|
|
@end smalllisp
|
|
|
|
Finally, two stragglers. @code{all-breakpoints} returns a list of all
|
|
current breakpoints. @code{describe-all-breakpoints} combines
|
|
@code{bp-describe} and @code{all-breakpoints} by printing a description
|
|
of all current breakpoints to standard output.
|
|
|
|
@node Other Breakpoint Types
|
|
@subsubsection Other Breakpoint Types
|
|
|
|
Besides source and procedural breakpoints, Guile includes an early
|
|
implementation of a third class of breakpoints: @dfn{range} breakpoints.
|
|
These are breakpoints that trigger when program execution enters (or
|
|
perhaps exits) a defined range of source locations.
|
|
|
|
Sadly, these don't yet work well. The apparent problem is that the
|
|
extra methods for @code{set-breakpoint!} and @code{get-breakpoint} cause
|
|
some kind of explosion in the time taken by GOOPS to construct its
|
|
method cache and to dispatch calls involving these generic functions.
|
|
But we haven't really investigated enough to be sure that this is the
|
|
real issue.
|
|
|
|
If you're interested in looking and/or investigating anyway, please feel
|
|
free to check out and play with the @code{(ice-9 debugger breakpoints
|
|
range)} module.
|
|
|
|
The other kind of breakpoint that we'd like to have is watchpoints, but
|
|
this hasn't been implemented at all yet. Watchpoints may turn out to be
|
|
impractical for performance reasons.
|
|
|
|
|
|
@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.
|
|
|
|
When you first enter the debugger, it introduces itself with a message
|
|
like this:
|
|
|
|
@lisp
|
|
This is the Guile debugger -- for help, type `help'.
|
|
There are 3 frames on the stack.
|
|
|
|
Frame 2 at standard input:36:19
|
|
[+ 3 #\s]
|
|
debug>
|
|
@end lisp
|
|
|
|
@noindent
|
|
``debug>'' is the debugger's prompt, and a useful reminder that you are
|
|
not in the normal Guile REPL. The available commands are described in
|
|
detail in the following subsections.
|
|
|
|
@menu
|
|
* Display Backtrace:: backtrace.
|
|
* Frame Selection:: up, down, frame.
|
|
* Frame Information:: info args, info frame, position.
|
|
* Frame Evaluation:: evaluate.
|
|
* Single Stepping:: step, next.
|
|
* Run To Frame Exit:: finish, trace-finish.
|
|
* Continue Execution:: continue.
|
|
* Leave Debugger:: quit.
|
|
@end menu
|
|
|
|
|
|
@node Display Backtrace
|
|
@subsubsection Display Backtrace
|
|
|
|
The @code{backtrace} command, which can also be invoked as @code{bt} or
|
|
@code{where}, displays the call stack (aka backtrace) at the point where
|
|
the debugger was entered:
|
|
|
|
@lisp
|
|
debug> bt
|
|
In standard input:
|
|
36: 0* [make-string ...
|
|
36: 1* [* 4 ...
|
|
36: 2* [+ 3 #\s]
|
|
@end lisp
|
|
|
|
@deffn {Debugger Command} backtrace [count]
|
|
@deffnx {Debugger Command} bt [count]
|
|
@deffnx {Debugger Command} where [count]
|
|
Print backtrace of all stack frames, or of the innermost @var{count}
|
|
frames. With a negative argument, print the outermost -@var{count}
|
|
frames. If the number of frames isn't explicitly given, the debug
|
|
option @code{depth} determines the maximum number of frames printed.
|
|
@end deffn
|
|
|
|
The format of the displayed backtrace is the same as for the
|
|
@code{backtrace} procedure --- see @ref{Backtrace Format} for details.
|
|
|
|
|
|
@node Frame Selection
|
|
@subsubsection Frame Selection
|
|
|
|
A call stack consists of a sequence of stack @dfn{frames}, with each
|
|
frame describing one level of the nested evaluations and applications
|
|
that the program was executing when it hit a breakpoint or an error.
|
|
Frames are numbered such that frame 0 is the outermost --- i.e. the
|
|
operation on the call stack that began least recently --- and frame N-1
|
|
the innermost (where N is the total number of frames on the stack).
|
|
|
|
When you enter the debugger, the innermost frame is selected, which
|
|
means that the commands for getting information about the ``current''
|
|
frame, or for evaluating expressions in the context of the current
|
|
frame, will do so by default with respect to the innermost frame. To
|
|
select a different frame, so that these operations will apply to it
|
|
instead, use the @code{up}, @code{down} and @code{frame} commands like
|
|
this:
|
|
|
|
@lisp
|
|
debug> up
|
|
Frame 1 at standard input:36:14
|
|
[* 4 ...
|
|
debug> frame 0
|
|
Frame 0 at standard input:36:1
|
|
[make-string ...
|
|
debug> down
|
|
Frame 1 at standard input:36:14
|
|
[* 4 ...
|
|
@end lisp
|
|
|
|
@deffn {Debugger Command} up [n]
|
|
Move @var{n} frames up the stack. For positive @var{n}, this
|
|
advances toward the outermost frame, to higher frame numbers, to
|
|
frames that have existed longer. @var{n} defaults to one.
|
|
@end deffn
|
|
|
|
@deffn {Debugger Command} down [n]
|
|
Move @var{n} frames down the stack. For positive @var{n}, this
|
|
advances toward the innermost frame, to lower frame numbers, to frames
|
|
that were created more recently. @var{n} defaults to one.
|
|
@end deffn
|
|
|
|
@deffn {Debugger Command} frame [n]
|
|
Select and print a stack frame. With no argument, print the selected
|
|
stack frame. (See also ``info frame''.) An argument specifies the
|
|
frame to select; it must be a stack-frame number.
|
|
@end deffn
|
|
|
|
|
|
@node Frame Information
|
|
@subsubsection Frame Information
|
|
|
|
[to be completed]
|
|
|
|
@deffn {Debugger Command} {info frame}
|
|
All about selected stack frame.
|
|
@end deffn
|
|
|
|
@deffn {Debugger Command} {info args}
|
|
Argument variables of current stack frame.
|
|
@end deffn
|
|
|
|
@deffn {Debugger Command} position
|
|
Display the position of the current expression.
|
|
@end deffn
|
|
|
|
|
|
@node Frame Evaluation
|
|
@subsubsection Frame Evaluation
|
|
|
|
[to be completed]
|
|
|
|
@deffn {Debugger Command} evaluate expression
|
|
Evaluate an expression.
|
|
The expression must appear on the same line as the command,
|
|
however it may be continued over multiple lines.
|
|
@end deffn
|
|
|
|
|
|
@node Single Stepping
|
|
@subsubsection Single Stepping
|
|
|
|
[to be completed]
|
|
|
|
@deffn {Debugger Command} step [n]
|
|
Continue until entry to @var{n}th next frame.
|
|
@end deffn
|
|
|
|
@deffn {Debugger Command} next [n]
|
|
Continue until entry to @var{n}th next frame in same file.
|
|
@end deffn
|
|
|
|
|
|
@node Run To Frame Exit
|
|
@subsubsection Run To Frame Exit
|
|
|
|
[to be completed]
|
|
|
|
@deffn {Debugger Command} finish
|
|
Continue until evaluation of the current frame is complete, and
|
|
print the result obtained.
|
|
@end deffn
|
|
|
|
@deffn {Debugger Command} trace-finish
|
|
Trace until evaluation of the current frame is complete.
|
|
@end deffn
|
|
|
|
|
|
@node Continue Execution
|
|
@subsubsection Continue Execution
|
|
|
|
[to be completed]
|
|
|
|
@deffn {Debugger Command} continue
|
|
Continue program execution.
|
|
@end deffn
|
|
|
|
|
|
@node Leave Debugger
|
|
@subsubsection Leave Debugger
|
|
|
|
[to be completed]
|
|
|
|
@deffn {Debugger Command} quit
|
|
Exit the debugger.
|
|
@end deffn
|
|
|
|
|
|
@node Tracing
|
|
@subsection Tracing
|
|
|
|
Tracing has already been described as a breakpoint behaviour
|
|
(@pxref{Breakpoint Behaviours}), but we mention it again here because it
|
|
is so useful, and because Guile actually now has @emph{two} mechanisms
|
|
for tracing, and its worth clarifying the differences between them.
|
|
|
|
@menu
|
|
* Old Tracing:: Tracing provided by (ice-9 debug).
|
|
* New Tracing:: Breakpoint-based tracing.
|
|
* Tracing Compared:: Differences between old and new.
|
|
@end menu
|
|
|
|
|
|
@node Old Tracing
|
|
@subsubsection Tracing Provided by @code{(ice-9 debug)}
|
|
|
|
The @code{(ice-9 debug)} module implements tracing of procedure
|
|
applications. When a procedure is @dfn{traced}, it means that every
|
|
call to that procedure is reported to the user during a program run.
|
|
The idea is that you can mark a collection of procedures for tracing,
|
|
and Guile will subsequently print out a line of the form
|
|
|
|
@smalllisp
|
|
| | [@var{procedure} @var{args} @dots{}]
|
|
@end smalllisp
|
|
|
|
whenever a marked procedure is about to be applied to its arguments.
|
|
This can help a programmer determine whether a function is being called
|
|
at the wrong time or with the wrong set of arguments.
|
|
|
|
In addition, the indentation of the output is useful for demonstrating
|
|
how the traced applications are or are not tail recursive with respect
|
|
to each other. Thus, a trace of a non-tail recursive factorial
|
|
implementation looks like this:
|
|
|
|
@smalllisp
|
|
[fact1 4]
|
|
| [fact1 3]
|
|
| | [fact1 2]
|
|
| | | [fact1 1]
|
|
| | | | [fact1 0]
|
|
| | | | 1
|
|
| | | 1
|
|
| | 2
|
|
| 6
|
|
24
|
|
@end smalllisp
|
|
|
|
While a typical tail recursive implementation would look more like this:
|
|
|
|
@smalllisp
|
|
[fact2 4]
|
|
[facti 1 4]
|
|
[facti 4 3]
|
|
[facti 12 2]
|
|
[facti 24 1]
|
|
[facti 24 0]
|
|
24
|
|
@end smalllisp
|
|
|
|
@deffn {Scheme Procedure} trace procedure
|
|
Enable tracing for @code{procedure}. While a program is being run,
|
|
Guile will print a brief report at each call to a traced procedure,
|
|
advising the user which procedure was called and the arguments that were
|
|
passed to it.
|
|
@end deffn
|
|
|
|
@deffn {Scheme Procedure} untrace procedure
|
|
Disable tracing for @code{procedure}.
|
|
@end deffn
|
|
|
|
Here is another example:
|
|
|
|
@lisp
|
|
(define (rev ls)
|
|
(if (null? ls)
|
|
'()
|
|
(append (rev (cdr ls))
|
|
(cons (car ls) '())))) @result{} rev
|
|
|
|
(trace rev) @result{} (rev)
|
|
|
|
(rev '(a b c d e))
|
|
@result{} [rev (a b c d e)]
|
|
| [rev (b c d e)]
|
|
| | [rev (c d e)]
|
|
| | | [rev (d e)]
|
|
| | | | [rev (e)]
|
|
| | | | | [rev ()]
|
|
| | | | | ()
|
|
| | | | (e)
|
|
| | | (e d)
|
|
| | (e d c)
|
|
| (e d c b)
|
|
(e d c b a)
|
|
(e d c b a)
|
|
@end lisp
|
|
|
|
Note the way Guile indents the output, illustrating the depth of
|
|
execution at each procedure call. This can be used to demonstrate, for
|
|
example, that Guile implements self-tail-recursion properly:
|
|
|
|
@lisp
|
|
(define (rev ls sl)
|
|
(if (null? ls)
|
|
sl
|
|
(rev (cdr ls)
|
|
(cons (car ls) sl)))) @result{} rev
|
|
|
|
(trace rev) @result{} (rev)
|
|
|
|
(rev '(a b c d e) '())
|
|
@result{} [rev (a b c d e) ()]
|
|
[rev (b c d e) (a)]
|
|
[rev (c d e) (b a)]
|
|
[rev (d e) (c b a)]
|
|
[rev (e) (d c b a)]
|
|
[rev () (e d c b a)]
|
|
(e d c b a)
|
|
(e d c b a)
|
|
@end lisp
|
|
|
|
Since the tail call is effectively optimized to a @code{goto} statement,
|
|
there is no need for Guile to create a new stack frame for each
|
|
iteration. Tracing reveals this optimization in operation.
|
|
|
|
|
|
@node New Tracing
|
|
@subsubsection Breakpoint-based Tracing
|
|
|
|
Guile's newer mechanism implements tracing as an optional behaviour for
|
|
any kind of breakpoint.
|
|
|
|
To trace a procedure (in the same kind of way as the older tracing), use
|
|
the @code{trace!} procedure to set a procedure breakpoint with
|
|
@code{trace-here} behaviour:
|
|
|
|
@lisp
|
|
(trace! fact1)
|
|
@print{}
|
|
Set breakpoint 1: [fact1]
|
|
@result{}
|
|
#<<procedure-breakpoint> 40337bf0>
|
|
|
|
(fact1 4)
|
|
@print{}
|
|
| [fact1 4]
|
|
| | [fact1 3]
|
|
| | | [fact1 2]
|
|
| | | | [fact1 1]
|
|
| | | | | [fact1 0]
|
|
| | | | | 1
|
|
| | | | 2
|
|
| | | 6
|
|
| | 24
|
|
| 24
|
|
@result{}
|
|
24
|
|
@end lisp
|
|
|
|
To trace evaluation of a source expression, evaluate code containing a
|
|
breakpoint marker @code{##} in the appropriate place, then use
|
|
@code{set-breakpoint} to change the behaviour of the new breakpoint to
|
|
@code{trace-here}:
|
|
|
|
@lisp
|
|
(define (fact1 n)
|
|
(if ##(= n 0)
|
|
1
|
|
(* n (fact1 (- n 1)))))
|
|
@print{}
|
|
Set breakpoint 4: standard input:13:9: (= n 0)
|
|
|
|
(use-modules (ice-9 debugger behaviour))
|
|
(set-breakpoint! trace-here 4)
|
|
@print{}
|
|
Breakpoint 4: standard input:13:9: (= n 0)
|
|
enabled? = #t
|
|
behaviour = #<procedure trace-here ()>
|
|
|
|
(fact1 4)
|
|
@print{}
|
|
| (= n 0)
|
|
| #f
|
|
| (= n 0)
|
|
| #f
|
|
| (= n 0)
|
|
| #f
|
|
| (= n 0)
|
|
| #f
|
|
| (= n 0)
|
|
| #t
|
|
@result{}
|
|
24
|
|
@end lisp
|
|
|
|
@noindent
|
|
(Note --- this example reveals a bug: each occurrence of @code{(= n 0)}
|
|
should be shown indented with respect to the one before it, as
|
|
@code{fact1} does not call itself tail-recursively.)
|
|
|
|
You can also give a breakpoint the @code{trace-subtree} behaviour, which
|
|
means to trace the breakpoint location itself plus any evaluations and
|
|
applications that occur below it in the call stack. In the following
|
|
example, this allows us to see the evaluated arguments that are being
|
|
compared by the @code{=} procedure:
|
|
|
|
@lisp
|
|
(set-breakpoint! trace-subtree 4)
|
|
@print{}
|
|
Breakpoint 4: standard input:13:9: (= n 0)
|
|
enabled? = #t
|
|
behaviour = #<procedure trace-subtree ()>
|
|
|
|
(fact1 4)
|
|
@print{}
|
|
| (= n 0)
|
|
| [= 4 0]
|
|
| #f
|
|
| (= n 0)
|
|
| [= 3 0]
|
|
| #f
|
|
| (= n 0)
|
|
| [= 2 0]
|
|
| #f
|
|
| (= n 0)
|
|
| [= 1 0]
|
|
| #f
|
|
| (= n 0)
|
|
| [= 0 0]
|
|
| #t
|
|
@result{}
|
|
24
|
|
@end lisp
|
|
|
|
|
|
@node Tracing Compared
|
|
@subsubsection Differences Between Old and New Tracing Mechanisms
|
|
|
|
The newer tracing mechanism is more general and so more powerful than
|
|
the older one: it works for expressions as well as procedure
|
|
applications, and it implements the useful @code{trace-subtree}
|
|
behaviour as well as the more traditional @code{trace-here}.
|
|
|
|
The older mechanism will probably become obsolete eventually, but it's
|
|
worth keeping it around for a while until we are sure that the new
|
|
mechanism is correct and does what programmers need.
|