Linux kernel 5.4 GCC 9.1.0 does not show code coverage

Viewed 264

we are using Linux kernel 5.4 with gcc 9.1.0 on different architectures (arm, arm64, x86_64). I am in charge of creating code coverage for kernel modules. I am not selecting the Linux kernel version nor the compiler version.

I am able to create code coverage for arm/arm64 and see the results in /sys/kernel/debugfs/gcov/... as usual. Also, loaded modules are visible in the gcov subdirectory.

However, for x86_64, I on only see /sys/kernel/debubfs/gcov/reset and nothing else, even if I set CONFIG_GCOV_COVERAGE_ALL=y.

The __gcov_init in kernel/gcov/base.c normally creates a

pr_info("version magic=...")

which is visible on arm/arm64 at boot time but not for x86_64. __gcov_init should be called for every source file as a gcc constructor and the first call creates the version magic message.

It seems to me that in my combination the code coverage function __gcov_init is never called in x86_64.

In the config, I use

CONFIG_GCOV_PROFILE=y
CONFIG_GCOV_FORMAT_4_7=y

and sometimes only for x86 CONFIG_GCOV_PROFILE_ALL=y. Nothing besides the "reset" file is visible /sys/kernel/debug/gcov/... for x86.

Any suggestions are welcome.

2 Answers

Code coverage constructors are now written in a ".ctors.65435" section (the number is possibly a constructor priority), but kernel 5.4 only knows ".ctors".

For the kernel internal code coverage, the following change (already in later kernels, e.g. 5.12) brings back code coverage

--- 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))               \

However, kernel/module.c does not know ".ctors.65435" either, and the modules compiled with gcc9 or gcc10 do not have a ".ctors" ELF sections. So I just changed as a 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",

This brings back module code coverage, but

.ctors.* for modules is not known in the newest 5.x kernel, and so I think this should be fixed in the Linux Kernel module handling

Instead of hacking and use ".ctors.65435" in kernel/module.c instead of ".ctors", the proper solution is to change the module linker script to combine all ".ctors.*" section with the ."ctors" section:

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

This brings back the code coverage for modules.

Related