GDB: An Open Source Debugger for Embedded Development
Back to Cygnus White Papers index

Future Plans
Internally, GDB has changed much over the years. A quick study of Cygnus' source repository shows that of the approximately 90,000 lines of code present in 1991, only about 30,000 lines remain unchanged, and 310,000 new lines have been added.

Despite all of the new code, most of the original design persists unchanged, and is now in need of updating. Most of the work described below is presently underway; we expect that the rest of it will happen over the next year or two. Cygnus is leading the development, and is also getting help from the net community, especially with testing and support for particular targets of interest to volunteers.

Dynamic Choice of Architecture
The original approach to GCC and GDB portability was to make symbolic links to machine-specific include files. So for instance, GDB's main include file defs.h includes the lines #include "xm.h" #include "tm.h" even though there are no files xm.h or tm.h to be found in the sources. How does this work? Suppose we want to build Windows cross PowerPC EABI tools. Then, running on Windows, we say (to the Cygwin port of the shell program bash): % ./configure --target=powerpc-eabi The configure script's main activity is to construct makefiles from Makefile.in files, filling in variables and adding dependencies for machine-specific files, such as the SDS protocol backend. But it also makes symbolic links: xm.h -> config/i386/xm-cygwin.h tm.h -> config/powerpc/tm-ppc-eabi.h

These include files contain the C macros defining the host and target architectures, as described earlier.

For GCC, this has been an efficient approach. It is possible to use #ifdefs to choose the compiler algorithms best suited to the target processor, thus not slowing down the compiler by making it choose while trying to get to the business of generating code.

However, for GDB, this doesn't work nearly so well. GDB sits at the end of the tool "food chain", and must always be prepared to deal with various object files, different compilation options, and different versions of the hardware. In addition, it does not have the same sort of performance issues. (There are really only two key performance issues for GDB: the speed of reading symbol files, and the efficiency of the remote debugging protocol.)

As noted previously, this general idea of dispatching at runtime is already in use for symbol readers and debugging protocols, and has been successful there. We are changing GDB to do the same kind of thing for target architecture definition.

Ultimately, it will be possible to have a "universal" GDB that has support for all possible processors. Although this is a nice idea, it won't matter to most shops, since they typically use only one or two different architectures. Of more practical interest will be the ability to handle different architecture variants; for instance, all the processors in the MIPS family, or all the versions of Hitachi SH. (GDB handles some of the variants now, but only by kludgery.)

Another interesting possibility will be the ability to have dynamically loaded architecture descriptions. Mentor/Microtec's description of their Xray debugger mentions this as a capability, although without supplying much detail. In GDB's case the documentation for how to do this will be publicly available along with the sources.

Event-driven behavior and asynchronous debugging
GDB's execution control, as described above, does not actually work well in an event-oriented environment. For example, the Insight GUI requires a certain amount of trickery in order to keep the interface working while wait_for_inferior is quietly waiting for the target.

GDB's new design is to break up the infinite loops. Instead, each GUI or command interpreter, as well as each target connection, will register itself as a generator of "events". Then GDB's waiting will consist of waiting for any event, and either dispatching it to an interface, or to a target vector.

This requires a complete reorganization of wait_for_inferior, a daunting task because of its complexities that were described earlier.

One big benefit will be the ability to do asynchronous debugging, which means interacting with the target while it is running. To use the command line as an example, the prompt will come back right away and allow typing of commands before the programs stops again: (gdb) continue (gdb) Computing away! [output from the program] (gdb) print avar avar = 45 More computing going on! [ more output] (gdb) print avar avar = 46 [program is modifying avar] Program stopped at foo() (gdb) print avar avar = 46 (gdb)

GUIs will be able to work similarly, so while right now the variable display window will be disabled while the program is running, with asynchronous debug all the data displays can remain active and usable.

Parallel debugging
Another vestige of the old GDB is the one-process assumption. While multi-thread support has been in GDB since 1994, GDB can still only reasonably handle a single executable program in a single address space. Modern embedded systems will require the removal of this limitation; new designs include multiple CPUs (such as ARM and DSP), multiple copies of a processor on a single die, and multiple CPUs executing from a partially shared memory.

Changes will include the encapsulation of global data about the program into objects. The event-driven architecture will help considerably here, and there will be additional work to develop an interface that will manage the multiple processors without unduly taxing the user.

Prev Table of Contents Next
Internal Structure of GDB   How to Learn More