libGDB architecture

Andrew Cagney ac131313@cygnus.com
Mon Aug 23 19:45:00 GMT 1999


Hello,

Attached is a document providing an architectural overview of a proposed
libGDB architecture.  The purpose of these changes is to make it
possible to efficiently integrate the debugger into a much larger
system.

I should note that this is far more than then your typical ``discussion
paper'' :-)  Cygnus (thanks to Fernando and Elena) have already
prototyped key components described below.  Our conclusion, thus far has
been ``we think it works''.

Questions, comments, suggestions, and any willingness to help more than
welcome,

Have a good one,

	Andrew

Ref:  http://sourceware.cygnus.com/gdb/papers/libgdb2/
This is libgdb.info, produced by Makeinfo version 3.12f from
libgdb.texi.

   This file documents the libGDB architecture, 1999 version.

   Copyright 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.

   Permission is granted to copy and distribute modified versions of
this manual under the conditions for verbatim copying, provided also
that the entire resulting derived work is distributed under the terms
of a permission notice identical to this one.

   Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions.

   This document describes ...

   This document applies to version ...  of the program named ...

Overview
********

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.

Acknowledgments
===============

   Thanks goes to Jim Blandy, Jim Ingham, Fernando Nasser, Stan Shebs
and Elena Zannonoi for their significant contributions.

Review of previous work
***********************

DDD (and xgdb, xxgdb, mxgdb, ...)
=================================

   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:

   * it is very sensitive to changes in GDB's output

   * performance is restricted by the speed of communication of between
     the GUI and GDB

   * it was difficult to keep the GUI consistent with the CLI

Insight (a.k.a. GDBtk)
======================

   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:

   * the need to share an event loop with GDB
     With the introduction of an event loop and the asynchronous in GDB
     it will finally becoming possible to address this issue.

   * As with DDD GDBtk was often affected by changes to GDB's output
     The recently introduced gdb-file object should provide significant
     help.

EMACS/annotate
==============

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

   libgdb 1.0 was an interesting learning experience.  Much of that
experience is being transfered to libGDB.  Issues that libgdb didn't
address were:

   * an event model and a notify mechanism

   * the assumption that reasonable performance could be achieved while
     relying purely on a textual interface.

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:

   * Query with builder

   * Event notify

   * Control

   * Output streams

   * Event loop

   * Start up

   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:

   * code requesting an asynchronous operation

   * code accepting asynchronous event-notification

   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:

   * output from the target (sim or remote)

   * internal traces and logs

   * CLI console output

   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:

   * bind itself to GDB's internal event-loop.
     Typical for command-line UIs.

   * implement a custom event loop that incorporates the functionality
     required by GDB.
     Typical for graphical UIs

   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.

Implementation
**************

   This strategy outline the recommended strategy for implementing each
of the components.

Query
=====

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

Notify
======

   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.

Operations
==========

   The control interface shall be based on GDB's existing set of `run'
/ `stop' et.al. commands.

ui-stream / gdb-file
====================

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

event-loop
==========

   The event loop is beyond the scope of this document.

Start up
========

   Although the initialization mechanism used by optional client's is
still undefined, the below outlines one possible sequence:

  1. The alternative client is linked in with GDB. The top-level code
     contained in `XXX-top.c'.  This file includes a standard
     __INITIALIZE_XXX function.

  2. When GDB is started -UI=NAME is passed as an argument.  GDB saves
     NAME in a global variable.

  3. Eventually control reaches __INITIALIZE_XXX.  That function checks
     to see if it matches NAME and if it does, registers its custom
     version of the main event loop.

  4. GDB continues initialization and then, eventually calls XXX's
     custom event loop.





More information about the Gdb mailing list