Linux 内核 5.4 GCC 9.1.0 不显示代码覆盖率

问题描述

我们在不同的架构(arm、arm64、x86_64)上使用 Linux 内核 5.4 和 gcc 9.1.0。我负责为内核模块创建代码覆盖率。我没有选择 Linux 内核版本,也没有选择编译器版本。

我可以像往常一样为 arm/arm64 创建代码覆盖率并在 /sys/kernel/debugfs/gcov/... 中查看结果。此外,加载的模块在 gcov 子目录中可见。

但是,对于 x86_64,即使我设置了 CONfig_GCOV_COVERAGE_ALL=y,我也只能看到 /sys/kernel/debubfs/gcov/reset 而没有其他内容

kernel/gcov/base.c 中的 __gcov_init 通常会创建一个

pr_info("version magic=...")

在启动时在 arm/arm64 上可见,但在 x86_64 上不可见。应该为每个源文件调用 __gcov_init 作为 gcc 构造函数,第一次调用会创建版本魔术消息。

在我看来,在我的组合中,代码覆盖函数 __gcov_init 在 x86_64 中从未被调用过。

在配置中,我使用

CONfig_GCOV_PROFILE=y
CONfig_GCOV_FORMAT_4_7=y

有时仅适用于 x86 CONfig_GCOV_PROFILE_ALL=y。除了 x86 的“重置”文件外,没有任何可见的 /sys/kernel/debug/gcov/...。

欢迎提出任何建议。

解决方法

代码覆盖构造函数现在写在“.ctors.65435”部分(数字可能是构造函数优先级),但内核 5.4 只知道“.ctors”。

对于内核内部代码覆盖率,以下更改(已经在以后的内核中,例如 5.12)恢复了代码覆盖率

--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -631,6 +631,7 @@
 #ifdef CONFIG_CONSTRUCTORS
 #define KERNEL_CTORS() . = ALIGN(8);                      \
                        __ctors_start = .;                 \
+                       KEEP(*(SORT(.ctors.*)))            \
                        KEEP(*(.ctors))                    \
                        KEEP(*(SORT(.init_array.*)))       \
                        KEEP(*(.init_array))               \

然而,kernel/module.c 也不知道“.ctors.65435”,并且用 gcc9 或 gcc10 编译的模块没有“.ctors”ELF 部分。所以我只是改成了 HACK (!)

--- a/kernel/module.c
+++ b/kernel/module.c
@@ -3294,7 +3294,7 @@ static int find_module_sections(struct module *mod,struct load_info *info)
        mod->unused_gpl_crcs = section_addr(info,"__kcrctab_unused_gpl");
 #endif
 #ifdef CONFIG_CONSTRUCTORS
-       mod->ctors = section_objs(info,".ctors",+       mod->ctors = section_objs(info,".ctors.65435",sizeof(*mod->ctors),&mod->num_ctors);
        if (!mod->ctors)
                mod->ctors = section_objs(info,".init_array",

这会带回模块代码覆盖率,但是

.ctors.* for modules 在最新的 5.x 内核中是未知的,所以我认为这应该在 Linux 内核模块处理中修复

,

与其破解并在 kernel/module.c 中使用“.ctors.65435”而不是“.ctors”,正确的解决方案是更改模块链接器脚本以将所有“.ctors.*”部分与 .ctors 部分结合起来。 “演员”部分:

diff --git a/scripts/module-common.lds b/scripts/module-common.lds
index d61b9e8678e8..0cd6aabaa460 100644
--- a/scripts/module-common.lds
+++ b/scripts/module-common.lds
@@ -20,6 +20,7 @@ SECTIONS {
        __kcrctab_unused_gpl    0 : { *(SORT(___kcrctab_unused_gpl+*)) }
        __kcrctab_gpl_future    0 : { *(SORT(___kcrctab_gpl_future+*)) }

+       .ctors                  0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) }
        .init_array             0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) }

        __jump_table            0 : ALIGN(8) { KEEP(*(__jump_table)) }
--
2.29.2

这将恢复模块的代码覆盖率。