[PATCH v4] xen: Support LLVM raw profile versions 5, 6, 7, 8, 9, and 10

Saman Dehghan posted 1 patch 1 day, 22 hours ago
Patches applied successfully (tree, apply log)
git fetch https://gitlab.com/xen-project/patchew/xen tags/patchew/6f708273afb6de9c5f26f2c71c34c98e957904a0.1761599320.git.samaan.dehghan@gmail.com
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(-)
[PATCH v4] xen: Support LLVM raw profile versions 5, 6, 7, 8, 9, and 10
Posted by Saman Dehghan 1 day, 22 hours ago
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 <samaan.dehghan@gmail.com>
Release-Acked-By: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Tested-by: Wentao Zhang <wentaoz5@illinois.edu>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
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
Re: [PATCH v4] xen: Support LLVM raw profile versions 5, 6, 7, 8, 9, and 10
Posted by Andrew Cooper 1 day, 20 hours ago
On 27/10/2025 9:30 pm, Saman Dehghan wrote:
> 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 <samaan.dehghan@gmail.com>
> Release-Acked-By: Oleksii Kurochko <oleksii.kurochko@gmail.com>
> Tested-by: Wentao Zhang <wentaoz5@illinois.edu>
> Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
> ---
> 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.
> ---

Excellent.  Thankyou.  This all looks in order.  I've committed it.

~Andrew