This change enables compatibility for measuring code coverage with Clang versions 11 through 20 by supporting their respective raw profile formats.
1- Added support for LLVM raw profile versions 5, 6, 7, 8, 9, and 10. 2- Initialized llvm_profile_header for all versions based on llvm source code in compiler-rt/include/profile/InstrProfData.inc for each version. 3- We tested this patch for all Clang versions from 11 through 20 on x86 platform. 4- Fixed linking warnings related to LLVM profile sections in x86. Signed-off-by: Saman Dehghan <[email protected]> Release-Acked-By: Oleksii Kurochko <[email protected]> Tested-by: Wentao Zhang <[email protected]> Acked-by: Andrew Cooper <[email protected]> --- Changes from v3 to v4: 1- Use LLVM_PROFILE_VERSION in preprocessor conditionals instead of __clang_major__. 2- Use DIV_ROUND_UP helper. 3- Remove unnecessary zero initialization inside struct. 4- Remove fallback macro definitions in linker script. Changes from v2 to v3: 1- Additionally support raw profile version 5, 6, 7 in clang 11, 12, 13. 2- Fix coverage related linking warnings in x86. 3- Revert unnecessary type changes, casting, etc. --- xen/arch/x86/xen.lds.S | 6 +++++ xen/common/coverage/llvm.c | 54 +++++++++++++++++++++++++++++++++----- xen/include/xen/xen.lds.h | 13 +++++++++ 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S index 966e514f20..5d02f83a40 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -186,6 +186,8 @@ SECTIONS } PHDR(note) PHDR(text) #endif + LLVM_COV_RO_DATA + _erodata = .; . = ALIGN(SECTION_ALIGN); @@ -323,6 +325,8 @@ SECTIONS *(.data .data.*) } PHDR(text) + LLVM_COV_RW_DATA + DECL_SECTION(.bss) { __bss_start = .; *(.bss.page_aligned*) @@ -357,6 +361,8 @@ SECTIONS DWARF2_DEBUG_SECTIONS + LLVM_COV_DEBUG + #ifdef CONFIG_HYPERV_GUEST hv_hcall_page = ABSOLUTE(HV_HCALL_PAGE - XEN_VIRT_START + __XEN_VIRT_START); #endif diff --git a/xen/common/coverage/llvm.c b/xen/common/coverage/llvm.c index 517b2aa8c2..532889c857 100644 --- a/xen/common/coverage/llvm.c +++ b/xen/common/coverage/llvm.c @@ -44,27 +44,65 @@ ((uint64_t)'f' << 16) | ((uint64_t)'R' << 8) | ((uint64_t)129) #endif -#define LLVM_PROFILE_VERSION 4 +#if __clang_major__ >= 19 && __clang_major__ <= 20 +#define LLVM_PROFILE_VERSION 10 +#define LLVM_PROFILE_NUM_KINDS 3 +#elif __clang_major__ == 18 +#define LLVM_PROFILE_VERSION 9 #define LLVM_PROFILE_NUM_KINDS 2 +#elif __clang_major__ >= 14 +#define LLVM_PROFILE_VERSION 8 +#define LLVM_PROFILE_NUM_KINDS 2 +#elif __clang_major__ == 13 +#define LLVM_PROFILE_VERSION 7 +#define LLVM_PROFILE_NUM_KINDS 2 +#elif __clang_major__ >= 11 +#define LLVM_PROFILE_VERSION 5 +#define LLVM_PROFILE_NUM_KINDS 2 +#else +#error "LLVM coverage selected but an unsupported clang version is used" +#endif struct llvm_profile_data { uint64_t name_ref; uint64_t function_hash; - void *counter; + void *relative_counter; +#if LLVM_PROFILE_VERSION >= 9 + void *relative_bitmap; +#endif void *function; void *values; uint32_t nr_counters; uint16_t nr_value_sites[LLVM_PROFILE_NUM_KINDS]; +#if LLVM_PROFILE_VERSION >= 9 + uint32_t numbitmap_bytes; +#endif }; struct llvm_profile_header { uint64_t magic; uint64_t version; - uint64_t data_size; - uint64_t counters_size; +#if LLVM_PROFILE_VERSION >= 7 + uint64_t binary_ids_size; +#endif + uint64_t num_data; + uint64_t padding_bytes_before_counters; + uint64_t num_counters; + uint64_t padding_bytes_after_counters; +#if LLVM_PROFILE_VERSION >= 9 + uint64_t num_bitmap_bytes; + uint64_t padding_bytes_after_bitmap_bytes; +#endif uint64_t names_size; uint64_t counters_delta; +#if LLVM_PROFILE_VERSION >= 9 + uint64_t bitmap_delta; +#endif uint64_t names_delta; +#if LLVM_PROFILE_VERSION == 10 + uint64_t num_vtables; + uint64_t vnames_size; +#endif uint64_t value_kind_last; }; @@ -107,10 +145,14 @@ static int cf_check dump( struct llvm_profile_header header = { .magic = LLVM_PROFILE_MAGIC, .version = LLVM_PROFILE_VERSION, - .data_size = (END_DATA - START_DATA) / sizeof(struct llvm_profile_data), - .counters_size = (END_COUNTERS - START_COUNTERS) / sizeof(uint64_t), + .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)), .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 .names_delta = (uintptr_t)START_NAMES, .value_kind_last = LLVM_PROFILE_NUM_KINDS - 1, }; diff --git a/xen/include/xen/xen.lds.h b/xen/include/xen/xen.lds.h index b126dfe887..d80c895959 100644 --- a/xen/include/xen/xen.lds.h +++ b/xen/include/xen/xen.lds.h @@ -81,6 +81,19 @@ .stab.index 0 : { *(.stab.index) } \ .stab.indexstr 0 : { *(.stab.indexstr) } +/* Clang coverage sections. */ +#define LLVM_COV_RW_DATA \ + DECL_SECTION(__llvm_prf_cnts) { *(__llvm_prf_cnts) } \ + DECL_SECTION(__llvm_prf_data) { *(__llvm_prf_data) } \ + DECL_SECTION(__llvm_prf_bits) { *(__llvm_prf_bits) } + +#define LLVM_COV_RO_DATA \ + DECL_SECTION(__llvm_prf_names) { *(__llvm_prf_names) } + +#define LLVM_COV_DEBUG \ + DECL_DEBUG(__llvm_covfun, 8) \ + DECL_DEBUG(__llvm_covmap, 8) + /* * ELF sections. * -- 2.49.0
