Previous Up Next

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.

11.3 Frames

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.


Previous Up Next