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: