Kernel code coverage 内核代码覆盖了

开启gcov

看下当前config里面是不是已经enable了gcov:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ zcat /proc/config.gz | egrep "GCOV_|DEBUG_FS"

CONFIG_GCOV_KERNEL=y
CONFIG_GCOV_PROFILE_ALL=y
CONFIG_DEBUG_FS=y

$ mount | grep debugfs
debugfs on /sys/kernel/debug type debugfs (rw,relatime)

# ls -la /sys/kernel/debug/gcov/
total 0
drwxr-xr-x 2 root root 0 Jun 14 2013 .
drwx------ 17 root root 0 Jun 14 2013 ..
-rw------- 1 root root 0 Jun 14 2013 reset

通常答案都是否定的,默认情况下一般不会开启。那就修改一下.config文件,重新编译、安装kernel。 过程略。
正确开启gcov之后,除了上面几个几部之外,可以通过下面kernel Document来验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
The gcov kernel support creates the following files in debugfs:

/sys/kernel/debug/gcov
Parent directory for all gcov-related files.

/sys/kernel/debug/gcov/reset
Global reset file: resets all coverage data to zero when
written to.

/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda
The actual gcov data file as understood by the gcov
tool. Resets file coverage data to zero when written to.

/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno
Symbolic link to a static data file required by the gcov
tool. This file is generated by gcc when compiling with
option -ftest-coverage.

收集code coverage信息

code coverage的信息收集需要2+1步:

  1. 收集 *.gcda
  2. 在编译kernel的环境中,转换为 .info
  3. 生成HTML文档

收集 *.gcda

gcov 官网非常贴心的给提供了一个脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash -e

DEST=$1
GCDA=/sys/kernel/debug/gcov/home/works/linux-stable/

if [ -z "$DEST" ] ; then
echo "Usage: $0 <output.tar.gz>" >&2
exit 1
fi

TEMPDIR=$(mktemp -d)
echo Collecting data..
find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
# find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
tar czf $DEST -C $TEMPDIR/$GCDA .
rm -rf $TEMPDIR

echo "$DEST successfully created, copy to build system and unpack with:"
echo " tar xfz $DEST"

这个脚本打包的那句感觉写的不是很准确,我稍微修改了一下。
注意,这个脚本必须在/sys/kernel/debug/gcov/home/works/linux-stable/这个目录下运行\
并且,中间那个手机*.gcno文件的一句话也不需要,而且是绝对不能加的。
脚本会把所有当前kernel内所有的文件的.gcda打包到参数$1指定的文件中,并且,最后告诉了解压的方法。

把.gcda放回编译环境

打包的.gcda如何使用呢? scp 到kernel编译环境,然后在内核根目录linux下执行上面的解压缩程序:

1
tar xfz <文件名>

成功之后,所有的.gcda文件就解压到对应的.c以及.c.gcno文件旁边。

转换

使用lcov工具,把gcov log文件转换位.info。同样,lcov官网也给出了建议的流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
Recommended procedure when capturing data for a test case:

1. create baseline coverage data file
# lcov -c -i -d appdir -o app_base.info

2. perform test
# appdir/test

3. create test coverage data file
# lcov -c -d appdir -o app_test.info

4. combine baseline and test coverage data
# lcov -a app_base.info -a app_test.info -o app_total.info

如果build环境和测试环境分开的话,也不需要严格的按照上面的步骤来。但上面的步骤至少提供了两个信息:

  • lcov怎么用
  • 如何合并多个info文件

同样在内核根目录下,执行

1
# lcov -c -i -d . -o app_base.info

然后去执行测试,并且重复上面.gcda文件的打包和解包过程,之后再执行:

1
2
# lcov -c -d appdir -o app_test.info
# lcov -a app_base.info -a app_test.info -o app_total.info

生成网页报告

使用工具genhtml,把最终的app_tatal.info文件转为html文件:

1
genhtml test.info --output-directory output --title "a simple test" --show-details --legend

gcov在user space下使用

  • 添加-ftest-coverage -fprofile-arcs变选项

    1
    gcc -ftest-coverage -fprofile-arcs main.c -o main
  • 使用gcov抓取coverage

    1
    gcov main.c
  • 使用lcov 和 genhtml生成报告

1
2
lcov -c -o main.info -d .  
genhtml main.info -o main_result

gcov for kernel modles

同样需要先enable kernel config
hello.cmakefile 举例:

  • 修改Makefile
    添加如下:

    1
    2
    3
    GCOV_PROFILE := y  
    CFLAGS=-ftest-coverage -fprofile-arcs
    export CFLAGS
  • 编译模块

    1
    make
  • 插入模块

    1
    insmod hello.ko
  • gcda文件

    1
    /sys/kernel/debug/gcov/<your dir>/program.gcda
  • cat并保存.gcda和.gcno到project目录

  • gcov

    1
    gcov hello.c
  • 生成html

    1
    2
    lcov -c -o hello.info -d .
    genhtml hello.info -o main_result
  • 删除gcov文件
    删除include开头的文件或者文件夹

    1
    # lcov -r hell.info "include*" -o hello.info2

Reference

Using gcov with the Linux kernel
lcov(1) - Linux man page

坚持原创技术分享,您的支持将鼓励我继续创作!
0%