Embedded Linux Kernel debugging using GDB and JTAG debugger
In previous posts we learned way to debug user layer application, u-boot bootloader on target hardware. Now it is time to get Linux Kernel debuggable. Here described steps to make Linux Kernel debugging on remote target hardware (IMX6ULL CPU) using JLink debugger via JTAG interface.
After getting source code and compiling it:
Kernel source code might be found at:
- optimize for perfomance
- optimize for size
No options like No optimization or Optimize for debugging. If you will try to walk through the image compiled with one of two options provided above you will face lot of optimized out variable values and randomly jumping Program Counter on trying to move step by step to the next instruction.
Another one an unpleasant surprise is that if you will try to edit Makefile manually to compile image with -O0/-Og you will get failed build process with lot of error messages. It turns out that you can’t just get and compile Linux Kernel without optimization. Here explained why. In short optimization used to remove dead code. But fortunately, search in google gave us explanation how to compile Linux Kernel with -Og flag. Awesome patch not approved for usage in kernel for some reasons.
Compile Linux Kernel with -Og flag
So you have to modify source code manually to build kernel optimized for debugging purpoces. Third build option to be added to Makefile:
Similar to U-boot (described here in IDE setup chapter) with only difference you have to import Linux Kernel sources (./build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/linux-imx6ull_cortexa7/linux-4.14.199/) instead of U-boot sources. Recompile project from Eclipse IDE so resulted image will be appeared inside the linux kernel folder.
At this moment we didn’t find way to make debugging process from Eclipse in GUI mode (only in command line mode described below) so at this moment we are using Eclipse for navigation only.
Debugging in command line mode
Let’s try to debug.
Power up board and type anything in COM port console before U-boot starts load kernel:
Start GDB server:
Start GDB session:
then in gdb console:
then in U-boot console start linux Kernel boot process:
then switch back to gdb console. You should see something like that:
try to walk through the code by typing s and print registers/variables value by using p (print) command:
Then set breakpoint at start_kernel function and run there:
You may use eclipse to navigate through the code. start_kernel function that implements most of initialization things might be found at ./build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/linux-imx6ull_cortexa7/linux-4.14.199/init/main.c file:
In next posts we will explain docker usage to simplify toolchain and ide setup, will try to load U-boot and kernel both using JTAG interface, will look how U-boot starts Kernel and other interesting things.