B.4 Using a Debugger with the Linux Kernel

   


A debugger is a tool that allows you to stop a program under development during its execution and to execute it step by step to monitor the program state the values of variables and the contents of memory locations and to modify it, if necessary. A debugger can also be used for development in the Linux kernel. However, there is no way of stopping or stepwise running, because stopping the kernel would immediately cause the entire system to become unusable. Reading global variables and other memory locations is possible while the kernel is running, and it can often be helpful for better understanding active processes.

Interface Between Kernel and Debugger

Debuggers normally offer a way to edit a so-called core file instead of a running program. Such a file can be created automatically when a program is terminated by an illegal memory access. It contains a copy of the memory locations occupied by this program. We can use a debugger, after reading a core file, to check the program state when the crash happened.

The core file, as interface between the debugger and the program state, can also be used to monitor the Linux kernel. To this end, the file /proc/kcore maps the entire main memory of the system to the format of a core file. So, if we give this file to a debugger as a core file, we can use the debugger tools to check the current state of the entire system.

Compiler Options

In addition to a core file, a debugger requires a file with the executable program. In case of the Linux kernel, this file is available under the name vmlinux in the directory in which the kernel was compiled. When compiling a program to be debugged, the compiler should have been instructed to embed debugging information (e.g., the full names of variables in text form and references to the relevant places in the source code). If this information is available, the debugger lets you (for example) query variables by their names.

The C compiler gcc lets you use the -g option to embed debugging information during compilation. This option has to be entered in a make file at the appropriate position to ensure that it will be used when the Linux kernel is compiled. If we want to achieve this for the entire kernel, we can add this option to the definition of the CFLAGS variable in the main make file in the top directory of the source-code tree. If we want to check only limited kernel areas in the debugger, it is sufficient to add one EXTRA_CFLAGS = -g line each to the make files in the directories that contain the files for each of these areas. For example, this would be net/ip4/Makefile if we were to check routing.

gdb and ddd

One of the most popular debuggers in the UNIX world is the gdb debugger, developed under the auspices of the Free Software Foundation (FSF). gdb offers only a text interface to the user, so it is universal, but not comfortable to use. More recently, several front ends have been developed to remove this drawback (e.g., by offering a graphical user interface). Two representatives of this kind were also developed by FSF: the Data Display Debugger, ddd, and the Grand Unified Debugger (gud) mode of the emacs text editor. ddd has options for graphic representation of data structures, which make it suitable particularly to check such data structures in the Linux kernel.

A detailed description of how these tools work would go beyond the scope and volume of this book. Detailed instructions are included in each of the distribution packages.

Example

Figure B-1 shows an example for the graphic representation of data structures in ddd. This example uses a fragment from a concrete variant of data structures to represent some of the routing tables described in Chapter 16.

Figure B-1. Example using ddd: Checking routing-table data structures. (See Chapter 16.)

graphics/xbfig01.jpg


The entry point is a global array, fig_tables, the 254th element of which is the fib_table structure of the routing table main. The fn_hash structure (reachable as * (struct fn_hash *) fib_tables[254]->tb_data) is appended to the main table. The fn_hash structure has a number of pointers to fn_zone structures for prefix lengths 0 through 31 in its fn_zones array. The figure represents the data structure for the zone with prefix length 8. An explicit type conversion is required to display the hash table referenced there, because the hash table size cannot be derived from the pointer type, fz_hash. Specifically, we have to give the expression that describes this pointer a leading (struct fib_node *[16]) * to make the hash table visible, as shown in the figure. The eighth element of the hash table is unequal null and refers to a fib_node structure for the prefix 10.0.0.0/8 (where the prefix length can be derived from the fn_zone structure further up). The figure also represents the associated fib_info structure, and the fib_prefsrc element of that structure contains the source address 10.0.0.1 in hexadecimal representation (in network byte order) and the hooked fib_nh structure.

To use ddd in this example, we inserted the mentioned line, EXTRA_CFLAGS = -g, in the file net/ipv4/Makefile before compiling the Linux kernel. Next, we installed the kernel prepared in this way; then we used the command ddd /usr/src/linux/vmlinux /proc/kcore to start ddd.

Notice that gdb, upon which ddd is based, cannot see later modifications to the data structures itself, because such modifications normally do not occur in core files. We can use the gdb command core /proc/kcore to make the debugger reread the core file, so that the displayed values are updated.


       


    Linux Network Architecture
    Linux Network Architecture
    ISBN: 131777203
    EAN: N/A
    Year: 2004
    Pages: 187

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net