The DEBUGGER-MANAGER library

The original version of this document was written by Paul Howard and Tony Mann in March 1997.

Introduction

The Debugger Manager (DM) is quite a high-level component of the debugger architecture. It sits between the access path interface and the debugger UI. The DM provides abstractions over the debug operations described by the access path interface, as well as providing dylan-specific debugging functionality.

DM

Debugger Manager. The component of the debugger described by this document.

RTM

Runtime Manager. The DM in conjunction with other internal support for the tether/interactivity: the access-path and interactive downloader.

UI

User Interface (of the debugging tool). Client of the DM.

DevelDBG

A simple Dylan debugger with a command-line interface. Some implementation details of DevelDBG require specific functionality from the Debugger Manager. These have been kept to a minimum and are flagged in this document by “DevelDBG only”.

For DevelDBG, the debugger UI will probably import most of the access path functionality as well as debugger manager functionality. It is doubtful that this model will be adopted for the final debugger. Certainly _some_ access path definitions will need to be exposed (stop-reasons being a good example), but exposing application control functions like “stop” and “continue” potentially allows the UI to interfere with the DM’s management of the running app.

Model of the Debugger Manager

The general model of the debugging tool can be reduced to two concurrent loops: a loop processing user input in the UI, and a loop receiving stop reasons from the running application. The DM takes charge of the latter, but synchronizes with the UI by operating a callback system, calling on UI routines when important events are received from the running application.

Callbacks are invoked under the following circumstances:

  1. The application stopped because a debug event or exception occurred (an “internal” stop), or because some event in the debugger UI signaled that the application should stop (an “external” stop).

  2. The application hit a breakpoint/watchpoint. At the low level, a breakpoint/watchpoint hit is just another variety of internal stop. However, the DM provides a separate mechanism of callbacks for them, since they are the vehicle for many higher-level debugging facilities such as tracing.

  3. The application is ready to continue. This means that the application had previously stopped for some reason (which may have involved the invocation of other callbacks), but the DM is now capable of allowing it to resume.

The following sections describe how and when these callbacks are registered, and the precise form they must take.

Debug Targets

A “debug target” represents whatever is being debugged. In most cases, this will be a newly created application. Basically, a debug target is very similar to an access path, and has a one-to-one correspondence with an <access-path> instance. The main difference is that the <access-path> is a sealed description of the connection to the debugger nub, whereas the <debug-target> can be subclassed to hold any information that clients of the DM wish to store.

<debug-target> Open Abstract Class
Superclasses:

<object>

Init-Keywords:
  • application-object – An instance of <object>.

  • compilation-context – An instance of <object>.

  • top-level-component-name – An instance of <string>, or #f.

Describes an application being debugged. Users of the DM are allowed to create appropriate concrete subclasses of <debug-target> with slots specific to their own purposes.

It is always possible to map between a <debug-target> and its corresponding <access-path>.

When a <debug-target> is made, an <access-path> of the appropriate type is made automatically. The DM will also install the <debug-target> as the access-path-abstract-handle slot of the access path.

This class is specified to take the same init-keywords as <access-path>. (They will just be passed on when the <access-path> instance is made.)

Example:

define class <knackered-application> (<debug-target>)
end class;

define variable my-app =
              make (<knackered-application>,
                    application: "spam",
                    arguments: "spam");
debug-target-access-path Generic function
Signature:

debug-target-access-path (object) => (value)

Parameters:
Values:

It’s not clear that we need to export this function at all from the DM. (Exporting it is advantageous for DevelDBG since it allows us to use all the access-path functionality as well, such as access-path-arguments). See the note in the Introduction.

debug-target-symbol-table Generic function
Signature:

debug-target-symbol-table (object) => (value)

Parameters:
Values:
  • value – An instance of <interactive-symbol-table>.

debug-target-compilation-context Generic function
Signature:

debug-target-compilation-context (object) => (value)

Parameters:
Values:
debug-target-compilation-context-setter Generic function
Signature:

debug-target-compilation-context-setter (value object) => (value)

Parameters:
Values:
find-library-called Generic function
Signature:

find-library-called (application core-name) => (maybe-lib)

Parameters:
Values:

Attempts to find a <remote-library> whose name matches the supplied string. Returns #f if no matching library is found.

obtain-component-name Open Generic function
Signature:

obtain-component-name (application libname) => (name)

Parameters:
Values:

A name context contains the name of a dylan library. Often, this needs to be mapped to the name of a shared object (or DLL), which should be performed via this function.

obtain-component-name(<debug-target>, <string>) Method
<interactor-return-breakpoint> Class
Superclasses:

<dylan-return-breakpoint>

Init-Keywords:
  • application-state (required) – An instance of <object>.

  • result-spec (required) – An instance of <symbol>.

interaction-request-application-state Open Generic function
Signature:

interaction-request-application-state (interaction-transaction-id) => (application-state)

Parameters:
  • interaction-transaction-id – An instance of <object>.

Values:
  • application-state – An instance of <object>.

interaction-request-application-state(<interactor-return-breakpoint>) Method
interaction-request-application-state-setter Open Generic function
Signature:

interaction-request-application-state-setter (application-state interaction-transaction-id) => (application-state)

Parameters:
  • application-state – An instance of <object>.

  • interaction-transaction-id – An instance of <object>.

Values:
  • application-state – An instance of <object>.

interaction-request-application-state-setter(<object>, <interactor-return-breakpoint>) Method

Debugger Transaction Caching Utilities

<page-relative-object-table> Open Abstract Class
Superclasses:

<object>

Init-Keywords:

A class used to store remote dylan objects in fast-lookup form. The values in the table can be arbitrary information that needs to be obtained from the key.

<page-relative-object-table-entry> Open Abstract Class
Superclasses:

<object>

add-object Open Generic function
Signature:

add-object (table instance entry) => ()

Parameters:
add-object(<page-relative-object-table>, <remote-value>, <page-relative-object-table-entry>) Method
enquire-object Open Generic function
Signature:

enquire-object (table instance) => (entry)

Parameters:
Values:

Checks to see whether a dylan object is present in a table. If so, returns the description that was supplied to add-object when the object was put into the table, otherwise returns #f.

enquire-object(<page-relative-object-table>, <remote-value>) Method
remove-object Open Generic function
Signature:

remove-object (table instance) => ()

Parameters:
remove-object(<page-relative-object-table>, <remote-value>) Method
invalidate-page-relative-object-table Open Generic function
Signature:

invalidate-page-relative-object-table (table) => ()

Parameters:
invalidate-page-relative-object-table(<page-relative-object-table>) Method

Stop Reasons

The access-path library exports the open abstract class <external-stop-reason> (as a subclass of <stop-reason>). The DM expands on this open branch of the hierarchy.

stop-reason-debug-points Generic function
Signature:

stop-reason-debug-points (application sr) => (interested-debug-points)

Parameters:
Values:
  • interested-debug-points – An instance of <sequence>.

Returns the sequence of <debug-point> objects that caused the stop reason. The sequence will only contain those debug-points whose callbacks returned #t (see Registering Debug Points).

<debugger-generated-stop-reason> Open Abstract Class
Superclasses:

<external-stop-reason>

Init-Keywords:
  • client-data – An instance of <object>.

A subclass of <external-stop-reason>. A stop reason indicating that the application was stopped by some action on the part of the UI.

stop-reason-client-data Generic function
Signature:

stop-reason-client-data (object) => (value)

Parameters:
Values:
<debugger-stop-application-stop-reason> Class
Superclasses:

<debugger-generated-stop-reason>

A subclass of <debugger-generated-stop-reason>. The stop reason generated when the UI calls stop-application (see Managing Application Control) for some reason.

The access-path also supports an open subclass of <internal-stop-reason> called <language-level-stop-reason>. This is so that the DM can, having examined the dynamic state of the application, present more informative stop-reasons. Here are the subclasses defined by the DM, along with various specific accessors.

<dylan-invoke-debugger-stop-reason> Class
Superclasses:

<with-stack-protocol-stop-reason>

A subclass of <language-level-stop-reason>. A stop-reason indicating that an unhandled Dylan condition resulted in a Dylan-level invocation of the debugger.

dylan-error-message-string Generic function
Signature:

dylan-error-message-string (sr) => (str)

Parameters:
Values:

Returns the error message that resulted in the condition.

<dylan-debug-message-stop-reason> Class
Superclasses:

<with-stack-protocol-stop-reason>

A subclass of <language-level-stop-reason>. A stop-reason indicating that the application called a dylan-level debug utility to generate a formatted debugging message.

dylan-debug-message-string Generic function
Signature:

dylan-debug-message-string (sr) => (str)

Parameters:
Values:

Builds up and returns the formatted string that was generated by the debug-message call.

<source-code-alignment-stop-reason> Class
Superclasses:

<language-level-stop-reason>

<interactor-return-stop-reason> Class
Superclasses:

<language-level-stop-reason>

Init-Keywords:
  • transaction-id (required) – An instance of <object>.

A subclass of <language-level-stop-reason>. A stop-reason indicating that the execution of an interactive form has just returned, and that its results are available.

<interactive-thread-initialized-stop-reason> Class
Superclasses:

<language-level-stop-reason>

Init-Keywords:
interactive-thread-name Generic function
Signature:

interactive-thread-name (object) => (value)

Parameters:
Values:
interactor-transaction-id Generic function
Signature:

interactor-transaction-id (object) => (value)

Parameters:
Values:

All interactive evaluations have a transaction-id associated with them. This accessor returns the id that was associated with the evaluation that just returned, generating the stop reason. This transaction-id will be == to the transaction-id that was returned when the interactor called execute-source (see gz’s CSI document).

interactor-return-values Generic function
Signature:

interactor-return-values (sr) => (vals)

Parameters:
Values:

Returns a vector of <remote-value>s corresponding to the sequence of return values generated by the interactive evaluation.

setup-interactor Generic function
Signature:

setup-interactor (application thread symbolic-c-entry-point symbolic-dll return-spec #rest args) => (transaction-id)

Parameters:
Values:
  • transaction-id – An instance of <object>.

handle-interactor-return Open Generic function
Signature:

handle-interactor-return (application thread transaction-id #rest return-values) => (stop?)

Parameters:
Values:
handle-interactor-return(<debug-target>, <remote-thread>, <object>) Method
<class-breakpoint-stop-reason> Class
Superclasses:

<language-level-stop-reason>

Init-Keywords:
class-breakpoint-class Generic function
Signature:

class-breakpoint-class (object) => (value)

Parameters:
Values:
class-breakpoint-size Generic function
Signature:

class-breakpoint-size (object) => (value)

Parameters:
Values:

Managing Application Control

The DM takes responsibility for most aspects of application control. There are no explicit functions to wait for stop-reasons or to continue execution — the DM performs these tasks on demand during an indefinite loop. Within this loop, the DM invokes various callbacks that can be registered by the UI.

stop-application Generic function
Signature:

stop-application (application #key stop-reason) => ()

Parameters:

Suspends the application with immediate effect.

kill-application Generic function
Signature:

kill-application (application) => ()

Parameters:

Terminates the application regardless of its state.

restart-application Generic function
Signature:

restart-application (application) => ()

Parameters:

Restarts the application from the beginning.

manage-running-application Generic function
signature:

manage-running-application (application #key stop-reason-callback poll-for-stop-callback ready-to-continue-callback) => ()

parameter application:

An instance of <debug-target>.

parameter #key stop-reason-callback:

An instance of <object>.

parameter #key poll-for-stop-callback:

An instance of <object>.

parameter #key ready-to-continue-callback:

An instance of <object>.

Starts up the application via its access path and enters an indefinite loop. Within this loop, the DM receives stop-reasons through the access-path and invokes the appropriate registered callback.

This function does not return until the running application exits or is killed.

A number of callbacks can be specified up-front as keyword parameters. The UI will almost certainly want to specify all of these, though defaults are provided.

stop-reason-callback

A function of two arguments, a <debug-target> and a <stop-reason>, which returns a boolean. The DM invokes this callback whenever a stop-reason is received from the application. Note that breakpoint exceptions are a special case (see Registering Debug Points).

If the callback returns #f, the application is silently resumed. If it returns true, the application remains suspended, and the ready-to-continue-callback is invoked with an instance of <internal-stop-reason>. The return value of true, therefore, indicates an “interest” in this stop reason, whereas #f effectively filters it out.

The application is known to be frozen during the entire execution of this callback.

poll-for-stop-callback

A function of one argument, a <debug-target>. In a single-threaded environment (which DevelDBG is), this function is needed to give the UI a chance to stop the application. The DevelDBG UI, for instance, has a “stop button” whose status can be checked during this periodic callback.

During execution of this callback, the UI may call stop-application. This will result in the ready-to-continue-callback being invoked with an instance of <debugger-stop-application-stop-reason>. But note that this will not happen until the poll-for-stop-callback returns.

The DM undertakes to call this function at frequent intervals. The default callback does nothing (and hence does not call stop-application).

For a multi-threaded GUI debugging tool, this callback will not be required.

The application may be running during the execution of this callback.

ready-to-continue-callback

A function of two arguments, a <debug-target> and a <stop-reason>.

This callback is invoked whenever the debugger manager is ready to continue the application. If the application stopped of its own accord (an internal stop), then other callbacks will already have had the chance to do their own processing (such as the handling of debug-points).

Reaching the ready-to-continue-callback means that all of this processing has been done, but the internal stop was still interesting enough for control to be passed to the UI before continuing.

This callback may call the function kill-application. In this case, the application will no longer be running, and manage-running-application will return. This callback may also call the function restart-application, in which case the app will be re-run from the beginning, but will continue to be managed in the same loop. (That is, manage-running-application will not return).

If the callback returns without having called kill-application or restart-application, the application will be resumed from the point where it stopped.

The default callback does nothing.

The application is known to be frozen during the entire execution of this callback.

In a multi-threaded UI environment, this callback will probably block on some resource which can be freed by a “continue” gesture in the GUI.

application-stopped? Generic function
Signature:

application-stopped? (object) => (value)

Parameters:
Values:
application-stopped?-setter Generic function
Signature:

application-stopped?-setter (value object) => (value)

Parameters:
Values:

Registering Debug Points

The DM allows any number of debug points to be positioned on any one address (obviously, the first such debug point results in actually setting a breakpoint or watchpoint in the application, but the DM takes care of this implicitly). In the DM, a debug point is described by an address paired with a callback.

Debug Point callbacks take three arguments, a <debug-target>, a <debug-point>, and a <remote-thread> (the thread that signaled the debug point exception), and return a boolean.

A true return value indicates that the application should stop as a result of this debug point (ie, the UI is interested in it, given the current context). #f implies that the callback has done all of the necessary processing and the application may continue.

Debug point callbacks have slightly different semantics than those callbacks described thus far. They are not functions that are immediately called when a debug-point is encountered. Instead, they are functions which can be called if the context is relevant. This is further described below.

<debug-point> Open Abstract Class
Superclasses:

<dm-registered-descriptor>

Init-Keywords:

This is NOT the same as <debug-point-stop-reason> as defined in the access-path library.

Requires the following init-keywords:

address:

A <remote-value> — the location at which this debug point is to be registered.

callback:

A <function> — the callback to be invoked when the debug-point is hit. Should accept a <debug-target>, a <debug-point> and a <remote-thread> as arguments, and return a boolean (as described above). Note that the DM does not directly invoke this callback. Instead, it calls the open generic function handle-debug-point-event (see below), which may or may not subsequently invoke the callback.

<breakpoint> Open Abstract Class
Superclasses:

<debug-point>

<watchpoint> Open Abstract Class
Superclasses:

<debug-point>

<tracepoint> Abstract Instantiable Class
Superclasses:

<debug-point>

All debug-points to do with function tracing are a subclass of <tracepoint>. Calling make on this class returns an instance of <entry-tracepoint>.

<entry-tracepoint> Open Abstract Class
Superclasses:

<tracepoint>

Init-Keywords:
  • return-callback (required) – An instance of <function>.

This requires a further init-keyword return-callback: (of the same specification as the callback: keyword argument).

The default handle-debug-point-event method for <entry-tracepoint> calls the registered callback as well as setting a <return-tracepoint> on the return address via a protocol described below. This <return-tracepoint> will have, as its registered callback, the function that was supplied as the return-callback.

Entry tracepoints can only be set at the very start of functions. The DM will refuse to register an <entry-tracepoint> whose address: keyword does not correspond to the first address of a function definition. A <debug-point-error> will be signaled if this condition is not met. (Maybe another error class should be defined for this specific case…?)

Valid addresses are therefore those which are known in advance to be the addresses of functions. Addresses obtained via dylan-method-iep, for example, will be valid. The address of a <remote-symbol> will only be valid if the symbol denotes a function.

<return-tracepoint> Open Abstract Instantiable Class
Superclasses:

<tracepoint>

Init-Keywords:

It is not intended that clients of the DM should create and register <return-tracepoint> objects except via the special mechanism that the DM provides (see the functions below).

The default handle-debug-point-event method for <return-tracepoint> will invoke the registered callback if (and only if) the thread and stack contexts are the same as when the corresponding <entry-tracepoint> was encountered. In this case, the <return-tracepoint> will also deregister itself.

make-return-tracepoint Open Generic function
Signature:

make-return-tracepoint (app bp thr #rest keys #key #all-keys) => (return-point)

Parameters:
Values:

When the DM encounters a debug-point of type <entry-tracepoint>, there is the need to set a <return-tracepoint> on the corresponding return address. The DM calls this open generic function in order to create it. This is required since <return-tracepoint> is an open class.

The default method simply returns an instance of <return-tracepoint>.

make-return-tracepoint(<debug-target>, <entry-tracepoint>, <remote-thread>) Method
make-return-tracepoint(<debug-target>, <starting-dynamic-initialization>, <remote-thread>) Method
initialize-return-tracepoint Open Generic function
Signature:

initialize-return-tracepoint (app bp thr #key #all-keys) => ()

Parameters:

After calling make-return-tracepoint, the DM also calls this open generic function with the newly created return-tracepoint. This allows the client to perform any other specialized initialization behaviour.

The default method actually registers the return-tracepoint, so clients defining methods on this function should make sure that they call next-method() at some point.

initialize-return-tracepoint(<debug-target>, <return-tracepoint>, <remote-thread>) Method
corresponding-entry-tracepoint Generic function
Signature:

corresponding-entry-tracepoint (object) => (value)

Parameters:
Values:

Given a return-tracepoint, returns the registered entry-tracepoint that created it.

dylan-trace-entry-arguments Generic function
Signature:

dylan-trace-entry-arguments (application thread function-signature) => (required-arguments rest-vector keyword-arguments)

Parameters:
Values:
dylan-trace-return-values Generic function
Signature:

dylan-trace-return-values (application thread) => (return-vals)

Parameters:
Values:
handle-debug-point-event Open Generic function
Signature:

handle-debug-point-event (application debug-point thr) => (register-interest?)

Parameters:
Values:
  • register-interest? – An instance of <boolean>.

When a debug-point is encountered at address X, the DM selects all debug-points that were registered at X and calls this GF with each debug-point in turn.

If any one of these calls returns true, the application will remain suspended, and the ready-to-continue-callback will be invoked with a <debug-point-stop-reason>. If all calls return #f, the application will be silently allowed to continue. Note that a true return value does not short-circuit this process — all selected debug-points still get handled.

Clients of the DM can add methods to this function to specialize the behaviour of their own debug-point subclasses.

The default method on this GF just invokes the registered callback for this debug-point, passing it the same arguments, and returning its return value. This default behaviour can be reached by calls to next-method().

Example:

define class <ph-breakpoint> (<breakpoint>)
end class;

    ...

define method handle-debug-point-event
                (app :: <debug-target>,
                 x :: <ph-breakpoint>,
                 t :: <remote-thread>) => (_ :: <boolean>)

     if (wind-blowing-in-the-right-direction())
         #f  // Don't invoke the registered callback, and
             // don't signal any interest in this breakpoint.
     else
         next-method()
     end if
 end method;
register-debug-point Generic function
Signature:

register-debug-point (application debug-point) => ()

Parameters:

Registers the <debug-point> with the DM. It is added to any others that have already been registered at the same address. (If there are no others, then this call will actually set a low-level breakpoint).

deregister-debug-point Generic function
Signature:

deregister-debug-point (application debug-point) => ()

Parameters:

De-registers the <debug-point>.

<debug-point-error> Class
Superclasses:

<error>

A condition of this type will be signaled by register-debug-point or deregister-debug-point if either operation fails for some reason. This might occur, for example, if an address in the application’s code was not mapped and so a breakpoint instruction could not be poked in.

application-running-on-code-entry? Generic function
Signature:

application-running-on-code-entry? (object) => (value)

Parameters:
Values:
application-running-on-code-entry?-setter Generic function
Signature:

application-running-on-code-entry?-setter (value object) => (value)

Parameters:
Values:
application-just-interacted? Generic function
Signature:

application-just-interacted? (object) => (value)

Parameters:
Values:
application-just-interacted?-setter Generic function
Signature:

application-just-interacted?-setter (value object) => (value)

Parameters:
Values:
interactor-deferred-id-table Generic function
Signature:

interactor-deferred-id-table (object) => (value)

Parameters:
Values:
  • value – An instance of <table>.

Example - simple function tracing

define class <my-entry-trace> (<entry-tracepoint>)
       slot traced-function :: <remote-symbol>,
            required-init-keyword: symbol:;
end class;

define class <my-return-trace> (<return-tracepoint>)
       slot traced-function :: <remote-symbol>,
            required-init-keyword: symbol:;
end class;

define method print-entry-data
               (app :: <debug-target>, bp :: <my-entry-trace>,
                thr :: <remote-thread>) => (_ :: <boolean>)
       format-out ("Entered %s in thread %s\n",
                   bp.traced-function.remote-symbol-name,
                   thr.thread-name);
       #f;
end method;

define method print-return-data
               (app :: <debug-target>, bp :: <my-return-trace>,
                thr :: <remote-thread>) => (_ :: <boolean>)
       format-out ("Returned from %s in thread %s\n",
                   bp.traced-function.remote-symbol-name,
                   thr.thread-name);
       #f;
end method;

define method make-return-tracepoint
               (app :: <debug-target>, bp :: <my-entry-trace>,
                thr :: <remote-thread>, #rest keys, #key, #all-keys)
                => (_ :: <my-return-trace>)
       apply (make, <my-return-trace>, symbol: bp.traced-function, keys)
end method;

// Just for completeness of the example...

define method initialize-return-tracepoint
               (app :: <debug-target>, bp :: <my-return-trace>,
                thr :: <remote-thread>, #key) => ()
       next-method ()
end method;
.
.
.
    register-debug-point (my-application,
                          make (<my-entry-trace>,
                                address: some-remote-value,
                                symbol: some-remote-symbol,
                                callback: print-entry-data,
                                return-callback: print-return-data))
.
.

Dylan Name Context

In order to resolve Dylan names, they need to be mangled by the debugger in the same way that they were mangled by the compiler. In order to do this, the debugger must know the “context” (the library name and module name) to mangle into. For example, if the context specifies the dylan library and the internal module, then *pants* mangles to TpantsTYinternalVdylan.

<dylan-name-context> Class
Superclasses:

<object>

Init-Keywords:

Specifies a context for name mangling. Calling make on this class returns a context specifying the dylan library and the internal module, but these can be overridden by supplying keyword arguments library: and module:, both with strings.

context-library Generic function
Signature:

context-library (object) => (value)

Parameters:
Values:

Returns the name of the library in this context as a string.

context-library-setter Generic function
Signature:

context-library-setter (value object) => (value)

Parameters:
Values:

Sets the name of the library for this context.

context-module Generic function
Signature:

context-module (object) => (value)

Parameters:
Values:

Returns the name of the module in this context.

context-module-setter Generic function
Signature:

context-module-setter (value object) => (value)

Parameters:
Values:

Sets the name of the module for this context.

demangle-dylan-name Generic function
Signature:

demangle-dylan-name (full-mangled-name) => (name-part module-part library-part method-name? method-iep? method-library-part method-number-part)

Parameters:
Values:
demangle-local-dylan-name Generic function
Signature:

demangle-local-dylan-name (full-mangled-name) => (demang)

Parameters:
Values:
mangle-local-dylan-name Generic function
Signature:

mangle-local-dylan-name (s) => (mangled)

Parameters:
Values:
mangle-in-context Generic function
Signature:

mangle-in-context (s cxt #key as-wrapper? as-static-object? as-entry-point?) => (mangled)

Parameters:
Values:

Transactions on dylan values

read-dylan-value Generic function
Signature:

read-dylan-value (ap address) => (v ok)

Parameters:
Values:
write-dylan-value Generic function
Signature:

write-dylan-value (ap address value) => (v ok)

Parameters:
Values:
read-instance-slot-element Generic function
Signature:

read-instance-slot-element (ap object i) => (v ok)

Parameters:
Values:

Printing and Inspecting Dylan Objects

print-dylan-object Generic function
Signature:

print-dylan-object (application instance #key length level decorate? format) => (rep)

Parameters:
Values:

Attempts to interpret the remote-value as a dylan object and generates a string representation of it. Immediates and “standard” objects (such as strings and simple-object-vectors) will be given direct representations. General instances might just be represented as [<SPAM>]. The DM will have special knowledge of (possibly a subset of) condition objects, and will print their formatted messages if possible.

Printable representations of collection objects (and other instances whose representations are structured) can expand to an inappropriately large size unless some limitations are specified. If length: is supplied, it should be an integer specifying the maximum number of components that should be printed for structured instances. (For example, the maximum number of elements of a collection. Collections with more than ‘length’ elements would be printed with the excess elements replaced by an ellipsis).

If level: is supplied, it should be an integer specifying the level of depth to which structured printing should proceed. Again, deeper levels are abbreviated with an ellipsis. For example, #[1, 2, 3, #[1, 2], 4, 5] would be printed as such if level: were greater than 0. With level: equal to 0, the representation would be #[1, 2, 3, #[...], 4, 5].

If the <remote-value> corresponds to a condition object in the runtime, the DM will attempt to generate the genuine formatted string by interpreting the condition’s format-string and format-args. The DM only guarantees this for instances of <simple-warning>, <simple-error> and <simple-restart>.

describe-dylan-object Generic function
Signature:

describe-dylan-object (application instance) => (class-name slots slot-values repeats repeated-slot-name repeated-slot-values)

Parameters:
Values:
  • class-name – An instance of <string>.

  • slots – An instance of <sequence>.

  • slot-values – An instance of <sequence>.

  • repeats – An instance of <integer>, or #f.

  • repeated-slot-name – An instance of <string>, or #f.

  • repeated-slot-values – An instance of <sequence>, or #f.

get-inspector-values Generic function
Signature:

get-inspector-values (application instance) => (instance-class instance-slots slot-getters slot-setters repeats rept-slot rept-getter rept-setter nonword-repeats nonword-repeat-vector)

Parameters:
Values:

A lower-level function similar in behaviour to describe-dylan-object, but with return values as follows:

class

A <remote-value> representing the <class> that describes this Dylan object.

slots

A sequence of <remote-value>s representing the slot descriptors for the class.

getters

A sequence of functions (closures) capable of reading the value from the corresponding slot. Each function takes no arguments and returns a <remote-value>.

setters

Another sequence of functions capable of setting the value of the corresponding slot. Each function takes a single <remote-value> (and also returns it), with the side-effect of inserting that <remote-value> into the slot.

The three sequences are parallel, so getters[0] returns the value of slots[0], and setters[0] sets that slot, and so forth.

repeats

If the instance has no repeated slot, this value will be #f. Otherwise, it will be an integer specifying the number of repeated elements. (Note that this integer can still be zero, thus distinguishing between an instance that has no repeated slot, and an instance that does have one except there are currently no elements).

repeated-slot

Unless repeats is #f, this will be a <remote-value> giving the slot descriptor for the repeated slot.

repeated-getter

Unless repeats is #f, this will be a function of one integer argument (i) that returns a <remote-value>. When called with some value i (where 0 <= i < repeats), it returns the ith repeated element in the instance. If i is not in the specified range, this function will return #f.

repeated-setter

Unless repeats is #f, this will be a function of two arguments, an <integer> and a <remote-value>. When called with some integer i (where 0 <= i < repeats), and some remote-value v, sets the ith repeated element in the instance to v. If i is not in the specified range, this function will return #f.

dylan-class-browser-information Generic function
Signature:

dylan-class-browser-information (application class-instance #key use-incarnation) => (slots navigation repeat count-offset element-size element-offset class-slot-count)

Parameters:
Values:
  • slots – An instance of <sequence>.

  • navigation – An instance of <string-table>.

  • repeat – An instance of <string>, or #f.

  • count-offset – An instance of <integer>, or #f.

  • element-size – An instance of <integer>, or #f.

  • element-offset – An instance of <integer>, or #f.

  • class-slot-count – An instance of <integer>.

dylan-class-slot-storage Generic function
Signature:

dylan-class-slot-storage (application class-instance #key use-incarnation) => (basic-names descriptors vals)

Parameters:
Values:
dylan-object? Generic function
Signature:

dylan-object? (ap instance #key address?) => (val)

Parameters:
Values:

Probes the object represented by remote-value and tries to deduce whether it is a valid Dylan object. Returns true if the remote-value is (apparently) a Dylan object, otherwise returns #f.

dylan-object-size Generic function
Signature:

dylan-object-size (application instance) => (byte-size-of-whole-object number-of-fixed-fields number-of-repeated-elements)

Parameters:
Values:
  • byte-size-of-whole-object – An instance of <integer>.

  • number-of-fixed-fields – An instance of <integer>.

  • number-of-repeated-elements – An instance of <integer>.

Mapping Between Symbolic Names and Objects

resolve-dylan-name Generic function
Signature:

resolve-dylan-name (application name context #key indirect? library) => (val address)

Parameters:
Values:

Mangles string according to the supplied name context and performs a symbol search for the mangled name.

Two values are returned: the value associated with the name, and the address associated with the name. If the lookup fails, both return values will be #f. Otherwise, the second return value is guaranteed to be a valid <remote-value>, though the first may still be #f.

If indirect?: is true, the DM will attempt to resolve the dylan name to a symbol. If the symbol is found, the DM will read a value from the symbol’s address. The value and the address that was indirected through are both returned. Note that the if the DM, for whatever reason, cannot read the value from the address, it will return #f as the value (although it will still return the address).

If indirect?: is #f, the DM will attempt to resolve the dylan name to an address. It also assumes this address to be the value, and does not perform an indirection. If the symbol is found, it just returns the address twice.

If you are not interested in the address of a symbol, you can ignore the second return value.

Note

The console debugger needs the second ‘address’ return value in order to set variables with values.

resolve-dylan-keyword Generic function
Signature:

resolve-dylan-keyword (application sym) => (addr)

Parameters:
Values:

Finds the address of a keyword (<symbol> object) in the runtime. The string is the name of the keyword, without any syntactic baggage (ie, spam rather than spam: or #"spam"). The DM will canonicalize any mixture of character case in the string, and search for the address of the keyword given the current state of the runtime’s symbol dictionary.

This function will return #f if the keyword is not found.

dylan-keyword-name Generic function
Signature:

dylan-keyword-name (application sym) => (str)

Parameters:
Values:
find-dylan-name Generic function
Signature:

find-dylan-name (application address #key disambiguate-methods?) => (name context precise? constant?)

Parameters:
Values:

Searches for a symbol whose definition is at (or close to) the given <remote-value>.

Return values:

name

The demangled name of the symbol that was found.

context

A <dylan-name-context> giving the name’s library and module. (This will have been generated from the stripped-off qualifiers during demangling).

precise?

Will be true if the symbol’s address exactly matched the remote-value, otherwise #f.

constant?

Will be true if the name represents a constant value.

find-closest-symbolic-name Generic function
Signature:

find-closest-symbolic-name (application instance) => (maybe-name precise?)

Parameters:
Values:

Given a <remote-value> instance, attempts to locate the <remote-symbol> object whose definition is at or close to that address. The first return value will be that symbol, or #f if no symbol could be found.

The second return value will be true if the symbol’s definition precisely matches the supplied address, and #f otherwise.

Note the use of the term symbolic rather than mangled in this function. There is no guarantee that the remote-value supplied is even a Dylan object, or that the symbol that defines it is a Dylan-emitted symbol. If any symbolic definition can be found, it will be returned.

The source of symbolic information will be the access-path, in combination with whatever mechanism we implement for describing interactively (re-)defined symbols.

resolve-symbolic-name Generic function
Signature:

resolve-symbolic-name (application symbolic-name #key library) => (definition-address)

Parameters:
Values:

Attempts to match the supplied name against symbolic information in the runtime. If a match is made, the address of the name’s definition is returned as the result.

#f will be returned if no matching symbol can be found.

Again, the source of information will be the access-path, in combination with whatever mechanism we implement for describing interactively (re-)defined symbols.

Convenience Interfaces for Dylan Objects

The general inspector interface can be used to look up all attributes of any arbitrary Dylan object. However, the DM has special knowledge of the Dylan runtime, and is able to deduce information about certain “standard” objects, saving clients the trouble of calculating with the inspector values. Function and class objects are good examples, though we may introduce more and more of these convenience accessors as time goes on.

dylan-generic-function-methods Generic function
Signature:

dylan-generic-function-methods (application gf-object) => (methods)

Parameters:
Values:

Given that gf-object is a remote instance of a generic function, returns a sequence of <remote-value>s that are remote instances of the methods of that generic function.

dylan-method-iep Generic function
Signature:

dylan-method-iep (application method-object) => (meth-iep)

Parameters:
Values:

Given that method-object is a remote instance of a method object (perhaps obtained by a call to dylan-generic-function-methods), returns a <remote-value> that holds the IEP of that method.

dylan-method-specializers Generic function
Signature:

dylan-method-specializers (application method-object) => (specializers)

Parameters:
Values:

Given that remote-value is a remote instance of a method object, returns a sequence of <remote-value>s that are remote instances of <type>.

dylan-slot-descriptor-getter Generic function
Signature:

dylan-slot-descriptor-getter (application descriptor) => (getter)

Parameters:
Values:

Given that descriptor is any remote instance of a slot descriptor, this function returns the getter (a remote instance of <function>) as a <remote-value>. (Slot descriptors are returned from a call to get-inspector-values. The “name” of a slot is effectively the name of its getter, obtained via this function. The getter can be passed to find-dylan-name for a name).

remote-instance? Generic function
Signature:

remote-instance? (application instance class-instance) => (answer)

Parameters:
Values:

Returns true if both <remote-value>s are Dylan objects, and the first is an instance of the second. Any <remote-value>s corresponding to statically-built objects can be used as valid arguments to this function. However, if a <remote-value> is not known to be statically built, the DM client is required to have that object registered, and to lookup the tracked value before calling this function.

The implementation of this function may involve the execution of code in the runtime. However, calling it does not end a debugger transaction.

dylan-value-unbound? Generic function
Signature:

dylan-value-unbound? (application instance) => (answer)

Parameters:
Values:

Returns true if the supplied <remote-value> corresponds to the runtime’s canonical UNBOUND marker. Otherwise, returns #f.

dylan-object-immediate-value Generic function
Signature:

dylan-object-immediate-value (application instance) => (replica success?)

Parameters:
Values:

If the supplied <remote-value> is an “uploadable immediate”, such as a tagged integer or character, this function returns an environment-side replica of the runtime value.

Note the second <boolean> return value. We cannot just use #f as a failure value in this case, since it’s conceivable that #f could be an uploaded immediate, if booleans were tagged. Hence, the second return value flags whether the replica was successfully generated.

Note that, even if the object can be uploaded to a replica, there is no guarantee that the precise type of the uploaded object will correspond to the type of the runtime object. For example, an <integer> in the runtime might get uploaded to an <extended-integer> in the environment.

Debugger Transactions and Remote Object Registration

More could be said about debugger transactions and remote object registration. For now, suffice it to say that a debugger transaction is in effect from the instant the application stops (for any reason) until the instant that it resumes. During this period, any <remote-value>s collected from the application remain valid. Between debugger transactions, objects can be relocated, so there is no guarantee that a <remote-value> that pointed to object X before still points to object X.

In terms of the DM interface described thus far, <remote-value>s remain valid up until an activation of the ready-to-continue-callback terminates. This callback is therefore a good place to register them as remote objects via the mechanism described below.

In order for a handle on an object to persist between debugger transactions, it must be “registered”. This is a facility that is provided by the Spy, with an interface to it being provided by the DM.

<remote-object> Abstract Class
Superclasses:

<runtime-registered-handle>

Init-Keywords:

Represents a persistent handle on an object within the running application. Unlike instances of <remote-value>, instances of <remote-object> remain valid between debugger transactions.

register-remote-object Generic function
Signature:

register-remote-object (application value #key finalize weak thread) => (robj)

Parameters:
Values:

Informs the Spy that the debugger now requires the object specified by value is to be tracked. The return value is an instance of <remote-object> which can be used to obtain the object’s value even if it is relocated.

This mechanism is implemented by creating a new reference to the object within the application (so that it will be kept current by the garbage collector) using functionality provided by the Spy.

If finalize is true (the default), then the reference will be implicitly freed by finalization when the development environment reclaims the remote object handle. If finalize is #f, the overhead for registration may be lower, but a memory leak will result unless the UI explicitly frees the handle (via free-remote-object).

Normally, while a remote value is registered, the remote garbage collector will be prevented from condemning the remote value in any way that causes the object to be “lost”. However, if weak is true, then the implementation is permitted to reference the remote value weakly, and to garbage collect it if there are no references within the running application itself. If the weakly registered object does get collected, subsequent calls to remote-object-value will return #f.

free-remote-object Generic function
Signature:

free-remote-object (application robj) => (#rest results)

Parameters:
Values:
  • #rest results – An instance of <object>.

Informs the Spy that the debugger no longer needs this <remote-object> to be tracked. Instances of <remote-object> become invalid once passed to this function.

remote-object-value Generic function
Signature:

remote-object-value (application robj) => (#rest results)

Parameters:
Values:

Maps a remote-object onto its remote-value.

<object-registration-error> Class
Superclasses:

<error>

An instance of this may be signaled by register-remote-object if, for instance, the Spy does not support remote object registration.

object-requires-registration? Generic function
Signature:

object-requires-registration? (application instance) => (answer)

Parameters:
Values:
call-debugger-function Open Generic function
Signature:

call-debugger-function (application function #rest arguments) => (#rest vals)

Parameters:
  • application – An instance of <debug-target>.

  • function – An instance of <function>.

  • arguments (#rest) – An instance of <object>.

Values:
  • #rest vals – An instance of <object>.

call-debugger-function(<debug-target>, <function>) Method

Stack Backtracing

Provides functionality for modeling the stack in a running Dylan application.

<application-stack-frame> Abstract Class
Superclasses:

<object>

Init-Keywords:

Represents a stack frame of any kind within the application. (In the future, we might want to consider making this an open class so that clients of the DM can describe their own weird and wonderful stack frames.)

first-stack-frame Generic function
Signature:

first-stack-frame (application thread) => (top-frame)

Parameters:
Values:

Returns the frame at the top of the stack in the running application, regardless of its type.

next-stack-frame Generic function
Signature:

next-stack-frame (application f) => (maybe-frame)

Parameters:
Values:

Given a stack frame, returns the next most recent stack frame, regardless of its type. Returns #f if there is no next frame.

previous-stack-frame Generic function
Signature:

previous-stack-frame (application f) => (maybe-frame)

Parameters:
Values:

Given a stack frame, returns the next oldest stack frame, regardless of its type. Returns #f if there is no previous frame.

<dylan-stack-frame-mixin> Abstract Class
Superclasses:

<object>

This is a superclass of any Dylan stack frame.

Note

Possibly obsolescent.

<call-frame> Class
Superclasses:

<access-path-stack-frame>

Init-Keywords:

This is a stack frame that corresponds to a function call.

call-frame-description Generic function
Signature:

call-frame-description (application frame) => (ap-frame)

Parameters:
Values:
call-frame-return-address Generic function
Signature:

call-frame-return-address (application f) => (top-frame)

Parameters:
Values:

Returns the call-frame’s return address as a <remote-value>.

call-frame-frame-pointer Generic function
Signature:

call-frame-frame-pointer (application f) => (top-frame)

Parameters:
Values:

Returns the call-frame’s frame pointer as a <remote-value>.

call-frame-frame-pointer Generic function
Signature:

call-frame-frame-pointer (application f) => (top-frame)

Parameters:
Values:

Returns the call-frame’s instruction pointer (PC) as a <remote-value>.

call-frame-nearest-source-locator Generic function
Signature:

call-frame-nearest-source-locator (application call-frame) => (maybe-locator)

Parameters:
Values:
  • maybe-locator – An instance of <source-locator>, or #f.

If possible, returns the nearest known source location to the instruction pointer for the given call frame. If the frame is not precisely aligned at a source locator, this function can be used by the UI to find the nearest relevant piece of source to indicate as being “current”.

call-frame-aligned-at-source-locator? Generic function
Signature:

call-frame-aligned-at-source-locator? (application call-frame) => (maybe-locator)

Parameters:
Values:
  • maybe-locator – An instance of <source-locator>, or #f.

If the program counter for this call frame corresponds exactly to a known source code location, then this function returns the locator.

If this function returns #f, then the instruction pointer is not at a known source code location. The function align-thread-to-source-location can be used to attempt alignment. If alignment succeeds, it is not guaranteed that the destination source locator will be the same as that returned beforehand by call-frame-nearest-source-locator.

call-frame-function Generic function
Signature:

call-frame-function (application frame) => (func-sym func-obj gf-obj)

Parameters:
Values:

Returns a <remote-symbol> that describes the function being called in this frame. This function might return #f if, for example, there is not sufficient symbolic debugging information.

The second return value will be #f for any non-Dylan frame, and also for Dylan frames where the called function has no current model in the compiler (e.g., it’s a closure, or a function from another project). Otherwise, the second return value will be a compiler model for the lambda being called in this frame. This model will have stored the correct (non-mangled) name for the function, as well as further information such as specializers.

number-of-lexical-variables Generic function
Signature:

number-of-lexical-variables (application dm-frame #key arguments-only?) => (i)

Parameters:
Values:

Returns the number of lexical variables active inside the call frame. Performance note: this function scans for the existence of live lexical variables without reading in names/addresses over the tether. If it turns out that performance is not affected too much by reading names and addresses straight away, we can ditch this function.

Note

This has nothing to do with Dylan. The integer returned will be the same as the number of elements in the sequence(s) returned by live-frame-lexical-variables NOT active-dylan-lexical-variables.

active-dylan-lexical-variables Generic function
Signature:

active-dylan-lexical-variables (application dm-frame #key arguments-only?) => (names types models vals locations)

Parameters:
Values:

Presents the compiler’s view of the set of live lexicals for the given <call-frame>.

The first return value is a sequence of lexical variable model objects.

The fourth return value is a sequence parallel to the first. Each element either contains a <remote-value> — the value of the corresponding variable (in the first sequence), or #f - meaning that this variable is not live. By “not live” we mean not live according to the debug information dump. It’s entirely possible that dylan variables may be lexically in-scope, while not having obtainable values in the runtime. (For example, their stack space may have been optimized away, or used for something else).

live-frame-lexical-variables Generic function
Signature:

live-frame-lexical-variables (application dm-frame #key arguments-only?) => (vars vals)

Parameters:
Values:

Presents the runtime’s view of the set of live lexicals for the given <call-frame>.

The first return value is a sequence of <lexical-variable> objects representing the lexical variables that are “live” in the given call frame. This information comes ultimately from the dumped debugging information.

The second return value is a parallel sequence of <remote-value> objects giving the values of the variables.

This is basically just a lower-level API than active-dylan-lexical-variables, assumed to be useful for frames running foreign code, and also frames running dylan code outside of the current project.

<dylan-call-frame> Class
Superclasses:

<call-frame>, <dylan-stack-frame-mixin>

Represents a frame corresponding to the activation of a Dylan function.

Note

Possibly obsolescent.

dylan-call-frame? Generic function
Signature:

dylan-call-frame? (application f) => (answer)

Parameters:
Values:
<implementation-stack-frame> Abstract Class
Superclasses:

<application-stack-frame>, <dylan-stack-frame-mixin>

Represents a “special” Dylan stack frame (not a call frame).

<bind-exit-frame> Class
Superclasses:

<implementation-stack-frame>

A subclass of <implementation-stack-frame>. A frame corresponding to the Dylan block (exit) ... end construct.

<unwind-protect-frame> Class
Superclasses:

<implementation-stack-frame>

Init-Keywords:

Corresponds to a block construct with a cleanup.

Restarts

This section documents the APIs by which the debugger can determine which restarts are available, and also signal a restart on a thread.

<remote-restart> Class
superclasses:

<object>

keyword abort?:

An instance of <boolean>.

keyword description:

An instance of <string>.

keyword format-args:

An instance of <vector>, or #f.

keyword format-string:

An instance of <remote-value>, or #f.

keyword formatted?:

An instance of <boolean>.

keyword required function:

An instance of <remote-value>.

keyword required index:

An instance of <integer>.

keyword required init-args:

An instance of <vector>.

keyword required target:

An instance of <debug-target>.

keyword required test:

An instance of <remote-value>.

keyword required type:

An instance of <remote-value>.

A debugger-level abstract handle onto a restart. This is the object used to model restarts in the runtime.

remote-restart-description Generic function
Signature:

remote-restart-description (remote-restart) => (str)

Parameters:
Values:

Returns a string describing the expected behaviour of the restart.

available-restarts-for-thread Generic function
Signature:

available-restarts-for-thread (application thread) => (restarts)

Parameters:
Values:

Examines the dynamic environment of the thread in order to generate a sequence of available restarts. Each member of the returned sequence is an instance of <remote-restart>.

signal-restart-on-thread Generic function
Signature:

signal-restart-on-thread (application thread rst) => ()

Parameters:

Instructs the DM that the specified thread should, upon completion of the current debugger transaction, continue by signalling the specified restart (a <remote-restart>).

Source-Level Stepping

These functions may only be called during a debugger transaction, and they do not cause the application to immediately run. In each case, the step operation occurs on the specified thread as soon as that thread resumes.

All of these functions register specialized breakpoints. They may also do some substantial low-level examination of the runtime, even down to machine code instructions. The breakpoints will be signalled later, when the thread reaches the destination source location.

Upon calling one of these functions, the DM attempts to calculate the destination <source-locator> for the step. There may be several possibilities (for example, the entry points of all methods when a generic function is being called). If the DM fails to calculate any possible destination, it will return #f as the success code from these functions. Otherwise, true is returned. (The most likely cause of failure would be a lack of line number information in the debug info format). Clients of DM should not expect any specialized breakpoints to be signalled following a #f result from one of these functions.

However, these functions may work even in the absence of debug information - just don’t rely on obtaining a <source-locator> for the destination when the thread arrives there! (Step-out, for example, can break the frame’s return address regardless of whether that address is a known source location).

These functions should be considered analogous to register-debug-point (since that is what they end up doing!), hence the need for the callback argument. The callbacks should be of the same signature as those passed to register-debug-point.

instruct-thread-to-step-over Generic function
Signature:

instruct-thread-to-step-over (application thread #key call-frame) => (success?)

Parameters:
Values:

Arranges for the thread to step to the next source location within the execution of this function frame (e.g., stepping over function invocations).

If the thread does not reach another source location within the execution of this function, then this will behave like a step-out operation instead.

instruct-thread-to-step-into Generic function
Signature:

instruct-thread-to-step-into (application thread #key call-frame precomputed-addresses) => (success?)

Parameters:
Values:

Arranges for the thread to step into a function.

If the thread is not positioned exactly at a function call, this will behave like a step-over operation instead.

instruct-thread-to-step-out Generic function
Signature:

instruct-thread-to-step-out (application thread #key call-frame) => (success?)

Parameters:
Values:

Arranges for the thread to step out of its current function frame.

align-thread-to-source-location Generic function
Signature:

align-thread-to-source-location (application thread #key interactive?) => (success?)

Parameters:
Values:

Attempts to align the program counter of this thread to a known source location.

These functions should work in foreign code as well, provided that sufficient debugging information is available for the source locators.

FIXME dropped a section here (about the relationship between tracing and stepping) which might not be valid anymore.

Mappings Between Addresses and Source Locators

This is a high-level abstraction for mapping locations in source code to instruction addresses in the runtime, for the purpose of inspecting local variables, or setting breakpoints etc. These functions are defined to work from whatever information is available to the DM, either from the Dylan compiler (if applicable), or from source location information within the runtime (if available). These two APIs represent a unified interface to these two sources of information.

remote-address-source-location Generic function
Signature:

remote-address-source-location (application address #key line-only? interactive-only? exact-only?) => (source-location exact?)

Parameters:
Values:
  • source-location – An instance of <source-location>, or #f.

  • exact? – An instance of <boolean>.

Attempts to map an instruction address in the runtime to a location in source code.

source-location-remote-address Generic function
Signature:

source-location-remote-address (application source-location #key line-only? interactive-only? entry-point-only? compilation-context) => (address)

Parameters:
  • application – An instance of <debug-target>.

  • source-location – An instance of <source-location>.

  • line-only? (#key) – An instance of <object>.

  • interactive-only? (#key) – An instance of <object>.

  • entry-point-only? (#key) – An instance of <object>.

  • compilation-context (#key) – An instance of <object>.

Values:

Attempts to map a location in source code to an instruction address in the runtime.

The keyword arguments are interpreted as follows for both mappings:

line-only?

Only use the max-one-per-line set of recorded source location points for the mapping.

interactive-only?:

Only use the set of recorded “interactive” source location points for the mapping.

All source-locators are described using the canonical class in the source-records library.

Note that <source-location> objects may be stored persistently. If the environment wishes to remember the locations of breakpoints between runs of the application, then it should keep a set of <source-location> objects. These can be mapped as breakpoints via the DM when the application is started.

The DM makes the following guarantees:

  1. It will map source locations via the compiler in preference to via the runtime.

  2. The mapping via the compiler uses the same set of source-locations as is available via the API between the compiler and the environment.

The implication of these two guarantees is that the DM will always find an exact mapping for any source-location retrieved via definition-code-locations, given the same values of ‘line-only?’ and ‘interactive-only?’

Note

This doesn’t appear to be correct, and definition-code-locations is an unimplemented stub.

Further Points:

  1. Source locations obtained from runtime data will be standard <source-location>s in standard source records. This will require extending the source record protocol to handle random (foreign) files.

  2. Source locations obtained from runtime data are necessarily not considered to be interactive.

Foreign Code Debugging

This chapter will be fleshed out when we have a solid story for debugging foreign code. At the moment:

foreign-object-type Generic function
Signature:

foreign-object-type (application foreign-instance) => (remote-type-description)

Parameters:
Values:
  • remote-type-description – An instance of <object>.

Returns, if possible, a <remote-type> (defined in access-path) that describes the supplied object. This function cannot guarantee to return a <remote-type>, and will return #f if no type description can be obtained.

Note

This is not implemented yet, and will just return #f.

Runtime Context

<runtime-context> Abstract Class
Superclasses:

<object>

Init-Keywords:

The DM is capable of allocating this object for any specified thread during a debugger transaction. Only the DM and the interactive downloader need to unpick this object.

runtime-context-debug-target Generic function
Signature:

runtime-context-debug-target (context) => (value)

Parameters:
Values:
runtime-context-frame Generic function
Signature:

runtime-context-frame (context) => (value)

Parameters:
Values:
runtime-context-thread Generic function
Signature:

runtime-context-thread (context) => (value)

Parameters:
Values:
active-lexical-variables(<runtime-context>) Method

A method on the open GF exported by dfmc-interactive-execution in the dfmc-browser-support library.

runtime-context-lexical-variable-value Generic function
Signature:

runtime-context-lexical-variable-value (context, index) => (value)

Parameters:
Values:

Returns the actual value of a lexical variable whose index was provided by active-lexical-variables.

current-runtime-context Generic function
Signature:

current-runtime-context (application thread #key stack-frame) => (context)

Parameters:
Values:

Creates and returns the runtime-context for a thread in an application.

Profiling

The Profiler Manager is used to collect profiling data from a running application. It allows a client to control when profiling information is to be collected and some limited control over what data is collected. The profiler manager API is closely associated with the Debugger Manager and is exported from the debugger-manager module in the debugger-manager library.

Controlling the Profiler Manager

Profiling is started by a call to start-profiling and is stopped by a call to stop-profiling, or when the target application exits. Profiling may be turned on and off any number of times and does not have to be in the same state when the application exits as it was when the application started.

The Profiler Manager gathers data by stopping the application at regular intervals and taking a “snapshot” of each thread’s stack. It’s possible to specify the interval between application stops and which threads you are interested in profiling. The volume of data collected can be further reduced by specifying a maximum stack depth to which stacks are examined during snapshots.

The profiler manager maintains a complete history of the snapshots it has collected, but allows this to be reset by a client library. The profiler manager returns all the data in its history to the client on request.

application-profiling? Generic function
Signature:

application-profiling? (application) => (profiling?)

Parameters:
Values:
control-profiling Generic function
Signature:

control-profiling (application #key reset? snapshot-limit interval class-profiling? stack-depth threads) => ()

Parameters:
  • application – An instance of <debug-target>.

  • reset? (#key) – An instance of <boolean>. If supplied with a boolean value of #t tells the profiler manager to reset its history i.e. throw away all the data it has collected so far. The default value is #f.

  • snapshot-limit (#key) – An instance of <object>.

  • interval (#key) – An instance of <integer>, or #f. Specifies the regular interval in millisecs after which the application will be stopped and data collected. There is no guarantee that the application will be stopped precisely on this interval, but it will not be stopped before the interval is up. Not all threads will necessarily have had the same amount of cpu-time during the interval, so the profiler provides a weight for each thread based on the amount of cpu-time it has had.

  • class-profiling? (#key) – An instance of <boolean>.

  • stack-depth (#key) – An instance of <object>. The maximum depth to which the profiler should trace stack frames. Stacks deeper than this are still traced, but only to the depth specified. The limit applies for each snapshot taken and to all threads which are being profiled. #f (the default) indicates no limit and the entire stack is traced.

  • threads (#key) – An instance of <object>. A collection of <remote-thread> objects which restricts the profiler to collecting data from the specified thread(s). #f (the default) indicates that data is to be collected from all threads. If one of the threads being profiled exits, the profiler manager stops collecting data for the thread, but keeps whatever data it has collected for it since the last reset in its history.

Can be called at any time during a debugger transaction irrespective of whether profiling is on or not. It may also be called before the target application is running.

start-profiling Generic function
Signature:

start-profiling (application #key reset? snapshot-limit interval class-profiling? stack-depth threads) => ()

Parameters:
  • application – An instance of <debug-target>.

  • reset? (#key) – An instance of <boolean>.

  • snapshot-limit (#key) – An instance of <object>.

  • interval (#key) – An instance of <integer>, or #f.

  • class-profiling? (#key) – An instance of <boolean>.

  • stack-depth (#key) – An instance of <object>.

  • threads (#key) – An instance of <object>.

Turns on profiling for the target application. If supplied, the keyword arguments override the properties set by any earlier control-profiling call. In effect control-profiling is called with the keyword arguments before profiling is switched on.

stop-profiling Generic function
Signature:

stop-profiling (application) => ()

Parameters:

Stops the profiling of the target application. This may only be called during a debugger transaction.

profile-data Generic function
Signature:

profile-data (object) => (#rest results)

Parameters:
Values:
  • #rest results – An instance of <object>.

Returns all the profiling data collected since the last reset. See the next section for a description of the structure of the returned data.

profile-data(<profile-state>) Method
profile-data(<debug-target>) Method
reset-profile-data Generic function
Signature:

reset-profile-data (application) => ()

Parameters:

Extracting the data

The data returned by the profiler comprises a series of snapshots for each thread that was profiled. During a snapshot, the profiler manager steps through the function call frames on the stack (to a maximum depth if one has been specified) collecting an instruction pointer for each frame. The instruction pointer is the address of the next instruction to execute for the frame.

<application-profile> Class
Superclasses:

<object>

Init-Keywords:
  • application-snapshots – An instance of <stretchy-object-vector>.

  • profile-threads – An instance of <stretchy-object-vector>.

application-snapshot-skip Generic function
Signature:

application-snapshot-skip (object) => (value)

Parameters:
Values:
application-snapshots Generic function
Signature:

application-snapshots (object) => (value)

Parameters:
Values:
  • value – An instance of <stretchy-object-vector>.

application-profile-threads Generic function
Signature:

application-profile-threads (object) => (value)

Parameters:
Values:
  • value – An instance of <stretchy-object-vector>.

<application-snapshot> Class
Superclasses:

<object>

Init-Keywords:
  • page-faults-increment (required) – An instance of <integer>.

  • thread-snapshots (required) – An instance of <sequence>.

  • wall-time-increment (required) – An instance of <integer>.

application-thread-snapshot Generic function
Signature:

application-thread-snapshot (snapshot thread) => (thread-snapshot)

Parameters:
Values:
wall-time-increment Generic function
Signature:

wall-time-increment (object) => (value)

Parameters:
Values:
page-faults-increment Generic function
Signature:

page-faults-increment (object) => (value)

Parameters:
Values:
thread-snapshots Generic function
Signature:

thread-snapshots (object) => (value)

Parameters:
Values:
<thread-snapshot> Class
Superclasses:

<object>

Init-Keywords:

Includes a <snapshot-sequence> for the thread and an indication of which thread the data was collected from.

This describes the data collected from a thread during a “snapshot”. It includes the sequence of instruction pointers associated with the stack frames on the thread’s stack at the time of the snapshot (to a maximum depth, if one was specified) and a weight for this data.

<instruction-pointers> Type
profile-thread Generic function
Signature:

profile-thread (object) => (value)

Parameters:
Values:

Returns the <remote-thread> object associated with the thread from which the data was collected.

cpu-time-increment Generic function
Signature:

cpu-time-increment (object) => (value)

Parameters:
Values:
allocation-increment Generic function
Signature:

allocation-increment (object) => (value)

Parameters:
Values:
allocated-class Generic function
Signature:

allocated-class (object) => (value)

Parameters:
Values:
instruction-pointers Generic function
Signature:

instruction-pointers (object) => (value)

Parameters:
Values:

Returns a sequence of instruction pointers associated with each stack frame on the thread’s stack. Each instruction pointer is the address of the next instruction to execute for the frame as a <remote-value>. The instruction pointers are ordered with those from the most recently created stack frames (top of stack) appearing first.

set-application-class-breakpoint Generic function
Signature:

set-application-class-breakpoint (application thread class) => (transaction)

Parameters:
Values:
  • transaction – An instance of <object>.

clear-application-class-breakpoint Generic function
Signature:

clear-application-class-breakpoint (application thread class #key stop-profile?) => (transaction)

Parameters:
Values:
  • transaction – An instance of <object>.

Clears a remote class breakpoint.

clear-application-class-breakpoints Generic function
Signature:

clear-application-class-breakpoints (application thread) => (transaction)

Parameters:
Values:
  • transaction – An instance of <object>.

Clears all remote class breakpoints.

Extension Interfaces

load-runtime-component Generic function
Signature:

load-runtime-component (application name) => (success?)

Parameters:
Values:

Attempts to dynamically load a runtime component (DLL).

spy-function-definer Macro
<c-spy-function-descriptor> Class
Superclasses:

<spy-function-descriptor>

Init-Keywords:

Describes a spy function that must be called with C calling conventions.

spy-function-runtime-name Generic function
Signature:

spy-function-runtime-name (sf) => (name)

Parameters:
  • sf – An instance of <spy-function-descriptor>.

Values:

Returns the name of the spy function.

spy-function-runtime-component Generic function
Signature:

spy-function-runtime-component (sf) => (name)

Parameters:
  • sf – An instance of <spy-function-descriptor>.

Values:

Returns the component name of the spy function

call-spy Generic function
Signature:

call-spy (spy-function application #rest arguments) => (result)

Parameters:
Values:
call-spy-on-thread Generic function
Signature:

call-spy-on-thread (spy-function application thread #rest arguments) => (result)

Parameters:
Values:
<spy-call-error> Abstract Class
Superclasses:

<error>

Init-Keywords:
  • arguments (required) – An instance of <sequence>.

  • debug-target (required) – An instance of <debug-target>.

  • function-descriptor (required) – An instance of <spy-function-descriptor>.

The common superclass of all exceptions that can occur when attempting to call a spy function.

spy-call-function-descriptor Generic function
Signature:

spy-call-function-descriptor (object) => (value)

Parameters:
Values:
  • value – An instance of <spy-function-descriptor>.

spy-call-debug-target Generic function
Signature:

spy-call-debug-target (object) => (value)

Parameters:
Values:
spy-call-arguments Generic function
Signature:

spy-call-arguments (object) => (value)

Parameters:
Values:
<spy-function-not-located> Class
Superclasses:

<spy-call-error>

<spy-call-aborted> Class
Superclasses:

<spy-call-error>

<spy-call-no-available-thread> Class
Superclasses:

<spy-call-error>

<spy-call-cannot-use-thread> Class
Superclasses:

<spy-call-error>

Init-Keywords:

An attempt was made to call a spy function on a specific thread, but the thread could not be used.

spy-call-selected-thread Generic function
Signature:

spy-call-selected-thread (object) => (value)

Parameters:
Values: