Clang >= 18 supports Modified Condition/Decision Coverage (MC/DC). This patch enables the detection and usage of this feature when compiling Xen with Clang.
- Update detection logic in Kconfig to check for the required set of Clang flags for MC/DC: '-fprofile-instr-generate -fcoverage-mapping -fcoverage-mcdc'. This bundle is necessary because '-fcoverage-mcdc' requires '-fcoverage-mapping', which in turn requires '-fprofile-instr-generate'. - Update llvm.c to handle the profile format changes (bitmap section) required for MC/DC. - Guard -Wno-error=coverage-too-many-conditions with CONFIG_CC_IS_GCC to avoid passing a GCC-only warning option to Clang Signed-off-by: Saman Dehghan <[email protected]> --- xen/Kconfig | 2 +- xen/Rules.mk | 1 + xen/arch/x86/Makefile | 2 +- xen/common/coverage/llvm.c | 24 +++++++++++++++++++++++- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/xen/Kconfig b/xen/Kconfig index a5e5af3b76..5508993f02 100644 --- a/xen/Kconfig +++ b/xen/Kconfig @@ -53,7 +53,7 @@ config CC_HAS_ASM_GOTO_OUTPUT # Compiler supports -fcondition-coverage aka MC/DC config CC_HAS_MCDC - def_bool $(cc-option,-fcondition-coverage) + def_bool $(cc-option,-fcondition-coverage) || $(cc-option,-fprofile-instr-generate -fcoverage-mapping -fcoverage-mcdc) # Set code alignment. # diff --git a/xen/Rules.mk b/xen/Rules.mk index 24f447b957..57ea664f02 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -136,6 +136,7 @@ non-init-objects = $(filter-out %.init.o, $(obj-y) $(obj-bin-y) $(extra-y)) ifeq ($(CONFIG_CC_IS_CLANG),y) cov-cflags-$(CONFIG_COVERAGE) := -fprofile-instr-generate -fcoverage-mapping + cov-cflags-$(CONFIG_CONDITION_COVERAGE) += -fcoverage-mcdc else cov-cflags-$(CONFIG_COVERAGE) := -fprofile-arcs -ftest-coverage cov-cflags-$(CONFIG_CONDITION_COVERAGE) += -fcondition-coverage diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 407571c510..6c0ff67fa8 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -98,7 +98,7 @@ $(obj)/usercopy.o: CFLAGS-y += -iquote . ifneq ($(CONFIG_HVM),y) $(obj)/x86_emulate.o: CFLAGS-y += -Wno-unused-label endif -ifeq ($(CONFIG_CONDITION_COVERAGE),y) +ifeq ($(CONFIG_CONDITION_COVERAGE)$(CONFIG_CC_IS_GCC),yy) $(obj)/x86_emulate.o: CFLAGS-y += -Wno-error=coverage-too-many-conditions endif diff --git a/xen/common/coverage/llvm.c b/xen/common/coverage/llvm.c index 532889c857..a8c7e7e8d2 100644 --- a/xen/common/coverage/llvm.c +++ b/xen/common/coverage/llvm.c @@ -120,6 +120,10 @@ extern const char __start___llvm_prf_names[]; extern const char __stop___llvm_prf_names[]; extern uint64_t __start___llvm_prf_cnts[]; extern uint64_t __stop___llvm_prf_cnts[]; +#ifdef CONFIG_CONDITION_COVERAGE +extern const char __start___llvm_prf_bits[]; +extern const char __stop___llvm_prf_bits[]; +#endif #define START_DATA ((const void *)__start___llvm_prf_data) #define END_DATA ((const void *)__stop___llvm_prf_data) @@ -127,16 +131,25 @@ extern uint64_t __stop___llvm_prf_cnts[]; #define END_NAMES ((const void *)__stop___llvm_prf_names) #define START_COUNTERS ((void *)__start___llvm_prf_cnts) #define END_COUNTERS ((void *)__stop___llvm_prf_cnts) +#define START_BITMAP ((void *)__start___llvm_prf_bits) +#define END_BITMAP ((void *)__stop___llvm_prf_bits) static void cf_check reset_counters(void) { memset(START_COUNTERS, 0, END_COUNTERS - START_COUNTERS); +#ifdef CONFIG_CONDITION_COVERAGE + memset(START_BITMAP, 0, END_BITMAP - START_BITMAP); +#endif } static uint32_t cf_check get_size(void) { - return ROUNDUP(sizeof(struct llvm_profile_header) + END_DATA - START_DATA + + uint32_t size = ROUNDUP(sizeof(struct llvm_profile_header) + END_DATA - START_DATA + END_COUNTERS - START_COUNTERS + END_NAMES - START_NAMES, 8); +#ifdef CONFIG_CONDITION_COVERAGE + size += ROUNDUP(END_BITMAP - START_BITMAP, 8); +#endif + return size; } static int cf_check dump( @@ -147,11 +160,17 @@ static int cf_check dump( .version = LLVM_PROFILE_VERSION, .num_data = DIV_ROUND_UP(END_DATA - START_DATA, sizeof(struct llvm_profile_data)), .num_counters = DIV_ROUND_UP(END_COUNTERS - START_COUNTERS, sizeof(uint64_t)), +#if defined(CONFIG_CONDITION_COVERAGE) && LLVM_PROFILE_VERSION >= 9 + .num_bitmap_bytes = END_BITMAP - START_BITMAP, +#endif .names_size = END_NAMES - START_NAMES, #if LLVM_PROFILE_VERSION >= 8 .counters_delta = START_COUNTERS - START_DATA, #else .counters_delta = (uintptr_t)START_COUNTERS, +#endif +#if defined(CONFIG_CONDITION_COVERAGE) && LLVM_PROFILE_VERSION >= 9 + .bitmap_delta = START_BITMAP - START_DATA, #endif .names_delta = (uintptr_t)START_NAMES, .value_kind_last = LLVM_PROFILE_NUM_KINDS - 1, @@ -168,6 +187,9 @@ static int cf_check dump( APPEND_TO_BUFFER(&header, sizeof(header)); APPEND_TO_BUFFER(START_DATA, END_DATA - START_DATA); APPEND_TO_BUFFER(START_COUNTERS, END_COUNTERS - START_COUNTERS); +#if defined(CONFIG_CONDITION_COVERAGE) + APPEND_TO_BUFFER(START_BITMAP, END_BITMAP - START_BITMAP); +#endif APPEND_TO_BUFFER(START_NAMES, END_NAMES - START_NAMES); #undef APPEND_TO_BUFFER -- 2.49.0
