diff --git a/ChangeLog b/ChangeLog index bfdc42f9d..20fe5eb79 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-03-12 Neil Jerram + + * configure.in (AC_CONFIG_FILES): Add emacs/Makefile and + ice-9/debugging/Makefile. + + * Makefile.am (SUBDIRS): Add emacs. + 2008-02-23 Neil Jerram * FAQ: New file. diff --git a/Makefile.am b/Makefile.am index 540653d2f..384ec5c6e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,7 +24,7 @@ # AUTOMAKE_OPTIONS = 1.10 -SUBDIRS = oop libguile ice-9 guile-config guile-readline \ +SUBDIRS = oop libguile ice-9 guile-config guile-readline emacs \ scripts srfi doc examples test-suite benchmark-suite lang am bin_SCRIPTS = guile-tools diff --git a/configure.in b/configure.in index e48f0d478..5dc280ae0 100644 --- a/configure.in +++ b/configure.in @@ -1442,6 +1442,7 @@ AC_CONFIG_FILES([ doc/r5rs/Makefile doc/ref/Makefile doc/tutorial/Makefile + emacs/Makefile examples/Makefile examples/box-dynamic-module/Makefile examples/box-dynamic/Makefile @@ -1453,6 +1454,7 @@ AC_CONFIG_FILES([ guile-config/Makefile ice-9/Makefile ice-9/debugger/Makefile + ice-9/debugging/Makefile lang/Makefile lang/elisp/Makefile lang/elisp/internals/Makefile diff --git a/doc/ref/ChangeLog b/doc/ref/ChangeLog index 7039a5584..87396d395 100644 --- a/doc/ref/ChangeLog +++ b/doc/ref/ChangeLog @@ -1,5 +1,41 @@ 2008-03-12 Neil Jerram + * scheme-debugging.texi: Remove lots of text that is now + duplicated (exactly) elsewhere, leaving only the `Tracing' node. + + * guile.texi: Replace `Debugging Features' (scheme-debugging.texi) + by `Using Guile Interactively' and `Using Guile in Emacs' + (scheme-using.texi). Move the `Tracing' content of + scheme-debugging.texi to the Modules section. + + * api-options.texi (Evaluator trap options): Move doc for + with-traps and debug-object? to here. + + * api-modules.texi (Included Guile Modules): Change reference from + `Debugging Features' to `Tracing'. + + * api-evaluation.texi (Evaluator Behaviour): Add reference to + `Evaluator trap options'. + + * api-debug.texi (Examining the Stack): Minor improvements to + display-backtrace doc. + + * api-debug.texi (Debug on Error): New text on how to catch errors + and the error stack. + + * api-debug.texi (High Level Traps): New. + + * api-debug.texi (Debugging): New intro text. New subsection + "Evaluation Model". Moved existing subsections "Capturing the + Stack or Innermost Stack Frame", "Examining the Stack", "Examining + Stack Frames", "Source Properties", "Decoding Memoized Source + Expressions" and "Starting a New Stack" under "Evaluation Model". + (Capturing the Stack or Innermost Stack Frame): Some new text, and + correction to doc for last-stack-frame. + (Debug on Error): Renamed from "Interactive Debugging". + + * Makefile (guile_TEXINFOS): Add scheme-using.texi. + * scheme-using.texi: New (merged with modifications from CVS HEAD). diff --git a/doc/ref/Makefile.am b/doc/ref/Makefile.am index 1e4f3cfee..76a66f0c9 100644 --- a/doc/ref/Makefile.am +++ b/doc/ref/Makefile.am @@ -56,6 +56,7 @@ guile_TEXINFOS = preface.texi \ gh.texi \ api-overview.texi \ scheme-debugging.texi \ + scheme-using.texi \ indices.texi \ script-getopt.texi \ data-rep.texi \ diff --git a/doc/ref/api-debug.texi b/doc/ref/api-debug.texi index 036065921..54c8c1fb0 100644 --- a/doc/ref/api-debug.texi +++ b/doc/ref/api-debug.texi @@ -8,36 +8,234 @@ @node Debugging @section Debugging Infrastructure +In order to understand Guile's debugging facilities, you first need to +understand a little about how the evaluator works and what the Scheme +stack is. With that in place we explain the low level trap calls that +the evaluator can be configured to make, and the trap and breakpoint +infrastructure that builds on top of those calls. + +@menu +* Evaluation Model:: Evaluation and the Scheme stack. +* Debug on Error:: Debugging when an error occurs. +* High Level Traps:: +@end menu + +@node Evaluation Model +@subsection Evaluation and the Scheme Stack + +The idea of the Scheme stack is central to a lot of debugging. It +always exists implicitly, as a result of the way that the Guile +evaluator works, and can be summoned into concrete existence as a +first-class Scheme value by the @code{make-stack} call, so that an +introspective Scheme program -- such as a debugger -- can present it in +some way and allow the user to query its details. The first thing to +understand, therefore, is how the workings of the evaluator build up the +stack. + +@cindex Evaluations +@cindex Applications +Broadly speaking, the evaluator performs @dfn{evaluations} and +@dfn{applications}. An evaluation means that it is looking at a source +code expression like @code{(+ x 5)} or @code{(if msg (loop))}, deciding +whether the top level of the expression is a procedure call, macro, +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 +@cindex Frames +@cindex Stack frames +Typically evaluations and applications alternate with each other, and +together they form a @dfn{stack} of operations pending completion. This +is because, on the one hand, evaluation of an expression like @code{(+ x +5)} requires --- once its arguments have been calculated --- an +application (in this case, of the procedure @code{+}) before it can +complete and return a result, and, on the other hand, the application of +a procedure written in Scheme involves evaluating the sequence of +expressions that constitute that procedure's code. Each level on this +stack is called a @dfn{frame}. + +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, +its state at that point can be represented by a @dfn{stack} of all the +evaluations and procedure applications that are logically in progress at +that time, each of which is known as a @dfn{frame}. The programmer can +learn more about the program's state at that point by inspecting the +stack and its frames. + @menu -* Interactive Debugging:: Functions intended for interactive use. -* Source Properties:: Remembering the source of an expression. -* Using Traps:: * Capturing the Stack or Innermost Stack Frame:: * Examining the Stack:: * Examining Stack Frames:: +* Source Properties:: Remembering the source of an expression. * Decoding Memoized Source Expressions:: * Starting a New Stack:: @end menu -@node Interactive Debugging -@subsection Interactive Debugging +@node Capturing the Stack or Innermost Stack Frame +@subsubsection Capturing the Stack or Innermost Stack Frame -@deffn {Scheme Procedure} backtrace [highlights] -@deffnx {C Function} scm_backtrace_with_highlights (highlights) -@deffnx {C Function} scm_backtrace () -Display a backtrace of the stack saved by the last error -to the current output port. When @var{highlights} is given, -it should be a list and all members of it are highligthed in -the backtrace. +A Scheme program can use the @code{make-stack} primitive anywhere in its +code, with first arg @code{#t}, to construct a Scheme value that +describes the Scheme stack at that point. + +@lisp +(make-stack #t) +@result{} +# +@end lisp + +@deffn {Scheme Procedure} make-stack obj . args +@deffnx {C Function} scm_make_stack (obj, args) +Create a new stack. If @var{obj} is @code{#t}, the current +evaluation stack is used for creating the stack frames, +otherwise the frames are taken from @var{obj} (which must be +either a debug object or a continuation). + +@var{args} should be a list containing any combination of +integer, procedure and @code{#t} values. + +These values specify various ways of cutting away uninteresting +stack frames from the top and bottom of the stack that +@code{make-stack} returns. They come in pairs like this: +@code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2} +@var{outer_cut_2} @dots{})}. + +Each @var{inner_cut_N} can be @code{#t}, an integer, or a +procedure. @code{#t} means to cut away all frames up to but +excluding the first user module frame. An integer means to cut +away exactly that number of frames. 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 +integer means to cut away that number of frames. 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 +taken as 0. @end deffn -@deffn {Scheme Procedure} debug -Invoke the Guile debugger to explore the context of the last error. +@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 +@subsubsection Examining the Stack + +@deffn {Scheme Procedure} stack? obj +@deffnx {C Function} scm_stack_p (obj) +Return @code{#t} if @var{obj} is a calling stack. +@end deffn + +@deffn {Scheme Procedure} stack-id stack +@deffnx {C Function} scm_stack_id (stack) +Return the identifier given to @var{stack} by @code{start-stack}. +@end deffn + +@deffn {Scheme Procedure} stack-length stack +@deffnx {C Function} scm_stack_length (stack) +Return the length of @var{stack}. +@end deffn + +@deffn {Scheme Procedure} stack-ref stack index +@deffnx {C Function} scm_stack_ref (stack, index) +Return the @var{index}'th frame from @var{stack}. +@end deffn + +@deffn {Scheme Procedure} display-backtrace stack port [first [depth [highlights]]] +@deffnx {C Function} scm_display_backtrace_with_highlights (stack, port, first, depth, highlights) +@deffnx {C Function} scm_display_backtrace (stack, port, first, depth) +Display a backtrace to the output port @var{port}. @var{stack} +is the stack to take the backtrace from, @var{first} specifies +where in the stack to start and @var{depth} how many frames +to display. @var{first} and @var{depth} can be @code{#f}, +which means that default values will be used. +If @var{highlights} is given it should be a list; the elements +of this list will be highlighted wherever they appear in the +backtrace. +@end deffn + + +@node Examining Stack Frames +@subsubsection Examining Stack Frames + +@deffn {Scheme Procedure} frame? obj +@deffnx {C Function} scm_frame_p (obj) +Return @code{#t} if @var{obj} is a stack frame. +@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 +@deffnx {C Function} scm_frame_previous (frame) +Return the previous frame of @var{frame}, or @code{#f} if +@var{frame} is the first frame in its stack. +@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 +@deffnx {C Function} scm_frame_procedure (frame) +Return the procedure for @var{frame}, or @code{#f} if no +procedure is associated with @var{frame}. +@end deffn + +@deffn {Scheme Procedure} frame-arguments frame +@deffnx {C Function} scm_frame_arguments (frame) +Return the arguments of @var{frame}. +@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]] +@deffnx {C Function} scm_display_application (frame, port, indent) +Display a procedure application @var{frame} to the output port +@var{port}. @var{indent} specifies the indentation of the +output. @end deffn @node Source Properties -@subsection Source Properties +@subsubsection Source Properties @cindex source properties As Guile reads in Scheme code from file or from standard input, it @@ -135,178 +333,8 @@ that will avoid bloating the source property hash table, which is really only intended for the specific purposes described in this section. -@node Using Traps -@subsection Using Traps - -@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 Capturing the Stack or Innermost Stack Frame -@subsection Capturing the Stack or Innermost Stack Frame - -When an error occurs in a running program, or the program hits a -breakpoint, its state at that point can be represented by a @dfn{stack} -of all the evaluations and procedure applications that are logically in -progress at that time, each of which is known as a @dfn{frame}. The -programmer can learn more about the program's state at the point of -interruption or error by inspecting the stack and its frames. - -@deffn {Scheme Procedure} make-stack obj . args -@deffnx {C Function} scm_make_stack (obj, args) -Create a new stack. If @var{obj} is @code{#t}, the current -evaluation stack is used for creating the stack frames, -otherwise the frames are taken from @var{obj} (which must be -either a debug object or a continuation). - -@var{args} should be a list containing any combination of -integer, procedure and @code{#t} values. - -These values specify various ways of cutting away uninteresting -stack frames from the top and bottom of the stack that -@code{make-stack} returns. They come in pairs like this: -@code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2} -@var{outer_cut_2} @dots{})}. - -Each @var{inner_cut_N} can be @code{#t}, an integer, or a -procedure. @code{#t} means to cut away all frames up to but -excluding the first user module frame. An integer means to cut -away exactly that number of frames. 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 -integer means to cut away that number of frames. 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 -taken as 0. -@end deffn - -@deffn {Scheme Procedure} last-stack-frame obj -@deffnx {C Function} scm_last_stack_frame (obj) -Return a stack which consists of a single frame, which is the -last stack frame for @var{obj}. @var{obj} must be either a -debug object or a continuation. -@end deffn - - -@node Examining the Stack -@subsection Examining the Stack - -@deffn {Scheme Procedure} stack? obj -@deffnx {C Function} scm_stack_p (obj) -Return @code{#t} if @var{obj} is a calling stack. -@end deffn - -@deffn {Scheme Procedure} stack-id stack -@deffnx {C Function} scm_stack_id (stack) -Return the identifier given to @var{stack} by @code{start-stack}. -@end deffn - -@deffn {Scheme Procedure} stack-length stack -@deffnx {C Function} scm_stack_length (stack) -Return the length of @var{stack}. -@end deffn - -@deffn {Scheme Procedure} stack-ref stack index -@deffnx {C Function} scm_stack_ref (stack, index) -Return the @var{index}'th frame from @var{stack}. -@end deffn - -@deffn {Scheme Procedure} display-backtrace stack port [first [depth [highlights]]] -@deffnx {C Function} scm_display_backtrace_with_highlights (stack, port, first, depth, highlights) -@deffnx {C Function} scm_display_backtrace (stack, port, first, depth) -Display a backtrace to the output port @var{port}. @var{stack} -is the stack to take the backtrace from, @var{first} specifies -where in the stack to start and @var{depth} how much frames -to display. Both @var{first} and @var{depth} can be @code{#f}, -which means that default values will be used. -When @var{highlights} is given, -it should be a list and all members of it are highligthed in -the backtrace. -@end deffn - - -@node Examining Stack Frames -@subsection Examining Stack Frames - -@deffn {Scheme Procedure} frame? obj -@deffnx {C Function} scm_frame_p (obj) -Return @code{#t} if @var{obj} is a stack frame. -@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 -@deffnx {C Function} scm_frame_previous (frame) -Return the previous frame of @var{frame}, or @code{#f} if -@var{frame} is the first frame in its stack. -@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 -@deffnx {C Function} scm_frame_procedure (frame) -Return the procedure for @var{frame}, or @code{#f} if no -procedure is associated with @var{frame}. -@end deffn - -@deffn {Scheme Procedure} frame-arguments frame -@deffnx {C Function} scm_frame_arguments (frame) -Return the arguments of @var{frame}. -@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]] -@deffnx {C Function} scm_display_application (frame, port, indent) -Display a procedure application @var{frame} to the output port -@var{port}. @var{indent} specifies the indentation of the -output. -@end deffn - - @node Decoding Memoized Source Expressions -@subsection Decoding Memoized Source Expressions +@subsubsection Decoding Memoized Source Expressions @deffn {Scheme Procedure} memoized? obj @deffnx {C Function} scm_memoized_p (obj) @@ -325,7 +353,7 @@ Return the environment of the memoized expression @var{m}. @node Starting a New Stack -@subsection Starting a New Stack +@subsubsection Starting a New Stack @deffn {Scheme Syntax} start-stack id exp Evaluate @var{exp} on a new calling stack with identity @var{id}. If @@ -336,6 +364,1335 @@ a convenience to the user. @end deffn +@node Debug on Error +@subsection Debugging when an error occurs + +A common requirement is to be able to show as much useful context as +possible when a Scheme program hits an error. The most immediate +information about an error is the kind of error that it is -- such as +``division by zero'' -- and any parameters that the code which signalled +the error chose explicitly to provide. This information originates with +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 +automatically to the handler procedure of the innermost applicable +@code{catch}, @code{lazy-catch} or @code{with-throw-handler} expression. + +@subsubsection Intercepting basic error information + +Therefore, to catch errors that occur within a chunk of Scheme code, and +to intercept basic information about those errors, you need to execute +that code inside the dynamic context of a @code{catch}, +@code{lazy-catch} or @code{with-throw-handler} expression, or the +equivalent in C. In Scheme, this means you need something like this: + +@lisp +(catch #t + (lambda () + ;; Execute the code in which + ;; you want to catch errors here. + ...) + (lambda (key . parameters) + ;; Put the code which you want + ;; to handle an error here. + ...)) +@end lisp + +@noindent +The @code{catch} here can also be @code{lazy-catch} or +@code{with-throw-handler}; see @ref{Throw Handlers} and @ref{Lazy Catch} +for the details of how these differ from @code{catch}. The @code{#t} +means that the catch is applicable to all kinds of error; if you want to +restrict your catch to just one kind of error, you can put the symbol +for that kind of error instead of @code{#t}. The equivalent to this in +C would be something like this: + +@lisp +SCM my_body_proc (void *body_data) +@{ + /* Execute the code in which + you want to catch errors here. */ + ... +@} + +SCM my_handler_proc (void *handler_data, + SCM key, + SCM parameters) +@{ + /* Put the code which you want + to handle an error here. */ + ... +@} + +@{ + ... + scm_c_catch (SCM_BOOL_T, + my_body_proc, body_data, + my_handler_proc, handler_data, + NULL, NULL); + ... +@} +@end lisp + +@noindent +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}, +and @code{SCM_BOOL_T} could instead be the symbol for a particular kind +of error. + +@subsubsection Capturing the full error stack + +The other interesting information about an error is the full Scheme +stack at the point where the error occurred; in other words what +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 +captures and can display this information as well, there are three +important things to understand. + +Firstly, the code in question must be executed using the debugging +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 +@code{scm_make_stack}). The Guile library does not do this +``automatically'' for you, so you will need to write code with a +@code{make-stack} or @code{scm_make_stack} call yourself. (We emphasise +this point because some people are misled by the fact that the Guile +interactive REPL code @emph{does} capture and display the stack +automatically. But the Guile interactive REPL is itself a Scheme +program@footnote{In effect, it is the default program which is run when +no commands or script file are specified on the Guile command line.} +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 +stack when an error occurs.) + +Thirdly, in order to capture the stack effectively at the point where +the error occurred, the @code{make-stack} call must be made before Guile +unwinds the stack back to the location of the prevailing catch +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} +expression, or the optional "pre-unwind" handler of a @code{catch}. +(For the full story of how these alternatives differ from each other, +see @ref{Exceptions}. The main difference is that @code{catch} +terminates the error, whereas @code{lazy-catch} and +@code{with-throw-handler} only intercept it temporarily and then allow +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. +For the purpose of these examples we assume that the captured stack +should be stored in a variable, so that it can be displayed or +arbitrarily processed later on. In Scheme: + +@lisp +(let ((captured-stack #f)) + (catch #t + (lambda () + ;; Execute the code in which + ;; you want to catch errors here. + ...) + (lambda (key . parameters) + ;; Put the code which you want + ;; to handle an error after the + ;; stack has been unwound here. + ...) + (lambda (key . parameters) + ;; Capture the stack here: + (set! captured-stack (make-stack #t)))) + ... + (if captured-stack + (begin + ;; Display or process the captured stack. + ...)) + ...) +@end lisp + +@noindent +And in C: + +@lisp +SCM my_body_proc (void *body_data) +@{ + /* Execute the code in which + you want to catch errors here. */ + ... +@} + +SCM my_handler_proc (void *handler_data, + SCM key, + SCM parameters) +@{ + /* Put the code which you want + to handle an error after the + stack has been unwound here. */ + ... +@} + +SCM my_preunwind_proc (void *handler_data, + SCM key, + SCM parameters) +@{ + /* Capture the stack here: */ + *(SCM *)handler_data = scm_make_stack (SCM_BOOL_T, SCM_EOL); +@} + +@{ + SCM captured_stack = SCM_BOOL_F; + ... + scm_c_catch (SCM_BOOL_T, + my_body_proc, body_data, + my_handler_proc, handler_data, + my_preunwind_proc, &captured_stack); + ... + if (captured_stack != SCM_BOOL_F) + @{ + /* Display or process the captured stack. */ + ... + @} + ... +@} +@end lisp + +@noindent +Note that you don't have to wait until after the @code{catch} or +@code{scm_c_catch} has returned. You can also do whatever you like with +the stack immediately after it has been captured in the pre-unwind +handler, or in the normal (post-unwind) handler. (Except that for the +latter case in C you will need to change @code{handler_data} in the +@code{scm_c_catch(@dots{})} call to @code{&captured_stack}, so that +@code{my_handler_proc} has access to the captured stack.) + +@subsubsection Displaying or interrogating the captured stack + +Once you have a captured stack, you can interrogate and display its +details in any way that you want, using the @code{stack-@dots{}} and +@code{frame-@dots{}} API described in @ref{Examining the Stack} and +@ref{Examining Stack Frames}. + +If you want to print out a backtrace in the same format that the Guile +REPL does, you can use the @code{display-backtrace} procedure to do so. +You can also use @code{display-application} to display an individual +application frame -- that is, a frame that satisfies the +@code{frame-procedure?} predicate -- in the Guile REPL format. + +@subsubsection What the Guile REPL does + +The Guile REPL code (in @file{ice-9/boot-9.scm}) uses a @code{catch} +with a pre-unwind handler to capture the stack when an error occurs in +an expression that was typed into the REPL, and saves the captured stack +in a fluid (@pxref{Fluids and Dynamic States}) called +@code{the-last-stack}. You can then use the @code{(backtrace)} command, +which is basically equivalent to @code{(display-backtrace (fluid-ref +the-last-stack))}, to print out this stack at any time until it is +overwritten by the next error that occurs. + +@deffn {Scheme Procedure} backtrace [highlights] +@deffnx {C Function} scm_backtrace_with_highlights (highlights) +@deffnx {C Function} scm_backtrace () +Display a backtrace of the stack saved by the last error +to the current output port. If @var{highlights} is given +it should be a list; the elements of this list will be +highlighted wherever they appear in the backtrace. +@end deffn + +You can also use the @code{(debug)} command to explore the saved stack +using an interactive command-line-driven debugger. See @ref{Interactive +Debugger} for more information about this. + +@deffn {Scheme Procedure} debug +Invoke the Guile debugger to explore the context of the last error. +@end deffn + + +@node High Level Traps +@subsection High Level Traps + +@cindex Traps +@cindex Evaluator trap calls +@cindex Breakpoints +@cindex Trace +@cindex Tracing +@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 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, Guile provides a higher level, +object-oriented interface for the manipulation of traps. Different +kinds of trap are represented as GOOPS classes; for example, the +@code{} class describes traps that are triggered by +invocation of a specified procedure. A particular instance of a trap +class --- or @dfn{trap object} --- describes the condition under which +a single trap will be triggered, and what will happen then; for +example, an instance of @code{} whose @code{procedure} +and @code{behaviour} slots contain @code{my-factorial} and +@code{debug-trap} would be a trap that enters the command line +debugger when the @code{my-factorial} procedure is invoked. + +The following subsubsections describe all this in greater detail, for both +the user wanting to use traps, and the developer interested in +understanding how the interface hangs together. + + +@subsubsection A Quick Note on Terminology + +@cindex Trap terminology +It feels natural to use the word ``trap'' in some form for all levels +of the structure just described, so we need to be clear on the +terminology we use to describe each particular level. The terminology +used in this subsection is as follows. + +@itemize @bullet +@item +@cindex Evaluator trap calls +@cindex Low level trap calls +``Low level trap calls'', or ``low level traps'', are the calls made +directly from the C code of the Guile evaluator. + +@item +@cindex Trap classes +``Trap classes'' are self-explanatory. + +@item +@cindex Trap objects +``Trap objects'', ``trap instances'', or just ``traps'', are instances +of a trap class, and each describe a single logical trap condition +plus behaviour as specified by the user of this interface. +@end itemize + +A good example of when it is important to be clear, is when we talk +below of behaviours that should only happen once per low level trap. +A single low level trap call will typically map onto the processing of +several trap objects, so ``once per low level trap'' is significantly +different from ``once per trap''. + + +@menu +* How to Set a Trap:: +* Specifying Trap Behaviour:: +* Trap Context:: +* Tracing Examples:: +* Tracing Configuration:: +* Tracing and (ice-9 debug):: +* Traps Installing More Traps:: +* Common Trap Options:: +* Procedure Traps:: +* Exit Traps:: +* Entry Traps:: +* Apply Traps:: +* Step Traps:: +* Source Traps:: +* Location Traps:: +* Trap Shorthands:: +* Trap Utilities:: +@end menu + + +@node How to Set a Trap +@subsubsection How to Set a Trap + +@cindex Setting traps +@cindex Installing and uninstalling traps +Setting a trap is done in two parts. First the trap is defined by +creating an instance of the appropriate trap class, with slot values +specifying the condition under which the trap will fire and the action +to take when it fires. Secondly the trap object thus created must be +@dfn{installed}. + +To make this immediately concrete, here is an example that sets a trap +to fire on the next application of the @code{facti} procedure, and to +handle the trap by entering the command line debugger. + +@lisp +(install-trap (make + #:procedure facti + #:single-shot #t + #:behaviour debug-trap)) +@end lisp + +@noindent +Briefly, the elements of this incantation are as follows. (All of +these are described more fully in the following subsubsections.) + +@itemize @bullet +@item +@code{} is the trap class for trapping on invocation +of a specific procedure. + +@item +@code{#:procedure facti} says that the specific procedure to trap on for this +trap object is @code{facti}. + +@item +@code{#:single-shot #t} says that this trap should only fire on the +@emph{next} invocation of @code{facti}, not on all future invocations +(which is the default if the @code{#:single-shot} option is not +specified). + +@item +@code{#:behaviour debug-trap} says that the trap infrastructure should +call the procedure @code{debug-trap} when this trap fires. + +@item +Finally, the @code{install-trap} call installs the trap immediately. +@end itemize + +@noindent +It is of course possible for the user to define more convenient +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 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 +executed when the conditions for the trap firing are met. +@end deffn + +@deffn {Generic Function} uninstall-trap trap +Uninstall the trap object @var{trap}, so that its behaviour will +@emph{not} be executed even if the conditions for the trap firing are +met. +@end deffn + + +@node Specifying Trap Behaviour +@subsubsection Specifying Trap Behaviour + +@cindex Trap behaviour +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 +@var{trap-context}, and to single-step or continue program execution +from that point. +@end deffn + +@deffn {Procedure} gds-debug-trap trap-context +Use the GDS debugging interface, which displays the stack and +corresponding source code via Emacs, to explore the stack at +@var{trap-context} and to single-step or continue program execution +from that point. +@end deffn + +@cindex Trace +@cindex Tracing +@deffn {Procedure} trace-trap trap-context +Display trace information to summarize the current @var{trap-context}. +@end deffn + +@deffn {Procedure} trace-at-exit trap-context +Install a further trap to cause the return value of the application or +evaluation just starting (as described by @var{trap-context}) to be +traced using @code{trace-trap}, when this application or evaluation +completes. The extra trap is automatically uninstalled after the +return value has been traced. +@end deffn + +@deffn {Procedure} trace-until-exit trap-context +Install a further trap so that every step that the evaluator performs +as part of the application or evaluation just starting (as described +by @var{trap-context}) is traced using @code{trace-trap}. The extra +trap is automatically uninstalled when the application or evaluation +is complete. @code{trace-until-exit} can be very useful as a first +step when all you know is that there is a bug ``somewhere in XXX or in +something that XXX calls''. +@end deffn + +@noindent +@code{debug-trap} and @code{gds-debug-trap} are provided by the modules +@code{(ice-9 debugger)} and @code{(ice-9 gds-client)} respectively, and +their behaviours are fairly self-explanatory. For more information on +the operation of the GDS interface via Emacs, see @ref{Using Guile in +Emacs}. The tracing behaviours are explained more fully below. + +@cindex Trap context +More generally, the @dfn{behaviour} specified for a trap can be any +procedure that expects to be called with one @dfn{trap context} +argument. A trivial example would be: + +@lisp +(define (report-stack-depth trap-context) + (display "Stack depth at the trap is: ") + (display (tc:depth trap-context)) + (newline)) +@end lisp + + +@node Trap Context +@subsubsection Trap Context + +The @dfn{trap context} is an object that caches information about the +low level trap call and the stack at the point of the trap, and is +passed as the only argument to all behaviour procedures. The +information in the trap context can be accessed through the procedures +beginning @code{tc:} that are exported by the @code{(ice-9 debugging +traps)} module@footnote{Plus of course any procedures that build on +these, such as the @code{trace/@dots{}} procedures exported by +@code{(ice-9 debugging trace)} (@pxref{Tracing Configuration}).}; the +most useful of these are as follows. + +@deffn {Generic Function} tc:type trap-context +Indicates the type of the low level trap by returning one of the +keywords @code{#:application}, @code{#:evaluation}, @code{#:return} or +@code{#:error}. +@end deffn + +@deffn {Generic Function} tc:return-value trap-context +When @code{tc:type} gives @code{#:return}, this provides the value +that is being returned. +@end deffn + +@deffn {Generic Function} tc:stack trap-context +Provides the stack at the point of the trap (as computed by +@code{make-stack}, but cached so that the lengthy @code{make-stack} +operation is not performed more than once for the same low level +trap). +@end deffn + +@deffn {Generic Function} tc:frame trap-context +The innermost frame of the stack at the point of the trap. +@end deffn + +@deffn {Generic Function} tc:depth trap-context +The number of frames (including tail recursive non-real frames) in the +stack at the point of the trap. +@end deffn + +@deffn {Generic Function} tc:real-depth trap-context +The number of real frames (that is, excluding the non-real frames that +describe tail recursive calls) in the stack at the point of the trap. +@end deffn + + +@node Tracing Examples +@subsubsection Tracing Examples + +The following examples show what tracing is and the kind of output that +it generates. In the first example, we define a recursive function for +reversing a list, then watch the effect of the recursive calls by +tracing each call and return value. + +@lisp +guile> (define (rev ls) + (if (null? ls) + ls + (append (rev (cdr ls)) + (list (car ls))))) +guile> (use-modules (ice-9 debugging traps) (ice-9 debugging trace)) +guile> (define t1 (make + #:procedure rev + #:behaviour (list trace-trap + trace-at-exit))) +guile> (install-trap t1) +guile> (rev '(a b c)) +| 2: [rev (a b c)] +| 3: [rev (b c)] +| 4: [rev (c)] +| 5: [rev ()] +| 5: =>() +| 4: =>(c) +| 3: =>(c b) +| 2: =>(c b a) +(c b a) +@end lisp + +@noindent +The number before the colon in this output (which follows @code{(ice-9 +debugging trace)}'s default output format) is the number of real frames +on the stack. The fact that this number increases for each recursive +call confirms that the implementation above of @code{rev} is not +tail-recursive. + +In the next example, we probe the @emph{internal} workings of +@code{rev} in more detail by using the @code{trace-until-exit} +behaviour. + +@lisp +guile> (uninstall-trap t1) +guile> (define t2 (make + #:procedure rev + #:behaviour (list trace-trap + trace-until-exit))) +guile> (install-trap t2) +guile> (rev '(a b)) +| 2: [rev (a b)] +| 2: (if (null? ls) ls (append (rev (cdr ls)) (list (car ls)))) +| 3: (null? ls) +| 3: [null? (a b)] +| 3: =>#f +| 2: (append (rev (cdr ls)) (list (car ls))) +| 3: (rev (cdr ls)) +| 4: (cdr ls) +| 4: [cdr (a b)] +| 4: =>(b) +| 3: [rev (b)] +| 3: (if (null? ls) ls (append (rev (cdr ls)) (list (car ls)))) +| 4: (null? ls) +| 4: [null? (b)] +| 4: =>#f +| 3: (append (rev (cdr ls)) (list (car ls))) +| 4: (rev (cdr ls)) +| 5: (cdr ls) +| 5: [cdr (b)] +| 5: =>() +| 4: [rev ()] +| 4: (if (null? ls) ls (append (rev (cdr ls)) (list (car ls)))) +| 5: (null? ls) +| 5: [null? ()] +| 5: =>#t +| 4: (list (car ls)) +| 5: (car ls) +| 5: [car (b)] +| 5: =>b +| 4: [list b] +| 4: =>(b) +| 3: [append () (b)] +| 3: =>(b) +| 3: (list (car ls)) +| 4: (car ls) +| 4: [car (a b)] +| 4: =>a +| 3: [list a] +| 3: =>(a) +| 2: [append (b) (a)] +| 2: =>(b a) +(b a) +@end lisp + +@noindent +The output in this case shows every step that the evaluator performs +in evaluating @code{(rev '(a b))}. + + +@node Tracing Configuration +@subsubsection Tracing Configuration + +The detail of what gets printed in each trace line, and the port to +which tracing is written, can be configured by the procedures +@code{set-trace-layout} and @code{trace-port}, both exported by the +@code{(ice-9 debugging trace)} module. + +@deffn {Procedure with Setter} trace-port +Get or set the port to which tracing is printed. The default is the +value of @code{(current-output-port)} when the @code{(ice-9 debugging +trace)} module is first loaded. +@end deffn + +@deffn {Procedure} set-trace-layout format-string . arg-procs +Layout each trace line using @var{format-string} and @var{arg-procs}. +For each trace line, the list of values to be printed is obtained by +calling all the @var{arg-procs}, passing the trap context as the only +parameter to each one. This list of values is then formatted using +the specified @var{format-string}. +@end deffn + +@noindent +The @code{(ice-9 debugging trace)} module exports a set of arg-proc +procedures to cover most common needs, with names beginning +@code{trace/}. These are all implemented on top of the @code{tc:} trap +context accessor procedures documented in @ref{Trap Context}, and if any +trace output not provided by the following is needed, it should be +possible to implement based on a combination of the @code{tc:} +procedures. + +@deffn {Procedure} trace/pid trap-context +An arg-proc that returns the current process ID. +@end deffn + +@deffn {Procedure} trace/stack-id trap-context +An arg-proc that returns the stack ID of the stack in which the +current trap occurred. +@end deffn + +@deffn {Procedure} trace/stack-depth trap-context +An arg-proc that returns the length (including non-real frames) of the +stack at the point of the current trap. +@end deffn + +@deffn {Procedure} trace/stack-real-depth trap-context +An arg-proc that returns the length excluding non-real frames of the +stack at the point of the current trap. +@end deffn + +@deffn {Procedure} trace/stack trap-context +An arg-proc that returns a string summarizing stack information. This +string includes the stack ID, real depth, and count of additional +non-real frames, with the format @code{"~a:~a+~a"}. +@end deffn + +@deffn {Procedure} trace/source-file-name trap-context +An arg-proc that returns the name of the source file for the innermost +stack frame, or an empty string if source is not available for the +innermost frame. +@end deffn + +@deffn {Procedure} trace/source-line trap-context +An arg-proc that returns the line number of the source code for the +innermost stack frame, or zero if source is not available for the +innermost frame. +@end deffn + +@deffn {Procedure} trace/source-column trap-context +An arg-proc that returns the column number of the start of the source +code for the innermost stack frame, or zero if source is not available +for the innermost frame. +@end deffn + +@deffn {Procedure} trace/source trap-context +An arg-proc that returns the source location for the innermost stack +frame. This is a string composed of file name, line and column number +with the format @code{"~a:~a:~a"}, or an empty string if source is not +available for the innermost frame. +@end deffn + +@deffn {Procedure} trace/type trap-context +An arg-proc that returns a three letter abbreviation indicating the +type of the current trap: @code{"APP"} for an application frame, +@code{"EVA"} for an evaluation, @code{"RET"} for an exit trap, or +@code{"ERR"} for an error (pseudo-)trap. +@end deffn + +@deffn {Procedure} trace/real? trap-context +An arg-proc that returns @code{" "} if the innermost stack frame is a +real frame, or @code{"t"} if it is not. +@end deffn + +@deffn {Procedure} trace/info trap-context +An arg-proc that returns a string describing the expression being +evaluated, application being performed, or return value, according to +the current trap type. +@end deffn + +@noindent +@code{trace/stack-depth} and @code{trace/stack-real-depth} are identical +to the trap context methods @code{tc:depth} and @code{tc:real-depth} +described before (@pxref{Trap Context}), but renamed here for +convenience. + +The default trace layout, as exhibited by the examples of the previous +subsubsubsection, is set by this line of code from the @code{(ice-9 debugging +traps)} module: + +@lisp +(set-trace-layout "|~3@@a: ~a\n" trace/stack-real-depth trace/info) +@end lisp + +@noindent +If we rerun the first of those examples, but with trace layout +configured to show source location and trap type in addition, the +output looks like this: + +@lisp +guile> (set-trace-layout "| ~25a ~3@@a: ~a ~a\n" + trace/source + trace/stack-real-depth + trace/type + trace/info) +guile> (rev '(a b c)) +| standard input:29:0 2: APP [rev (a b c)] +| standard input:4:21 3: APP [rev (b c)] +| standard input:4:21 4: APP [rev (c)] +| standard input:4:21 5: APP [rev ()] +| standard input:2:9 5: RET =>() +| standard input:4:13 4: RET =>(c) +| standard input:4:13 3: RET =>(c b) +| standard input:4:13 2: RET =>(c b a) +(c b a) +@end lisp + + +@node Tracing and (ice-9 debug) +@subsubsection Tracing and (ice-9 debug) + +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 +The @code{(ice-9 debug)} trace gives a nice pictorial view of changes +in stack depth, by using indentation like this: + +@lisp +[fact1 4] +| [fact1 3] +| | [fact1 2] +| | | [fact1 1] +| | | | [fact1 0] +| | | | 1 +| | | 1 +| | 2 +| 6 +24 +@end lisp + +However its output can @emph{only} show the information seen here, +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 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. 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{(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 +@subsubsection Traps Installing More Traps + +Sometimes it is desirable for the behaviour at one trap to install +further traps. In other words, the behaviour is something like +``Don't do much right now, but set things up to stop after two or +three more steps'', or ``@dots{} when this frame completes''. This is +absolutely fine. For example, it is easy to code a generic ``do +so-and-so when the current frame exits'' procedure, which can be used +wherever a trap context is available, as follows. + +@lisp +(define (at-exit trap-context behaviour) + (install-trap (make + #:depth (tc:depth trap-context) + #:single-shot #t + #:behaviour behaviour))) +@end lisp + +To continue and pin down the example, this could then be used as part +of a behaviour whose purpose was to measure the accumulated time spent +in and below a specified procedure. + +@lisp +(define calls 0) +(define total 0) + +(define accumulate-time + (lambda (trap-context) + (set! calls (+ calls 1)) + (let ((entry (current-time))) + (at-exit trap-context + (lambda (ignored) + (set! total + (+ total (- (current-time) + entry)))))))) + +(install-trap (make + #:procedure my-proc + #:behaviour accumulate-time)) +@end lisp + + +@node Common Trap Options +@subsubsection Common Trap Options + +When creating any kind of trap object, settings for the trap being +created are specified as options on the @code{make} call using syntax +like this: + +@lisp +(make <@var{trap-class}> + #:@var{option-keyword} @var{setting} + @dots{}) +@end lisp + +The following common options are provided by the base class +@code{}, and so can be specified for any kind of trap. + +@deffn {Class} +Base class for trap objects. +@end deffn + +@deffn {Trap Option} #:condition thunk +If not @code{#f}, this is a thunk which is called when the trap fires, +to determine whether trap processing should proceed any further. If +the thunk returns @code{#f}, the trap is basically suppressed. +Otherwise processing continues normally. (Default value @code{#f}.) +@end deffn + +@deffn {Trap Option} #:skip-count count +A count of valid (after @code{#:condition} processing) firings of this +trap to skip. (Default value 0.) +@end deffn + +@deffn {Trap Option} #:single-shot boolean +If not @code{#f}, this indicates that the trap should be automatically +uninstalled after it has successfully fired (after @code{#:condition} +and @code{#:skip-count} processing) for the first time. (Default +value @code{#f}.) +@end deffn + +@deffn {Trap Option} #:behaviour behaviour-proc +A trap behaviour procedure --- as discussed in the preceding subsubsection +--- or a list of such procedures, in which case each procedure is +called in turn when the trap fires. (Default value @code{'()}.) +@end deffn + +@deffn {Trap Option} #:repeat-identical-behaviour boolean +Normally, if multiple trap objects are triggered by the same low level +trap, and they request the same behaviour, it's only actually useful +to do that behaviour once (per low level trap); so by default multiple +requests for the same behaviour are coalesced. If this option is set +other than @code{#f}, the contents of the @code{#:behaviour} option +are uniquified so that they avoid being coalesced in this way. +(Default value @code{#f}.) +@end deffn + + +@node Procedure Traps +@subsubsection Procedure Traps + +The @code{} class implements traps that are triggered +upon application of a specified procedure. Instances of this class +should use the @code{#:procedure} option to specify the procedure to +trap on. + +@deffn {Class} +Class for traps triggered by application of a specified procedure. +@end deffn + +@deffn {Trap Option} #:procedure procedure +Specifies the procedure to trap on. +@end deffn + +@noindent +Example: + +@lisp +(install-trap (make + #:procedure my-proc + #:behaviour (list trace-trap + trace-until-exit))) +@end lisp + + +@node Exit Traps +@subsubsection Exit Traps + +The @code{} class implements traps that are triggered upon +stack frame exit past a specified stack depth. Instances of this +class should use the @code{#:depth} option to specify the target stack +depth. + +@deffn {Class} +Class for traps triggered by exit past a specified stack depth. +@end deffn + +@deffn {Trap Option} #:depth depth +Specifies the reference depth for the trap. +@end deffn + +@noindent +Example: + +@lisp +(define (trace-at-exit trap-context) + (install-trap (make + #:depth (tc:depth trap-context) + #:single-shot #t + #:behaviour trace-trap))) +@end lisp + +@noindent +(This is the actual definition of the @code{trace-at-exit} behaviour.) + + +@node Entry Traps +@subsubsection Entry Traps + +The @code{} class implements traps that are triggered upon +any stack frame entry. No further parameters are needed to specify an +instance of this class, so there are no class-specific trap options. +Note that it remains possible to use the common trap options +(@pxref{Common Trap Options}), for example to set a trap for the +@var{n}th next frame entry. + +@deffn {Class} +Class for traps triggered by any stack frame entry. +@end deffn + +@noindent +Example: + +@lisp +(install-trap (make + #:skip-count 5 + #:behaviour gds-debug-trap)) +@end lisp + + +@node Apply Traps +@subsubsection Apply Traps + +The @code{} class implements traps that are triggered upon +any procedure application. No further parameters are needed to +specify an instance of this class, so there are no class-specific trap +options. Note that it remains possible to use the common trap options +(@pxref{Common Trap Options}), for example to set a trap for the next +application where some condition is true. + +@deffn {Class} +Class for traps triggered by any procedure application. +@end deffn + +@noindent +Example: + +@lisp +(install-trap (make + #:condition my-condition + #:behaviour gds-debug-trap)) +@end lisp + + +@node Step Traps +@subsubsection Step Traps + +The @code{} class implements traps that do single-stepping +through a program's execution. They come in two flavours, with and +without a specified file name. If a file name is specified, the trap +is triggered by the next evaluation, application or frame exit +pertaining to source code from the specified file. If a file name is +not specified, the trap is triggered by the next evaluation, +application or frame exit from any file (or for code whose source +location was not recorded), in other words by the next evaluator step +of any kind. + +The design goal of the @code{} class is to match what a +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 a step trap to single-step through code and finding +its behaviour counter-intuitive, please report that so we can improve +it. + +The implementation and options of the @code{} class are +complicated by the fact that it is unreliable to determine whether a +low level frame exit trap is applicable to a specified file by +examining the details of the reported frame. This is a consequence of +tail recursion, which has the effect that many frames can be removed +from the stack at once, with only the outermost frame being reported +by the low level trap call. The effects of this on the +@code{} class are such as to require the introduction of +the strange-looking @code{#:exit-depth} option, for the following +reasons. + +@itemize @bullet +@item +When stopped at the start of an application or evaluation frame, and +it is desired to continue execution until the next ``step'' in the same +source file, that next step could be the start of a nested application +or evaluation frame, or --- if the procedure definition is in a +different file, for example --- it could be the exit from the current +frame. + +@item +Because of the effects of tail recursion noted above, the current +frame exit possibility must be expressed as frame exit past a +specified stack depth. When an instance of the @code{} +class is installed from the context of an application or evaluation +frame entry, the @code{#:exit-depth} option should be used to specify +this stack depth. + +@item +When stopped at a frame exit, on the other hand, we know that the next +step must be an application or evaluation frame entry. In this +context the @code{#:exit-depth} option is not needed and should be +omitted or set to @code{#f}. +@end itemize + +@noindent +When a step trap is installed without @code{#:single-shot #t}, such +that it keeps firing, the @code{} code automatically +updates its idea of the @code{#:exit-depth} setting each time, so that +the trap always fires correctly for the following step. + +@deffn {Class} +Class for single-stepping traps. +@end deffn + +@deffn {Trap Option} #:file-name name +If not @code{#f}, this is a string containing the name of a source +file, and restricts the step trap to evaluation steps within that +source file. (Default value @code{#f}.) +@end deffn + +@deffn {Trap Option} #:exit-depth depth +If not @code{#f}, this is a positive integer implying that the next +step may be frame exit past the stack depth @var{depth}. See the +discussion above for more details. (Default value @code{#f}.) +@end deffn + +@noindent +Example: + +@lisp +(install-trap (make + #:file-name (frame-file-name + (stack-ref stack index)) + #:exit-depth (- (stack-length stack) + (stack-ref stack index)) + #:single-shot #t + #:behaviour debug-trap)) +@end lisp + + +@node Source Traps +@subsubsection Source Traps + +The @code{} class implements traps that are attached to a +precise source code expression, as read by the reader, and which fire +each time that that expression is evaluated. These traps use a low +level Guile feature which can mark individual expressions for +trapping, and are relatively efficient. But it can be tricky to get +at the source expression in the first place, and these traps are +liable to become irrelevant if the procedure containing the expression +is reevaluated; these issues are discussed further below. + +@deffn {Class} +Class for traps triggered by evaluation of a specific Scheme +expression. +@end deffn + +@deffn {Trap Option} #:expression expr +Specifies the Scheme expression to trap on. +@end deffn + +@noindent +Example: + +@lisp +(display "Enter an expression: ") +(let ((x (read))) + (install-trap (make + #:expression x + #:behaviour (list trace-trap + trace-at-exit))) + (primitive-eval x)) +@print{} +Enter an expression: (+ 1 2 3 4 5 6) +| 3: (+ 1 2 3 4 5 6) +| 3: =>21 +21 +@end lisp + +The key point here is that the expression specified by the +@code{#:expression} option must be @emph{exactly} (i.e. @code{eq?} to) +what is going to be evaluated later. It doesn't work, for example, to +say @code{#:expression '(+ x 3)}, with the expectation that the trap +will fire whenever evaluating any expression @code{(+ x 3)}. + +The @code{trap-here} macro can be used in source code to create and +install a source trap correctly. Take for example the factorial +function defined in the @code{(ice-9 debugging example-fns)} module: + +@lisp +(define (fact1 n) + (if (= n 0) + 1 + (* n (fact1 (- n 1))))) +@end lisp + +@noindent +To set a source trap on a particular expression --- let's say the +expression @code{(= n 0)} --- edit the code so that the expression is +enclosed in a @code{trap-here} macro call like this: + +@lisp +(define (fact1 n) + (if (trap-here (= n 0) #:behaviour debug-trap) + 1 + (* n (fact1 (- n 1))))) +@end lisp + +@deffn {Macro} trap-here expression . trap-options +Install a source trap with options @var{trap-options} on +@var{expression}, then return with the whole call transformed to +@code{(begin @var{expression})}. +@end deffn + +Note that if the @code{trap-here} incantation is removed, and +@code{fact1} then redefined by reloading its source file, the effect +of the source trap is lost, because the text ``(= n 0)'' is read again +from scratch and becomes a new expression @code{(= n 0)} which does +not have the ``trap here'' mark on it. + +If the semantics and setting of source traps seem unwieldy, location +traps may meet your need more closely; these are described in the +following subsubsection. + + +@node Location Traps +@subsubsection Location Traps + +The @code{} class implements traps that are triggered +by evaluation of code at a specific source location or within a +specified range of source locations. When compared with source traps, +they are easier to set, and do not become irrelevant when the relevant +code is reloaded; but unfortunately they are considerably less +efficient, as they require running some ``are we in the right place +for a trap'' code on every low level frame entry trap call. + +@deffn {Class} +Class for traps triggered by evaluation of code at a specific source +location or in a specified range of source locations. +@end deffn + +@deffn {Trap Option} #:file-regexp regexp +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}.) +@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}.) +@end deffn + +@noindent +Example: + +@lisp +(install-trap (make + #:file-regexp "example-fns.scm" + #:line '(11 . 13) + #:behaviour gds-debug-trap)) +@end lisp + + +@node Trap Shorthands +@subsubsection Trap Shorthands + +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. + +@lisp +(define (break! proc) + (install-trap (make + #:procedure proc + #:behaviour gds-debug-trap))) + +(define (trace! proc) + (install-trap (make + #:procedure proc + #:behaviour (list trace-trap + trace-at-exit)))) + +(define (trace-subtree! proc) + (install-trap (make + #:procedure proc + #:behaviour (list trace-trap + trace-until-exit)))) +@end lisp + +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 +@subsubsection Trap Utilities + +@code{list-traps} can be used to print a description of all known trap +objects. This uses a weak value hash table, keyed by a trap index +number. Each trap object has its index number assigned, and is added +to the hash table, when it is created by a @code{make @var{trap-class} +@dots{}} call. When a trap object is GC'd, it is automatically +removed from the hash table, and so no longer appears in the output +from @code{list-traps}. + +@deffn {Variable} all-traps +Weak value hash table containing all known trap objects. +@end deffn + +@deffn {Procedure} list-traps +Print a description of all known trap objects. +@end deffn + +The following example shows a single trap that traces applications of +the procedure @code{facti}. + +@lisp +guile> (list-traps) +#< 100d2e30> is an instance of class +Slots are: + number = 1 + installed = #t + condition = #f + skip-count = 0 + single-shot = #f + behaviour = (#) + repeat-identical-behaviour = #f + procedure = # +@end lisp + +When @code{all-traps} or @code{list-traps} reveals a trap that you +want to modify but no longer have a reference to, you can retrieve the +trap object by calling @code{get-trap} with the trap's number. For +example, here's how you could change the behaviour of the trap listed +just above. + +@lisp +(slot-set! (get-trap 1) 'behaviour (list debug-trap)) +@end lisp + +@deffn {Procedure} get-trap number +Return the trap object with the specified @var{number}, or @code{#f} +if there isn't one. +@end deffn + + @c Local Variables: @c TeX-master: "guile.texi" @c End: diff --git a/doc/ref/api-evaluation.texi b/doc/ref/api-evaluation.texi index 1da13de43..6fd363df2 100644 --- a/doc/ref/api-evaluation.texi +++ b/doc/ref/api-evaluation.texi @@ -629,6 +629,9 @@ Like @code{help}, but also print programmer options. Modify the evaluator options. @code{trap-enable} should be used with boolean options and switches them on, @code{trap-disable} switches them off. @code{trap-set!} can be used to set an option to a specific value. + +See @ref{Evaluator trap options} for more information on the available +trap handlers. @end deffn @deffn {Scheme Procedure} evaluator-traps-interface [setting] diff --git a/doc/ref/api-modules.texi b/doc/ref/api-modules.texi index 415c9cba6..94b93bdc1 100644 --- a/doc/ref/api-modules.texi +++ b/doc/ref/api-modules.texi @@ -679,7 +679,7 @@ Guile starts up. @item (ice-9 debug) Mikael Djurfeldt's source-level debugging support for Guile -(@pxref{Debugging Features}). +(@pxref{Tracing}). @item (ice-9 expect) Actions based on matching input from a port (@pxref{Expect}). diff --git a/doc/ref/api-options.texi b/doc/ref/api-options.texi index 6dbc37062..ed1c42d01 100644 --- a/doc/ref/api-options.texi +++ b/doc/ref/api-options.texi @@ -612,6 +612,16 @@ way. @var{retval} is the return value. @end deffn +@deffn {Scheme Procedure} with-traps thunk +@deffnx {C Function} scm_with_traps (thunk) +Call @var{thunk} with traps enabled. +@end deffn + +@deffn {Scheme Procedure} debug-object? obj +@deffnx {C Function} scm_debug_object_p (obj) +Return @code{#t} if @var{obj} is a debug object. +@end deffn + @node Debugger options @subsubsection Debugger options diff --git a/doc/ref/guile.texi b/doc/ref/guile.texi index 0487dccb5..9e742f436 100644 --- a/doc/ref/guile.texi +++ b/doc/ref/guile.texi @@ -137,7 +137,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.44.2.1 2006-10-04 21:40:24 kryde Exp $ +@c @subtitle $Id: guile.texi,v 1.44.2.2 2008-03-12 00:57:40 ossau Exp $ @c See preface.texi for the list of authors @author The Guile Developers @@ -219,14 +219,15 @@ etc. that make up Guile's application programming interface (API), * Basic Ideas:: Basic ideas in Scheme. * Guile Scheme:: Guile's implementation of Scheme. * Guile Scripting:: How to write Guile scripts. -* Debugging Features:: Features for finding errors. +* Using Guile Interactively:: Guile's REPL features. +* Using Guile in Emacs:: Guile and Emacs. * Further Reading:: Where to find out more about Scheme. @end menu @include scheme-ideas.texi @include scheme-intro.texi @include scheme-scripts.texi -@include scheme-debugging.texi +@include scheme-using.texi @include scheme-reading.texi @node Programming in C @@ -302,7 +303,7 @@ available through both Scheme and C interfaces. * Options and Config:: Configuration, features and runtime options. * Translation:: Support for translating other languages. * Internationalization:: Support for gettext, etc. -* Debugging:: Internal debugging interface. +* Debugging:: Debugging infrastructure and Scheme interface. * GH:: The deprecated GH interface. @end menu @@ -347,6 +348,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 @@ -357,6 +359,7 @@ available through both Scheme and C interfaces. @include misc-modules.texi @include expect.texi @include scsh.texi +@include scheme-debugging.texi @include data-rep.texi @include fdl.texi diff --git a/doc/ref/scheme-debugging.texi b/doc/ref/scheme-debugging.texi index df0234d47..6166b2448 100644 --- a/doc/ref/scheme-debugging.texi +++ b/doc/ref/scheme-debugging.texi @@ -5,251 +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. - -@menu -* Debug Last Error:: Debugging the most recent error. -* 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: - -@c Note: line break in "enter the debugger" to avoid an over-long -@c line in both info and DVI. -@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}. - - -@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 reminder that you are not -in the normal Guile REPL. In case you find yourself in the debugger by -mistake, the @code{quit} command will return you to the REPL. - -@deffn {Debugger Command} quit -Exit the debugger. -@end deffn - -The other available commands are described in the following subsections. - -@menu -* Display Backtrace:: backtrace. -* Frame Selection:: up, down, frame. -* Frame Information:: info args, info frame, position. -* Frame Evaluation:: evaluate. -@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. - - -@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 lower 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 higher 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 - -The following commands return detailed information about the currently -selected frame. - -@deffn {Debugger Command} {info frame} -Display a verbose description of the selected frame. The information -that this command provides is equivalent to what can be deduced from the -one line summary for the frame that appears in a backtrace, but is -presented and explained more clearly. -@end deffn - -@deffn {Debugger Command} {info args} -Display the argument variables of the current stack frame. Arguments -can also be seen in the backtrace, but are presented more clearly by -this command. -@end deffn - -@deffn {Debugger Command} position -Display the name of the source file that the current expression comes -from, and the line and column number of the expression's opening -parenthesis within that file. This information is only available when -the @code{positions} read option is enabled (@pxref{Reader options}). -@end deffn - - -@node Frame Evaluation -@subsubsection Frame Evaluation - -The @code{evaluate} command is most useful for querying the value of a -variable, either global or local, in the environment of the selected -stack frame, but it can be used more generally to evaluate any -expression. - -@deffn {Debugger Command} evaluate expression -Evaluate an expression in the environment of the selected stack frame. -The expression must appear on the same line as the command, however it -may be continued over multiple lines. -@end deffn - - @node Tracing -@subsection Tracing +@section Tracing The @code{(ice-9 debug)} module implements tracing of procedure applications. When a procedure is @dfn{traced}, it means that every diff --git a/ice-9/ChangeLog b/ice-9/ChangeLog index 3f3deccef..4f0f9fd5e 100644 --- a/ice-9/ChangeLog +++ b/ice-9/ChangeLog @@ -1,5 +1,11 @@ 2008-03-12 Neil Jerram + * debugger/commands.scm (evaluate, info-args, info-frame, + position, up, down): Improve/fix doc strings. + + * Makefile.am (SUBDIRS): Add debugging. + (ice9_sources): Add gds-client.scm and gds-server.scm. + * debugging/Makefile.am, debugging/example-fns.scm, debugging/ice-9-debugger-extensions.scm, debugging/steps.scm, debugging/trace.scm, debugging/traps.scm, debugging/trc.scm: New diff --git a/ice-9/Makefile.am b/ice-9/Makefile.am index 734185570..87a39e51c 100644 --- a/ice-9/Makefile.am +++ b/ice-9/Makefile.am @@ -21,7 +21,7 @@ AUTOMAKE_OPTIONS = gnu -SUBDIRS = debugger +SUBDIRS = debugger debugging # These should be installed and distributed. ice9_sources = \ @@ -35,7 +35,8 @@ ice9_sources = \ streams.scm string-fun.scm syncase.scm threads.scm \ buffered-input.scm time.scm history.scm channel.scm \ pretty-print.scm ftw.scm gap-buffer.scm occam-channel.scm \ - weak-vector.scm deprecated.scm list.scm serialize.scm + weak-vector.scm deprecated.scm list.scm serialize.scm \ + gds-client.scm gds-server.scm subpkgdatadir = $(pkgdatadir)/${GUILE_EFFECTIVE_VERSION}/ice-9 subpkgdata_DATA = $(ice9_sources) diff --git a/ice-9/debugger/commands.scm b/ice-9/debugger/commands.scm index 1d716e2bb..ef6f79026 100644 --- a/ice-9/debugger/commands.scm +++ b/ice-9/debugger/commands.scm @@ -67,9 +67,9 @@ If the number of frames isn't explicitly given, the debug option (throw 'continue)) (define (evaluate state expression) - "Evaluate an expression. -The expression must appear on the same line as the command, -however it may be continued over multiple lines." + "Evaluate an expression in the environment of the selected stack frame. +The expression must appear on the same line as the command, however it +may be continued over multiple lines." (let ((source (frame-source (stack-ref (state-stack state) (state-index state))))) (if (not source) @@ -100,18 +100,26 @@ however it may be continued over multiple lines." (lambda args args))))) (define (info-args state) - "Argument variables of current stack frame." + "Display the argument variables of the current stack frame. +Arguments can also be seen in the backtrace, but are presented more +clearly by this command." (let ((index (state-index state))) (let ((frame (stack-ref (state-stack state) index))) (write-frame-index-long frame) (write-frame-args-long frame)))) (define (info-frame state) - "All about selected stack frame." + "Display a verbose description of the selected frame. The +information that this command provides is equivalent to what can be +deduced from the one line summary for the frame that appears in a +backtrace, but is presented and explained more clearly." (write-state-long state)) (define (position state) - "Display the position of the current expression." + "Display the name of the source file that the current expression +comes from, and the line and column number of the expression's opening +parenthesis within that file. This information is only available when +the 'positions read option is enabled." (let* ((frame (stack-ref (state-stack state) (state-index state))) (source (frame-source frame))) (if (not source) @@ -124,14 +132,14 @@ however it may be continued over multiple lines." (define (up state n) "Move @var{n} frames up the stack. For positive @var{n}, this -advances toward the outermost frame, to higher frame numbers, to +advances toward the outermost frame, to lower frame numbers, to frames that have existed longer. @var{n} defaults to one." (set-stack-index! state (+ (state-index state) (or n 1))) (write-state-short state)) (define (down state n) "Move @var{n} frames down the stack. For positive @var{n}, this -advances toward the innermost frame, to lower frame numbers, to frames +advances toward the innermost frame, to higher frame numbers, to frames that were created more recently. @var{n} defaults to one." (set-stack-index! state (- (state-index state) (or n 1))) (write-state-short state))