Remote Debugging of Loadable Kernel Modules with kgdb: a Knowledge-based Article for Getting Started
In order for us to use kgdb to debug loadable modules, we must understand how the remote kernel communicates with gdb on the development machine. Remember, the mechanism's default communication between gdb on the development machine and the debugging stub on the target machine transpires via a serial driver interface (called gdbserial.o). In order for the debugging process to begin, two things must happen from within this driver. First, the set_debug_traps( ) is initiated. This function is defined in the debugging stub and informs the remote kernel that all breakpoints, error conditions and other exception handling is to be intercepted and handled by gdb. Secondly, the serial driver must call the function breakpoint( ). This function is also defined in the debugging stub and is used to initiate the communication by issuing a breakpoint interrupt:
asm( " int $3");
Since gdb is now configured to intercept such a condition (i.e., the set_debug_traps( ) call), the kernel on the target machine halts and transfers control to gdb on the development machine. It is from this point that the user may begin normal debugging such as single-stepping, issuing of breakpoints, stack tracing, etc. However, if we were to begin stepping from this initial point, the code we would be examining would be in gdbserial immediately following the call to the debugging stub's breakpoint( ) (since this is where program execution has halted).
For example, Listing 2 is the excerpt of gdbserial in which the two calls to the previously explained stub functions are called.
Now, if we initiate another debug session and issue a step command after gdb receives the stub's breakpoint interrupt, we would step to the next line of code in gdbserial after the breakpoint( ) is made (which should be gdb_null in the example in Listing 3).
As was mentioned before, gdb can return the remote kernel to a running state by issuing a continue command. If this is done, gdb patiently waits until the remote kernel returns control by issuing some sort of exception (such as a user-defined breakpoint, segmentation fault, etc.).
For a better understanding of how the entire process works review the debugging stub code found in /usr/src/linux/arch/i386/kernel/gdbstub.c and the serial driver interface, which can be found in /usr/src/linux/drivers/char/gdbserial.c.
We now have almost all the information we need in order begin using the kgdb mechanism to debug loadable modules. Remember, the important information we must retain from kgdb's communication process in order to initiate module debugging is: 1) at the beginning of the debug session, the debugging stub informs gdb on the development machine that it is responsible for intercepting and handling all exceptions from the remote target kernel for example, gdbserial's initial call to set_debug"traps( ); 2) the initial debug process begins with the serial interface's call to the debugging stub's breakpoint( ) function; 3) gdb can return the remote kernel to a running state but will regain control once the remote kernel issues any type of exception.
Additionally, we must consider that because the module will be loaded on the target machine and the gdb session runs on another machine, gdb will have no idea where in the target machine's memory the module code will be loaded. We must therefore determine this location and inform gdb of its whereabouts before the debugging of the module can begin.
During the kernel-building process, the kernel produces a file that maps addresses in memory to function names for the modules/drivers that are built during the compile process. This file is usually placed in the root of the kernel source directory (i.e., /usr/src/linux/System.map) and is used by the kernel to access those compiled devices properly in the correct memory location. However, at the construction of that file the kernel is unaware of where in memory a particular module may be loaded at a later time.
Fortunately, we can determine the memory location for modularized code during its load process. This is accomplished by using insmod with the -m parameter that informs insmod to produce a load map. This map informs us of where in memory the object-code sections reside. Ultimately, we must locate this information in order to inform gdb on our development machine of where our module's object code resides on the target machine. To illustrate, let's consider the module code shown in Listing 4, which we will refer to as the simple module.
As you can see, the simple module contains just enough functionality to to identify its memory address on the target machine when loaded.
On the development machine compile the module:
gcc -c -O2 -g simple.c
Be sure to include the -g option during compilation in order to enable debugging symbols for gdb.
Copy the compiled object code to the target machine.
Install the object code into the kernel using insmod's -m parameter:
insmod -m simple.oThis, of course, loads the module and produces a similar load map as shown in Listing 5.
Record the hex address of the .text section (0xc480004c in our example) for use later. This section represents the beginning of the module code in memory. We will use this value to inform the development machine running gdb of the module's whereabouts in memory.
Unload the module:
Fast/Flexible Linux OS Recovery
On Demand Now
In this live one-hour webinar, learn how to enhance your existing backup strategies for complete disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible full-system recovery solution for UNIX and Linux systems.
Join Linux Journal's Shawn Powers and David Huffman, President/CEO, Storix, Inc.
Free to Linux Journal readers.Register Now!
- Download "Linux Management with Red Hat Satellite: Measuring Business Impact and ROI"
- Sony Settles in Linux Battle
- Libarchive Security Flaw Discovered
- Profiles and RC Files
- Maru OS Brings Debian to Your Phone
- Understanding Ceph and Its Place in the Market
- Snappy Moves to New Platforms
- Astronomy for KDE
- The Giant Zero, Part 0.x
- Git 2.9 Released
With all the industry talk about the benefits of Linux on Power and all the performance advantages offered by its open architecture, you may be considering a move in that direction. If you are thinking about analytics, big data and cloud computing, you would be right to evaluate Power. The idea of using commodity x86 hardware and replacing it every three years is an outdated cost model. It doesn’t consider the total cost of ownership, and it doesn’t consider the advantage of real processing power, high-availability and multithreading like a demon.
This ebook takes a look at some of the practical applications of the Linux on Power platform and ways you might bring all the performance power of this open architecture to bear for your organization. There are no smoke and mirrors here—just hard, cold, empirical evidence provided by independent sources. I also consider some innovative ways Linux on Power will be used in the future.Get the Guide