Linux Kernel Series - 12 - GDB Part 3 - Kernel Debugging
Hello Everyone, hope you are all doing great. I am back with another exciting article in the Linux Kernel Series by the name
"GDB Part - 3 - Kernel Debugging".
In the previous articles, we have seen various ways to debug our program using "On the system GDB", "GDB Remote Server" and we have learned various mechanisms and commands of the GDB to debug and identify bugs and issues in our programs efficiently.
In this article, we will discuss the setup of the GDB to debug the Linux Kernel and Kernel Modules LKM using Serial Connection. Many times when we are developing the code, there will be necessity to debug for identifying the bugs and issues. But keeping print statements always is not a viable solution. This is even problematic in the kernel space as too many "printk" statements will lead to other problems. So to effectively debug the kernel code and kernel modules (LKM) code we need to debug it with the help of GDB. This article aims to give the entire details from setup to debug.
So lets dive into the exciting topic without any further delay
💡Hardware and Connections
For this example, I am using BeagleBoneBlack, but you can use any of your SoC Platforms. The connection and setup diagram is shown below.
In the above diagram we can see that the BeagleBoneBlack is connected to upstream router via Ethernet. Linux Laptop is connected to the same router via Ethernet/WIFI and Linux Laptop is connected to BeagleBoneBlack UART Pins
💡Enabling KGDB in BeagleBone Black OS
The first step to debug the kernel is to enable the KGDB support. Since I am building the OS of the BeagleBoneBlack in buildroot, I will be making the necessary changes in buildroot configuration. Please see the configurations given in the screenshot below. You need to adapt the similar configurations if you are using "OpenWRT", "Yocto" or any other build system.
# This command is to configure the Linux Kernel in Buildroot
make linux-menuconfig
Note that I am NOT using "make menuconfig" command.
After making these changes, build the entire image and transfer to BeagleBoneBlack. You can confirm if the debug symbols are enabled in the kernel by running the following command after the build is success
file output/build/linux-custom/vmlinux
In my build, vmlinux size was around 300+ MB by enabling the debug symbols.
💡Sample Kernel Module Program to debug - sammy.c
Now we need a kernel module to debug, so let's build a very small kernel module with kthread implementation, where it prints a variable "i" value for every 1 second.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/kthread.h>
static struct task_struct *thread;
static int my_thread_function(void *data){
int i = 0;
while(!kthread_should_stop()){
printk(KERN_INFO "SAMMY: I value is: %d", i++);
msleep(1000);
}
return 0;
}
int __init sammy_module_init(void){
printk(KERN_INFO "SAMMY: Module init");
thread = kthread_run(my_thread_function, NULL, "sammy_thread");
if(IS_ERR(thread)){
printk(KERN_ERR "SAMMY: Failed to launch the kthread");
return -1;
}
return 0;
}
void __exit sammy_module_exit(void){
if(thread){
kthread_stop(thread);
printk(KERN_INFO "SAMMY: kthread stopped");
}
printk(KERN_INFO "SAMMY: Module exit");
}
module_init(sammy_module_init);
module_exit(sammy_module_exit);
MODULE_AUTHOR("G. Naveen Kumar");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Sample kernel module for gdb debugging");
MODULE_VERSION("1.0.0");
obj-m+=sammy.o
ccflags-y := -g -DDEBUG
all:
$(MAKE) -C $(LINUX_DIR) M=$(PWD) modules
clean:
$(MAKE) -C $(LINUX_DIR) M=$(PWD) clean
NOTE: Please see the above make file where the "-g" option is enabled
💡Compile and Transfer the kernel module to the BeagleBoneBlack
After the compilation is completed, transfer the kernel module "sammy.ko" file to the BeagleBoneBlack and insert it with "insmod" command. You can use "scp" or "tftp" to transfer the module via Ethernet connection of BBB.
# insert the kernel module
insmod sammy.ko
💡BeagleBoneBlack Setup to enable KGDB
KGDB can be enabled in two ways
Please use the following method to enable the kgdboc at runtime. kgdboc stands for "kgdb over console".
# If you have changed the ttyS0 to any other during build, you need # to provide the respective tty number here
cd /sys/module/kgdboc/parameters
echo ttyS0 > kgdboc
You should get the following output, when you register ttyS0 to the kgdboc
💡Get the .text section address of sammy.ko LKM to load the symbols in GDB
In the above screenshot we can see the .text section address. We need this address to load the symbols and let GDB know where to look for the symbols.
💡Host System Setup with GDB - gdb-multiarch
We need to use the gdb-multiarch for this purpose, as we are debugging ARM architecture from x86_64 system. Use the following command to launch the gdb-multiarch
Recommended by LinkedIn
gdb-multiarch output/build/linux-custom/vmlinux -tui
Here the second argument is the vmlinux location, that is build with debug symbols enabled. Upon executing this command you will see the following screenshot.
Use the following command in the gdb to load the symbol table of the sammy.ko LKM module
# 2nd argument is the path where sammy.ko is built. (This path is on # buildroot)
# 3rd argument is the .text address read from loading the LKM
add-symbol-file output/build/sammykernelmodules-1.0/sammy.ko 0xbf0a1000
# Execute the following command in gdb
set architecture arm
For RaspberryPI 3 32bit - "set architecture arm"
For RaspberryPI 5 64bit - "set architecture aarch64"
For Qualcomm Oak and Hawkeye - "set architecture aarch64"
For BananaPI 64bit - "set architecture aarch64"
# Execute in GDB shell
set serial baud 115200
This is the end of all the setup instructions that are needed to setup GDB to debug Kernel and Kernel Modules on BeagleBoneBlack.
💡Start the Debugging
Let's start the main event of this entire article. DEBUGGING.
Execute the following commands as mentioned one by one. Please note in the code snippet, I will mention where to run these commands. i.e., in Host or BBB
# Command 1: BBB
echo g > /proc/sysrq-trigger
NOTE: IF YOU HAVE MINICOM WINDOW OPENED, YOU NEED TO EXIT BEFORE RUNNING NEXT COMMANDS. OTHERWISE THIS WILL FAIL
# Command 2: GDB
target remote /dev/ttyUSB0
This command will attach the GDB to the kernel and you will get the following output
Once the GDB is attached, let's create the breakpoint to stop the execution when it reaches in our LKM Code. For this example, I am keeping the breakpoint at line number 12 of the code.
12: printk(KERN_INFO "SAMMY: I value is: %d", i++);
Type the following command in the GDB console
b sammy.c:12
My source code file name is sammy.c, and when I loaded the symbol table this path is also available. Change the file name as per your customisation. Once you have issued the command, the breakpoint is created as shown in the screenshot below.
Confirm the breakpoints information with the following command
# Command 3: GDB
info breakpoints
Give the next command to the GDB shell by pressing "n" on the keyboard and your breakpoint in the LKM will be triggered as shown in the screenshot below
If you have got the same screenshot in your system, when you are debugging, then you have done an awesome job. You have successfully used GDB to debug the LKM modules in the Linux Kernel.
Really awesome and good job...
Kudos 👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏👏
After this, you can run the GDB commands like "n", "s", "print", "c" etc., and debug your program.
💡Important Points to note
Using this method, you can debug the code of Linux Kernel or LKM modules effectively. If you are facing few issues such as "ReplyTimeout", "Incorrect Symbols" or any other errors, then kindly check the following things
💡Conclusion
Hope you have enjoyed this article and understood the process of debugging Kernel modules and Linux Kernel with GDB. If you like these articles, kindly subscribe to the LinkedIn Articles and my YouTube Channel for exciting information related to technology.
I will soon be back with another exciting article, till then
"Stay Happy, Stay Safe and wish you an exciting programming experience..."
See you all soon, thanks and bye.
💡References