Sunday, August 9, 2015

Linux Kernel Debugging using KGDB and User space process debugging using gdb

Linux Kernel Debugging using KGDB:

Kernel can be debugged using kgdb via serial port , virtual machine and via network configuration.

We required 2 systems to debug kernel using kgdb. Lets see how to debug using serial port connection.

Target system : Developing kernel to be run on this machine.

Host system :  Using gdb on host machine we can debug kernel running on target machine.

Make sure KGDB related config is enabled .
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y

Add boot parameters as "kgdbwait kgdboc=ttyS4,115200" in target system. For more clarity on adding boot parameters refer "http://ayyappa-ch.blogspot.in/2015/07/serial-console-logging.html"

Need to boot the target machine with mentioned boot parameters.


When i try to debug , after this screen target machine is not responding. So the actual limitation is KGDB will not support usb based key board. So , out target will support only USB based keyboard. So , we modified boot parameters as "console=ttyS4,115200n8 kgdbwait kgdboc=ttyS4".

This configuration will help COM port as console. Host and Target are connected via serial port.
On host serial we could see same message and able to enter to kdb mode. So now target is in waiting state for Host to connect via gdb. After target enters into kdb mode we need to close serial port terminal as we are going to use same serial port to debug the kernel.

Start the host machine and make sure source , map , vmlinux and other obj files available in host machine. Go to the location where vmlinux exist.

$ gdb ./vmlinux

$ gdb > set debug serial 1

$ gdb > break emmc_init -> set break point at emmc_init

$ gdb> target remote /dev/ttyS4
This will make the connection between host and target mechine. After this control comes to Host mechine and Target waits on host.

$gdb> cont
This will continue the boot process in target and control comes to target . On host terminal will be waiitng.

On target machine enter  $  echo "g"  >  /proc/sysrq-trigger.
This will give control to host machine to continue debugging.

Continue debugging as usual with gdb.
$gdb> bt - gives back trace of the kernel
$gdb> cont
This will continue until break point hits or if no break point hits , control goes to target machine.

Again in target mechine enter $  echo "g"  >  /proc/sysrq-trigger.
This will again give control to host machine . So we can debug again.

We can use either Linux machine or Windows machine as Host system. If we use windows system use MinGW gdb at windows side

Kernel module debugging:
On target machine get required module information:
 $ modprobe  your_module
$cd /sys/module/your_module/sections
$ cat .text
$ cat .bss
$ cat .data
$ cat .rodata

On host machine add module for debugging:
 $ gdb> add-symbol-file  module_name_with complete_path  \
 text_segment_address \
-s .bss    bss_segment_address \
-s .rodata   rodata_segment_address \
-s .data    data_segment_address

Now we can set break points even in  our modules.

User Space Process debugging:
we will see how to debug Xorg process.

$ ps -e | grep Xorg - get Xorg process pid

$ sudo gdb -p (pidof Xorg) - connect gdb to Xorg process

$gdb > bt -> will get stack trace of Xorg

Below link has some good info about gdb list and disassemble commands examples.

https://wiki.ubuntu.com/Kernel/KernelDebuggingTricks

gdb debugging commands:

step - step into sub-routine

next - run over sub-routine in a go

finish - run till current function returns

return - make selected stack frame return to its caller

jump [address] - continue program at specified line or address

list  - print 10 more lines

info break - show list and status of break points

break function - setting break point at function

break file:line - setting a break point at a file of line .

bt - display back trace

info args - shows args of current frame

info locals - shows locals of current frame

thread apply all bt  - Back trace of all the threads

info threads - information about threads