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-condition

s 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

nil

if 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