The other day I came across a memory leak in a char device driver I am implementing for the Linux Kernel. While in user space one can make use of Valgrind (see post), kernel space is not that simple to monitor. Instead, one can use kmemleak, a memory leak detector embedded in the kernel which, among other architectures, supports ARM. In this post I will cover one minor configuration obstacle that one must overcome to get kmemleak to work on the Zynq ZC702.
As found in the kernel documentation (Documentation/kmemleak.txt), in order to enable kmemleak it is necessary to check CONFIG_DEBUG_KMEMLEAK in “kernel hacking”. If you are not using a GUI, then just enable it in the configuration file (CONFIG_DEBUG_KMEMLEAK=y). As pointed in the configuration file (lin/Kconfig.debug), kmemleak has some dependencies (DEBUG_KERNEL, EXPERIMENTAL, and HAVE_DEBUG_KMEMLEAK). It is therefore mandatory to enable them.
If you recompile your kernel and run it in the Zynq, it is probable that /sys/kernel/debug/kmemleak is not there. Checking the logs (dmesg) you will see that an error points to kmemleak not having enough early log buffer size when it is being initialized at boot time . The solution, is pretty simple, just modify CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE to have a larger buffer. By default, its value is 400, which in this case is not enough. I set mine to 1500. Recompile, run, and /sys/kernel/debug/kmemleak should be in place for you to start debugging 🙂
Note that you should disable kmemleak when your system gets in production, or if you intend to evaluate it. Not only does it introduce a big overhead, but – as any other debug tool – is vulnerable entry point for attackers.