diff --git a/xen/common/coverage/Makefile b/xen/common/coverage/Makefile
index 63f98c71d6..75d05909f8 100644
--- a/xen/common/coverage/Makefile
+++ b/xen/common/coverage/Makefile
@@ -5,7 +5,9 @@ obj-y += $(call cc-ifversion,-lt,0407, \
 		gcc_3_4.o, $(call cc-ifversion,-lt,0409, \
 		gcc_4_7.o, $(call cc-ifversion,-lt,0500, \
 		gcc_4_9.o, $(call cc-ifversion,-lt,0700, \
-		gcc_5.o, gcc_7.o))))
+		gcc_5.o, $(call cc-ifversion,-lt,1000, \
+		gcc_7.o,  $(call cc-ifversion,-lt,1200, \
+		gcc_10.o, gcc_12.o))))))
 else
 obj-y += llvm.o
 endif
diff --git a/xen/common/coverage/gcc_10.c b/xen/common/coverage/gcc_10.c
new file mode 100644
index 0000000000..f03f5c0f21
--- /dev/null
+++ b/xen/common/coverage/gcc_10.c
@@ -0,0 +1,31 @@
+/*
+ *  This code provides functions to handle gcc's profiling data format
+ *  introduced with gcc 10.
+ *
+ *  For a better understanding, refer to gcc source:
+ *  gcc/gcov-io.h
+ *  libgcc/libgcov.c
+ *
+ *  Uses gcc-internal data definitions.
+ */
+
+#include "gcov.h"
+
+#if GCC_VERSION < 100000 || GCC_VERSION > 120000
+#error "Wrong version of GCC used to compile gcov"
+#endif
+
+#define GCOV_COUNTERS 8
+#define GCOV_UNIT_SIZE 1
+
+#include "gcc_4_7.c"
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/common/coverage/gcc_12.c b/xen/common/coverage/gcc_12.c
new file mode 100644
index 0000000000..a551b6a51b
--- /dev/null
+++ b/xen/common/coverage/gcc_12.c
@@ -0,0 +1,32 @@
+/*
+ *  This code provides functions to handle gcc's profiling data format
+ *  introduced with gcc 12.
+ *
+ *  For a better understanding, refer to gcc source:
+ *  gcc/gcov-io.h
+ *  libgcc/libgcov.c
+ *
+ *  Uses gcc-internal data definitions.
+ */
+
+#include "gcov.h"
+
+#if GCC_VERSION < 120000
+#error "Wrong version of GCC used to compile gcov"
+#endif
+
+#define GCOV_COUNTERS 8
+/* Since GCC 12.1, sizes are in BYTES and not in WORDS (4B). */
+#define GCOV_UNIT_SIZE 4
+
+#include "gcc_4_7.c"
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/common/coverage/gcc_4_7.c b/xen/common/coverage/gcc_4_7.c
index 25b4a8bcdc..bf99062fcb 100644
--- a/xen/common/coverage/gcc_4_7.c
+++ b/xen/common/coverage/gcc_4_7.c
@@ -27,6 +27,7 @@
 #  error "Wrong version of GCC used to compile gcov"
 # endif
 #define GCOV_COUNTERS 8
+#define GCOV_UNIT_SIZE 1
 #endif
 
 #define GCOV_TAG_FUNCTION_LENGTH        3
@@ -88,6 +89,10 @@ struct gcov_info {
     unsigned int version;
     struct gcov_info *next;
     unsigned int stamp;
+#if (GCC_VERSION >= 120000)
+    /*  GCC 12.1 introduced a checksum field */
+    unsigned int checksum;
+#endif
     const char *filename;
     void (*merge[GCOV_COUNTERS])(gcov_type *, unsigned int);
     unsigned int n_functions;
@@ -160,13 +165,18 @@ size_t gcov_info_to_gcda(char *buffer, const struct gcov_info *info)
     pos += gcov_store_uint32(buffer, pos, info->version);
     pos += gcov_store_uint32(buffer, pos, info->stamp);
 
+#if (GCC_VERSION >= 120000)
+    /* Use zero as checksum of the compilation unit. */
+    pos += gcov_store_uint32(buffer, pos, 0);
+#endif
+
     for ( fi_idx = 0; fi_idx < info->n_functions; fi_idx++ )
     {
         fi_ptr = info->functions[fi_idx];
 
         /* Function record. */
         pos += gcov_store_uint32(buffer, pos, GCOV_TAG_FUNCTION);
-        pos += gcov_store_uint32(buffer, pos, GCOV_TAG_FUNCTION_LENGTH);
+        pos += gcov_store_uint32(buffer, pos, GCOV_TAG_FUNCTION_LENGTH * GCOV_UNIT_SIZE);
         pos += gcov_store_uint32(buffer, pos, fi_ptr->ident);
         pos += gcov_store_uint32(buffer, pos, fi_ptr->lineno_checksum);
         pos += gcov_store_uint32(buffer, pos, fi_ptr->cfg_checksum);
@@ -181,7 +191,7 @@ size_t gcov_info_to_gcda(char *buffer, const struct gcov_info *info)
             /* Counter record. */
             pos += gcov_store_uint32(buffer, pos,
                                      GCOV_TAG_FOR_COUNTER(ct_idx));
-            pos += gcov_store_uint32(buffer, pos, ci_ptr->num * 2);
+            pos += gcov_store_uint32(buffer, pos, ci_ptr->num * 2 * GCOV_UNIT_SIZE);
 
             for ( cv_idx = 0; cv_idx < ci_ptr->num; cv_idx++ )
                 pos += gcov_store_uint64(buffer, pos, ci_ptr->values[cv_idx]);
diff --git a/xen/common/coverage/gcc_4_9.c b/xen/common/coverage/gcc_4_9.c
index dcea961936..ded89ab9d2 100644
--- a/xen/common/coverage/gcc_4_9.c
+++ b/xen/common/coverage/gcc_4_9.c
@@ -19,6 +19,7 @@
 #endif
 
 #define GCOV_COUNTERS 9
+#define GCOV_UNIT_SIZE 1
 
 #include "gcc_4_7.c"
 
diff --git a/xen/common/coverage/gcc_5.c b/xen/common/coverage/gcc_5.c
index 6e0d276f3b..fe39053311 100644
--- a/xen/common/coverage/gcc_5.c
+++ b/xen/common/coverage/gcc_5.c
@@ -19,6 +19,7 @@
 #endif
 
 #define GCOV_COUNTERS 10
+#define GCOV_UNIT_SIZE 1
 
 #include "gcc_4_7.c"
 
diff --git a/xen/common/coverage/gcc_7.c b/xen/common/coverage/gcc_7.c
index 3962eb4c76..edfdc9fa44 100644
--- a/xen/common/coverage/gcc_7.c
+++ b/xen/common/coverage/gcc_7.c
@@ -11,11 +11,12 @@
 
 #include "gcov.h"
 
-#if GCC_VERSION < 70000
+#if GCC_VERSION < 70000 || GCC_VERSION >= 100000
 #error "Wrong version of GCC used to compile gcov"
 #endif
 
 #define GCOV_COUNTERS 9
+#define GCOV_UNIT_SIZE 1
 
 #include "gcc_4_7.c"
 
