1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

Update api-debug.texi; there is a ways to go.

* doc/ref/api-debug.texi: Update a bit.
This commit is contained in:
Andy Wingo 2010-03-14 23:05:42 +01:00
parent 5c43d9c783
commit 42cb9b0311

View file

@ -10,9 +10,9 @@
@cindex Debugging @cindex Debugging
In order to understand Guile's debugging facilities, you first need to In order to understand Guile's debugging facilities, you first need to
understand a little about how the evaluator works and what the Scheme understand a little about how Guile represent the Scheme control stack.
stack is. With that in place we explain the low level trap calls that With that in place we explain the low level trap calls that the
the evaluator can be configured to make, and the trap and breakpoint evaluator can be configured to make, and the trap and breakpoint
infrastructure that builds on top of those calls. infrastructure that builds on top of those calls.
@menu @menu
@ -25,41 +25,31 @@ infrastructure that builds on top of those calls.
@node Evaluation Model @node Evaluation Model
@subsection Evaluation and the Scheme Stack @subsection Evaluation and the Scheme Stack
The idea of the Scheme stack is central to a lot of debugging. It The idea of the Scheme stack is central to a lot of debugging. The
always exists implicitly, as a result of the way that the Guile Scheme stack is a reified representation of the pending function returns
evaluator works, and can be summoned into concrete existence as a in an expression's continuation. As Guile implements function calls
first-class Scheme value by the @code{make-stack} call, so that an using a stack, this reification takes the form of a number of nested
introspective Scheme program -- such as a debugger -- can present it in stack frames, each of which has the procedure and its arguments, along
some way and allow the user to query its details. The first thing to with local variables and temporary values.
understand, therefore, is how the workings of the evaluator build up the
stack.
@cindex Evaluations A Scheme stack always exists implicitly, and can be summoned into
@cindex Applications concrete existence as a first-class Scheme value by the
Broadly speaking, the evaluator performs @dfn{evaluations} and @code{make-stack} call, so that an introspective Scheme program -- such
@dfn{applications}. An evaluation means that it is looking at a source as a debugger -- can present it in some way and allow the user to query
code expression like @code{(+ x 5)} or @code{(if msg (loop))}, deciding its details. The first thing to understand, therefore, is how Guile's
whether the top level of the expression is a procedure call, macro, function call convention creates the stack.
builtin syntax, or whatever, and doing some appropriate processing in
each case. (In the examples here, @code{(+ x 5)} would normally be a
procedure call, and @code{(if msg (loop))} builtin syntax.) For a
procedure call, ``appropriate processing'' includes evaluating the
procedure's arguments, as that must happen before the procedure itself
can be called. An application means calling a procedure once its
arguments have been calculated.
@cindex Stack Broadly speaking, Guile represents all control flow on a stack. Calling
@cindex Frames a function involves pushing an empty frame on the stack, then evaluating
@cindex Stack frames the procedure and its arguments, then fixing up the new frame so that it
Typically evaluations and applications alternate with each other, and points to the old one. Frames on the stack are thus linked together. A
together they form a @dfn{stack} of operations pending completion. This tail call is the same, except it reuses the existing frame instead of
is because, on the one hand, evaluation of an expression like @code{(+ x pushing on a new one.
5)} requires --- once its arguments have been calculated --- an
application (in this case, of the procedure @code{+}) before it can In this way, the only frames that are on the stack are ``active''
complete and return a result, and, on the other hand, the application of frames, frames which need to do some work before the computation is
a procedure written in Scheme involves evaluating the sequence of complete. On the other hand, a function that has tail-called another
expressions that constitute that procedure's code. Each level on this function will not be on the stack, as it has no work left to do.
stack is called a @dfn{frame}.
Therefore, when an error occurs in a running program, or the program Therefore, when an error occurs in a running program, or the program
hits a breakpoint, or in fact at any point that the programmer chooses, hits a breakpoint, or in fact at any point that the programmer chooses,
@ -74,7 +64,6 @@ stack and its frames.
* Examining the Stack:: * Examining the Stack::
* Examining Stack Frames:: * Examining Stack Frames::
* Source Properties:: Remembering the source of an expression. * Source Properties:: Remembering the source of an expression.
* Decoding Memoized Source Expressions::
* Starting a New Stack:: * Starting a New Stack::
@end menu @end menu
@ -96,10 +85,10 @@ describes the Scheme stack at that point.
Create a new stack. If @var{obj} is @code{#t}, the current Create a new stack. If @var{obj} is @code{#t}, the current
evaluation stack is used for creating the stack frames, evaluation stack is used for creating the stack frames,
otherwise the frames are taken from @var{obj} (which must be otherwise the frames are taken from @var{obj} (which must be
either a debug object or a continuation). a continuation or a frame object).
@var{args} should be a list containing any combination of @var{args} should be a list containing any combination of
integer, procedure and @code{#t} values. integer, procedure, prompt tag and @code{#t} values.
These values specify various ways of cutting away uninteresting These values specify various ways of cutting away uninteresting
stack frames from the top and bottom of the stack that stack frames from the top and bottom of the stack that
@ -107,28 +96,26 @@ stack frames from the top and bottom of the stack that
@code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2} @code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2}
@var{outer_cut_2} @dots{})}. @var{outer_cut_2} @dots{})}.
Each @var{inner_cut_N} can be @code{#t}, an integer, or a Each @var{inner_cut_N} can be @code{#t}, an integer, a prompt
procedure. @code{#t} means to cut away all frames up to but tag, or a procedure. @code{#t} means to cut away all frames up
excluding the first user module frame. An integer means to cut to but excluding the first user module frame. An integer means
away exactly that number of frames. A procedure means to cut to cut away exactly that number of frames. A prompt tag means
away all frames up to but excluding the application frame whose to cut away all frames that are inside a prompt with the given
procedure matches the specified one. tag. A procedure means to cut away all frames up to but
excluding the application frame whose procedure matches the
specified one.
Each @var{outer_cut_N} can be an integer or a procedure. An Each @var{outer_cut_N} can be an integer, a prompt tag, or a
integer means to cut away that number of frames. A procedure procedure. An integer means to cut away that number of frames.
means to cut away frames down to but excluding the application A prompt tag means to cut away all frames that are outside a
frame whose procedure matches the specified one. prompt with the given tag. A procedure means to cut away
frames down to but excluding the application frame whose
procedure matches the specified one.
If the @var{outer_cut_N} of the last pair is missing, it is If the @var{outer_cut_N} of the last pair is missing, it is
taken as 0. taken as 0.
@end deffn @end deffn
@deffn {Scheme Procedure} last-stack-frame obj
@deffnx {C Function} scm_last_stack_frame (obj)
Return the last (innermost) frame of @var{obj}, which must be
either a debug object or a continuation.
@end deffn
@node Examining the Stack @node Examining the Stack
@subsubsection Examining the Stack @subsubsection Examining the Stack
@ -175,33 +162,12 @@ backtrace.
Return @code{#t} if @var{obj} is a stack frame. Return @code{#t} if @var{obj} is a stack frame.
@end deffn @end deffn
@deffn {Scheme Procedure} frame-number frame
@deffnx {C Function} scm_frame_number (frame)
Return the frame number of @var{frame}.
@end deffn
@deffn {Scheme Procedure} frame-previous frame @deffn {Scheme Procedure} frame-previous frame
@deffnx {C Function} scm_frame_previous (frame) @deffnx {C Function} scm_frame_previous (frame)
Return the previous frame of @var{frame}, or @code{#f} if Return the previous frame of @var{frame}, or @code{#f} if
@var{frame} is the first frame in its stack. @var{frame} is the first frame in its stack.
@end deffn @end deffn
@deffn {Scheme Procedure} frame-next frame
@deffnx {C Function} scm_frame_next (frame)
Return the next frame of @var{frame}, or @code{#f} if
@var{frame} is the last frame in its stack.
@end deffn
@deffn {Scheme Procedure} frame-source frame
@deffnx {C Function} scm_frame_source (frame)
Return the source of @var{frame}.
@end deffn
@deffn {Scheme Procedure} frame-procedure? frame
@deffnx {C Function} scm_frame_procedure_p (frame)
Return @code{#t} if a procedure is associated with @var{frame}.
@end deffn
@deffn {Scheme Procedure} frame-procedure frame @deffn {Scheme Procedure} frame-procedure frame
@deffnx {C Function} scm_frame_procedure (frame) @deffnx {C Function} scm_frame_procedure (frame)
Return the procedure for @var{frame}, or @code{#f} if no Return the procedure for @var{frame}, or @code{#f} if no
@ -213,21 +179,6 @@ procedure is associated with @var{frame}.
Return the arguments of @var{frame}. Return the arguments of @var{frame}.
@end deffn @end deffn
@deffn {Scheme Procedure} frame-evaluating-args? frame
@deffnx {C Function} scm_frame_evaluating_args_p (frame)
Return @code{#t} if @var{frame} contains evaluated arguments.
@end deffn
@deffn {Scheme Procedure} frame-overflow? frame
@deffnx {C Function} scm_frame_overflow_p (frame)
Return @code{#t} if @var{frame} is an overflow frame.
@end deffn
@deffn {Scheme Procedure} frame-real? frame
@deffnx {C Function} scm_frame_real_p (frame)
Return @code{#t} if @var{frame} is a real frame.
@end deffn
@deffn {Scheme Procedure} display-application frame [port [indent]] @deffn {Scheme Procedure} display-application frame [port [indent]]
@deffnx {C Function} scm_display_application (frame, port, indent) @deffnx {C Function} scm_display_application (frame, port, indent)
Display a procedure application @var{frame} to the output port Display a procedure application @var{frame} to the output port
@ -242,14 +193,12 @@ output.
@cindex source properties @cindex source properties
As Guile reads in Scheme code from file or from standard input, it As Guile reads in Scheme code from file or from standard input, it
remembers the file name, line number and column number where each remembers the file name, line number and column number where each
expression begins. These pieces of information are known as the expression begins. These pieces of information are known as the
@dfn{source properties} of the expression. If an expression undergoes @dfn{source properties} of the expression. Syntax expanders and the
transformation --- for example, if there is a syntax transformer in compiler propagate these source properties to compiled procedures, so
effect, or the expression is a macro call --- the source properties are that, if an error occurs when evaluating the transformed expression,
copied from the untransformed to the transformed expression so that, if Guile's debugger can point back to the file and location where the
an error occurs when evaluating the transformed expression, Guile's expression originated.
debugger can point back to the file and location where the expression
originated.
The way that source properties are stored means that Guile can only The way that source properties are stored means that Guile can only
associate source properties with parenthesized expressions, and not, for associate source properties with parenthesized expressions, and not, for
@ -275,10 +224,7 @@ port>''.
The recording of source properties is controlled by the read option The recording of source properties is controlled by the read option
named ``positions'' (@pxref{Reader options}). This option is switched named ``positions'' (@pxref{Reader options}). This option is switched
@emph{on} by default, together with the debug options ``debug'' and @emph{on} by default.
``backtrace'' (@pxref{Debugger options}), when Guile is run
interactively; all these options are @emph{off} by default when Guile
runs a script non-interactively.
The following procedures can be used to access and set the source The following procedures can be used to access and set the source
properties of read expressions. properties of read expressions.
@ -306,52 +252,9 @@ Return the property specified by @var{key} from @var{obj}'s source
properties. properties.
@end deffn @end deffn
In practice there are only two ways that you should use the ability to If the @code{positions} reader option is enabled, each parenthesized
set an expression's source properties. expression will have values set for the @code{filename}, @code{line} and
@code{column} properties.
@itemize
@item
To set a breakpoint on an expression, use @code{(set-source-property!
@var{expr} 'breakpoint #t)}. If you do this, you should also set the
@code{traps} and @code{enter-frame-handler} trap options
(@pxref{Evaluator trap options}) and @code{breakpoints} debug option
(@pxref{Debugger options}) appropriately, and the evaluator will then
call your enter frame handler whenever it is about to evaluate that
expression.
@item
To make a read or constructed expression appear to have come from a
different source than what the expression's source properties already
say, you can use @code{set-source-property!} to set the expression's
@code{filename}, @code{line} and @code{column} properties. The
properties that you set will then show up later if that expression is
involved in a backtrace or error report.
@end itemize
If you are looking for a way to attach arbitrary information to an
expression other than these properties, you should use
@code{make-object-property} instead (@pxref{Object Properties}). That
will avoid bloating the source property hash table, which is really
only intended for the debugging purposes just described.
@node Decoding Memoized Source Expressions
@subsubsection Decoding Memoized Source Expressions
@deffn {Scheme Procedure} memoized? obj
@deffnx {C Function} scm_memoized_p (obj)
Return @code{#t} if @var{obj} is memoized.
@end deffn
@deffn {Scheme Procedure} unmemoize m
@deffnx {C Function} scm_unmemoize (m)
Unmemoize the memoized expression @var{m},
@end deffn
@deffn {Scheme Procedure} memoized-environment m
@deffnx {C Function} scm_memoized_environment (m)
Return the environment of the memoized expression @var{m}.
@end deffn
@node Starting a New Stack @node Starting a New Stack
@ -377,15 +280,15 @@ the error chose explicitly to provide. This information originates with
the @code{error} or @code{throw} call (or their C code equivalents, if the @code{error} or @code{throw} call (or their C code equivalents, if
the error is detected by C code) that signals the error, and is passed the error is detected by C code) that signals the error, and is passed
automatically to the handler procedure of the innermost applicable automatically to the handler procedure of the innermost applicable
@code{catch}, @code{lazy-catch} or @code{with-throw-handler} expression. @code{catch} or @code{with-throw-handler} expression.
@subsubsection Intercepting basic error information @subsubsection Intercepting basic error information
Therefore, to catch errors that occur within a chunk of Scheme code, and Therefore, to catch errors that occur within a chunk of Scheme code, and
to intercept basic information about those errors, you need to execute to intercept basic information about those errors, you need to execute
that code inside the dynamic context of a @code{catch}, that code inside the dynamic context of a @code{catch} or
@code{lazy-catch} or @code{with-throw-handler} expression, or the @code{with-throw-handler} expression, or the equivalent in C. In Scheme,
equivalent in C. In Scheme, this means you need something like this: this means you need something like this:
@lisp @lisp
(catch #t (catch #t
@ -436,9 +339,8 @@ SCM my_handler_proc (void *handler_data,
@noindent @noindent
Again, as with the Scheme version, @code{scm_c_catch} could be replaced Again, as with the Scheme version, @code{scm_c_catch} could be replaced
by @code{scm_internal_lazy_catch} or @code{scm_c_with_throw_handler}, by @code{scm_c_with_throw_handler}, and @code{SCM_BOOL_T} could instead
and @code{SCM_BOOL_T} could instead be the symbol for a particular kind be the symbol for a particular kind of error.
of error.
@subsubsection Capturing the full error stack @subsubsection Capturing the full error stack
@ -446,19 +348,10 @@ The other interesting information about an error is the full Scheme
stack at the point where the error occurred; in other words what stack at the point where the error occurred; in other words what
innermost expression was being evaluated, what was the expression that innermost expression was being evaluated, what was the expression that
called that one, and so on. If you want to write your code so that it called that one, and so on. If you want to write your code so that it
captures and can display this information as well, there are three captures and can display this information as well, there are a couple
important things to understand. important things to understand.
Firstly, the code in question must be executed using the debugging Firstly, the stack at the point of the error needs to be explicitly
version of the evaluator, because information about the Scheme stack is
only available at all from the debugging evaluator. Using the debugging
evaluator means that the debugger option (@pxref{Debugger options})
called @code{debug} must be enabled; this can be done by running
@code{(debug-enable 'debug)} or @code{(turn-on-debugging)} at the top
level of your program; or by running guile with the @code{--debug}
command line option, if your program begins life as a Scheme script.
Secondly, the stack at the point of the error needs to be explicitly
captured by a @code{make-stack} call (or the C equivalent captured by a @code{make-stack} call (or the C equivalent
@code{scm_make_stack}). The Guile library does not do this @code{scm_make_stack}). The Guile library does not do this
``automatically'' for you, so you will need to write code with a ``automatically'' for you, so you will need to write code with a
@ -472,16 +365,15 @@ running on top of the Guile library, and which uses @code{catch} and
@code{make-stack} in the way we are about to describe to capture the @code{make-stack} in the way we are about to describe to capture the
stack when an error occurs.) stack when an error occurs.)
Thirdly, in order to capture the stack effectively at the point where And secondly, in order to capture the stack effectively at the point
the error occurred, the @code{make-stack} call must be made before Guile where the error occurred, the @code{make-stack} call must be made before
unwinds the stack back to the location of the prevailing catch Guile unwinds the stack back to the location of the prevailing catch
expression. This means that the @code{make-stack} call must be made expression. This means that the @code{make-stack} call must be made
within the handler of a @code{lazy-catch} or @code{with-throw-handler} within the handler of a @code{with-throw-handler} expression, or the
expression, or the optional "pre-unwind" handler of a @code{catch}. optional "pre-unwind" handler of a @code{catch}. (For the full story of
(For the full story of how these alternatives differ from each other, how these alternatives differ from each other, see @ref{Exceptions}. The
see @ref{Exceptions}. The main difference is that @code{catch} main difference is that @code{catch} terminates the error, whereas
terminates the error, whereas @code{lazy-catch} and @code{with-throw-handler} only intercepts it temporarily and then allow
@code{with-throw-handler} only intercept it temporarily and then allow
it to continue propagating up to the next innermost handler.) it to continue propagating up to the next innermost handler.)
So, here are some examples of how to do all this in Scheme and in C. So, here are some examples of how to do all this in Scheme and in C.
@ -582,11 +474,11 @@ application frame -- that is, a frame that satisfies the
@subsubsection What the Guile REPL does @subsubsection What the Guile REPL does
The Guile REPL code (in @file{ice-9/boot-9.scm}) uses a @code{catch} The Guile REPL code (in @file{system/repl/repl.scm} and related files)
with a pre-unwind handler to capture the stack when an error occurs in uses a @code{catch} with a pre-unwind handler to capture the stack when
an expression that was typed into the REPL, and saves the captured stack an error occurs in an expression that was typed into the REPL, and saves
in a fluid (@pxref{Fluids and Dynamic States}) called the captured stack in a fluid (@pxref{Fluids and Dynamic States}) called
@code{the-last-stack}. You can then use the @code{(backtrace)} command, @code{the-last-stack}. You can then use the @code{(backtrace)} command,
which is basically equivalent to @code{(display-backtrace (fluid-ref which is basically equivalent to @code{(display-backtrace (fluid-ref
the-last-stack))}, to print out this stack at any time until it is the-last-stack))}, to print out this stack at any time until it is
overwritten by the next error that occurs. overwritten by the next error that occurs.
@ -619,17 +511,16 @@ Invoke the Guile debugger to explore the context of the last error.
@cindex Tracing @cindex Tracing
@cindex Code coverage @cindex Code coverage
@cindex Profiling @cindex Profiling
The low level C code of Guile's evaluator can be configured to call Guile's virtual machine can be configured to call out at key points to
out at key points to arbitrary user-specified procedures. These arbitrary user-specified procedures. For more information on these
procedures, and the circumstances under which the evaluator calls hooks, and the circumstances under which the VM calls them, see @ref{VM
them, are configured by the ``evaluator trap options'' interface Behaviour}.
(@pxref{Evaluator trap options}), and by the @code{trace} and
@code{breakpoints} fields of the ``debug options'' interface In principle, these hooks allow Scheme code to implement any model it
(@pxref{Debugger options}). In principle this allows Scheme code to chooses for examining the evaluation stack as program execution
implement any model it chooses for examining the evaluation stack as proceeds, and for suspending execution to be resumed later. Possible
program execution proceeds, and for suspending execution to be resumed applications of this feature include breakpoints, runtime tracing, code
later. Possible applications of this feature include breakpoints, coverage, and profiling.
runtime tracing, code coverage, and profiling.
@cindex Trap classes @cindex Trap classes
@cindex Trap objects @cindex Trap objects
@ -650,6 +541,14 @@ user wanting to use traps, and the developer interested in
understanding how the interface hangs together. understanding how the interface hangs together.
@subsubsection Actually, this section is bitrotten
Dear reader: the following sections have some great ideas, and some code
that just needs a few days of massaging to get it to work with the VM
(as opposed to the old interpreter). Want to help? Yes? Yes!
@code{guile-devel@@gnu.org}, that's where.
@subsubsection A Quick Note on Terminology @subsubsection A Quick Note on Terminology
@cindex Trap terminology @cindex Trap terminology
@ -1886,19 +1785,6 @@ hi!
guile> guile>
@end lisp @end lisp
@anchor{Memoization}
@cindex Memoization
(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 Local Variables:
@c TeX-master: "guile.texi" @c TeX-master: "guile.texi"
@c End: @c End: