Next: , Previous: Native Debugging, Up: Top

15 Support Libraries

15.1 BFD

BFD provides support for gdb in several ways:

identifying executable and core files
BFD will identify a variety of file types, including a.out, coff, and several variants thereof, as well as several kinds of core files.
access to sections of files
BFD parses the file headers to determine the names, virtual addresses, sizes, and file locations of all the various named sections in files (such as the text section or the data section). gdb simply calls BFD to read or write section x at byte offset y for length z.
specialized core file support
BFD provides routines to determine the failing command name stored in a core file, the signal with which the program failed, and whether a core file matches (i.e. could be a core dump of) a particular executable file.
locating the symbol information
gdb uses an internal interface of BFD to determine where to find the symbol information in an executable file or symbol-file. gdb itself handles the reading of symbols, since BFD does not “understand” debug symbols, but gdb uses BFD's cached information to find the symbols, string table, etc.

15.2 opcodes

The opcodes library provides gdb's disassembler. (It's a separate library because it's also used in binutils, for objdump).

15.3 readline

The readline library provides a set of functions for use by applications that allow users to edit command lines as they are typed in.

15.4 libiberty

The libiberty library provides a set of functions and features that integrate and improve on functionality found in modern operating systems. Broadly speaking, such features can be divided into three groups: supplemental functions (functions that may be missing in some environments and operating systems), replacement functions (providing a uniform and easier to use interface for commonly used standard functions), and extensions (which provide additional functionality beyond standard functions).

gdb uses various features provided by the libiberty library, for instance the C++ demangler, the IEEE floating format support functions, the input options parser getopt, the obstack extension, and other functions.

15.4.1 obstacks in gdb

The obstack mechanism provides a convenient way to allocate and free chunks of memory. Each obstack is a pool of memory that is managed like a stack. Objects (of any nature, size and alignment) are allocated and freed in a LIFO fashion on an obstack (see libiberty's documentation for a more detailed explanation of obstacks).

The most noticeable use of the obstacks in gdb is in object files. There is an obstack associated with each internal representation of an object file. Lots of things get allocated on these obstacks: dictionary entries, blocks, blockvectors, symbols, minimal symbols, types, vectors of fundamental types, class fields of types, object files section lists, object files section offset lists, line tables, symbol tables, partial symbol tables, string tables, symbol table private data, macros tables, debug information sections and entries, import and export lists (som), unwind information (hppa), dwarf2 location expressions data. Plus various strings such as directory names strings, debug format strings, names of types.

An essential and convenient property of all data on obstacks is that memory for it gets allocated (with obstack_alloc) at various times during a debugging session, but it is released all at once using the obstack_free function. The obstack_free function takes a pointer to where in the stack it must start the deletion from (much like the cleanup chains have a pointer to where to start the cleanups). Because of the stack like structure of the obstacks, this allows to free only a top portion of the obstack. There are a few instances in gdb where such thing happens. Calls to obstack_free are done after some local data is allocated to the obstack. Only the local data is deleted from the obstack. Of course this assumes that nothing between the obstack_alloc and the obstack_free allocates anything else on the same obstack. For this reason it is best and safest to use temporary obstacks.

Releasing the whole obstack is also not safe per se. It is safe only under the condition that we know the obstacks memory is no longer needed. In gdb we get rid of the obstacks only when we get rid of the whole objfile(s), for instance upon reading a new symbol file.

15.5 gnu-regex

Regex conditionals.


15.6 Array Containers

Often it is necessary to manipulate a dynamic array of a set of objects. C forces some bookkeeping on this, which can get cumbersome and repetitive. The vec.h file contains macros for defining and using a typesafe vector type. The functions defined will be inlined when compiling, and so the abstraction cost should be zero. Domain checks are added to detect programming errors.

An example use would be an array of symbols or section information. The array can be grown as symbols are read in (or preallocated), and the accessor macros provided keep care of all the necessary bookkeeping. Because the arrays are type safe, there is no danger of accidentally mixing up the contents. Think of these as C++ templates, but implemented in C.

Because of the different behavior of structure objects, scalar objects and of pointers, there are three flavors of vector, one for each of these variants. Both the structure object and pointer variants pass pointers to objects around — in the former case the pointers are stored into the vector and in the latter case the pointers are dereferenced and the objects copied into the vector. The scalar object variant is suitable for int-like objects, and the vector elements are returned by value.

There are both index and iterate accessors. The iterator returns a boolean iteration condition and updates the iteration variable passed by reference. Because the iterator will be inlined, the address-of can be optimized away.

The vectors are implemented using the trailing array idiom, thus they are not resizeable without changing the address of the vector object itself. This means you cannot have variables or fields of vector type — always use a pointer to a vector. The one exception is the final field of a structure, which could be a vector type. You will have to use the embedded_size & embedded_init calls to create such objects, and they will probably not be resizeable (so don't use the safe allocation variants). The trailing array idiom is used (rather than a pointer to an array of data), because, if we allow NULL to also represent an empty vector, empty vectors occupy minimal space in the structure containing them.

Each operation that increases the number of active elements is available in quick and safe variants. The former presumes that there is sufficient allocated space for the operation to succeed (it dies if there is not). The latter will reallocate the vector, if needed. Reallocation causes an exponential increase in vector size. If you know you will be adding N elements, it would be more efficient to use the reserve operation before adding the elements with the quick operation. This will ensure there are at least as many elements as you ask for, it will exponentially increase if there are too few spare slots. If you want reserve a specific number of slots, but do not want the exponential increase (for instance, you know this is the last allocation), use a negative number for reservation. You can also create a vector of a specific size from the get go.

You should prefer the push and pop operations, as they append and remove from the end of the vector. If you need to remove several items in one go, use the truncate operation. The insert and remove operations allow you to change elements in the middle of the vector. There are two remove operations, one which preserves the element ordering ordered_remove, and one which does not unordered_remove. The latter function copies the end element into the removed slot, rather than invoke a memmove operation. The lower_bound function will determine where to place an item in the array using insert that will maintain sorted order.

If you need to directly manipulate a vector, then the address accessor will return the address of the start of the vector. Also the space predicate will tell you whether there is spare capacity in the vector. You will not normally need to use these two functions.

Vector types are defined using a DEF_VEC_{O,P,I}(typename) macro. Variables of vector type are declared using a VEC(typename) macro. The characters O, P and I indicate whether typename is an object (O), pointer (P) or integral (I) type. Be careful to pick the correct one, as you'll get an awkward and inefficient API if you use the wrong one. There is a check, which results in a compile-time warning, for the P and I versions, but there is no check for the O versions, as that is not possible in plain C.

An example of their use would be,

     DEF_VEC_P(tree);   // non-managed tree vector.
     struct my_struct {
       VEC(tree) *v;      // A (pointer to) a vector of tree pointers.
     struct my_struct *s;
     if (VEC_length(tree, s->v)) { we have some contents }
     VEC_safe_push(tree, s->v, decl); // append some decl onto the end
     for (ix = 0; VEC_iterate(tree, s->v, ix, elt); ix++)
       { do something with elt }

The vec.h file provides details on how to invoke the various accessors provided. They are enumerated here:

Return the number of items in the array,
Return true if the array has no elements.
Return the last or arbitrary item in the array.
Access an array element and indicate whether the array has been traversed.
Create and destroy an array.
Helpers for embedding an array as the final element of another struct.
Duplicate an array.
Return the amount of free space in an array.
Ensure a certain amount of free space.
Append to an array, either assuming the space is available, or making sure that it is.
Remove the last item from an array.
Remove several items from the end of an array.
Add several items to the end of an array.
Overwrite an item in the array.
Insert an item into the middle of the array. Either the space must already exist, or the space is created.
Remove an item from the array, preserving order or not.
Remove a set of items from the array.
Provide the address of the first element.
Binary search the array.

15.7 include