This patch updates the LLVM profile raw format in
`xen/common/coverage/llvm.c` from version 4 to version 10,
enabling compatibility with LLVM versions 19 and 20.
While the patch supports only one version:
1. It seems better to support one version than no version --
the current profile version 4 is not compatible with
LLVM version 11 or later
2. The patch could be extended to support multiple
LLVM profile versions, e.g., from 5 to 10
The llvm-cov toolchain, with its Source-based Code Coverage,
offers two substantial advantages over gcov:
- More accurate coverage reporting when compiler optimizations
are enabled, ensuring better analysis of optimized code.
- Better tracking of coverage across inlined function boundaries,
critical for complex control flows in Xen.
Overall, this change would enhance Xen's code coverage analysis
capabilities by leveraging the latest LLVM toolchain improvements,
particularly for safety-critical hypervisor code.
The patch modifies only `xen/common/coverage/llvm.c`,
maintaining API compatibility while enabling modern toolchain support.
Testing was performed with LLVM 19 and 20 to confirm functionality.
---
xen/common/coverage/llvm.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/xen/common/coverage/llvm.c b/xen/common/coverage/llvm.c
index 517b2aa8c2..3da82c6cda 100644
--- a/xen/common/coverage/llvm.c
+++ b/xen/common/coverage/llvm.c
@@ -44,27 +44,37 @@
((uint64_t)'f' << 16) | ((uint64_t)'R' << 8) | ((uint64_t)129)
#endif
-#define LLVM_PROFILE_VERSION 4
-#define LLVM_PROFILE_NUM_KINDS 2
+#define LLVM_PROFILE_VERSION 10
+#define LLVM_PROFILE_NUM_KINDS 3
struct llvm_profile_data {
uint64_t name_ref;
uint64_t function_hash;
- void *counter;
+ void *relative_counter;
+ void *relative_bitmap;
void *function;
void *values;
uint32_t nr_counters;
uint16_t nr_value_sites[LLVM_PROFILE_NUM_KINDS];
+ uint32_t numbitmap_bytes;
};
struct llvm_profile_header {
uint64_t magic;
uint64_t version;
- uint64_t data_size;
- uint64_t counters_size;
+ uint64_t binary_ids_size;
+ uint64_t num_data;
+ uint64_t padding_bytes_before_counters;
+ uint64_t num_counters;
+ uint64_t padding_bytes_after_counters;
+ uint64_t num_bitmap_bytes;
+ uint64_t padding_bytes_after_bitmap_bytes;
uint64_t names_size;
uint64_t counters_delta;
+ uint64_t bitmap_delta;
uint64_t names_delta;
+ uint64_t num_vtables;
+ uint64_t vnames_size;
uint64_t value_kind_last;
};
@@ -110,7 +120,7 @@ static int cf_check dump(
.data_size = (END_DATA - START_DATA) / sizeof(struct llvm_profile_data),
.counters_size = (END_COUNTERS - START_COUNTERS) / sizeof(uint64_t),
.names_size = END_NAMES - START_NAMES,
- .counters_delta = (uintptr_t)START_COUNTERS,
+ .counters_delta = (uintptr_t)(START_COUNTERS - START_DATA),
.names_delta = (uintptr_t)START_NAMES,
.value_kind_last = LLVM_PROFILE_NUM_KINDS - 1,
};
--
2.49.0
This change enables compatibility for measuring code coverage
with Clang versions 14 through 20 by supporting their
respective raw profile formats.
1- Add support for LLVM raw profile versions 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 14 through 20 on both
ARM and X86 platform
Signed-off-by: Saman Dehghan <samaan.dehghan@gmail.com>
---
xen/common/coverage/llvm.c | 78 +++++++++++++++++++++++++++-----------
xen/include/xen/types.h | 1 +
2 files changed, 57 insertions(+), 22 deletions(-)
diff --git a/xen/common/coverage/llvm.c b/xen/common/coverage/llvm.c
index 517b2aa8c2..f92f10654c 100644
--- a/xen/common/coverage/llvm.c
+++ b/xen/common/coverage/llvm.c
@@ -44,27 +44,55 @@
((uint64_t)'f' << 16) | ((uint64_t)'R' << 8) | ((uint64_t)129)
#endif
-#define LLVM_PROFILE_VERSION 4
+#if __clang_major__ >= 19
+#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
+#else
+#error "Unsupported Clang version"
+#endif
struct llvm_profile_data {
uint64_t name_ref;
uint64_t function_hash;
- void *counter;
- void *function;
- void *values;
+ intptr_t *relative_counter;
+#if __clang_major__ >= 18
+ intptr_t *relative_bitmap;
+#endif
+ intptr_t *function;
+ intptr_t *values;
uint32_t nr_counters;
uint16_t nr_value_sites[LLVM_PROFILE_NUM_KINDS];
+#if __clang_major__ >= 18
+ uint32_t numbitmap_bytes;
+#endif
};
struct llvm_profile_header {
uint64_t magic;
uint64_t version;
- uint64_t data_size;
- uint64_t counters_size;
+ uint64_t binary_ids_size;
+ uint64_t num_data;
+ uint64_t padding_bytes_before_counters;
+ uint64_t num_counters;
+ uint64_t padding_bytes_after_counters;
+ uint64_t num_bitmap_bytes;
+ uint64_t padding_bytes_after_bitmap_bytes;
uint64_t names_size;
+#if __clang_major__ >= 18
uint64_t counters_delta;
+ uint64_t bitmap_delta;
+#endif
uint64_t names_delta;
+#if __clang_major__ >= 19
+ uint64_t num_vtables;
+ uint64_t vnames_size;
+#endif
uint64_t value_kind_last;
};
@@ -76,19 +104,20 @@ struct llvm_profile_header {
*/
int __llvm_profile_runtime;
-extern const struct llvm_profile_data __start___llvm_prf_data[];
-extern const struct llvm_profile_data __stop___llvm_prf_data[];
-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[];
+extern char __start___llvm_prf_data[];
+extern char __stop___llvm_prf_data[];
+extern char __start___llvm_prf_names[];
+extern char __stop___llvm_prf_names[];
+extern char __start___llvm_prf_cnts[];
+extern char __stop___llvm_prf_cnts[];
+
+#define START_DATA ((const char *)__start___llvm_prf_data)
+#define END_DATA ((const char *)__stop___llvm_prf_data)
+#define START_NAMES ((const char *)__start___llvm_prf_names)
+#define END_NAMES ((const char *)__stop___llvm_prf_names)
+#define START_COUNTERS ((char *)__start___llvm_prf_cnts)
+#define END_COUNTERS ((char *)__stop___llvm_prf_cnts)
-#define START_DATA ((const void *)__start___llvm_prf_data)
-#define END_DATA ((const void *)__stop___llvm_prf_data)
-#define START_NAMES ((const void *)__start___llvm_prf_names)
-#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)
static void cf_check reset_counters(void)
{
@@ -107,10 +136,15 @@ 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),
- .names_size = END_NAMES - START_NAMES,
- .counters_delta = (uintptr_t)START_COUNTERS,
+ .binary_ids_size = 0,
+ .num_data = (((intptr_t)END_DATA + sizeof(struct
llvm_profile_data) - 1)
+ - (intptr_t)START_DATA) / sizeof(struct llvm_profile_data),
+ .padding_bytes_before_counters = 0,
+ .num_counters = (((intptr_t)END_COUNTERS + sizeof(uint64_t) - 1)
+ - (intptr_t)START_COUNTERS) / sizeof(uint64_t),
+ .padding_bytes_after_counters = 0,
+ .names_size = (END_NAMES - START_NAMES) * sizeof(char),
+ .counters_delta = (uintptr_t)START_COUNTERS -
(uintptr_t)START_DATA,
.names_delta = (uintptr_t)START_NAMES,
.value_kind_last = LLVM_PROFILE_NUM_KINDS - 1,
};
diff --git a/xen/include/xen/types.h b/xen/include/xen/types.h
index 73ddccbbd5..799bfe0b95 100644
--- a/xen/include/xen/types.h
+++ b/xen/include/xen/types.h
@@ -18,6 +18,7 @@ typedef signed long ssize_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __INTPTR_TYPE__ intptr_t;
/*
* Users of this macro are expected to pass a positive value.
--
2.49.0
On Mon, Sep 15, 2025 at 11:56 AM Saman Dehghan <samaan.dehghan@gmail.com>
wrote:
> This patch updates the LLVM profile raw format in
> `xen/common/coverage/llvm.c` from version 4 to version 10,
> enabling compatibility with LLVM versions 19 and 20.
> While the patch supports only one version:
> 1. It seems better to support one version than no version --
> the current profile version 4 is not compatible with
> LLVM version 11 or later
> 2. The patch could be extended to support multiple
> LLVM profile versions, e.g., from 5 to 10
>
> The llvm-cov toolchain, with its Source-based Code Coverage,
> offers two substantial advantages over gcov:
> - More accurate coverage reporting when compiler optimizations
> are enabled, ensuring better analysis of optimized code.
> - Better tracking of coverage across inlined function boundaries,
> critical for complex control flows in Xen.
>
> Overall, this change would enhance Xen's code coverage analysis
> capabilities by leveraging the latest LLVM toolchain improvements,
> particularly for safety-critical hypervisor code.
>
> The patch modifies only `xen/common/coverage/llvm.c`,
> maintaining API compatibility while enabling modern toolchain support.
> Testing was performed with LLVM 19 and 20 to confirm functionality.
>
> ---
> xen/common/coverage/llvm.c | 22 ++++++++++++++++------
> 1 file changed, 16 insertions(+), 6 deletions(-)
>
> diff --git a/xen/common/coverage/llvm.c b/xen/common/coverage/llvm.c
> index 517b2aa8c2..3da82c6cda 100644
> --- a/xen/common/coverage/llvm.c
> +++ b/xen/common/coverage/llvm.c
> @@ -44,27 +44,37 @@
> ((uint64_t)'f' << 16) | ((uint64_t)'R' << 8) | ((uint64_t)129)
> #endif
>
> -#define LLVM_PROFILE_VERSION 4
> -#define LLVM_PROFILE_NUM_KINDS 2
> +#define LLVM_PROFILE_VERSION 10
> +#define LLVM_PROFILE_NUM_KINDS 3
>
> struct llvm_profile_data {
> uint64_t name_ref;
> uint64_t function_hash;
> - void *counter;
> + void *relative_counter;
> + void *relative_bitmap;
> void *function;
> void *values;
> uint32_t nr_counters;
> uint16_t nr_value_sites[LLVM_PROFILE_NUM_KINDS];
> + uint32_t numbitmap_bytes;
> };
>
> struct llvm_profile_header {
> uint64_t magic;
> uint64_t version;
> - uint64_t data_size;
> - uint64_t counters_size;
> + uint64_t binary_ids_size;
> + uint64_t num_data;
> + uint64_t padding_bytes_before_counters;
> + uint64_t num_counters;
> + uint64_t padding_bytes_after_counters;
> + uint64_t num_bitmap_bytes;
> + uint64_t padding_bytes_after_bitmap_bytes;
> uint64_t names_size;
> uint64_t counters_delta;
> + uint64_t bitmap_delta;
> uint64_t names_delta;
> + uint64_t num_vtables;
> + uint64_t vnames_size;
> uint64_t value_kind_last;
> };
>
> @@ -110,7 +120,7 @@ static int cf_check dump(
> .data_size = (END_DATA - START_DATA) / sizeof(struct
> llvm_profile_data),
> .counters_size = (END_COUNTERS - START_COUNTERS) /
> sizeof(uint64_t),
> .names_size = END_NAMES - START_NAMES,
> - .counters_delta = (uintptr_t)START_COUNTERS,
> + .counters_delta = (uintptr_t)(START_COUNTERS - START_DATA),
> .names_delta = (uintptr_t)START_NAMES,
> .value_kind_last = LLVM_PROFILE_NUM_KINDS - 1,
> };
> --
> 2.49.0
>
>
On 15.09.2025 18:56, Saman Dehghan wrote: > This patch updates the LLVM profile raw format in > `xen/common/coverage/llvm.c` from version 4 to version 10, > enabling compatibility with LLVM versions 19 and 20. > While the patch supports only one version: > 1. It seems better to support one version than no version -- > the current profile version 4 is not compatible with > LLVM version 11 or later Indeed. > 2. The patch could be extended to support multiple > LLVM profile versions, e.g., from 5 to 10 Would certainly be nice, perhaps as a follow-on. > The llvm-cov toolchain, with its Source-based Code Coverage, > offers two substantial advantages over gcov: > - More accurate coverage reporting when compiler optimizations > are enabled, ensuring better analysis of optimized code. > - Better tracking of coverage across inlined function boundaries, > critical for complex control flows in Xen. > > Overall, this change would enhance Xen's code coverage analysis > capabilities by leveraging the latest LLVM toolchain improvements, > particularly for safety-critical hypervisor code. > > The patch modifies only `xen/common/coverage/llvm.c`, > maintaining API compatibility while enabling modern toolchain support. > Testing was performed with LLVM 19 and 20 to confirm functionality. > > --- What's missing in any event is your Signed-off-by:. Jan
Saman,
> -----Original Message-----
> From: Xen-devel <xen-devel-bounces@lists.xenproject.org> On Behalf Of Saman Dehghan
> Sent: Monday, September 15, 2025 9:56 AM
> To: xen-devel@lists.xenproject.org
> Cc: Saman Dehghan <samaan.dehghan@gmail.com>; Jan Beulich <jbeulich@suse.com>
> Subject: [EXTERNAL] [llvm coverage] Update LLVM profile raw format from v4 to v10
>
> EXT email: be mindful of links/attachments.
>
>
>
> This patch updates the LLVM profile raw format in `xen/common/coverage/llvm.c` from version 4 to version 10, enabling compatibility with LLVM versions 19 and 20.
> While the patch supports only one version:
> 1. It seems better to support one version than no version --
> the current profile version 4 is not compatible with
> LLVM version 11 or later
I'd suggest adding logic to check the LLVM version and conditionally add the struct field(s). e.g., "__clang__", "__clang_major__" and "__clang_minor__".
[snip]
>
> Overall, this change would enhance Xen's code coverage analysis capabilities by leveraging the latest LLVM toolchain improvements, particularly for safety-critical hypervisor code.
>
> The patch modifies only `xen/common/coverage/llvm.c`, maintaining API compatibility while enabling modern toolchain support.
> Testing was performed with LLVM 19 and 20 to confirm functionality.
Please elaborate on your testing. You could put it under the --- so it's show what you did but not included in the git description when merged.
E.g. what dom0 was used, command sequence, etc.
[snip]
> struct llvm_profile_header {
> uint64_t magic;
> uint64_t version;
> - uint64_t data_size;
> - uint64_t counters_size;
> + uint64_t binary_ids_size;
> + uint64_t num_data;
> + uint64_t padding_bytes_before_counters;
> + uint64_t num_counters;
> + uint64_t padding_bytes_after_counters;
> + uint64_t num_bitmap_bytes;
The above line has extra spaces at the end.
> + uint64_t padding_bytes_after_bitmap_bytes;
> uint64_t names_size;
> uint64_t counters_delta;
> + uint64_t bitmap_delta;
> uint64_t names_delta;
> + uint64_t num_vtables;
> + uint64_t vnames_size;
> uint64_t value_kind_last;
> };
>
Steps I used to build
- I checked out latest master (656b9ca03b)
- Applied this patch
- menuconfig'd to disable livepatch and enable coverage
- make dist-xen clang=y
I got the following.
CC common/coverage/llvm.o
common/coverage/llvm.c:120:10: error: field designator 'data_size' does not refer to any field in type 'struct llvm_profile_header'
.data_size = (END_DATA - START_DATA) / sizeof(struct llvm_profile_data),
^
common/coverage/llvm.c:121:10: error: field designator 'counters_size' does not refer to any field in type 'struct llvm_profile_header'
.counters_size = (END_COUNTERS - START_COUNTERS) / sizeof(uint64_t),
^
Best Regards,
Matt
This change enables compatibility for measuring code coverage
with Clang versions 14 through 20 by supporting their
respective raw profile formats.
1- Add support for LLVM raw profile versions 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 14 through 20 on both ARM and X86 platform
Signed-off-by: Saman Dehghan <samaan.dehghan@gmail.com>
---
xen/common/coverage/llvm.c | 78 +++++++++++++++++++++++++++-----------
xen/include/xen/types.h | 1 +
2 files changed, 57 insertions(+), 22 deletions(-)
diff --git a/xen/common/coverage/llvm.c b/xen/common/coverage/llvm.c
index 517b2aa8c2..f92f10654c 100644
--- a/xen/common/coverage/llvm.c
+++ b/xen/common/coverage/llvm.c
@@ -44,27 +44,55 @@
((uint64_t)'f' << 16) | ((uint64_t)'R' << 8) | ((uint64_t)129)
#endif
-#define LLVM_PROFILE_VERSION 4
+#if __clang_major__ >= 19
+#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
+#else
+#error "Unsupported Clang version"
+#endif
struct llvm_profile_data {
uint64_t name_ref;
uint64_t function_hash;
- void *counter;
- void *function;
- void *values;
+ intptr_t *relative_counter;
+#if __clang_major__ >= 18
+ intptr_t *relative_bitmap;
+#endif
+ intptr_t *function;
+ intptr_t *values;
uint32_t nr_counters;
uint16_t nr_value_sites[LLVM_PROFILE_NUM_KINDS];
+#if __clang_major__ >= 18
+ uint32_t numbitmap_bytes;
+#endif
};
struct llvm_profile_header {
uint64_t magic;
uint64_t version;
- uint64_t data_size;
- uint64_t counters_size;
+ uint64_t binary_ids_size;
+ uint64_t num_data;
+ uint64_t padding_bytes_before_counters;
+ uint64_t num_counters;
+ uint64_t padding_bytes_after_counters;
+ uint64_t num_bitmap_bytes;
+ uint64_t padding_bytes_after_bitmap_bytes;
uint64_t names_size;
+#if __clang_major__ >= 18
uint64_t counters_delta;
+ uint64_t bitmap_delta;
+#endif
uint64_t names_delta;
+#if __clang_major__ >= 19
+ uint64_t num_vtables;
+ uint64_t vnames_size;
+#endif
uint64_t value_kind_last;
};
@@ -76,19 +104,20 @@ struct llvm_profile_header {
*/
int __llvm_profile_runtime;
-extern const struct llvm_profile_data __start___llvm_prf_data[];
-extern const struct llvm_profile_data __stop___llvm_prf_data[];
-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[];
+extern char __start___llvm_prf_data[];
+extern char __stop___llvm_prf_data[];
+extern char __start___llvm_prf_names[];
+extern char __stop___llvm_prf_names[];
+extern char __start___llvm_prf_cnts[];
+extern char __stop___llvm_prf_cnts[];
+
+#define START_DATA ((const char *)__start___llvm_prf_data)
+#define END_DATA ((const char *)__stop___llvm_prf_data)
+#define START_NAMES ((const char *)__start___llvm_prf_names)
+#define END_NAMES ((const char *)__stop___llvm_prf_names)
+#define START_COUNTERS ((char *)__start___llvm_prf_cnts)
+#define END_COUNTERS ((char *)__stop___llvm_prf_cnts)
-#define START_DATA ((const void *)__start___llvm_prf_data)
-#define END_DATA ((const void *)__stop___llvm_prf_data)
-#define START_NAMES ((const void *)__start___llvm_prf_names)
-#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)
static void cf_check reset_counters(void)
{
@@ -107,10 +136,15 @@ 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),
- .names_size = END_NAMES - START_NAMES,
- .counters_delta = (uintptr_t)START_COUNTERS,
+ .binary_ids_size = 0,
+ .num_data = (((intptr_t)END_DATA + sizeof(struct llvm_profile_data) - 1)
+ - (intptr_t)START_DATA) / sizeof(struct llvm_profile_data),
+ .padding_bytes_before_counters = 0,
+ .num_counters = (((intptr_t)END_COUNTERS + sizeof(uint64_t) - 1)
+ - (intptr_t)START_COUNTERS) / sizeof(uint64_t),
+ .padding_bytes_after_counters = 0,
+ .names_size = (END_NAMES - START_NAMES) * sizeof(char),
+ .counters_delta = (uintptr_t)START_COUNTERS - (uintptr_t)START_DATA,
.names_delta = (uintptr_t)START_NAMES,
.value_kind_last = LLVM_PROFILE_NUM_KINDS - 1,
};
diff --git a/xen/include/xen/types.h b/xen/include/xen/types.h
index 73ddccbbd5..799bfe0b95 100644
--- a/xen/include/xen/types.h
+++ b/xen/include/xen/types.h
@@ -18,6 +18,7 @@ typedef signed long ssize_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __INTPTR_TYPE__ intptr_t;
/*
* Users of this macro are expected to pass a positive value.
--
2.49.0
On Wed, Oct 01, 2025 at 05:09:52PM -0500, Saman Dehghan wrote:
> This change enables compatibility for measuring code coverage
> with Clang versions 14 through 20 by supporting their
> respective raw profile formats.
>
> 1- Add support for LLVM raw profile versions 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 14 through 20 on both ARM and X86 platform
>
> Signed-off-by: Saman Dehghan <samaan.dehghan@gmail.com>
> ---
> xen/common/coverage/llvm.c | 78 +++++++++++++++++++++++++++-----------
> xen/include/xen/types.h | 1 +
> 2 files changed, 57 insertions(+), 22 deletions(-)
>
> diff --git a/xen/common/coverage/llvm.c b/xen/common/coverage/llvm.c
> index 517b2aa8c2..f92f10654c 100644
> --- a/xen/common/coverage/llvm.c
> +++ b/xen/common/coverage/llvm.c
> @@ -44,27 +44,55 @@
> ((uint64_t)'f' << 16) | ((uint64_t)'R' << 8) | ((uint64_t)129)
> #endif
>
> -#define LLVM_PROFILE_VERSION 4
> +#if __clang_major__ >= 19
> +#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
> +#else
> +#error "Unsupported Clang version"
No strong opinion, but it would be nice if we could support all
profiles from clang >= 11, as that's the minimum stated clang version.
Again I don't know how much work this will involve, so not going to
insist.
It would be extremely helpful if clang could provide a set of builtin
functions for freestanding environments to handle the performance data
in an opaque way:
https://github.com/llvm/llvm-project/issues/123034
At a minimum it would be good if the compiler exported a define
signaling the profiling version it's using, as we could then fail the
build nicely if coverage support is enabled against a version of clang
we don't support. Right now anything >= 19 will assume to be using
profiling version 10, but that will go stale sooner or later.
> +#endif
>
> struct llvm_profile_data {
> uint64_t name_ref;
> uint64_t function_hash;
> - void *counter;
> - void *function;
> - void *values;
> + intptr_t *relative_counter;
> +#if __clang_major__ >= 18
> + intptr_t *relative_bitmap;
> +#endif
I would prefer if this was done based on LLVM_PROFILE_VERSION rather
than __clang_major__ (same for the instances below). The field are
related to the profile version implemented by the compiler, so it's
clearer if the check is against the profile version.
> + intptr_t *function;
> + intptr_t *values;
> uint32_t nr_counters;
> uint16_t nr_value_sites[LLVM_PROFILE_NUM_KINDS];
> +#if __clang_major__ >= 18
> + uint32_t numbitmap_bytes;
> +#endif
> };
>
> struct llvm_profile_header {
> uint64_t magic;
> uint64_t version;
> - uint64_t data_size;
> - uint64_t counters_size;
> + uint64_t binary_ids_size;
> + uint64_t num_data;
> + uint64_t padding_bytes_before_counters;
> + uint64_t num_counters;
> + uint64_t padding_bytes_after_counters;
> + uint64_t num_bitmap_bytes;
> + uint64_t padding_bytes_after_bitmap_bytes;
> uint64_t names_size;
> +#if __clang_major__ >= 18
> uint64_t counters_delta;
> + uint64_t bitmap_delta;
> +#endif
> uint64_t names_delta;
> +#if __clang_major__ >= 19
> + uint64_t num_vtables;
> + uint64_t vnames_size;
> +#endif
> uint64_t value_kind_last;
> };
>
> @@ -76,19 +104,20 @@ struct llvm_profile_header {
> */
> int __llvm_profile_runtime;
>
> -extern const struct llvm_profile_data __start___llvm_prf_data[];
> -extern const struct llvm_profile_data __stop___llvm_prf_data[];
> -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[];
> +extern char __start___llvm_prf_data[];
> +extern char __stop___llvm_prf_data[];
> +extern char __start___llvm_prf_names[];
> +extern char __stop___llvm_prf_names[];
> +extern char __start___llvm_prf_cnts[];
> +extern char __stop___llvm_prf_cnts[];
What's the point of defining those uniformly as char instead of the
more accurate types used previously?
> +#define START_DATA ((const char *)__start___llvm_prf_data)
> +#define END_DATA ((const char *)__stop___llvm_prf_data)
> +#define START_NAMES ((const char *)__start___llvm_prf_names)
> +#define END_NAMES ((const char *)__stop___llvm_prf_names)
> +#define START_COUNTERS ((char *)__start___llvm_prf_cnts)
> +#define END_COUNTERS ((char *)__stop___llvm_prf_cnts)
>
> -#define START_DATA ((const void *)__start___llvm_prf_data)
> -#define END_DATA ((const void *)__stop___llvm_prf_data)
> -#define START_NAMES ((const void *)__start___llvm_prf_names)
> -#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)
Kind of similar question here, what's the benefit of using char *
instead of void *?
> static void cf_check reset_counters(void)
> {
> @@ -107,10 +136,15 @@ 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),
> - .names_size = END_NAMES - START_NAMES,
> - .counters_delta = (uintptr_t)START_COUNTERS,
> + .binary_ids_size = 0,
We don't usually explicitly initialize fields to 0, as that's the
default already.
> + .num_data = (((intptr_t)END_DATA + sizeof(struct llvm_profile_data) - 1)
> + - (intptr_t)START_DATA) / sizeof(struct llvm_profile_data),
> + .padding_bytes_before_counters = 0,
> + .num_counters = (((intptr_t)END_COUNTERS + sizeof(uint64_t) - 1)
> + - (intptr_t)START_COUNTERS) / sizeof(uint64_t),
> + .padding_bytes_after_counters = 0,
> + .names_size = (END_NAMES - START_NAMES) * sizeof(char),
> + .counters_delta = (uintptr_t)START_COUNTERS - (uintptr_t)START_DATA,
The casting here seems not uniform. Why is intptr_t used in some
instances while others use uintptr_t?
I also think you could just use void *, as Xen uses the GCC extension
that allows arithmetic on void pointers.
Thanks, Roger.
On 01/10/2025 11:09 pm, Saman Dehghan wrote:
> This change enables compatibility for measuring code coverage
> with Clang versions 14 through 20 by supporting their
> respective raw profile formats.
>
> 1- Add support for LLVM raw profile versions 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 14 through 20 on both ARM and X86 platform
>
> Signed-off-by: Saman Dehghan <samaan.dehghan@gmail.com>
CC-ing Oleksii. This should be considered for 4.21 at this point.
Coverage is an optional feature, off-by-default, but Xen does support
GCC and Clang (older Clang at least), and right now newer Clang simply
malfunctions.
I guess I should update
https://xenbits.xen.org/docs/latest/hypervisor-guide/code-coverage.html
given the new toolchain baselines.
> ---
> xen/common/coverage/llvm.c | 78 +++++++++++++++++++++++++++-----------
> xen/include/xen/types.h | 1 +
> 2 files changed, 57 insertions(+), 22 deletions(-)
>
> diff --git a/xen/common/coverage/llvm.c b/xen/common/coverage/llvm.c
> index 517b2aa8c2..f92f10654c 100644
> --- a/xen/common/coverage/llvm.c
> +++ b/xen/common/coverage/llvm.c
> @@ -44,27 +44,55 @@
> ((uint64_t)'f' << 16) | ((uint64_t)'R' << 8) | ((uint64_t)129)
> #endif
>
> -#define LLVM_PROFILE_VERSION 4
> +#if __clang_major__ >= 19
> +#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
> +#else
> +#error "Unsupported Clang version"
> +#endif
Does this exclude Clang 13?
Our baseline is 11 or later. How hard would it be to support those too?
>
> struct llvm_profile_data {
> uint64_t name_ref;
> uint64_t function_hash;
> - void *counter;
> - void *function;
> - void *values;
> + intptr_t *relative_counter;
> +#if __clang_major__ >= 18
> + intptr_t *relative_bitmap;
> +#endif
> + intptr_t *function;
> + intptr_t *values;
> uint32_t nr_counters;
> uint16_t nr_value_sites[LLVM_PROFILE_NUM_KINDS];
> +#if __clang_major__ >= 18
> + uint32_t numbitmap_bytes;
> +#endif
> };
>
> struct llvm_profile_header {
> uint64_t magic;
> uint64_t version;
> - uint64_t data_size;
> - uint64_t counters_size;
> + uint64_t binary_ids_size;
> + uint64_t num_data;
> + uint64_t padding_bytes_before_counters;
> + uint64_t num_counters;
> + uint64_t padding_bytes_after_counters;
> + uint64_t num_bitmap_bytes;
> + uint64_t padding_bytes_after_bitmap_bytes;
> uint64_t names_size;
> +#if __clang_major__ >= 18
> uint64_t counters_delta;
> + uint64_t bitmap_delta;
> +#endif
> uint64_t names_delta;
> +#if __clang_major__ >= 19
> + uint64_t num_vtables;
> + uint64_t vnames_size;
> +#endif
> uint64_t value_kind_last;
> };
>
> @@ -76,19 +104,20 @@ struct llvm_profile_header {
> */
> int __llvm_profile_runtime;
>
> -extern const struct llvm_profile_data __start___llvm_prf_data[];
> -extern const struct llvm_profile_data __stop___llvm_prf_data[];
> -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[];
> +extern char __start___llvm_prf_data[];
> +extern char __stop___llvm_prf_data[];
> +extern char __start___llvm_prf_names[];
> +extern char __stop___llvm_prf_names[];
> +extern char __start___llvm_prf_cnts[];
> +extern char __stop___llvm_prf_cnts[];
> +
> +#define START_DATA ((const char *)__start___llvm_prf_data)
> +#define END_DATA ((const char *)__stop___llvm_prf_data)
> +#define START_NAMES ((const char *)__start___llvm_prf_names)
> +#define END_NAMES ((const char *)__stop___llvm_prf_names)
> +#define START_COUNTERS ((char *)__start___llvm_prf_cnts)
> +#define END_COUNTERS ((char *)__stop___llvm_prf_cnts)
>
> -#define START_DATA ((const void *)__start___llvm_prf_data)
> -#define END_DATA ((const void *)__stop___llvm_prf_data)
> -#define START_NAMES ((const void *)__start___llvm_prf_names)
> -#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)
Why change these from char to void ?
>
> static void cf_check reset_counters(void)
> {
> @@ -107,10 +136,15 @@ 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),
> - .names_size = END_NAMES - START_NAMES,
> - .counters_delta = (uintptr_t)START_COUNTERS,
> + .binary_ids_size = 0,
> + .num_data = (((intptr_t)END_DATA + sizeof(struct llvm_profile_data) - 1)
> + - (intptr_t)START_DATA) / sizeof(struct llvm_profile_data),
I can see why we might want to round-down END, but this doesn't need
casting to intptr_t irrespective of char vs void.
> + .padding_bytes_before_counters = 0,
> + .num_counters = (((intptr_t)END_COUNTERS + sizeof(uint64_t) - 1)
> + - (intptr_t)START_COUNTERS) / sizeof(uint64_t),
> + .padding_bytes_after_counters = 0,
> + .names_size = (END_NAMES - START_NAMES) * sizeof(char),
sizeof(char) is by definition 1.
> + .counters_delta = (uintptr_t)START_COUNTERS - (uintptr_t)START_DATA,
> .names_delta = (uintptr_t)START_NAMES,
> .value_kind_last = LLVM_PROFILE_NUM_KINDS - 1,
> };
> diff --git a/xen/include/xen/types.h b/xen/include/xen/types.h
> index 73ddccbbd5..799bfe0b95 100644
> --- a/xen/include/xen/types.h
> +++ b/xen/include/xen/types.h
> @@ -18,6 +18,7 @@ typedef signed long ssize_t;
>
> typedef __PTRDIFF_TYPE__ ptrdiff_t;
> typedef __UINTPTR_TYPE__ uintptr_t;
> +typedef __INTPTR_TYPE__ intptr_t;
>
> /*
> * Users of this macro are expected to pass a positive value.
On 10/2/25 11:53 AM, Andrew Cooper wrote:
> On 01/10/2025 11:09 pm, Saman Dehghan wrote:
>> This change enables compatibility for measuring code coverage
>> with Clang versions 14 through 20 by supporting their
>> respective raw profile formats.
>>
>> 1- Add support for LLVM raw profile versions 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 14 through 20 on both ARM and X86 platform
>>
>> Signed-off-by: Saman Dehghan<samaan.dehghan@gmail.com>
> CC-ing Oleksii. This should be considered for 4.21 at this point.
>
> Coverage is an optional feature, off-by-default, but Xen does support
> GCC and Clang (older Clang at least), and right now newer Clang simply
> malfunctions.
In this case, I agree that it should be considered for 4.21:
Release-Acked-By: Oleksii Kurochko<oleksii.kurochko@gmail.com>
Thanks.
~ Oleksii
>
> I guess I should update
> https://xenbits.xen.org/docs/latest/hypervisor-guide/code-coverage.html
> given the new toolchain baselines.
>
>> ---
>> xen/common/coverage/llvm.c | 78 +++++++++++++++++++++++++++-----------
>> xen/include/xen/types.h | 1 +
>> 2 files changed, 57 insertions(+), 22 deletions(-)
>>
>> diff --git a/xen/common/coverage/llvm.c b/xen/common/coverage/llvm.c
>> index 517b2aa8c2..f92f10654c 100644
>> --- a/xen/common/coverage/llvm.c
>> +++ b/xen/common/coverage/llvm.c
>> @@ -44,27 +44,55 @@
>> ((uint64_t)'f' << 16) | ((uint64_t)'R' << 8) | ((uint64_t)129)
>> #endif
>>
>> -#define LLVM_PROFILE_VERSION 4
>> +#if __clang_major__ >= 19
>> +#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
>> +#else
>> +#error "Unsupported Clang version"
>> +#endif
> Does this exclude Clang 13?
>
> Our baseline is 11 or later. How hard would it be to support those too?
>
>>
>> struct llvm_profile_data {
>> uint64_t name_ref;
>> uint64_t function_hash;
>> - void *counter;
>> - void *function;
>> - void *values;
>> + intptr_t *relative_counter;
>> +#if __clang_major__ >= 18
>> + intptr_t *relative_bitmap;
>> +#endif
>> + intptr_t *function;
>> + intptr_t *values;
>> uint32_t nr_counters;
>> uint16_t nr_value_sites[LLVM_PROFILE_NUM_KINDS];
>> +#if __clang_major__ >= 18
>> + uint32_t numbitmap_bytes;
>> +#endif
>> };
>>
>> struct llvm_profile_header {
>> uint64_t magic;
>> uint64_t version;
>> - uint64_t data_size;
>> - uint64_t counters_size;
>> + uint64_t binary_ids_size;
>> + uint64_t num_data;
>> + uint64_t padding_bytes_before_counters;
>> + uint64_t num_counters;
>> + uint64_t padding_bytes_after_counters;
>> + uint64_t num_bitmap_bytes;
>> + uint64_t padding_bytes_after_bitmap_bytes;
>> uint64_t names_size;
>> +#if __clang_major__ >= 18
>> uint64_t counters_delta;
>> + uint64_t bitmap_delta;
>> +#endif
>> uint64_t names_delta;
>> +#if __clang_major__ >= 19
>> + uint64_t num_vtables;
>> + uint64_t vnames_size;
>> +#endif
>> uint64_t value_kind_last;
>> };
>>
>> @@ -76,19 +104,20 @@ struct llvm_profile_header {
>> */
>> int __llvm_profile_runtime;
>>
>> -extern const struct llvm_profile_data __start___llvm_prf_data[];
>> -extern const struct llvm_profile_data __stop___llvm_prf_data[];
>> -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[];
>> +extern char __start___llvm_prf_data[];
>> +extern char __stop___llvm_prf_data[];
>> +extern char __start___llvm_prf_names[];
>> +extern char __stop___llvm_prf_names[];
>> +extern char __start___llvm_prf_cnts[];
>> +extern char __stop___llvm_prf_cnts[];
>> +
>> +#define START_DATA ((const char *)__start___llvm_prf_data)
>> +#define END_DATA ((const char *)__stop___llvm_prf_data)
>> +#define START_NAMES ((const char *)__start___llvm_prf_names)
>> +#define END_NAMES ((const char *)__stop___llvm_prf_names)
>> +#define START_COUNTERS ((char *)__start___llvm_prf_cnts)
>> +#define END_COUNTERS ((char *)__stop___llvm_prf_cnts)
>>
>> -#define START_DATA ((const void *)__start___llvm_prf_data)
>> -#define END_DATA ((const void *)__stop___llvm_prf_data)
>> -#define START_NAMES ((const void *)__start___llvm_prf_names)
>> -#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)
> Why change these from char to void ?
>
>>
>> static void cf_check reset_counters(void)
>> {
>> @@ -107,10 +136,15 @@ 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),
>> - .names_size = END_NAMES - START_NAMES,
>> - .counters_delta = (uintptr_t)START_COUNTERS,
>> + .binary_ids_size = 0,
>> + .num_data = (((intptr_t)END_DATA + sizeof(struct llvm_profile_data) - 1)
>> + - (intptr_t)START_DATA) / sizeof(struct llvm_profile_data),
> I can see why we might want to round-down END, but this doesn't need
> casting to intptr_t irrespective of char vs void.
>
>> + .padding_bytes_before_counters = 0,
>> + .num_counters = (((intptr_t)END_COUNTERS + sizeof(uint64_t) - 1)
>> + - (intptr_t)START_COUNTERS) / sizeof(uint64_t),
>> + .padding_bytes_after_counters = 0,
>> + .names_size = (END_NAMES - START_NAMES) * sizeof(char),
> sizeof(char) is by definition 1.
>
>> + .counters_delta = (uintptr_t)START_COUNTERS - (uintptr_t)START_DATA,
>> .names_delta = (uintptr_t)START_NAMES,
>> .value_kind_last = LLVM_PROFILE_NUM_KINDS - 1,
>> };
>> diff --git a/xen/include/xen/types.h b/xen/include/xen/types.h
>> index 73ddccbbd5..799bfe0b95 100644
>> --- a/xen/include/xen/types.h
>> +++ b/xen/include/xen/types.h
>> @@ -18,6 +18,7 @@ typedef signed long ssize_t;
>>
>> typedef __PTRDIFF_TYPE__ ptrdiff_t;
>> typedef __UINTPTR_TYPE__ uintptr_t;
>> +typedef __INTPTR_TYPE__ intptr_t;
>>
>> /*
>> * Users of this macro are expected to pass a positive value.
This change enables compatibility for measuring code coverage
with Clang versions 14 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 coverage code in x86.
Signed-off-by: Saman Dehghan <samaan.dehghan@gmail.com>
---
xen/arch/x86/xen.lds.S | 6 ++++
xen/common/coverage/llvm.c | 73 ++++++++++++++++++++++++++++++++++----
xen/include/xen/xen.lds.h | 18 ++++++++++
3 files changed, 91 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..e3272a546f 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 __clang_major__ >= 18
+ void *relative_bitmap;
+#endif
void *function;
void *values;
uint32_t nr_counters;
uint16_t nr_value_sites[LLVM_PROFILE_NUM_KINDS];
+#if __clang_major__ >= 18
+ uint32_t numbitmap_bytes;
+#endif
};
struct llvm_profile_header {
uint64_t magic;
uint64_t version;
- uint64_t data_size;
- uint64_t counters_size;
+#if __clang_major__ >= 13
+ 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 __clang_major__ >= 18
+ uint64_t num_bitmap_bytes;
+ uint64_t padding_bytes_after_bitmap_bytes;
+#endif
uint64_t names_size;
uint64_t counters_delta;
+#if __clang_major__ >= 18
+ uint64_t bitmap_delta;
+#endif
uint64_t names_delta;
+#if __clang_major__ >= 19 && __clang_major__ <= 20
+ uint64_t num_vtables;
+ uint64_t vnames_size;
+#endif
uint64_t value_kind_last;
};
@@ -107,11 +145,34 @@ 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),
+#if __clang_major__ >= 13
+ .binary_ids_size = 0,
+#endif
+ .num_data = ((END_DATA + sizeof(struct llvm_profile_data) - 1)
+ - START_DATA) / sizeof(struct llvm_profile_data),
+ .padding_bytes_before_counters = 0,
+ .num_counters = ((END_COUNTERS + sizeof(uint64_t) - 1)
+ - START_COUNTERS) / sizeof(uint64_t),
+ .padding_bytes_after_counters = 0,
+#if __clang_major__ >= 18
+ .num_bitmap_bytes = 0,
+ .padding_bytes_after_bitmap_bytes = 0,
+#endif
.names_size = END_NAMES - START_NAMES,
+#if __clang_major__ >= 14
+ .counters_delta = START_COUNTERS - START_DATA,
+#else
.counters_delta = (uintptr_t)START_COUNTERS,
+#endif
+
+#if __clang_major__ >= 18
+ .bitmap_delta = 0,
+#endif
.names_delta = (uintptr_t)START_NAMES,
+#if __clang_major__ >= 19 && __clang_major__ <= 20
+ .num_vtables = 0,
+ .vnames_size = 0,
+#endif
.value_kind_last = LLVM_PROFILE_NUM_KINDS - 1,
};
unsigned int off = 0;
diff --git a/xen/include/xen/xen.lds.h b/xen/include/xen/xen.lds.h
index b126dfe887..42550a85a2 100644
--- a/xen/include/xen/xen.lds.h
+++ b/xen/include/xen/xen.lds.h
@@ -81,6 +81,24 @@
.stab.index 0 : { *(.stab.index) } \
.stab.indexstr 0 : { *(.stab.indexstr) }
+#if defined(CONFIG_COVERAGE) && defined(CONFIG_CC_IS_CLANG)
+
+#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)
+#else
+#define LLVM_COV_RW_DATA
+#define LLVM_COV_RO_DATA
+#define LLVM_COV_DEBUG
+#endif
/*
* ELF sections.
*
--
2.49.0
The subject should have a "xen: " prefix, as this applies to the
hypervisor and not other
On 24/10/2025 1:16 am, Saman Dehghan wrote:
> This change enables compatibility for measuring code coverage
> with Clang versions 14 through 20 by supporting their
Stale 14? It looks to be 11 now.
> 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 coverage code in x86.
>
> Signed-off-by: Saman Dehghan <samaan.dehghan@gmail.com>
> ---
When sending multiple revisions, it's customary to put a short list here
if what you've changed from the previous revision.
Also, you didn't accumulate your release ack from v2.
Release-Acked-By: Oleksii Kurochko <oleksii.kurochko@gmail.com>
> xen/arch/x86/xen.lds.S | 6 ++++
> xen/common/coverage/llvm.c | 73 ++++++++++++++++++++++++++++++++++----
> xen/include/xen/xen.lds.h | 18 ++++++++++
> 3 files changed, 91 insertions(+), 6 deletions(-)
>
> diff --git a/xen/common/coverage/llvm.c b/xen/common/coverage/llvm.c
> index 517b2aa8c2..e3272a546f 100644
> --- a/xen/common/coverage/llvm.c
> +++ b/xen/common/coverage/llvm.c
> @@ -107,11 +145,34 @@ 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),
> +#if __clang_major__ >= 13
> + .binary_ids_size = 0,
> +#endif
> + .num_data = ((END_DATA + sizeof(struct llvm_profile_data) - 1)
> + - START_DATA) / sizeof(struct llvm_profile_data),
There's a helper for this expression.
DIV_ROUND_UP(END_DATA - START_DATA, sizeof(llvm_profile_data))
> + .padding_bytes_before_counters = 0,
> + .num_counters = ((END_COUNTERS + sizeof(uint64_t) - 1)
> + - START_COUNTERS) / sizeof(uint64_t),
DIV_ROUND_UP(END_COUNTERS - START_COUNTERS, sizeof(uint64_t))
> + .padding_bytes_after_counters = 0,
> +#if __clang_major__ >= 18
> + .num_bitmap_bytes = 0,
> + .padding_bytes_after_bitmap_bytes = 0,
> +#endif
> .names_size = END_NAMES - START_NAMES,
> +#if __clang_major__ >= 14
> + .counters_delta = START_COUNTERS - START_DATA,
> +#else
> .counters_delta = (uintptr_t)START_COUNTERS,
> +#endif
> +
> +#if __clang_major__ >= 18
> + .bitmap_delta = 0,
> +#endif
> .names_delta = (uintptr_t)START_NAMES,
> +#if __clang_major__ >= 19 && __clang_major__ <= 20
> + .num_vtables = 0,
> + .vnames_size = 0,
> +#endif
Because this is a structure initialiser, everything set explicitly to 0
can be omitted. This removes all #ifdef-ary except the .counters_delta
I believe, as well as the .padding_byte_* fields.
The resulting diff is far smaller.
> .value_kind_last = LLVM_PROFILE_NUM_KINDS - 1,
> };
> unsigned int off = 0;
> diff --git a/xen/include/xen/xen.lds.h b/xen/include/xen/xen.lds.h
> index b126dfe887..42550a85a2 100644
> --- a/xen/include/xen/xen.lds.h
> +++ b/xen/include/xen/xen.lds.h
> @@ -81,6 +81,24 @@
> .stab.index 0 : { *(.stab.index) } \
> .stab.indexstr 0 : { *(.stab.indexstr) }
>
> +#if defined(CONFIG_COVERAGE) && defined(CONFIG_CC_IS_CLANG)
> +
> +#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)
> +#else
> +#define LLVM_COV_RW_DATA
> +#define LLVM_COV_RO_DATA
> +#define LLVM_COV_DEBUG
> +#endif
Newline here.
But, there's no problem stating sections which are unused. I think the
outer #if/#else can be dropped.
Otherwise, Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
I can fix these all up on commit, seeing as it's release acked for 4.21
~Andrew
On Fri, Oct 24, 2025 at 4:33 AM Andrew Cooper <andrew.cooper3@citrix.com> wrote:
>
> The subject should have a "xen: " prefix, as this applies to the
> hypervisor and not other
>
> On 24/10/2025 1:16 am, Saman Dehghan wrote:
> > This change enables compatibility for measuring code coverage
> > with Clang versions 14 through 20 by supporting their
>
> Stale 14? It looks to be 11 now.
Sorry for the mistake. I meant "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 coverage code in x86.
> >
> > Signed-off-by: Saman Dehghan <samaan.dehghan@gmail.com>
> > ---
>
> When sending multiple revisions, it's customary to put a short list here
> if what you've changed from the previous revision.
Changes since version 2:
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.
>
> Also, you didn't accumulate your release ack from v2.
>
> Release-Acked-By: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Sorry we missed this. Thanks for reminding us.
>
> > xen/arch/x86/xen.lds.S | 6 ++++
> > xen/common/coverage/llvm.c | 73 ++++++++++++++++++++++++++++++++++----
> > xen/include/xen/xen.lds.h | 18 ++++++++++
> > 3 files changed, 91 insertions(+), 6 deletions(-)
> >
> > diff --git a/xen/common/coverage/llvm.c b/xen/common/coverage/llvm.c
> > index 517b2aa8c2..e3272a546f 100644
> > --- a/xen/common/coverage/llvm.c
> > +++ b/xen/common/coverage/llvm.c
> > @@ -107,11 +145,34 @@ 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),
> > +#if __clang_major__ >= 13
> > + .binary_ids_size = 0,
> > +#endif
> > + .num_data = ((END_DATA + sizeof(struct llvm_profile_data) - 1)
> > + - START_DATA) / sizeof(struct llvm_profile_data),
>
> There's a helper for this expression.
>
> DIV_ROUND_UP(END_DATA - START_DATA, sizeof(llvm_profile_data))
>
> > + .padding_bytes_before_counters = 0,
> > + .num_counters = ((END_COUNTERS + sizeof(uint64_t) - 1)
> > + - START_COUNTERS) / sizeof(uint64_t),
>
> DIV_ROUND_UP(END_COUNTERS - START_COUNTERS, sizeof(uint64_t))
>
>
> > + .padding_bytes_after_counters = 0,
> > +#if __clang_major__ >= 18
> > + .num_bitmap_bytes = 0,
> > + .padding_bytes_after_bitmap_bytes = 0,
> > +#endif
> > .names_size = END_NAMES - START_NAMES,
> > +#if __clang_major__ >= 14
> > + .counters_delta = START_COUNTERS - START_DATA,
> > +#else
> > .counters_delta = (uintptr_t)START_COUNTERS,
> > +#endif
> > +
> > +#if __clang_major__ >= 18
> > + .bitmap_delta = 0,
> > +#endif
> > .names_delta = (uintptr_t)START_NAMES,
> > +#if __clang_major__ >= 19 && __clang_major__ <= 20
> > + .num_vtables = 0,
> > + .vnames_size = 0,
> > +#endif
>
> Because this is a structure initialiser, everything set explicitly to 0
> can be omitted. This removes all #ifdef-ary except the .counters_delta
> I believe, as well as the .padding_byte_* fields.
>
Is it undefined behaviour to leave struct members uninitialized for
local variables?
> The resulting diff is far smaller.
>
> > .value_kind_last = LLVM_PROFILE_NUM_KINDS - 1,
> > };
> > unsigned int off = 0;
> > diff --git a/xen/include/xen/xen.lds.h b/xen/include/xen/xen.lds.h
> > index b126dfe887..42550a85a2 100644
> > --- a/xen/include/xen/xen.lds.h
> > +++ b/xen/include/xen/xen.lds.h
> > @@ -81,6 +81,24 @@
> > .stab.index 0 : { *(.stab.index) } \
> > .stab.indexstr 0 : { *(.stab.indexstr) }
> >
> > +#if defined(CONFIG_COVERAGE) && defined(CONFIG_CC_IS_CLANG)
> > +
> > +#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)
> > +#else
> > +#define LLVM_COV_RW_DATA
> > +#define LLVM_COV_RO_DATA
> > +#define LLVM_COV_DEBUG
> > +#endif
>
> Newline here.
>
> But, there's no problem stating sections which are unused. I think the
> outer #if/#else can be dropped.
>
> Otherwise, Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
>
> I can fix these all up on commit, seeing as it's release acked for 4.21
Thank you for offering to fix them up. Let me know how I can help or
if I need to send another version.
Thanks,
Saman
>
> ~Andrew
On 25/10/2025 12:38 am, Saman Dehghan wrote:
>>> + .padding_bytes_after_counters = 0,
>>> +#if __clang_major__ >= 18
>>> + .num_bitmap_bytes = 0,
>>> + .padding_bytes_after_bitmap_bytes = 0,
>>> +#endif
>>> .names_size = END_NAMES - START_NAMES,
>>> +#if __clang_major__ >= 14
>>> + .counters_delta = START_COUNTERS - START_DATA,
>>> +#else
>>> .counters_delta = (uintptr_t)START_COUNTERS,
>>> +#endif
>>> +
>>> +#if __clang_major__ >= 18
>>> + .bitmap_delta = 0,
>>> +#endif
>>> .names_delta = (uintptr_t)START_NAMES,
>>> +#if __clang_major__ >= 19 && __clang_major__ <= 20
>>> + .num_vtables = 0,
>>> + .vnames_size = 0,
>>> +#endif
>> Because this is a structure initialiser, everything set explicitly to 0
>> can be omitted. This removes all #ifdef-ary except the .counters_delta
>> I believe, as well as the .padding_byte_* fields.
>>
> Is it undefined behaviour to leave struct members uninitialized for
> local variables?
They are well defined as 0 when using a structure initialiser.
>
>> The resulting diff is far smaller.
>>
>>> .value_kind_last = LLVM_PROFILE_NUM_KINDS - 1,
>>> };
>>> unsigned int off = 0;
>>> diff --git a/xen/include/xen/xen.lds.h b/xen/include/xen/xen.lds.h
>>> index b126dfe887..42550a85a2 100644
>>> --- a/xen/include/xen/xen.lds.h
>>> +++ b/xen/include/xen/xen.lds.h
>>> @@ -81,6 +81,24 @@
>>> .stab.index 0 : { *(.stab.index) } \
>>> .stab.indexstr 0 : { *(.stab.indexstr) }
>>>
>>> +#if defined(CONFIG_COVERAGE) && defined(CONFIG_CC_IS_CLANG)
>>> +
>>> +#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)
>>> +#else
>>> +#define LLVM_COV_RW_DATA
>>> +#define LLVM_COV_RO_DATA
>>> +#define LLVM_COV_DEBUG
>>> +#endif
>> Newline here.
>>
>> But, there's no problem stating sections which are unused. I think the
>> outer #if/#else can be dropped.
>>
>> Otherwise, Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
>>
>> I can fix these all up on commit, seeing as it's release acked for 4.21
> Thank you for offering to fix them up. Let me know how I can help or
> if I need to send another version.
This is the version with the fixups I suggested, run through CI:
https://gitlab.com/xen-project/hardware/xen-staging/-/pipelines/2118913271
https://gitlab.com/xen-project/hardware/xen-staging/-/commit/c06dadb80a1e4058c7cdef4144a7e4c4799a38a7
However, one further thing I noticed. On v2, Roger asked you to express
struct llvm_profile_{header,data} in terms of LLVM_PROFILE_VERSION,
rather than __clang_major__.
If you want to start from the version I cleaned up, and then submit a v4
addressing Roger's feedback, please feel free. This will save needing
to fix it up later.
~Andrew
On 24.10.2025 02:16, Saman Dehghan wrote:
> This change enables compatibility for measuring code coverage
> with Clang versions 14 through 20 by supporting their
> respective raw profile formats.
Isn't the 14 here stale now?
> 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 coverage code in x86.
>
> Signed-off-by: Saman Dehghan <samaan.dehghan@gmail.com>
> ---
> xen/arch/x86/xen.lds.S | 6 ++++
> xen/common/coverage/llvm.c | 73 ++++++++++++++++++++++++++++++++++----
> xen/include/xen/xen.lds.h | 18 ++++++++++
> 3 files changed, 91 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
Since only x86 is documented to support building with Clang, adding just to
x86's linker script is likely fine.
Oleksii, what's your thought towards still taking this for 4.21?
In any event, a ChangeLog entry should likely be added.
Jan
Tested with Clang 20.1.8 on Debian bookworm x86_64 and arm64.
Carry this if appropriate:
Tested-by: Wentao Zhang <wentaoz5@illinois.edu>
Steps for build:
$ make CC=/lib/llvm-20/bin/clang -C xen defconfig
$ pushd xen
$ kconfig-tweak -d LIVEPATCH
$ kconfig-tweak -e COVERAGE
# The below two are Arm only
$ kconfig-tweak -e UNSUPPORTED
$ kconfig-tweak -e ACPI
$ popd
$ make CC=/lib/llvm-20/bin/clang -C xen olddefconfig
$ /usr/bin/time -v make CC=/lib/llvm-20/bin/clang -j$(nproc) efi-y= dist-xen
$ sudo make CC=/lib/llvm-20/bin/clang -j$(nproc) efi-y= install-xen
$ sudo update-grub
Steps after reinstall:
$ COVERAGE_REPORT_DIR=`mktemp -d`
$ XEN_BUILD=$HOME/v4
$ sudo xencov read | tee >/dev/null default.profraw
$ file default.profraw
$ /lib/llvm-20/bin/llvm-profdata merge default.profraw -o default.profdata
$ file default.profdata
$ /lib/llvm-20/bin/llvm-cov show \
-instr-profile default.profdata \
-output-dir $COVERAGE_REPORT_DIR \
-show-directory-coverage \
-show-branches=count \
-use-color=false \
$XEN_BUILD/xen/xen-syms
Example reports:
$ less $COVERAGE_REPORT_DIR/index.txt
$ less $COVERAGE_REPORT_DIR/coverage/$XEN_BUILD/xen/common/coverage/llvm.c.txt
Notes:
1. On x86_64, LD=ld.lld also works (in fact, faster). On arm64, the build
would fail.
2. On arm64, a workaround is needed regardless of the linker:
diff --git a/xen/arch/arm/arm64/vfp.c b/xen/arch/arm/arm64/vfp.c
index c4f89c7b0e..dbe87f3f34 100644
--- a/xen/arch/arm/arm64/vfp.c
+++ b/xen/arch/arm/arm64/vfp.c
@@ -4,6 +4,7 @@
#include <asm/vfp.h>
#include <asm/arm64/sve.h>
+__attribute__((target("+fp+simd")))
static inline void save_state(uint64_t *fpregs)
{
asm volatile("stp q0, q1, [%1, #16 * 0]\n\t"
@@ -25,6 +26,7 @@ static inline void save_state(uint64_t *fpregs)
: "=Q" (*fpregs) : "r" (fpregs));
}
+__attribute__((target("+fp+simd")))
static inline void restore_state(const uint64_t *fpregs)
{
asm volatile("ldp q0, q1, [%1, #16 * 0]\n\t"
@@ -46,6 +48,7 @@ static inline void restore_state(const uint64_t *fpregs)
: : "Q" (*fpregs), "r" (fpregs));
}
+__attribute__((target("+fp+simd")))
void vfp_save_state(struct vcpu *v)
{
if ( !cpu_has_fp )
@@ -62,6 +65,7 @@ void vfp_save_state(struct vcpu *v)
v->arch.vfp.fpexc32_el2 = READ_SYSREG(FPEXC32_EL2);
}
+__attribute__((target("+fp+simd")))
void vfp_restore_state(struct vcpu *v)
{
if ( !cpu_has_fp )
For the above two issues, see the report in [1].
Once this patch gets in, we can help update [2] with Andrew Cooper and
send a follow-up supporting llvm-cov MC/DC [3].
[1] https://lists.xenproject.org/archives/html/xen-devel/2025-10/msg00805.html
[2] https://xenbits.xen.org/docs/latest/hypervisor-guide/code-coverage.html
[3] https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#mc-dc-instrumentation
Thanks,
Wentao
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
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
© 2016 - 2025 Red Hat, Inc.