Copyright (C) 1999, Cygnus Solutions
Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.
Function and Purpose
This document provides an architectural overview of a proposed library implementation of GDB. The intended purpose of the library is to facilitate the development of scripted and GUI interfaces based on the GNU debugger GDB.
Thanks goes to Jim Blandy, Jim Ingham, Fernando Nasser, Stan Shebs and Elena Zannonoi for their significant contributions.
Each of these debug GUI interfaces are implemented using an identical technique. GDB (or some other debugger) is started as a separate server process, debug commands are sent to that process and all output is then parsed. Of these, DDD is probably the most successful.
Unfortunately this technique has several limitations:
The initial GDBtk implementation was very like DDD except that it was embedded in the same process as the debugger. Commands would be sent to GDB and the resultant output would then be parsed. As GDBtk evolved, and bottle-necks were identified, more direct calls into GDB's internals have been implemented (ex the assembler window).
Limitations of GDBtk can be identified:
GDB can produce annotated text output through the set annotate
command. In addition to the normal text, GDB includes numeric markers
that identify key output tokens (a line number, a file name). EMACS
parses the annotations and makes use of that information.
The one key failing of this annotate mode is that the output fields are identified numerically instead of symbolically as found things like XML.
While the annotate code is not being actively developed it does have a significant installed base and consequently needs to be maintained.
libgdb 1.0 was an interesting learning experience. Much of that experience is being transfered to libGDB. Issues that libgdb didn't address were:
This section describes the enhancements being made to GDB so that it can facilitate the efficient integration of new interfaces such as scripting languages and GUIs.
libGDB is not a single interface. Rather it is a set of components that make it possible to integrate GDB into a larger system.
That system might be the existing GDB-CLI, a scripting language such as GUILE, or a true GUI. Dependant on the functionality required, the system would make use of one or more of the components that libGDB provides.
For instance, one of the libGDB components is a target output stream. All remote-target output being channeled through this. The existing GDB-CLI allows that output to flow through to the user's terminal while a GUI would implement a target-console window and channel the remote-target output through to that.
The components are:
In the following section each of these interfaces is described.
Fundamental to a GDB library is the mechanism that allow the UI to obtain symbolic information and also ensure that any information obtained is synchronized with the current value on the target.
This is provided by request and notify (callback) mechanisms.
While GDB is good at combining binary data (obtained from the target) with debug information (obtained from the object file) producing output that represents the raw data in a symbolic form, GDB is useless when it comes to managing those symbolic values in a more object oriented way.
Consequently, it is expected that non-trivial clients would use GDB as part of a more sophisticated object framework.
Corresponding to each "object" that GDB can represent symbolically would be a client object. That client object would query GDB for relevant symbolic information as needed. Such a query might be triggered by a user-interface request or, possibly, by libGDB notifying the client that certain symbolic values are out-of-date.
For example, consider breakpoints. A client might implement a breakpoint object. There being a one-to-one correspondence between GDB's breakpoints and each instance of the breakpoint object. When the user (via the client's user-interface) requests that a breakpoint be created the client would create its breakpoint object and then request that GDB did the same. When GDB detected that the state of a breakpoint hand changed, it would notify the client of this. The client could then refresh its local breakpoint state.
Over the longer term, a generic implementation of such objects would become available and that would be integrated into libGDB.
This is the most fundamental of the proposed changes to GDB. Up until now, code that implementing a query operation returned raw text (possibly annotated). As explained in the previous section this operation is both un-reliable and inefficient. [I'd better add an explanation].
In libGDB, all query operations are parameterized with a builder object (ref something to do with builder and something to do with XML). Internally, GDB describes the symbolic data using the more descriptive builder interface where as previously it would have converted that information into simple text. The default builder (for the existing CLI) would implement methods that continued to display that symbolic data as straight text.
A given UI would construct a builder that meet its specific needs. A GUILE builder could construct a tagged list structure that would be directly accessible from its interpreter.
For instance, details of a breakpoint are available using GDB's
info breakpoint
command vis:
(gdb) info breakpoint 1 Num Type Disp Enb Address What 1 breakpoint keep y 0x0000003d in main at hello.c:3 breakpoint already hit 1 time
Within libGDB the internal code that described the breakpoint would be accessible. In the GUILE case, that internal code would be called with a GUILE builder and would construct an object like:
(breakpoint ((number 1) (type "breakpoint") (disp "keep") (enabled "y") (addr "0x0000003d") (func "main") (file "hello.c" 3)))
The next component is the notify mechanism. When GDB determines that a significant event has occurred (memory changed, breakpoint changed, target started, target stopped) it advises the target using a notify call.
For each "object" that GDB can represent symbolically, there is notify mechanism that allows GDB to inform the UI that information has been invalidated. The exact mechanism used depends on the type of data involved.
For instance, looking at the existing GDB CLI:
(gdb) disable 1 (gdb) info breakpoint Num Type Disp Enb Address What 1 breakpoint keep n 0x0000003d in main at hello.c:3 breakpoint already hit 1 time
After the command disable 1
has been issued, GDB's internal state
of breakpoint has been changed. Consequently, as part of updating the
breakpoint internal state, libGDB would notify the client that the
breakpoints state has changed. The client could then query libGDB for
the new breakpoint state.
Note: libGDB is not re-entrant. The client must ensure that it has only one query outstanding at any time.
An operator manipulates the state of GDB or the target.
An operation is either synchronous or asynchronous. A synchronous operation completes synchronously with the client. An asynchronous operation, which involves execution (free running) by the target, has no bounded completion time.
Note: A synchronous that operation communicates with the target bounds the length of time required for the communication though the use of timeouts.
Such operations include changing the state of GDB and/or the target. For instance, modifying, adding or deleting a breakpoints; Modifying the value of a register on the target.
Such operations return a simple result indication. They do not return more complex data. For instance, the operator for creating a breakpoint would return a success indication. The event-notify mechanism would be used to advice the client of the existence of the new breakpoint identifier.
As a consequence of the ASYNC work, most control operations - step, continue, run, stop - are asynchronous. In addition, some of the less obvious operations such as expression evaluation (this can involve an inferior function call) are also considered asynchronous.
To correctly interact with libGDB, the client must implement:
For instance, a client requests libGDB to continue the program running on the target. The operation returns immediately. At some later stage libGDB notifies the client that the program has halted and the client can then query GDB for the stop status.
Note: The client is responsible for policy issues such as how to handle failed asynchronous requests. For instance, a GUI, in response to the stop button being pressed may elect to leave the button depressed until the target-stop notify event (or internal timeout) occurs or pop the button immediately and then allow the user to re-attempt the stop operation.
Note: The mechanism for notifying the client of the final result from an inferior function call have not been determined. Asynchronous inferior function calls are work-in-progress. One possible mechanism would be for GDB to notify the client of a result-handle and then allow the client to query the value of that handle.
In addition to providing access to the target (via the query/notify mechanism), GDB also has a number of out-of-band text streams:
Each of these text streams are implemented with corresponding stream object. A client can control a given stream by providing its own stream implementation.
GDB, internally is event driven (well it is getting there). The UI must either:
The event loop interface is still being developed.
Since the objective is to facilitate the addition of new GUI and scripting interfaces integrated into GDB (rather than separate as with DDD) a more clearly defined startup mechanism is required.
That sequence is still being defined.
Below are several worked examples illustrating likely interactions between a libGDB and a client.
This example illustrates a possible sequence of interactions that could occur between GDB and the client when the user, via the clients user interface, requests the evaluation of an expression that contained a function call.
In this example, it is assumed that the client is maintaining an internal breakpoint structure that is separate to GDB. That client-structure is referred to when ever the client is annotating a source code window with markers for the currently active breakpoints.
In this final example, the client is tracking the value of a global variable. It is assumed that in addition to an object responsible for managing that variables value, the client also has a mechanism for mapping address ranges onto variables. GDB notifies the client of a potential variable change by specifying the memory address and number of bytes that were modified.
Note: Here one possible implementation is presented. Different clients may elect to implement this differently.
The user than modifies the variable indirectly:
This strategy outline the recommended strategy for implementing each of the components.
The set of possible requests, and their behavour will initially be based on a subset of the existing CLI command set. In particular the commands:
show ...
info ...
would be used as a starting point.
Rather than clone those commands, the query methods would be implemented by modifying the existing code base so that it "builds" each result. The existing CLI would call the code with a simple text builder (`cli-out.[hc]'?); GUILE would make the same call but with its own complicated builder (`guile-out.[hc]'?).
As an example of the change required, the function breakpoint_1()
in `breakpoint.c' would be modified from:
annotate_breakpoint (bs->breakpoint_at->number); printf_filtered ("\nBreakpoint %d, ", bs->breakpoint_at->number);
to:
annotate_breakpoint (bs->breakpoint_at->number); ui_out_text (uiout, "\nBreakpoint "); ui_out_field_int (uiout, "bkptno", bs->breakpoint_at->number); ui_out_text (uiout, ", ");
A GUILE builder would construct the internal structure:
(..... (bkptno 1) ...)
The notify mechanism is based on the hook system already provided to GDBtk. The mechanism would need to be formalized (`gdb-hooks.[hc]') (say).
The set of notify hooks would be expected to evolve over time as the needs of the clients are better understood.
The control interface shall be based on GDB's existing set of run
/ stop
et.al. commands.
The mechanism for capturing output directed to various streams (such as output from the remote target) is the gdb_file. Apart from a number of minor refinements, that mechanism is already in place.
In the near term, gdb-file should be broken out of `utils.c' and moved to a new file `ui-stream.[hc]' (say).
The event loop is beyond the scope of this document.
Although the initialization mechanism used by optional client's is still undefined, the below outlines one possible sequence:
This document was generated on August, 24 1999 using texi2html 1.57.