[Contents]   [Back]   [Prev]   [Up]   [Next]   [Forward]  


libGDB

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.

Overview

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.

Expected client interaction

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.

Interfaces

Query/builder

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

Event notify

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.

Operators (anyone got a better name)

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.

Synchronous operations

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.

Asynchronous control

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.

Output streams

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.

Event Loop

GDB, internally is event driven (well it is getting there). The UI must either:

The event loop interface is still being developed.

Start Up

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.

Worked Examples

Below are several worked examples illustrating likely interactions between a libGDB and a client.

Inferior Function Call

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.

  1. The client receives control from the event-loop (a request to evaluate an expression by the user).
  2. The client requests that GDB evaluate an arbitrary expression using a synchronous expression evaluator.
  3. GDB rejects the request (as the expression includes an inferior function call) returning a fail status to the client.
  4. The client requests that GDB evalue an arbitrary expression using the asynchronous expression evaluator.
  5. GDB accepts the request.
  6. GDB determines that an inferior function call is required, starts the target and notifies the client that the target is running.
  7. GDB returns control to the client.
  8. The client returns control to the event loop.
  9. GDB receives control from the event-loop - the target stopped.
  10. GDB notifies the client that the target stopped
  11. GDB notifies the client of the result of the expression. Say via a handle. The client requests that it be scheduled next.
  12. GDB returns control to the event-loop.
  13. The client receives control from the event-loop.
  14. The client queries GDB for the actual result of the expression.
  15. The client displays the result.
  16. The client returns control to the event-loop

Breakpoints

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.

Set a new breakpoint

  1. The client receives the request for a breakpoint at function F.
  2. The client requests that GDB set a breakpoint at function F
  3. GDB performs the action; notifies client that a breakpoint has been created; and then returns control to client.
  4. The client requests details of the newly created breakpoint from GDB and updates local breakpoint table.

Restart program with new executable

  1. The client receives the request to re-load the file.
  2. The client notifies GDB that the file should be re-loaded.
  3. GDB loads the updated executable and, in the process adjusts several breakpoints.
  4. GDB notifies the client of the breakpoints that changed.
  5. The client refreshes its breakpoint database by requesting up-to-date information from GDB.

Global Variable

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.

  1. client receives a request to display a variable's value
  2. client requests details of specified variable from GDB
  3. GDB returns variable details (value, memory location, stack or heap based, ...)
  4. client creates an object to manage the value. That object registers its presence with the change notification system indicating its address/size.

The user than modifies the variable indirectly:

  1. client requests GDB to perform an operation that modifies the variable mentioned above.
  2. GDB notifies client that a specific memory range has been changed.
  3. Client notifies variable object that it's value has been changed.
  4. Client's variable object requests GDB for an up-to-date value of that variable.


[Contents]   [Back]   [Prev]   [Up]   [Next]   [Forward]