Chapter 11 Debugger Programmer's
Interface
The debugger
programmers interface is exported from from the DEBUG-INTERNALS or DI package.
This is a CMU extension that allows debugging tools to be written
without detailed knowledge of the compiler or run-time system.
Some of the interface routines take a code-location as an argument.
As described in the section on code-locations, some code-locations
are unknown. When a function calls for a basic-code-location, it takes either type, but when
it specifically names the argument code-location, the routine will signal an error if
you give it an unknown code-location.
11.1 DI Exceptional Conditions
Some of these operations fail depending on the availability
debugging information. In the most severe case, when someone saved
a Lisp image stripping all debugging data structures, no operations
are valid. In this case, even backtracing and finding frames is
impossible. Some interfaces can simply return values indicating the
lack of information, or their return values are naturally
meaningful in light missing data. Other routines, as documented
below, will signal serious-conditions when
they discover awkward situations. This interface does not provide
for programs to detect these situations other than by calling a
routine that detects them and signals a condition. These are
serious-conditions because the program using the interface must
handle them before it can correctly continue execution. These
debugging conditions are not errors since it is no fault of the
programmers that the conditions occur.
11.1.1 Debug-conditions
The debug internals interface signals conditions when it can't
adhere to its contract. These are serious-conditions because the
program using the interface must handle them before it can
correctly continue execution. These debugging conditions are not
errors since it is no fault of the programmers that the conditions
occur. The interface does not provide for programs to detect these
situations other than calling a routine that detects them and
signals a condition.
[Condition]
debug-condition
This condition inherits from serious-condition, and all
debug-conditions inherit from this. These must be handled, but they
are not programmer errors.
[Condition]
no-debug-info
This condition indicates there is absolutely no debugging
information available.
[Condition]
no-debug-function-returns
This condition indicates the system cannot return values from a
frame since its debug-function lacks debug information details
about returning values.
[Condition]
no-debug-blocks
This condition indicates that a function
was not compiled with debug-block information, but this information
is necessary necessary for some requested operation.
[Condition]
no-debug-variables
Similar to no-debug-blocks, except that variable information was
requested.
[Condition]
lambda-list-unavailable
Similar to no-debug-blocks, except that lambda list information
was requested.
[Condition]
invalid-value
This condition indicates a debug-variable has :invalid or :unknown value in a
particular frame.
[Condition]
ambiguous-variable-name
This condition indicates a user supplied debug-variable name
identifies more than one valid variable in a particular
frame.
11.1.2 Debug-errors
These are programmer errors resulting from misuse of the debugging
tools' programmers' interface. You could have avoided an occurrence
of one of these by using some routine to check the use of the
routine generating the error.
[Condition]
debug-error
This condition inherits from error, and
all user programming errors inherit from this
condition.
[Condition]
unhandled-condition
This error results from a signalled
debug-condition occurring without anyone
handling it.
[Condition]
unknown-code-location
This error indicates the invalid use of
an unknown-code-location.
[Condition]
unknown-debug-variable
This error indicates an attempt to use a debug-variable in
conjunction with an inappropriate debug-function; for example,
checking the variable's validity using a code-location in the wrong
debug-function will signal this error.
[Condition]
frame-function-mismatch
This error indicates you called a function returned by preprocess-for-eval on a frame other than the one for
which the function had been prepared.
11.2 Debug-variables
Debug-variables represent the constant information about where the
system stores argument and local variable values. The system
uniquely identifies with an integer every instance of a variable
with a particular name and package. To access a value, you must
supply the frame along with the debug-variable since these are
particular to a function, not every instance of a variable on the
stack.
[Function]
debug-variable-name debug-variable
This function returns the name of the debug-variable. The name is the name of the symbol
used as an identifier when writing the code.
[Function]
debug-variable-package debug-variable
This function returns the package name of the debug-variable. This is the package name of the
symbol used as an identifier when writing the code.
[Function]
debug-variable-symbol debug-variable
This function returns the symbol from interning debug-variable-name in the package named by debug-variable-package.
[Function]
debug-variable-id debug-variable
This function returns the integer that makes debug-variable's name and package name unique with
respect to other debug-variable's in the
same function.
[Function]
debug-variable-validity debug-variable basic-code-location
This function returns three values reflecting the validity of
debug-variable's value at basic-code-location:
- :valid
- The value is known to be available.
- :invalid
- The value is known to be unavailable.
- :unknown
- The value's availability is unknown.
[Function]
debug-variable-value debug-variable frame
This function returns the value stored for debug-variable in frame.
The value may be invalid. This is SETF'able.
[Function]
debug-variable-valid-value
debug-variable frame
This function returns the value stored for debug-variable in frame.
If the value is not :valid, then this signals
an invalid-value error.
Frames describe a particular call on the stack for a particular
thread. This is the environment for name resolution, getting
arguments and locals, and returning values. The stack conceptually
grows up, so the top of the stack is the most recently called
function.
top-frame, frame-down,
frame-up, and frame-debug-function can only fail when there is
absolutely no debug information available. This can only happen
when someone saved a Lisp image specifying that the system dump all
debugging data.
[Function]
top-frame
This function never returns the frame for itself, always the frame
before calling top-frame.
[Function]
frame-down frame
This returns the frame immediately below frame on the stack. When frame is the bottom of the stack, this returns
nil.
[Function]
frame-up frame
This returns the frame immediately above frame on the stack. When frame is the top of the stack, this returns
nil.
[Function]
frame-debug-function frame
This function returns the debug-function for the function whose
call frame represents.
[Function]
frame-code-location frame
This function returns the code-location where frame's debug-function will continue running when
program execution returns to frame. If
someone interrupted this frame, the result could be an unknown
code-location.
[Function]
frame-catches frame
This function returns an a-list for all active catches in
frame mapping catch tags to the
code-locations at which the catch re-enters.
[Function]
eval-in-frame frame form
This evaluates form in frame's environment. This can signal several
different debug-conditions since its success relies on a variety of
inexact debug information: invalid-value,
ambiguous-variable-name, frame-function-mismatch. See also preprocess-for-eval.
11.4 Debug-functions
Debug-functions represent the static information about a function
determined at compile time—argument and variable storage,
their lifetime information, etc. The debug-function also contains
all the debug-blocks representing basic-blocks of code, and these
contains information about specific code-locations in a
debug-function.
[Macro]
do-debug-function-blocks (block-var debug-function
{result-form}) {form}*
This executes the forms in a context with block-var bound to each debug-block in debug-function successively. Result-form is an optional form to execute for a
return value, and do-debug-function-blocks
returns nilif there is no result-form. This signals a no-debug-blocks condition when the debug-function lacks debug-block
information.
[Function]
debug-function-lambda-list
debug-function
This function returns a list representing the lambda-list for
debug-function. The list has the
following structure:
(required-var1 required-var2
...
(:optional var3 suppliedp-var4)
(:optional var5)
...
(:rest var6) (:rest var7)
...
(:keyword keyword-symbol var8 suppliedp-var9)
(:keyword keyword-symbol var10)
...
)
Each varn is a
debug-variable; however, the symbol :deleted
appears instead whenever the argument remains unreferenced
throughout debug-function.
If there is no lambda-list information, this signals a lambda-list-unavailable condition.
[Macro]
do-debug-function-variables
(var debug-function {result})
{form}*
This macro executes each form in a
context with var bound to each
debug-variable in debug-function. This
returns the value of executing result
(defaults to nil). This may iterate over only
some of debug-function's variables or
none depending on debug policy; for example, possibly the
compilation only preserved argument information.
[Function]
debug-variable-info-available
debug-function
This function returns whether there is any variable information for
debug-function. This is useful for
distinguishing whether there were no locals in a function or
whether there was no variable information. For example, if
do-debug-function-variables executes its
forms zero times, then you can use this function to determine the
reason.
[Function]
debug-function-symbol-variables
debug-function symbol
This function returns a list of debug-variables in debug-function having the same name and package as
symbol. If symbol is uninterned, then this returns a list of
debug-variables without package names and with the same name as
symbol. The result of this function is
limited to the availability of variable information in debug-function; for example, possibly debug-function only knows about its
arguments.
[Function]
ambiguous-debug-variables debug-function name-prefix-string
This function returns a list of debug-variables in debug-function whose names contain name-prefix-string as an initial substring. The
result of this function is limited to the availability of variable
information in debug-function; for
example, possibly debug-function only
knows about its arguments.
[Function]
preprocess-for-eval form basic-code-location
This function returns a function of one argument that evaluates
form in the lexical context of basic-code-location. This allows efficient repeated
evaluation of form at a certain place in
a function which could be useful for conditional breaking. This
signals a no-debug-variables condition when
the code-location's debug-function has no debug-variable
information available. The returned function takes a frame as an
argument. See also eval-in-frame.
[Function]
function-debug-function function
This function returns a debug-function that represents debug
information for function.
[Function]
debug-function-kind debug-function
This function returns the kind of function debug-function represents. The value is one of the
following:
- :optional
- This kind of function is an entry point to an
ordinary function. It handles optional defaulting, parsing
keywords, etc.
- :external
- This kind of function is an entry point to an
ordinary function. It checks argument values and count and calls
the defined function.
- :top-level
- This kind of function executes one or more
random top-level forms from a file.
- :cleanup
- This kind of function represents the cleanup
forms in an unwind-protect.
- nil
- This kind of function is not one of the above;
that is, it is not specially marked in any way.
[Function]
debug-function-function debug-function
This function returns the Common Lisp function associated with the
debug-function. This returns nil if the function is unavailable or is non-existent
as a user callable function object.
[Function]
debug-function-name debug-function
This function returns the name of the function represented by
debug-function. This may be a string or a
cons; do not assume it is a symbol.
11.5 Debug-blocks
Debug-blocks contain information pertinent to a specific range of
code in a debug-function.
[Macro]
do-debug-block-locations (code-var debug-block
{result}) {form}*
This macro executes each form in a
context with code-var bound to each
code-location in debug-block. This
returns the value of executing result
(defaults to nil).
[Function]
debug-block-successors debug-block
This function returns the list of possible code-locations where
execution may continue when the basic-block represented by
debug-block completes its
execution.
[Function]
debug-block-elsewhere-p debug-block
This function returns whether debug-block
represents elsewhere code. This is code the compiler has moved out
of a function's code sequence for optimization reasons.
Code-locations in these blocks are unsuitable for stepping tools,
and the first code-location has nothing to do with a normal
starting location for the block.
11.6 Breakpoints
A breakpoint represents a function the system calls with the
current frame when execution passes a certain code-location. A
break point is active or inactive independent of its existence.
They also have an extra slot for users to tag the breakpoint with
information.
[Function]
make-breakpoint hook-function what
&key :kind
:info :function-end-cookie
This function creates and returns a breakpoint. When program
execution encounters the breakpoint, the system calls hook-function. hook-function takes the current frame for the
function in which the program is running and the breakpoint
object.
what and kind
determine where in a function the system invokes hook-function. what is
either a code-location or a debug-function. kind is one of :code-location, :function-start,
or :function-end. Since the starts and ends
of functions may not have code-locations representing them,
designate these places by supplying what
as a debug-function and kind indicating
the :function-start or :function-end. When what is a
debug-function and kind is :function-end, then hook-function must take two
additional arguments, a list of values returned by the function and
a function-end-cookie.
info is information supplied by and used
by the user.
function-end-cookie is a function. To
implement function-end breakpoints, the system uses starter
breakpoints to establish the function-end breakpoint for each
invocation of the function. Upon each entry, the system creates a
unique cookie to identify the invocation, and when the user
supplies a function for this argument, the system invokes it on the
cookie. The system later invokes the function-end breakpoint hook
on the same cookie. The user may save the cookie when passed to the
function-end-cookie function for later comparison in the hook
function.
This signals an error if what is an
unknown code-location.
Note: Breakpoints in interpreted code or byte-compiled code are
not implemented. Function-end breakpoints are not implemented for
compiled functions that use the known local return convention (e.g.
for block-compiled or self-recursive functions.)
[Function]
activate-breakpoint breakpoint
This function causes the system to invoke the breakpoint's hook-function until the next call to
deactivate-breakpoint or delete-breakpoint. The system invokes breakpoint hook
functions in the opposite order that you activate
them.
[Function]
deactivate-breakpoint breakpoint
This function stops the system from invoking the breakpoint's hook-function.
[Function]
breakpoint-active-p breakpoint
This returns whether breakpoint is
currently active.
[Function]
breakpoint-hook-function breakpoint
This function returns the breakpoint's
function the system calls when execution encounters breakpoint, and it is active. This is SETF'able.
[Function]
breakpoint-info breakpoint
This function returns breakpoint's
information supplied by the user. This is SETF'able.
[Function]
breakpoint-kind breakpoint
This function returns the breakpoint's
kind specification.
[Function]
breakpoint-what breakpoint
This function returns the breakpoint's
what specification.
[Function]
delete-breakpoint breakpoint
This function frees system storage and removes computational
overhead associated with breakpoint.
After calling this, breakpoint is useless
and can never become active again.
11.7 Code-locations
Code-locations represent places in functions where the system has
correct information about the function's environment and where
interesting operations can occur—asking for a local
variable's value, setting breakpoints, evaluating forms within the
function's environment, etc.
Sometimes the interface returns unknown code-locations. These
represent places in functions, but there is no debug information
associated with them. Some operations accept these since they may
succeed even with missing debug data. These operations' argument is
named basic-code-location indicating they
take known and unknown code-locations. If an operation names its
argument code-location, and you supply an
unknown one, it will signal an error. For example, frame-code-location may return an unknown code-location
if someone interrupted Lisp in the given frame. The system knows
where execution will continue, but this place in the code may not
be a place for which the compiler dumped debug information.
[Function]
code-location-debug-function
basic-code-location
This function returns the debug-function representing information
about the function corresponding to the code-location.
[Function]
code-location-debug-block basic-code-location
This function returns the debug-block containing code-location if
it is available. Some debug policies inhibit debug-block
information, and if none is available, then this signals a
no-debug-blocks condition.
[Function]
code-location-top-level-form-offset
code-location
This function returns the number of top-level forms before the one
containing code-location as seen by the
compiler in some compilation unit. A compilation unit is not
necessarily a single file, see the section on
debug-sources.
[Function]
code-location-form-number code-location
This function returns the number of the form corresponding to
code-location. The form number is derived
by walking the subforms of a top-level form in depth-first order.
While walking the top-level form, count one in depth-first order
for each subform that is a cons. See form-number-translations.
[Function]
code-location-debug-source
code-location
This function returns code-location's
debug-source.
[Function]
code-location-unknown-p basic-code-location
This function returns whether basic-code-location is unknown. It returns
nil when the code-location is
known.
[Function]
code-location= code-location1 code-location2
This function returns whether the two code-locations are the
same.
11.8 Debug-sources
Debug-sources represent how to get back the source for some code.
The source is either a file (compile-file or
load), a lambda-expression (compile, defun, defmacro), or a stream (something particular to CMUCL,
compile-from-stream).
When compiling a source, the compiler counts each top-level form it
processes, but when the compiler handles multiple files as one
block compilation, the top-level form count continues past file
boundaries. Therefore code-location-top-level-form-offset returns an offset
that does not always start at zero for the code-location's
debug-source. The offset into a particular source is code-location-top-level-form-offset minus debug-source-root-number.
Inside a top-level form, a code-location's form number indicates
the subform corresponding to the code-location.
[Function]
debug-source-from debug-source
This function returns an indication of the type of source. The
following are the possible values:
- :file
- from a file (obtained by compile-file if compiled).
- :lisp
- from Lisp (obtained by compile if compiled).
- :stream
- from a non-file stream (CMUCL supports
compile-from-stream).
[Function]
debug-source-name debug-source
This function returns the actual source in some sense represented
by debug-source, which is related to debug-source-from:
- :file
- the pathname of the file.
- :lisp
- a lambda-expression.
- :stream
- some descriptive string that's otherwise
useless.
[Function]
debug-source-created debug-source
This function returns the universal time someone created the
source. This may be nil if it is
unavailable.
[Function]
debug-source-compiled debug-source
This function returns the time someone compiled the source. This is
nil if the source is uncompiled.
[Function]
debug-source-root-number debug-source
This returns the number of top-level forms processed by the
compiler before compiling this source. If this source is
uncompiled, this is zero. This may be zero even if the source is
compiled since the first form in the first file compiled in one
compilation, for example, must have a root number of zero—the
compiler saw no other top-level forms before it.
11.9 Source Translation Utilities
These two functions provide a mechanism for converting the rather
obscure (but highly compact) representation of source locations
into an actual source form:
[Function]
debug-source-start-positions
debug-source
This function returns the file position of each top-level form as a
vector if debug-source is from a
:file. If debug-source-from is :lisp or
:stream, or the file is byte-compiled, then
the result is nil.
[Function]
form-number-translations form tlf-number
This function returns a table mapping form numbers (see code-location-form-number) to source-paths. A
source-path indicates a descent into the top-level-form form, going directly to the subform corresponding
to a form number. tlf-number is the
top-level-form number of form.
[Function]
source-path-context form path context
This function returns the subform of form
indicated by the source-path. Form is a
top-level form, and path is a source-path
into it. Context is the number of
enclosing forms to return instead of directly returning the
source-path form. When context is
non-zero, the form returned contains a marker, #:****HERE****, immediately before the form indicated
by path.