Kernel developent inside Qt Creator

I’ve always found myself missing a friendly environment for exploring the Linux kernel. One where I could quickly go to macro and find function usages without grepping through the entire code. I got motivated by this talk so I decided to try and out and polish it a bit.

Assumptions

I’m assuming that you have QtCreator installed. The simplest way I’ve found is to just install the whole Qt installer for the Open source version.

Steps

The setup bases itself on the script I’ve wrote for the purpose of reducing the number of files that need to be included in the project.

The steps apply for building on Lubuntu 16.10 in Virtualbox.

1. Building the kernel

~$ sudo apt-get install libncurses5-dev gcc make git exuberant-ctags bc libssl-dev
~$ git clone https://github.com/torvalds/linux.git
~$ cd linux
~/linux$ git checkout v4.8
~/linux$ make clean
~/linux$ cp /boot/config-`uname -r`* .config

Make a file mkfile.patch with the following content:

Signed-off-by: Steve Beattie <steve.beattie at canonical.com>
[apw at canonical.com: shifted up so works in arch/<arch/Makefile.]
BugLink: http://bugs.launchpad.net/bugs/1574982
Signed-off-by: Andy Whitcroft <apw at canonical.com>
---
 Makefile | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Makefile b/Makefile
index dda982c..f96b174 100644
--- a/Makefile
+++ b/Makefile
@@ -608,6 +608,12 @@ endif # $(dot-config)
 # Defaults to vmlinux, but the arch makefile usually adds further targets
 all: vmlinux

+# force no-pie for distro compilers that enable pie by default
+KBUILD_CFLAGS += $(call cc-option, -fno-pie)
+KBUILD_CFLAGS += $(call cc-option, -no-pie)
+KBUILD_AFLAGS += $(call cc-option, -fno-pie)
+KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)
+
 # The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default
 # values of the respective KBUILD_* variables
 ARCH_CPPFLAGS :=
--
2.8.1

Continue with the steps

~/linux$ patch < mkfile.patch
~/linux$ sed -i 's/CONFIG_CC_STACKPROTECTOR=y/# CONFIG_CC_STACKPROTECTOR is not set/' .config
~/linux$ sed -i 's/# CONFIG_CC_STACKPROTECTOR_NONE is not set/CONFIG_CC_STACKPROTECTOR_NONE=y/' .config
~/linux$ sed -i 's/CONFIG_CC_STACKPROTECTOR_STRONG=y/# CONFIG_CC_STACKPROTECTOR_STRONG is not set/' .config
~/linux$ sed -i 's/CONFIG_LOCALVERSION=""/CONFIG_LOCALVERSION="my-dev"/' .config
~/linux$ make KBUILD_VERBOSE=1 | tee build.log
~/linux$ sudo make modules_install install
~/linux$ sudo sed -i 's/GRUB_HIDDEN_TIMEOUT_QUIET=true/#GRUB_HIDDEN_TIMEOUT_QUIET=true/' /etc/default/grub
~/linux$ sudo sed -i 's/GRUB_HIDDEN_TIMEOUT=0/#GRUB_HIDDEN_TIMEOUT=0/' /etc/default/grub
~/linux$ sudo update-grub2

Reboot and select Ubuntu, with Linux 4.8.0my-dev+ in the Advanced options for Ubuntu of grub menu.

There are some issues with building the kernel in virtualbox with the gcc flag -fstack-protector-strong. The patches and edits of the config files are a workaround for that.

We’re keeping the log of the build which will be a basis for knowing what files to include in the Qt creator project.

2. Creating the QtCreator project

~/linux$ git clone https://github.com/TheMeaningfulEngineer/linux-in-qtcreator.git
~/linux$ cp linux-in-qtcreator/prepare_kernel_project.py .
~/linux$ chmod 755 prepare_kernel_project.py
~/linux$ ./prepare_kernel_project.py build.log linux

This runs the script responsible for parsing the build log and creating the OtCreator project config files. Argument build.log is the path to the build log and linux is the project name in QtCreator.

~/Qt/Tools/QtCreator/bin/$ ./qtcreator -noload Welcome -noload QmlDesigner -noload QmlProfiler

File -> Open File or Project -> ~/workspace/linux/linux.creator

This will open the project that contains all the files used for building the kernel in step one. This allows you to use QtCreators search functions to explore the code.

qtcreator is run from the default installation location with flags that prevent issues in Virtualbox.

Be aware that it takes some time for Qt Creator to index all the files once you open the project.

3. Setting the new kernel module

~/linux$ mkdir out-of-tree-modules
~/linux$ echo "out-of-tree-modules/our-module.c" >> linux-rpi.files

Two files need to be created in ~/linux/out-of-tree-modules

  • Makefile

    obj-m+=our-module.o
    all:
        make -C ../ M=$(PWD) modules
    clean:
        make -C . M=$(PWD) clean
    
  • our-module.c

    #include <linux/module.h>    // included for all kernel modules
    #include <linux/kernel.h>    // included for KERN_INFO
    #include <linux/init.h>      // included for __init and __exit macros
    
    MODULE_LICENSE("GPL");
    
    static int __init hello_init(void)
    {
        printk(KERN_INFO "It's me, Mr. Kernel Module and I'm just being initialized\n");
        return 0;    // Non-zero return means that the module couldn't be loaded.
    }
    
    static void __exit hello_cleanup(void)
    {
        printk(KERN_INFO "Cleaning up module.\n");
    }
    
    module_init(hello_init);
    module_exit(hello_cleanup);
    

Continue with building and loading the module.

~/linux/out-of-tree-modules$ make
~/linux/out-of-tree-modules$ sudo insmod our-module.ko

If all went well, you should see a line printed when running dmesg.

[   37.737250] It's me, Mr. Kernel Module and I'm just being initialized

Conclusion

This is the most practical driver development environment I found so far. Am open to hear your comments, critics or different approaches. If you find issues in the script, please support it by submitting them in the github repo.

Be Well :)

Written on May 10, 2017