Blame SOURCES/v0.9.7-backport-MR-1315-Static-call-fixes.patch

cf3d8e
From 358743e6d8748510f4c9a71511d7ceea7c72f7aa Mon Sep 17 00:00:00 2001
cf3d8e
From: Josh Poimboeuf <jpoimboe@redhat.com>
cf3d8e
Date: Mon, 21 Nov 2022 19:23:07 -0800
cf3d8e
Subject: [PATCH] v0.9.7 backport: MR!1315 ("Static call fixes")
cf3d8e
cf3d8e
commit 87ad96760a3af0db294d44865dfa1703f57f5595
cf3d8e
Author: Josh Poimboeuf <jpoimboe@redhat.com>
cf3d8e
Date:   Mon Nov 21 19:23:07 2022 -0800
cf3d8e
cf3d8e
    create-diff-object: fix s390 special_section initializer spacing
cf3d8e
cf3d8e
    Align the s390 special_section initializers to improve readability and
cf3d8e
    for consistency with the rest.
cf3d8e
cf3d8e
    Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
cf3d8e
cf3d8e
commit 56bd8c4d0da1634f8549e7269f77a53e9d936a57
cf3d8e
Author: Josh Poimboeuf <jpoimboe@redhat.com>
cf3d8e
Date:   Mon Nov 21 19:27:23 2022 -0800
cf3d8e
cf3d8e
    create-diff-object: refactor jump label filtering
cf3d8e
cf3d8e
    Convert the hard-coded should_keep_jump_label() to a proper callback,
cf3d8e
    since static calls will need a similar filter.
cf3d8e
cf3d8e
    Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
cf3d8e
cf3d8e
commit f83218ad12a2d9e20d99d379c78974a576aa558c
cf3d8e
Author: Josh Poimboeuf <jpoimboe@redhat.com>
cf3d8e
Date:   Mon Nov 21 19:29:53 2022 -0800
cf3d8e
cf3d8e
    create-diff-object: detect unsupported static calls
cf3d8e
cf3d8e
    Similar to jump labels, static calls aren't supported when the static
cf3d8e
    call key was originally defined in a module rather than in vmlinux.
cf3d8e
    Detect those cases and either remove them (in the case of tracepoints)
cf3d8e
    or error out.
cf3d8e
cf3d8e
    Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
cf3d8e
cf3d8e
commit ab2397c03e31f0f697aa8bf943d70b4e5a7def54
cf3d8e
Author: Josh Poimboeuf <jpoimboe@redhat.com>
cf3d8e
Date:   Mon Nov 21 19:41:30 2022 -0800
cf3d8e
cf3d8e
    kpatch-macros: add KPATCH_STATIC_CALL()
cf3d8e
cf3d8e
    Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
cf3d8e
cf3d8e
commit 92c178b6a30a827c48db46ff4238501ec406a28e
cf3d8e
Author: Josh Poimboeuf <jpoimboe@redhat.com>
cf3d8e
Date:   Tue Nov 22 12:53:09 2022 -0800
cf3d8e
cf3d8e
    create-diff-object: use errx() instead of err()
cf3d8e
cf3d8e
    Otherwise on recent distros it appends the errno to the error message,
cf3d8e
    like:
cf3d8e
cf3d8e
      create-diff-object: ERROR: x86.o: kpatch_regenerate_special_section: 2633: Found 1 unsupported static call(s) in the patched code. Use KPATCH_STATIC_CALL() instead.: Success
cf3d8e
cf3d8e
    which is not what we want in most cases.
cf3d8e
cf3d8e
    Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
cf3d8e
cf3d8e
Signed-off-by: Yannick Cote <ycote@redhat.com>
cf3d8e
---
cf3d8e
 kmod/patch/kpatch-macros.h        |  11 +
cf3d8e
 kpatch-build/create-diff-object.c | 328 ++++++++++++++++++------------
cf3d8e
 kpatch-build/log.h                |   2 +-
cf3d8e
 3 files changed, 211 insertions(+), 130 deletions(-)
cf3d8e
cf3d8e
diff --git a/kmod/patch/kpatch-macros.h b/kmod/patch/kpatch-macros.h
cf3d8e
index 8e09702ea001..b797838849ca 100644
cf3d8e
--- a/kmod/patch/kpatch-macros.h
cf3d8e
+++ b/kmod/patch/kpatch-macros.h
cf3d8e
@@ -141,4 +141,15 @@ struct kpatch_post_unpatch_callback {
cf3d8e
 		printk(_fmt, ## __VA_ARGS__); \
cf3d8e
 })
cf3d8e
 
cf3d8e
+/*
cf3d8e
+ * KPATCH_STATIC_CALL macro
cf3d8e
+ *
cf3d8e
+ * Replace usages of static_call() with this macro, when create-diff-object
cf3d8e
+ * recommends it due to the original static call key living in a module.
cf3d8e
+ *
cf3d8e
+ * This converts the static call to a regular indirect call.
cf3d8e
+ */
cf3d8e
+#define KPATCH_STATIC_CALL(name) \
cf3d8e
+	((typeof(STATIC_CALL_TRAMP(name))*)(STATIC_CALL_KEY(name).func))
cf3d8e
+
cf3d8e
 #endif /* __KPATCH_MACROS_H_ */
cf3d8e
diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c
cf3d8e
index 7106b67cfd25..ddaa9b44f11e 100644
cf3d8e
--- a/kpatch-build/create-diff-object.c
cf3d8e
+++ b/kpatch-build/create-diff-object.c
cf3d8e
@@ -56,7 +56,7 @@
cf3d8e
 #define DIFF_FATAL(format, ...) \
cf3d8e
 ({ \
cf3d8e
 	fprintf(stderr, "ERROR: %s: " format "\n", childobj, ##__VA_ARGS__); \
cf3d8e
-	err(EXIT_STATUS_DIFF_FATAL, "unreconcilable difference"); \
cf3d8e
+	errx(EXIT_STATUS_DIFF_FATAL, "unreconcilable difference"); \
cf3d8e
 })
cf3d8e
 
cf3d8e
 char *childobj;
cf3d8e
@@ -71,6 +71,8 @@ enum loglevel loglevel = NORMAL;
cf3d8e
 
cf3d8e
 bool KLP_ARCH;
cf3d8e
 
cf3d8e
+int jump_label_errors, static_call_errors;
cf3d8e
+
cf3d8e
 /*******************
cf3d8e
  * Data structures
cf3d8e
  * ****************/
cf3d8e
@@ -78,6 +80,9 @@ struct special_section {
cf3d8e
 	char *name;
cf3d8e
 	enum architecture arch;
cf3d8e
 	int (*group_size)(struct kpatch_elf *kelf, int offset);
cf3d8e
+	bool (*group_filter)(struct lookup_table *lookup,
cf3d8e
+			     struct section *relasec, unsigned int offset,
cf3d8e
+			     unsigned int size);
cf3d8e
 };
cf3d8e
 
cf3d8e
 /*************
cf3d8e
@@ -2215,6 +2220,169 @@ static int fixup_group_size(struct kpatch_elf *kelf, int offset)
cf3d8e
 	return (int)(rela->addend - offset);
cf3d8e
 }
cf3d8e
 
cf3d8e
+static bool jump_table_group_filter(struct lookup_table *lookup,
cf3d8e
+				    struct section *relasec,
cf3d8e
+				    unsigned int group_offset,
cf3d8e
+				    unsigned int group_size)
cf3d8e
+{
cf3d8e
+	struct rela *code = NULL, *key = NULL, *rela;
cf3d8e
+	bool tracepoint = false, dynamic_debug = false;
cf3d8e
+	struct lookup_result symbol;
cf3d8e
+	int i = 0;
cf3d8e
+
cf3d8e
+	/*
cf3d8e
+	 * Here we hard-code knowledge about the contents of the jump_entry
cf3d8e
+	 * struct.  It has three fields: code, target, and key.  Each field has
cf3d8e
+	 * a relocation associated with it.
cf3d8e
+	 */
cf3d8e
+	list_for_each_entry(rela, &relasec->relas, list) {
cf3d8e
+		if (rela->offset >= group_offset &&
cf3d8e
+		    rela->offset < group_offset + group_size) {
cf3d8e
+			if (i == 0)
cf3d8e
+				code = rela;
cf3d8e
+			else if (i == 2)
cf3d8e
+				key = rela;
cf3d8e
+			i++;
cf3d8e
+		}
cf3d8e
+	}
cf3d8e
+
cf3d8e
+	if (i != 3 || !key || !code)
cf3d8e
+		ERROR("BUG: __jump_table has an unexpected format");
cf3d8e
+
cf3d8e
+	if (!strncmp(key->sym->name, "__tracepoint_", 13))
cf3d8e
+		tracepoint = true;
cf3d8e
+
cf3d8e
+	if (is_dynamic_debug_symbol(key->sym))
cf3d8e
+		dynamic_debug = true;
cf3d8e
+
cf3d8e
+	if (KLP_ARCH) {
cf3d8e
+		/*
cf3d8e
+		 * On older kernels (with .klp.arch support), jump labels
cf3d8e
+		 * aren't supported at all.  Error out when they occur in a
cf3d8e
+		 * replacement function, with the exception of tracepoints and
cf3d8e
+		 * dynamic debug printks.  An inert tracepoint or printk is
cf3d8e
+		 * harmless enough, but a broken jump label can cause
cf3d8e
+		 * unexpected behavior.
cf3d8e
+		 */
cf3d8e
+		if (tracepoint || dynamic_debug)
cf3d8e
+			return false;
cf3d8e
+
cf3d8e
+		/*
cf3d8e
+		 * This will be upgraded to an error after all jump labels have
cf3d8e
+		 * been reported.
cf3d8e
+		 */
cf3d8e
+		log_normal("Found a jump label at %s()+0x%lx, using key %s.  Jump labels aren't supported with this kernel.  Use static_key_enabled() instead.\n",
cf3d8e
+			   code->sym->name, code->addend, key->sym->name);
cf3d8e
+		jump_label_errors++;
cf3d8e
+		return false;
cf3d8e
+	}
cf3d8e
+
cf3d8e
+	/*
cf3d8e
+	 * On newer (5.8+) kernels, jump labels are supported in the case where
cf3d8e
+	 * the corresponding static key lives in vmlinux.  That's because such
cf3d8e
+	 * kernels apply vmlinux-specific .klp.rela sections at the same time
cf3d8e
+	 * (in the klp module load) as normal relas, before jump label init.
cf3d8e
+	 * On the other hand, jump labels based on static keys which are
cf3d8e
+	 * defined in modules aren't supported, because late module patching
cf3d8e
+	 * can result in the klp relas getting applied *after* the klp module's
cf3d8e
+	 * jump label init.
cf3d8e
+	 */
cf3d8e
+
cf3d8e
+	if (lookup_symbol(lookup, key->sym, &symbol) &&
cf3d8e
+	    strcmp(symbol.objname, "vmlinux")) {
cf3d8e
+
cf3d8e
+		/* The static key lives in a module -- not supported */
cf3d8e
+
cf3d8e
+		/* Inert tracepoints and dynamic debug printks are harmless */
cf3d8e
+		if (tracepoint || dynamic_debug)
cf3d8e
+			return false;
cf3d8e
+
cf3d8e
+		/*
cf3d8e
+		 * This will be upgraded to an error after all jump label
cf3d8e
+		 * errors have been reported.
cf3d8e
+		 */
cf3d8e
+		log_normal("Found a jump label at %s()+0x%lx, using key %s, which is defined in a module.  Use static_key_enabled() instead.\n",
cf3d8e
+			   code->sym->name, code->addend, key->sym->name);
cf3d8e
+		jump_label_errors++;
cf3d8e
+		return false;
cf3d8e
+	}
cf3d8e
+
cf3d8e
+	/* The static key lives in vmlinux or the patch module itself */
cf3d8e
+
cf3d8e
+	/*
cf3d8e
+	 * If the jump label key lives in the '__dyndbg' section, make sure
cf3d8e
+	 * the section gets included, because we don't use klp relocs for
cf3d8e
+	 * dynamic debug symbols.  For an example of such a key, see
cf3d8e
+	 * DYNAMIC_DEBUG_BRANCH().
cf3d8e
+	 */
cf3d8e
+	if (dynamic_debug)
cf3d8e
+		kpatch_include_symbol(key->sym);
cf3d8e
+
cf3d8e
+	return true;
cf3d8e
+}
cf3d8e
+
cf3d8e
+static bool static_call_sites_group_filter(struct lookup_table *lookup,
cf3d8e
+					   struct section *relasec,
cf3d8e
+					   unsigned int group_offset,
cf3d8e
+					   unsigned int group_size)
cf3d8e
+{
cf3d8e
+	struct rela *code = NULL, *key = NULL, *rela;
cf3d8e
+	bool tracepoint = false;
cf3d8e
+	struct lookup_result symbol;
cf3d8e
+	int i = 0;
cf3d8e
+
cf3d8e
+	/*
cf3d8e
+	 * Here we hard-code knowledge about the contents of the jump_entry
cf3d8e
+	 * struct.  It has three fields: code, target, and key.  Each field has
cf3d8e
+	 * a relocation associated with it.
cf3d8e
+	 */
cf3d8e
+	list_for_each_entry(rela, &relasec->relas, list) {
cf3d8e
+		if (rela->offset >= group_offset &&
cf3d8e
+		    rela->offset < group_offset + group_size) {
cf3d8e
+			if (i == 0)
cf3d8e
+				code = rela;
cf3d8e
+			else if (i == 1)
cf3d8e
+				key = rela;
cf3d8e
+			i++;
cf3d8e
+		}
cf3d8e
+	}
cf3d8e
+
cf3d8e
+	if (i != 2 || !key || !code)
cf3d8e
+		ERROR("BUG: .static_call_sites has an unexpected format");
cf3d8e
+
cf3d8e
+	if (!strncmp(key->sym->name, "__SCK__tp_func_", 15))
cf3d8e
+		tracepoint = true;
cf3d8e
+
cf3d8e
+	/*
cf3d8e
+	 * Static calls are only supported in the case where the corresponding
cf3d8e
+	 * static call key lives in vmlinux (see explanation in
cf3d8e
+	 * jump_table_group_filter).
cf3d8e
+	 */
cf3d8e
+
cf3d8e
+	if (lookup_symbol(lookup, key->sym, &symbol) &&
cf3d8e
+	    strcmp(symbol.objname, "vmlinux")) {
cf3d8e
+
cf3d8e
+		/* The key lives in a module -- not supported */
cf3d8e
+
cf3d8e
+		/* Inert tracepoints are harmless */
cf3d8e
+		if (tracepoint)
cf3d8e
+			return false;
cf3d8e
+
cf3d8e
+		/*
cf3d8e
+		 * This will be upgraded to an error after all static call
cf3d8e
+		 * errors have been reported.
cf3d8e
+		 */
cf3d8e
+		log_normal("Found a static call at %s()+0x%lx, using key %s, which is defined in a module.  Use KPATCH_STATIC_CALL() instead.\n",
cf3d8e
+			   code->sym->name, code->addend, key->sym->name);
cf3d8e
+		static_call_errors++;
cf3d8e
+		return false;
cf3d8e
+	}
cf3d8e
+
cf3d8e
+	/* The key lives in vmlinux or the patch module itself */
cf3d8e
+	return true;
cf3d8e
+}
cf3d8e
+
cf3d8e
+
cf3d8e
 static struct special_section special_sections[] = {
cf3d8e
 	{
cf3d8e
 		.name		= "__bug_table",
cf3d8e
@@ -2235,6 +2403,7 @@ static struct special_section special_sections[] = {
cf3d8e
 		.name		= "__jump_table",
cf3d8e
 		.arch		= X86_64 | PPC64 | S390,
cf3d8e
 		.group_size	= jump_table_group_size,
cf3d8e
+		.group_filter	= jump_table_group_filter,
cf3d8e
 	},
cf3d8e
 	{
cf3d8e
 		.name		= ".printk_index",
cf3d8e
@@ -2260,6 +2429,7 @@ static struct special_section special_sections[] = {
cf3d8e
 		.name		= ".static_call_sites",
cf3d8e
 		.arch		= X86_64,
cf3d8e
 		.group_size	= static_call_sites_group_size,
cf3d8e
+		.group_filter	= static_call_sites_group_filter,
cf3d8e
 	},
cf3d8e
 	{
cf3d8e
 		.name		= ".retpoline_sites",
cf3d8e
@@ -2297,138 +2467,36 @@ static struct special_section special_sections[] = {
cf3d8e
 		.group_size	= fixup_barrier_nospec_group_size,
cf3d8e
 	},
cf3d8e
 	{
cf3d8e
-		.name = ".s390_return_mem",
cf3d8e
-		.arch = S390,
cf3d8e
-		.group_size = s390_expolines_group_size,
cf3d8e
+		.name		= ".s390_return_mem",
cf3d8e
+		.arch		= S390,
cf3d8e
+		.group_size	= s390_expolines_group_size,
cf3d8e
 	},
cf3d8e
 	{
cf3d8e
-		.name = ".s390_return_reg",
cf3d8e
-		.arch = S390,
cf3d8e
-		.group_size = s390_expolines_group_size,
cf3d8e
+		.name		= ".s390_return_reg",
cf3d8e
+		.arch		= S390,
cf3d8e
+		.group_size	= s390_expolines_group_size,
cf3d8e
 	},
cf3d8e
 	{
cf3d8e
-		.name = ".s390_indirect_call",
cf3d8e
-		.arch = S390,
cf3d8e
-		.group_size = s390_expolines_group_size,
cf3d8e
+		.name		= ".s390_indirect_call",
cf3d8e
+		.arch		= S390,
cf3d8e
+		.group_size	= s390_expolines_group_size,
cf3d8e
 	},
cf3d8e
 	{
cf3d8e
-		.name = ".s390_indirect_branches",
cf3d8e
-		.arch = S390,
cf3d8e
-		.group_size = s390_expolines_group_size,
cf3d8e
+		.name		= ".s390_indirect_branches",
cf3d8e
+		.arch		= S390,
cf3d8e
+		.group_size	= s390_expolines_group_size,
cf3d8e
 	},
cf3d8e
 	{
cf3d8e
-		.name = ".s390_indirect_jump",
cf3d8e
-		.arch = S390,
cf3d8e
-		.group_size = s390_expolines_group_size,
cf3d8e
+		.name		= ".s390_indirect_jump",
cf3d8e
+		.arch		= S390,
cf3d8e
+		.group_size	= s390_expolines_group_size,
cf3d8e
 	},
cf3d8e
 	{},
cf3d8e
 };
cf3d8e
 
cf3d8e
-static bool should_keep_jump_label(struct lookup_table *lookup,
cf3d8e
-				   struct section *relasec,
cf3d8e
-				   unsigned int group_offset,
cf3d8e
-				   unsigned int group_size,
cf3d8e
-				   int *jump_labels_found)
cf3d8e
-{
cf3d8e
-	struct rela *code = NULL, *key = NULL, *rela;
cf3d8e
-	bool tracepoint = false, dynamic_debug = false;
cf3d8e
-	struct lookup_result symbol;
cf3d8e
-	int i = 0;
cf3d8e
-
cf3d8e
-	/*
cf3d8e
-	 * Here we hard-code knowledge about the contents of the jump_entry
cf3d8e
-	 * struct.  It has three fields: code, target, and key.  Each field has
cf3d8e
-	 * a relocation associated with it.
cf3d8e
-	 */
cf3d8e
-	list_for_each_entry(rela, &relasec->relas, list) {
cf3d8e
-		if (rela->offset >= group_offset &&
cf3d8e
-		    rela->offset < group_offset + group_size) {
cf3d8e
-			if (i == 0)
cf3d8e
-				code = rela;
cf3d8e
-			else if (i == 2)
cf3d8e
-				key = rela;
cf3d8e
-			i++;
cf3d8e
-		}
cf3d8e
-	}
cf3d8e
-
cf3d8e
-	if (i != 3 || !key || !code)
cf3d8e
-		ERROR("BUG: __jump_table has an unexpected format");
cf3d8e
-
cf3d8e
-	if (!strncmp(key->sym->name, "__tracepoint_", 13))
cf3d8e
-		tracepoint = true;
cf3d8e
-
cf3d8e
-	if (is_dynamic_debug_symbol(key->sym))
cf3d8e
-		dynamic_debug = true;
cf3d8e
-
cf3d8e
-	if (KLP_ARCH) {
cf3d8e
-		/*
cf3d8e
-		 * On older kernels (with .klp.arch support), jump labels
cf3d8e
-		 * aren't supported at all.  Error out when they occur in a
cf3d8e
-		 * replacement function, with the exception of tracepoints and
cf3d8e
-		 * dynamic debug printks.  An inert tracepoint or printk is
cf3d8e
-		 * harmless enough, but a broken jump label can cause
cf3d8e
-		 * unexpected behavior.
cf3d8e
-		 */
cf3d8e
-		if (tracepoint || dynamic_debug)
cf3d8e
-			return false;
cf3d8e
-
cf3d8e
-		/*
cf3d8e
-		 * This will be upgraded to an error after all jump labels have
cf3d8e
-		 * been reported.
cf3d8e
-		 */
cf3d8e
-		log_normal("Found a jump label at %s()+0x%lx, using key %s.  Jump labels aren't supported with this kernel.  Use static_key_enabled() instead.\n",
cf3d8e
-			   code->sym->name, code->addend, key->sym->name);
cf3d8e
-		(*jump_labels_found)++;
cf3d8e
-		return false;
cf3d8e
-	}
cf3d8e
-
cf3d8e
-	/*
cf3d8e
-	 * On newer (5.8+) kernels, jump labels are supported in the case where
cf3d8e
-	 * the corresponding static key lives in vmlinux.  That's because such
cf3d8e
-	 * kernels apply vmlinux-specific .klp.rela sections at the same time
cf3d8e
-	 * (in the klp module load) as normal relas, before jump label init.
cf3d8e
-	 * On the other hand, jump labels based on static keys which are
cf3d8e
-	 * defined in modules aren't supported, because late module patching
cf3d8e
-	 * can result in the klp relas getting applied *after* the klp module's
cf3d8e
-	 * jump label init.
cf3d8e
-	 */
cf3d8e
-
cf3d8e
-	if (lookup_symbol(lookup, key->sym, &symbol) &&
cf3d8e
-	    strcmp(symbol.objname, "vmlinux")) {
cf3d8e
-
cf3d8e
-		/* The static key lives in a module -- not supported */
cf3d8e
-
cf3d8e
-		/* Inert tracepoints and dynamic debug printks are harmless */
cf3d8e
-		if (tracepoint || dynamic_debug)
cf3d8e
-			return false;
cf3d8e
-
cf3d8e
-		/*
cf3d8e
-		 * This will be upgraded to an error after all jump labels have
cf3d8e
-		 * been reported.
cf3d8e
-		 */
cf3d8e
-		log_normal("Found a jump label at %s()+0x%lx, using key %s, which is defined in a module.  Use static_key_enabled() instead.\n",
cf3d8e
-			   code->sym->name, code->addend, key->sym->name);
cf3d8e
-		(*jump_labels_found)++;
cf3d8e
-		return false;
cf3d8e
-	}
cf3d8e
-
cf3d8e
-	/* The static key lives in vmlinux or the patch module itself */
cf3d8e
-
cf3d8e
-	/*
cf3d8e
-	 * If the jump label key lives in the '__dyndbg' section, make sure
cf3d8e
-	 * the section gets included, because we don't use klp relocs for
cf3d8e
-	 * dynamic debug symbols.  For an example of such a key, see
cf3d8e
-	 * DYNAMIC_DEBUG_BRANCH().
cf3d8e
-	 */
cf3d8e
-	if (dynamic_debug)
cf3d8e
-		kpatch_include_symbol(key->sym);
cf3d8e
-
cf3d8e
-	return true;
cf3d8e
-}
cf3d8e
-
cf3d8e
 static bool should_keep_rela_group(struct lookup_table *lookup,
cf3d8e
 				   struct section *relasec, unsigned int offset,
cf3d8e
-				   unsigned int size, int *jump_labels_found)
cf3d8e
+				   unsigned int size)
cf3d8e
 {
cf3d8e
 	struct rela *rela;
cf3d8e
 	bool found = false;
cf3d8e
@@ -2448,10 +2516,6 @@ static bool should_keep_rela_group(struct lookup_table *lookup,
cf3d8e
 	if (!found)
cf3d8e
 		return false;
cf3d8e
 
cf3d8e
-	if (!strcmp(relasec->name, ".rela__jump_table"))
cf3d8e
-		return should_keep_jump_label(lookup, relasec, offset, size,
cf3d8e
-					      jump_labels_found);
cf3d8e
-
cf3d8e
 	return true;
cf3d8e
 }
cf3d8e
 
cf3d8e
@@ -2488,7 +2552,6 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf,
cf3d8e
 	struct rela *rela, *safe;
cf3d8e
 	char *src, *dest;
cf3d8e
 	unsigned int group_size, src_offset, dest_offset;
cf3d8e
-	int jump_labels_found = 0;
cf3d8e
 
cf3d8e
 	LIST_HEAD(newrelas);
cf3d8e
 
cf3d8e
@@ -2523,8 +2586,11 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf,
cf3d8e
 		if (src_offset + group_size > relasec->base->sh.sh_size)
cf3d8e
 			group_size = (unsigned int)(relasec->base->sh.sh_size - src_offset);
cf3d8e
 
cf3d8e
-		if (!should_keep_rela_group(lookup, relasec, src_offset, group_size,
cf3d8e
-					    &jump_labels_found))
cf3d8e
+		if (!should_keep_rela_group(lookup, relasec, src_offset, group_size))
cf3d8e
+			continue;
cf3d8e
+
cf3d8e
+		if (special->group_filter &&
cf3d8e
+		    !special->group_filter(lookup, relasec, src_offset, group_size))
cf3d8e
 			continue;
cf3d8e
 
cf3d8e
 		/*
cf3d8e
@@ -2557,9 +2623,13 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf,
cf3d8e
 		dest_offset += group_size;
cf3d8e
 	}
cf3d8e
 
cf3d8e
-	if (jump_labels_found)
cf3d8e
-		ERROR("Found %d jump label(s) in the patched code. Jump labels aren't currently supported. Use static_key_enabled() instead.",
cf3d8e
-		      jump_labels_found);
cf3d8e
+	if (jump_label_errors)
cf3d8e
+		ERROR("Found %d unsupported jump label(s) in the patched code. Use static_key_enabled() instead.",
cf3d8e
+		      jump_label_errors);
cf3d8e
+
cf3d8e
+	if (static_call_errors)
cf3d8e
+		ERROR("Found %d unsupported static call(s) in the patched code. Use KPATCH_STATIC_CALL() instead.",
cf3d8e
+		      static_call_errors);
cf3d8e
 
cf3d8e
 	if (!dest_offset) {
cf3d8e
 		/* no changed or global functions referenced */
cf3d8e
diff --git a/kpatch-build/log.h b/kpatch-build/log.h
cf3d8e
index eefa0fce7b08..dbdc212713e1 100644
cf3d8e
--- a/kpatch-build/log.h
cf3d8e
+++ b/kpatch-build/log.h
cf3d8e
@@ -9,7 +9,7 @@ extern enum loglevel loglevel;
cf3d8e
 extern char *childobj;
cf3d8e
 
cf3d8e
 #define ERROR(format, ...) \
cf3d8e
-	err(EXIT_STATUS_ERROR, "ERROR: %s: %s: %d: " format, childobj, __FUNCTION__, __LINE__, ##__VA_ARGS__)
cf3d8e
+	errx(EXIT_STATUS_ERROR, "ERROR: %s: %s: %d: " format, childobj, __FUNCTION__, __LINE__, ##__VA_ARGS__)
cf3d8e
 
cf3d8e
 #define log_debug(format, ...) log(DEBUG, format, ##__VA_ARGS__)
cf3d8e
 #define log_normal(format, ...) log(NORMAL, "%s: " format, childobj, ##__VA_ARGS__)
cf3d8e
-- 
cf3d8e
2.38.1
cf3d8e