Thursday, January 9, 2014

How to - gcov/lcov for linux kernel modules


To test & explore gcov/lcov functionality for kernel modules, here are the steps I used:

  • Re-compile the kernel with GCOV functionality enabled. To enable Gcov functionality in kernel, enable CONFIG_DEBUG_FS, CONFIG_GCOV_KERNEL, CONFIG_GCOV_FORMAT_AUTODETECT and CONFIG_GCOV_PROFILE_ALL (if entire linux kernel requires coverage). If "make menuconfig" is ued, the following screens screens help to enable gcov in kernel:







       I followed http://techvolve.blogspot.com/2014/02/how-to-linux-kernel-compilation.html to recompile. 


  • To instrument the code with gcov, I enabled gcov compilation flags in the makefile of simple_krn_drv & simple_test_app, but left out hello_lkm. I also turned off any gcc optimization by removing "O" flags :

root@babu-VirtualBox:~/gcov_tests/lkm# grep -irne "-fprofile-arcs" *
simple_krn_drv/Makefile:5:CFLAGS=-ftest-coverage -fprofile-arcs  --disable-initfini-array 
simple_test_app/Makefile:6:CFLAGS       = -fPIC -pedantic -fprofile-arcs -ftest-coverage -march=native -ggdb3

root@babu-VirtualBox:~/gcov_tests/lkm# 


  • I compiled all the kernel modules & the user space test application. 
  • After compilation, I see that gcc generated .gcov files in the two kernel modules instrumented with gcov flags:


root@babu-VirtualBox:~/gcov_tests/lkm# find . -type f -name "*.gcno"
./simple_krn_drv/.tmp_simple_dev.gcno
./simple_krn_drv/simple_dev.mod.gcno
./simple_test_app/simple_hello.gcno
root@babu-VirtualBox:~/gcov_tests/lkm# 


  • The gcov run time date is not available before I inserted my kernel modules: 
                  root@babu-VirtualBox:~/gcov_tests/lkm# ls /sys/kernel/debug/gcov/
                  reset  usr  var
                  root@babu-VirtualBox:~/gcov_tests/lkm# 

  • Test modules: Insert LKMs, run the simple_test_app
  • Merge run time coverage information from debugfs to build directory. 


root@babu-VirtualBox:~/gcov_tests/lkm# ./fetch_n_merge_gcov 

Usage: fetch_n_merge_gcov --[local/remote] --kinfo --uinfo

                    [--kp <kdir_prefix>] [--up <udir_prefix>]

Execute this script from any build sub-directory to update

corresponding run time coverage info

root@babu-VirtualBox:~/gcov_tests/lkm#



    • As my test & build machine are both same, I used this with "--local --kinfo" options.



root@babu-VirtualBox:~/gcov_tests/lkm# ./fetch_n_merge_gcov --local --kinfo
Is /home/babu/gcov_tests/lkm the build sub-directory you want to update run time coverage info with? : (y/n)?y
Deleting old run time runtime info in build directory: /home/babu/gcov_tests/lkm
/home/babu/gcov_tests/lkm/simple_krn_drv/simple_dev.gcda
/home/babu/gcov_tests/lkm/simple_test_app/simple_hello.gcda
Importing new kspace coverage run time info from test device....
Treating /sys/kernel/debug/gcov/ as top level kspace gcov directory in test machine
mount: none already mounted or /sys/kernel/debug/ busy
mount: according to mtab, none is already mounted on /sys/kernel/debug
Merging new kspace coverage run time info to the build directory....
/home/babu/gcov_tests/lkm/simple_krn_drv/simple_dev.gcda
root@babu-VirtualBox:~/gcov_tests/lkm#

    • In case the test machine is different from the build machine, use this script with "--remote --kinfo" options.

  • Then, from my top build directory, I ran the following lcov commands:
root@babu-VirtualBox:~/gcov_tests/lkm# geninfo  . -o ./coverage.info
Found gcov version: 4.8.1
Scanning . for .gcda files ...
Found 2 data files in .
Processing simple_krn_drv/simple_dev.gcda
Cannot open source file include/linux/fs.h
Processing hello_lkm/hello.gcda
Finished .info-file creation
root@babu-VirtualBox:~/gcov_tests/lkm#



root@babu-VirtualBox:~/gcov_tests/lkm# genhtml -o ./lcov_data/ ./coverage.info

Reading data file ./coverage.info

Found 4 entries.

Found common filename prefix "/home/babu/gcov_tests/lkm/simple_krn_drv"

Writing .css and .png files.
Generating output.
Processing file /home/babu/gcov_tests/lkm/hello_lkm/hello.c
Processing file simple_dev.c
Processing file include/linux/fs.h
Processing file /usr/src/linux-3.13.5/arch/x86/include/asm/uaccess.h
Writing directory view page.
Overall coverage rate:
 lines......: 23.1% (9 of 39 lines)
 functions..: 28.6% (2 of 7 functions)
 branches...: 11.1% (1 of 9 branches)
root@babu-VirtualBox:~/gcov_tests/lkm#


  • I used firefox to view code coverage information of my tests. 
root@babu-VirtualBox:~/gcov_tests# firefox ./lcov_data/index.html


  • Among the two kernel modules I have, lcov report included only one module instrumented with gcov. So, engineers should NOT be hasty in concluding the coverage information based on just lcov report, but should cautiously check whether all the code expected to be compiled with gocv flags is compiled so. Any code that is not compiled with gcov flags should be categorized "unknown coverage".


Hope this helps.

3 comments:

Tejas Upadhyay said...

I have tried similar thing. we got gcno.a created on remote board. But we see issue with linking.

gcno.a links to some directory which referencing build system path. I tried to remove link and recreate, but It doesnt permit to do so.

I have also copied same directory and files at concerned location of symbolic link. But it didnt help.

Can you please advise what might be wrong?

Thanks,
Tejas

chaitanya said...

tried it on arm target. when kernel modules are loaded into target,simple_dev.gcno and simple_dev.gcda is generated, but both files seems to be empty and no use. So we cannot run the gcov command against the simple_dev.c file to generate coverage data.

Rathinavel said...

I have the same question as Tejas and Chaitanya. Can you help?

UA-48797665-1