Search code examples
linuxgdbembedded-linuxyoctoremote-debugging

Debugging Linux Kernel with Yocto SDK


I'm trying to use KGDB to debug the Linux kernel from the generated SDK of my arm Yocto image. To do so, I first make sure KGDB is compiled as a built-in module with:

CONFIG_KGDB=y CONFIG_KGDB_SERIAL_CONSOLE=y

Also, in my image.bb I have installed the kernel sources with:

`TOOLCHAIN_TARGET_TASK += "kernel-devsrc"`

Finally, I start KGDB at boot time by adding kgdboc=ttySTM0,115200 kgdbwait to the Kernel boot command. Which stops the boot process until KGDB connects to a GDB on the host side. Then, by starting arm-ostl-linux-gnueabi-gdb from the Yocto-SDK and setting set serial baud 115200 and target remote /dev/ttyUSB1 I can resume and debug the remaining boot routines.

The KGDB<->GDB connection over serial at boot time works just fine. However, my current problem is that not all sources of the Kernel are installed in the SDK, which makes GDB complain with /usr/src/kernel/*/*/*.c: No such file or directory., making debugging pretty much useless.

Thus, I forced installation of all .c sources by adding cp --parents $(find -type f -name "*.c") $kerneldir/build to the do_install() function of openembedded-core/meta/recipes-kernel/linux/kernel-devsrc.bb, which gets called with the above mentioned TOOLCHAIN_TARGET_TASK += "kernel-devsrc".

This effectively adds all resulting Kernel .c files to the SDK after adding my patches to the kernel sources but it also adds lots of .c that are not even required for my architecture (arm), making the SDK unnecessarily large.

So, my questions are:

  • Is there a better way to do this with Yocto?
  • If not, how can I filter only the required .c to be added in the SDK?

Thanks in advance!


Solution

  • One way to filter out not required sources is expanding the oppenembedded kernel-devsrc.bb by creating a kernel-devsrc.bbappend in your meta-layer with following script:

    do_install_append(){
        bbplain "--------------Including Kernel Sources------------------"
        cd ${S}
        # Find binary files (*.o) as a hint to find relevant sources
        for f in `find ${B} -type f -name "*.o"`; do
            # Extract file name
            file="${f##*/}"
            # Extract only path
            path=${f%/*}
            # Remove global part of the path
            path="${path##@(${B})}"
            # Remove object extension
            file=${file%.o}
            # Copy relevant sources to the SDK
            cp --parents $(find .$path -maxdepth 1 -type f -name ${file}.c -o -name ${file}.S) $kerneldir/build 2>/dev/null || :
        done
    }
    

    With this approach we look first in the binaries folder for compiled object files as those give us the information of which kernel components are being used for the current defconfig. With this information we can find corresponding kernel .c and .S sources and install them in the SDK. This avoids copying all sources, which in my case reduces the src folder from ~610MB to 18MB.

    Known limitation:

    There are a few object files (in my case 5) without a corresponding source with the same name, i.e. .tmp_vmlinux.kallsyms2.o, dtc-parser.tab.o, dtc-lexer.lex.o, .tmp_vmlinux.kallsyms1.o and vmlinux.o. We could make the script more complex to catch those corner cases or just ignore them with 2>/dev/null || :, as shown.