Go to the first, previous, next, last section, table of contents.


Debugger User Interface

When debugging a program, programmers often find it helpful to examine the program's internal status while it runs: the values of internal variables, the choices made in if and cond statements, and so forth. Guile Scheme provides a debugging interface that programmers can use to single-step through Scheme functions and examine symbol bindings. This is different from the section Internal Debugging Interface, which permits programmers to debug the Guile interpreter itself. Most programmers will be more interested in debugging their own Scheme programs than the interpreter which evaluates them.

[FIXME: should we include examples of traditional debuggers and explain why they can't be used to debug interpreted Scheme or Lisp?]

Single-Step

Trace

When a function is traced, it means that every call to that function is reported to the user during a program run. This can help a programmer determine whether a function is being called at the wrong time or with the wrong set of arguments.

Function: trace function
Enable debug tracing on function. While a program is being run, Guile will print a brief report at each call to a traced function, advising the user which function was called and the arguments that were passed to it.

Function: untrace function
Disable debug tracing for function.

Example:

(define (rev ls)
  (if (null? ls)
      '()
      (append (rev (cdr ls))
              (cons (car ls) '())))) => rev

(trace rev) => (rev)

(rev '(a b c d e))
=> [rev (a b c d e)]
   |  [rev (b c d e)]
   |  |  [rev (c d e)]
   |  |  |  [rev (d e)]
   |  |  |  |  [rev (e)]
   |  |  |  |  |  [rev ()]
   |  |  |  |  |  ()
   |  |  |  |  (e)
   |  |  |  (e d)
   |  |  (e d c)
   |  (e d c b)
   (e d c b a)
   (e d c b a)

Note the way Guile indents the output, illustrating the depth of execution at each function call. This can be used to demonstrate, for example, that Guile implements self-tail-recursion properly:

(define (rev ls sl)
  (if (null? ls)
      sl
      (rev (cdr ls)
           (cons (car ls) sl)))) => rev
 
(trace rev) => (rev)
 
(rev '(a b c d e) '())
=> [rev (a b c d e) ()]
   [rev (b c d e) (a)]
   [rev (c d e) (b a)]
   [rev (d e) (c b a)]
   [rev (e) (d c b a)]
   [rev () (e d c b a)]
   (e d c b a)
   (e d c b a)

Since the tail call is effectively optimized to a goto statement, there is no need for Guile to create a new stack frame for each iteration. Using trace here helps us see why this is so.

Backtrace

Stacks and Frames

When a running program is interrupted, usually upon reaching an error or breakpoint, its state is represented by a stack of suspended function calls, each of which is called a frame. The programmer can learn more about the program's state at the point of interruption by inspecting and modifying these frames.

Scheme Procedure: stack? obj
Return #t if obj is a calling stack.

Scheme Procedure: make-stack

syntax: start-stack id exp
Evaluate exp on a new calling stack with identity id. If exp is interrupted during evaluation, backtraces will not display frames farther back than exp's top-level form. This macro is a way of artificially limiting backtraces and stack procedures, largely as a convenience to the user.

Scheme Procedure: stack-id stack
Return the identifier given to stack by start-stack.

Scheme Procedure: stack-ref

Scheme Procedure: stack-length

Scheme Procedure: frame?

Scheme Procedure: last-stack-frame

Scheme Procedure: frame-number

Scheme Procedure: frame-source

Scheme Procedure: frame-procedure

Scheme Procedure: frame-arguments

Scheme Procedure: frame-previous

Scheme Procedure: frame-next

Scheme Procedure: frame-real?

Scheme Procedure: frame-procedure?

Scheme Procedure: frame-evaluating-args?

Scheme Procedure: frame-overflow


Go to the first, previous, next, last section, table of contents.