问题描述
我们在不同的架构(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
这将恢复模块的代码覆盖率。