linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused
@ 2025-08-28 18:27 Steven Rostedt
  2025-08-28 18:27 ` [for-next][PATCH 1/3] sorttable: Move ELF parsing into scripts/elf-parse.[ch] Steven Rostedt
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Steven Rostedt @ 2025-08-28 18:27 UTC (permalink / raw)
  To: linux-kernel, Stephen Rothwell
  Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Linus Torvalds


Stephen,

I plan on pushing this to my for-next branch, which will add this to the
linux-next tree. When the kconfig option "TRACEPOINT_WARN_ON_UNUSED" is
enabled, it will warn whenever a tracepoint is created but not used. This is
similar to adding a static variable or function and not using it. This means
that an allmodconfig and allyesconfig builds may start having warnings that
will get bisected down to this commit. The bug is not this commit though, but
whatever has created an event but never used it. As tracepoints can take up to
5K of memory, even when not used, this is a waste and should be fixed.

I hope that adding this to linux-next will start the push to clean up these
unused tracepoints that are in the kernel, as well as prevent new ones from
being added. Hopefully by the time the merge window rolls around, most of
these will be cleaned up and this can be merged upstream without triggering
warnings.

I built this against all archs in my tree (26 of them) with a allyesconfig.
Unfortunately, only 10 build successfully with that (they all build
successfully with defconfig and this option with tracing enabled). This
detected 178 unique tracepoints that are defined and not used:

$ grep '^warning:' /work/autotest/cross-unused-traceevnts.log | sort -u |wc -l
178

Among them, 78 tracepoints were created and never referenced.

$ grep '^warning:' /work/autotest/cross-unused-traceevents.log | sort -u |cut -d"'" -f2 |
    while read a ; do if ! git grep -q trace_$a ; then echo $a; fi ; done | wc -l
78

The 100 remaining are likely in strange #ifdef CONFIG combinations where an
allyesconfig defines the tracepoint but doesn't enable the code that uses
them.

Expect even more warnings with different combos of config settings, as this
will warn whenever a tracepoint is defined but not used.

-- Steve

  git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
unused-tracepoints/for-next

Head SHA1: d492e79ec6892ce1928a4c929ea29c0d5986e117


Steven Rostedt (3):
      sorttable: Move ELF parsing into scripts/elf-parse.[ch]
      tracing: Add a tracepoint verification check at build time
      tracepoint: Do not warn for unused event that is exported

----
 include/asm-generic/vmlinux.lds.h |   1 +
 include/linux/tracepoint.h        |  12 +
 kernel/trace/Kconfig              |  10 +
 scripts/Makefile                  |   6 +
 scripts/Makefile.vmlinux          |   2 +
 scripts/elf-parse.c               | 198 ++++++++++++++++
 scripts/elf-parse.h               | 305 ++++++++++++++++++++++++
 scripts/link-vmlinux.sh           |   4 +
 scripts/sorttable.c               | 477 +++-----------------------------------
 scripts/tracepoint-update.c       | 232 ++++++++++++++++++
 10 files changed, 804 insertions(+), 443 deletions(-)
 create mode 100644 scripts/elf-parse.c
 create mode 100644 scripts/elf-parse.h
 create mode 100644 scripts/tracepoint-update.c

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [for-next][PATCH 1/3] sorttable: Move ELF parsing into scripts/elf-parse.[ch]
  2025-08-28 18:27 [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused Steven Rostedt
@ 2025-08-28 18:27 ` Steven Rostedt
  2025-08-28 19:03   ` Nicolas Schier
  2025-08-28 18:27 ` [for-next][PATCH 2/3] tracing: Add a tracepoint verification check at build time Steven Rostedt
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Steven Rostedt @ 2025-08-28 18:27 UTC (permalink / raw)
  To: linux-kernel, Stephen Rothwell
  Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Linus Torvalds, Arnd Bergmann, Masahiro Yamada, Nathan Chancellor,
	Nicolas Schier, Nick Desaulniers, Catalin Marinas, Randy Dunlap

From: Steven Rostedt <rostedt@goodmis.org>

In order to share the elf parsing that is in sorttable.c so that other
programs could use the same code, move it into elf-parse.c and
elf-parse.h.

Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas.schier@linux.dev>
Cc: Nick Desaulniers <nick.desaulniers+lkml@gmail.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Link: https://lore.kernel.org/20250825231355.597630284@kernel.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 scripts/Makefile         |   3 +
 scripts/Makefile.vmlinux |   2 +
 scripts/elf-parse.c      | 198 ++++++++++++++++
 scripts/elf-parse.h      | 305 +++++++++++++++++++++++++
 scripts/sorttable.c      | 477 +++------------------------------------
 5 files changed, 542 insertions(+), 443 deletions(-)
 create mode 100644 scripts/elf-parse.c
 create mode 100644 scripts/elf-parse.h

diff --git a/scripts/Makefile b/scripts/Makefile
index 46f860529df5..f19624b3ed92 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -12,6 +12,8 @@ hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE)	+= insert-sys-cert
 hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS)		+= rustdoc_test_builder
 hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS)		+= rustdoc_test_gen
 
+sorttable-objs := sorttable.o elf-parse.o
+
 ifneq ($(or $(CONFIG_X86_64),$(CONFIG_X86_32)),)
 always-$(CONFIG_RUST)					+= target.json
 filechk_rust_target = $< < include/config/auto.conf
@@ -25,6 +27,7 @@ generate_rust_target-rust := y
 rustdoc_test_builder-rust := y
 rustdoc_test_gen-rust := y
 
+HOSTCFLAGS_elf-parse.o = -I$(srctree)/tools/include
 HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
 HOSTLDLIBS_sorttable = -lpthread
 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
index b64862dc6f08..ebbb8b5aca83 100644
--- a/scripts/Makefile.vmlinux
+++ b/scripts/Makefile.vmlinux
@@ -97,6 +97,8 @@ ifdef CONFIG_BUILDTIME_TABLE_SORT
 $(vmlinux-final): scripts/sorttable
 endif
 
+.PRECIOUS: $(vmlinux-final)
+
 # modules.builtin.ranges
 # ---------------------------------------------------------------------------
 ifdef CONFIG_BUILTIN_MODULE_RANGES
diff --git a/scripts/elf-parse.c b/scripts/elf-parse.c
new file mode 100644
index 000000000000..99869ff91a8c
--- /dev/null
+++ b/scripts/elf-parse.c
@@ -0,0 +1,198 @@
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "elf-parse.h"
+
+struct elf_funcs elf_parser;
+
+/*
+ * Get the whole file as a programming convenience in order to avoid
+ * malloc+lseek+read+free of many pieces.  If successful, then mmap
+ * avoids copying unused pieces; else just read the whole file.
+ * Open for both read and write.
+ */
+static void *map_file(char const *fname, size_t *size)
+{
+	int fd;
+	struct stat sb;
+	void *addr = NULL;
+
+	fd = open(fname, O_RDWR);
+	if (fd < 0) {
+		perror(fname);
+		return NULL;
+	}
+	if (fstat(fd, &sb) < 0) {
+		perror(fname);
+		goto out;
+	}
+	if (!S_ISREG(sb.st_mode)) {
+		fprintf(stderr, "not a regular file: %s\n", fname);
+		goto out;
+	}
+
+	addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+	if (addr == MAP_FAILED) {
+		fprintf(stderr, "Could not mmap file: %s\n", fname);
+		goto out;
+	}
+
+	*size = sb.st_size;
+
+out:
+	close(fd);
+	return addr;
+}
+
+static int elf_parse(const char *fname, void *addr, uint32_t types)
+{
+	Elf_Ehdr *ehdr = addr;
+	uint16_t type;
+
+	switch (ehdr->e32.e_ident[EI_DATA]) {
+	case ELFDATA2LSB:
+		elf_parser.r	= rle;
+		elf_parser.r2	= r2le;
+		elf_parser.r8	= r8le;
+		elf_parser.w	= wle;
+		elf_parser.w8	= w8le;
+		break;
+	case ELFDATA2MSB:
+		elf_parser.r	= rbe;
+		elf_parser.r2	= r2be;
+		elf_parser.r8	= r8be;
+		elf_parser.w	= wbe;
+		elf_parser.w8	= w8be;
+		break;
+	default:
+		fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
+			ehdr->e32.e_ident[EI_DATA], fname);
+		return -1;
+	}
+
+	if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
+	    ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
+		fprintf(stderr, "unrecognized ELF file %s\n", fname);
+		return -1;
+	}
+
+	type = elf_parser.r2(&ehdr->e32.e_type);
+	if (!((1 << type) & types)) {
+		fprintf(stderr, "Invalid ELF type file %s\n", fname);
+		return -1;
+	}
+
+	switch (ehdr->e32.e_ident[EI_CLASS]) {
+	case ELFCLASS32: {
+		elf_parser.ehdr_shoff		= ehdr32_shoff;
+		elf_parser.ehdr_shentsize	= ehdr32_shentsize;
+		elf_parser.ehdr_shstrndx	= ehdr32_shstrndx;
+		elf_parser.ehdr_shnum		= ehdr32_shnum;
+		elf_parser.shdr_addr		= shdr32_addr;
+		elf_parser.shdr_offset		= shdr32_offset;
+		elf_parser.shdr_link		= shdr32_link;
+		elf_parser.shdr_size		= shdr32_size;
+		elf_parser.shdr_name		= shdr32_name;
+		elf_parser.shdr_type		= shdr32_type;
+		elf_parser.shdr_entsize		= shdr32_entsize;
+		elf_parser.sym_type		= sym32_type;
+		elf_parser.sym_name		= sym32_name;
+		elf_parser.sym_value		= sym32_value;
+		elf_parser.sym_shndx		= sym32_shndx;
+		elf_parser.rela_offset		= rela32_offset;
+		elf_parser.rela_info		= rela32_info;
+		elf_parser.rela_addend		= rela32_addend;
+		elf_parser.rela_write_addend	= rela32_write_addend;
+
+		if (elf_parser.r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) ||
+		    elf_parser.r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) {
+			fprintf(stderr,
+				"unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
+			return -1;
+		}
+
+		}
+		break;
+	case ELFCLASS64: {
+		elf_parser.ehdr_shoff		= ehdr64_shoff;
+		elf_parser.ehdr_shentsize		= ehdr64_shentsize;
+		elf_parser.ehdr_shstrndx		= ehdr64_shstrndx;
+		elf_parser.ehdr_shnum		= ehdr64_shnum;
+		elf_parser.shdr_addr		= shdr64_addr;
+		elf_parser.shdr_offset		= shdr64_offset;
+		elf_parser.shdr_link		= shdr64_link;
+		elf_parser.shdr_size		= shdr64_size;
+		elf_parser.shdr_name		= shdr64_name;
+		elf_parser.shdr_type		= shdr64_type;
+		elf_parser.shdr_entsize		= shdr64_entsize;
+		elf_parser.sym_type		= sym64_type;
+		elf_parser.sym_name		= sym64_name;
+		elf_parser.sym_value		= sym64_value;
+		elf_parser.sym_shndx		= sym64_shndx;
+		elf_parser.rela_offset		= rela64_offset;
+		elf_parser.rela_info		= rela64_info;
+		elf_parser.rela_addend		= rela64_addend;
+		elf_parser.rela_write_addend	= rela64_write_addend;
+
+		if (elf_parser.r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) ||
+		    elf_parser.r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) {
+			fprintf(stderr,
+				"unrecognized ET_EXEC/ET_DYN file: %s\n",
+				fname);
+			return -1;
+		}
+
+		}
+		break;
+	default:
+		fprintf(stderr, "unrecognized ELF class %d %s\n",
+			ehdr->e32.e_ident[EI_CLASS], fname);
+		return -1;
+	}
+	return 0;
+}
+
+int elf_map_machine(void *addr)
+{
+	Elf_Ehdr *ehdr = addr;
+
+	return elf_parser.r2(&ehdr->e32.e_machine);
+}
+
+int elf_map_long_size(void *addr)
+{
+	Elf_Ehdr *ehdr = addr;
+
+	return ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+}
+
+void *elf_map(char const *fname, size_t *size, uint32_t types)
+{
+	void *addr;
+	int ret;
+
+	addr = map_file(fname, size);
+	if (!addr)
+		return NULL;
+
+	ret = elf_parse(fname, addr, types);
+	if (ret < 0) {
+		elf_unmap(addr, *size);
+		return NULL;
+	}
+
+	return addr;
+}
+
+void elf_unmap(void *addr, size_t size)
+{
+	munmap(addr, size);
+}
diff --git a/scripts/elf-parse.h b/scripts/elf-parse.h
new file mode 100644
index 000000000000..f4411e03069d
--- /dev/null
+++ b/scripts/elf-parse.h
@@ -0,0 +1,305 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _SCRIPTS_ELF_PARSE_H
+#define _SCRIPTS_ELF_PARSE_H
+
+#include <elf.h>
+
+#include <tools/be_byteshift.h>
+#include <tools/le_byteshift.h>
+
+typedef union {
+	Elf32_Ehdr	e32;
+	Elf64_Ehdr	e64;
+} Elf_Ehdr;
+
+typedef union {
+	Elf32_Shdr	e32;
+	Elf64_Shdr	e64;
+} Elf_Shdr;
+
+typedef union {
+	Elf32_Sym	e32;
+	Elf64_Sym	e64;
+} Elf_Sym;
+
+typedef union {
+	Elf32_Rela	e32;
+	Elf64_Rela	e64;
+} Elf_Rela;
+
+struct elf_funcs {
+	int (*compare_extable)(const void *a, const void *b);
+	uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr);
+	uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr);
+	uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr);
+	uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr);
+	uint64_t (*shdr_addr)(Elf_Shdr *shdr);
+	uint64_t (*shdr_offset)(Elf_Shdr *shdr);
+	uint64_t (*shdr_size)(Elf_Shdr *shdr);
+	uint64_t (*shdr_entsize)(Elf_Shdr *shdr);
+	uint32_t (*shdr_link)(Elf_Shdr *shdr);
+	uint32_t (*shdr_name)(Elf_Shdr *shdr);
+	uint32_t (*shdr_type)(Elf_Shdr *shdr);
+	uint8_t (*sym_type)(Elf_Sym *sym);
+	uint32_t (*sym_name)(Elf_Sym *sym);
+	uint64_t (*sym_value)(Elf_Sym *sym);
+	uint16_t (*sym_shndx)(Elf_Sym *sym);
+	uint64_t (*rela_offset)(Elf_Rela *rela);
+	uint64_t (*rela_info)(Elf_Rela *rela);
+	uint64_t (*rela_addend)(Elf_Rela *rela);
+	void (*rela_write_addend)(Elf_Rela *rela, uint64_t val);
+	uint32_t (*r)(const uint32_t *);
+	uint16_t (*r2)(const uint16_t *);
+	uint64_t (*r8)(const uint64_t *);
+	void (*w)(uint32_t, uint32_t *);
+	void (*w8)(uint64_t, uint64_t *);
+};
+
+extern struct elf_funcs elf_parser;
+
+static inline uint64_t ehdr64_shoff(Elf_Ehdr *ehdr)
+{
+	return elf_parser.r8(&ehdr->e64.e_shoff);
+}
+
+static inline uint64_t ehdr32_shoff(Elf_Ehdr *ehdr)
+{
+	return elf_parser.r(&ehdr->e32.e_shoff);
+}
+
+static inline uint64_t ehdr_shoff(Elf_Ehdr *ehdr)
+{
+	return elf_parser.ehdr_shoff(ehdr);
+}
+
+#define EHDR_HALF(fn_name)				\
+static inline uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr)	\
+{							\
+	return elf_parser.r2(&ehdr->e64.e_##fn_name);	\
+}							\
+							\
+static inline uint16_t ehdr32_##fn_name(Elf_Ehdr *ehdr)	\
+{							\
+	return elf_parser.r2(&ehdr->e32.e_##fn_name);	\
+}							\
+							\
+static inline uint16_t ehdr_##fn_name(Elf_Ehdr *ehdr)	\
+{							\
+	return elf_parser.ehdr_##fn_name(ehdr);		\
+}
+
+EHDR_HALF(shentsize)
+EHDR_HALF(shstrndx)
+EHDR_HALF(shnum)
+
+#define SHDR_WORD(fn_name)				\
+static inline uint32_t shdr64_##fn_name(Elf_Shdr *shdr)	\
+{							\
+	return elf_parser.r(&shdr->e64.sh_##fn_name);	\
+}							\
+							\
+static inline uint32_t shdr32_##fn_name(Elf_Shdr *shdr)	\
+{							\
+	return elf_parser.r(&shdr->e32.sh_##fn_name);	\
+}							\
+							\
+static inline uint32_t shdr_##fn_name(Elf_Shdr *shdr)	\
+{							\
+	return elf_parser.shdr_##fn_name(shdr);	\
+}
+
+#define SHDR_ADDR(fn_name)				\
+static inline uint64_t shdr64_##fn_name(Elf_Shdr *shdr)	\
+{							\
+	return elf_parser.r8(&shdr->e64.sh_##fn_name);	\
+}							\
+							\
+static inline uint64_t shdr32_##fn_name(Elf_Shdr *shdr)	\
+{							\
+	return elf_parser.r(&shdr->e32.sh_##fn_name);	\
+}							\
+							\
+static inline uint64_t shdr_##fn_name(Elf_Shdr *shdr)	\
+{							\
+	return elf_parser.shdr_##fn_name(shdr);		\
+}
+
+#define SHDR_WORD(fn_name)				\
+static inline uint32_t shdr64_##fn_name(Elf_Shdr *shdr)	\
+{							\
+	return elf_parser.r(&shdr->e64.sh_##fn_name);	\
+}							\
+							\
+static inline uint32_t shdr32_##fn_name(Elf_Shdr *shdr)	\
+{							\
+	return elf_parser.r(&shdr->e32.sh_##fn_name);	\
+}							\
+static inline uint32_t shdr_##fn_name(Elf_Shdr *shdr)	\
+{							\
+	return elf_parser.shdr_##fn_name(shdr);		\
+}
+
+SHDR_ADDR(addr)
+SHDR_ADDR(offset)
+SHDR_ADDR(size)
+SHDR_ADDR(entsize)
+
+SHDR_WORD(link)
+SHDR_WORD(name)
+SHDR_WORD(type)
+
+#define SYM_ADDR(fn_name)				\
+static inline uint64_t sym64_##fn_name(Elf_Sym *sym)	\
+{							\
+	return elf_parser.r8(&sym->e64.st_##fn_name);	\
+}							\
+							\
+static inline uint64_t sym32_##fn_name(Elf_Sym *sym)	\
+{							\
+	return elf_parser.r(&sym->e32.st_##fn_name);	\
+}							\
+							\
+static inline uint64_t sym_##fn_name(Elf_Sym *sym)	\
+{							\
+	return elf_parser.sym_##fn_name(sym);		\
+}
+
+#define SYM_WORD(fn_name)				\
+static inline uint32_t sym64_##fn_name(Elf_Sym *sym)	\
+{							\
+	return elf_parser.r(&sym->e64.st_##fn_name);	\
+}							\
+							\
+static inline uint32_t sym32_##fn_name(Elf_Sym *sym)	\
+{							\
+	return elf_parser.r(&sym->e32.st_##fn_name);	\
+}							\
+							\
+static inline uint32_t sym_##fn_name(Elf_Sym *sym)	\
+{							\
+	return elf_parser.sym_##fn_name(sym);		\
+}
+
+#define SYM_HALF(fn_name)				\
+static inline uint16_t sym64_##fn_name(Elf_Sym *sym)	\
+{							\
+	return elf_parser.r2(&sym->e64.st_##fn_name);	\
+}							\
+							\
+static inline uint16_t sym32_##fn_name(Elf_Sym *sym)	\
+{							\
+	return elf_parser.r2(&sym->e32.st_##fn_name);	\
+}							\
+							\
+static inline uint16_t sym_##fn_name(Elf_Sym *sym)	\
+{							\
+	return elf_parser.sym_##fn_name(sym);		\
+}
+
+static inline uint8_t sym64_type(Elf_Sym *sym)
+{
+	return ELF64_ST_TYPE(sym->e64.st_info);
+}
+
+static inline uint8_t sym32_type(Elf_Sym *sym)
+{
+	return ELF32_ST_TYPE(sym->e32.st_info);
+}
+
+static inline uint8_t sym_type(Elf_Sym *sym)
+{
+	return elf_parser.sym_type(sym);
+}
+
+SYM_ADDR(value)
+SYM_WORD(name)
+SYM_HALF(shndx)
+
+#define __maybe_unused			__attribute__((__unused__))
+
+#define RELA_ADDR(fn_name)						\
+static inline uint64_t rela64_##fn_name(Elf_Rela *rela)			\
+{									\
+	return elf_parser.r8((uint64_t *)&rela->e64.r_##fn_name);	\
+}									\
+									\
+static inline uint64_t rela32_##fn_name(Elf_Rela *rela)			\
+{									\
+	return elf_parser.r((uint32_t *)&rela->e32.r_##fn_name);	\
+}									\
+									\
+static inline uint64_t __maybe_unused rela_##fn_name(Elf_Rela *rela)	\
+{									\
+	return elf_parser.rela_##fn_name(rela);				\
+}
+
+RELA_ADDR(offset)
+RELA_ADDR(info)
+RELA_ADDR(addend)
+
+static inline void rela64_write_addend(Elf_Rela *rela, uint64_t val)
+{
+	elf_parser.w8(val, (uint64_t *)&rela->e64.r_addend);
+}
+
+static inline void rela32_write_addend(Elf_Rela *rela, uint64_t val)
+{
+	elf_parser.w(val, (uint32_t *)&rela->e32.r_addend);
+}
+
+static inline uint32_t rbe(const uint32_t *x)
+{
+	return get_unaligned_be32(x);
+}
+
+static inline uint16_t r2be(const uint16_t *x)
+{
+	return get_unaligned_be16(x);
+}
+
+static inline uint64_t r8be(const uint64_t *x)
+{
+	return get_unaligned_be64(x);
+}
+
+static inline uint32_t rle(const uint32_t *x)
+{
+	return get_unaligned_le32(x);
+}
+
+static inline uint16_t r2le(const uint16_t *x)
+{
+	return get_unaligned_le16(x);
+}
+
+static inline uint64_t r8le(const uint64_t *x)
+{
+	return get_unaligned_le64(x);
+}
+
+static inline void wbe(uint32_t val, uint32_t *x)
+{
+	put_unaligned_be32(val, x);
+}
+
+static inline void wle(uint32_t val, uint32_t *x)
+{
+	put_unaligned_le32(val, x);
+}
+
+static inline void w8be(uint64_t val, uint64_t *x)
+{
+	put_unaligned_be64(val, x);
+}
+
+static inline void w8le(uint64_t val, uint64_t *x)
+{
+	put_unaligned_le64(val, x);
+}
+
+void *elf_map(char const *fname, size_t *size, uint32_t types);
+void elf_unmap(void *addr, size_t size);
+int elf_map_machine(void *addr);
+int elf_map_long_size(void *addr);
+
+#endif /* _SCRIPTS_ELF_PARSE_H */
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index deed676bfe38..e8ed11c680c6 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -21,10 +21,8 @@
  */
 
 #include <sys/types.h>
-#include <sys/mman.h>
 #include <sys/stat.h>
 #include <getopt.h>
-#include <elf.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -34,8 +32,7 @@
 #include <errno.h>
 #include <pthread.h>
 
-#include <tools/be_byteshift.h>
-#include <tools/le_byteshift.h>
+#include "elf-parse.h"
 
 #ifndef EM_ARCOMPACT
 #define EM_ARCOMPACT	93
@@ -65,335 +62,8 @@
 #define EM_LOONGARCH	258
 #endif
 
-typedef union {
-	Elf32_Ehdr	e32;
-	Elf64_Ehdr	e64;
-} Elf_Ehdr;
-
-typedef union {
-	Elf32_Shdr	e32;
-	Elf64_Shdr	e64;
-} Elf_Shdr;
-
-typedef union {
-	Elf32_Sym	e32;
-	Elf64_Sym	e64;
-} Elf_Sym;
-
-typedef union {
-	Elf32_Rela	e32;
-	Elf64_Rela	e64;
-} Elf_Rela;
-
-static uint32_t (*r)(const uint32_t *);
-static uint16_t (*r2)(const uint16_t *);
-static uint64_t (*r8)(const uint64_t *);
-static void (*w)(uint32_t, uint32_t *);
-static void (*w8)(uint64_t, uint64_t *);
 typedef void (*table_sort_t)(char *, int);
 
-static struct elf_funcs {
-	int (*compare_extable)(const void *a, const void *b);
-	uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr);
-	uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr);
-	uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr);
-	uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr);
-	uint64_t (*shdr_addr)(Elf_Shdr *shdr);
-	uint64_t (*shdr_offset)(Elf_Shdr *shdr);
-	uint64_t (*shdr_size)(Elf_Shdr *shdr);
-	uint64_t (*shdr_entsize)(Elf_Shdr *shdr);
-	uint32_t (*shdr_link)(Elf_Shdr *shdr);
-	uint32_t (*shdr_name)(Elf_Shdr *shdr);
-	uint32_t (*shdr_type)(Elf_Shdr *shdr);
-	uint8_t (*sym_type)(Elf_Sym *sym);
-	uint32_t (*sym_name)(Elf_Sym *sym);
-	uint64_t (*sym_value)(Elf_Sym *sym);
-	uint16_t (*sym_shndx)(Elf_Sym *sym);
-	uint64_t (*rela_offset)(Elf_Rela *rela);
-	uint64_t (*rela_info)(Elf_Rela *rela);
-	uint64_t (*rela_addend)(Elf_Rela *rela);
-	void (*rela_write_addend)(Elf_Rela *rela, uint64_t val);
-} e;
-
-static uint64_t ehdr64_shoff(Elf_Ehdr *ehdr)
-{
-	return r8(&ehdr->e64.e_shoff);
-}
-
-static uint64_t ehdr32_shoff(Elf_Ehdr *ehdr)
-{
-	return r(&ehdr->e32.e_shoff);
-}
-
-static uint64_t ehdr_shoff(Elf_Ehdr *ehdr)
-{
-	return e.ehdr_shoff(ehdr);
-}
-
-#define EHDR_HALF(fn_name)				\
-static uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr)	\
-{							\
-	return r2(&ehdr->e64.e_##fn_name);		\
-}							\
-							\
-static uint16_t ehdr32_##fn_name(Elf_Ehdr *ehdr)	\
-{							\
-	return r2(&ehdr->e32.e_##fn_name);		\
-}							\
-							\
-static uint16_t ehdr_##fn_name(Elf_Ehdr *ehdr)		\
-{							\
-	return e.ehdr_##fn_name(ehdr);			\
-}
-
-EHDR_HALF(shentsize)
-EHDR_HALF(shstrndx)
-EHDR_HALF(shnum)
-
-#define SHDR_WORD(fn_name)				\
-static uint32_t shdr64_##fn_name(Elf_Shdr *shdr)	\
-{							\
-	return r(&shdr->e64.sh_##fn_name);		\
-}							\
-							\
-static uint32_t shdr32_##fn_name(Elf_Shdr *shdr)	\
-{							\
-	return r(&shdr->e32.sh_##fn_name);		\
-}							\
-							\
-static uint32_t shdr_##fn_name(Elf_Shdr *shdr)		\
-{							\
-	return e.shdr_##fn_name(shdr);			\
-}
-
-#define SHDR_ADDR(fn_name)				\
-static uint64_t shdr64_##fn_name(Elf_Shdr *shdr)	\
-{							\
-	return r8(&shdr->e64.sh_##fn_name);		\
-}							\
-							\
-static uint64_t shdr32_##fn_name(Elf_Shdr *shdr)	\
-{							\
-	return r(&shdr->e32.sh_##fn_name);		\
-}							\
-							\
-static uint64_t shdr_##fn_name(Elf_Shdr *shdr)		\
-{							\
-	return e.shdr_##fn_name(shdr);			\
-}
-
-#define SHDR_WORD(fn_name)				\
-static uint32_t shdr64_##fn_name(Elf_Shdr *shdr)	\
-{							\
-	return r(&shdr->e64.sh_##fn_name);		\
-}							\
-							\
-static uint32_t shdr32_##fn_name(Elf_Shdr *shdr)	\
-{							\
-	return r(&shdr->e32.sh_##fn_name);		\
-}							\
-static uint32_t shdr_##fn_name(Elf_Shdr *shdr)		\
-{							\
-	return e.shdr_##fn_name(shdr);			\
-}
-
-SHDR_ADDR(addr)
-SHDR_ADDR(offset)
-SHDR_ADDR(size)
-SHDR_ADDR(entsize)
-
-SHDR_WORD(link)
-SHDR_WORD(name)
-SHDR_WORD(type)
-
-#define SYM_ADDR(fn_name)			\
-static uint64_t sym64_##fn_name(Elf_Sym *sym)	\
-{						\
-	return r8(&sym->e64.st_##fn_name);	\
-}						\
-						\
-static uint64_t sym32_##fn_name(Elf_Sym *sym)	\
-{						\
-	return r(&sym->e32.st_##fn_name);	\
-}						\
-						\
-static uint64_t sym_##fn_name(Elf_Sym *sym)	\
-{						\
-	return e.sym_##fn_name(sym);		\
-}
-
-#define SYM_WORD(fn_name)			\
-static uint32_t sym64_##fn_name(Elf_Sym *sym)	\
-{						\
-	return r(&sym->e64.st_##fn_name);	\
-}						\
-						\
-static uint32_t sym32_##fn_name(Elf_Sym *sym)	\
-{						\
-	return r(&sym->e32.st_##fn_name);	\
-}						\
-						\
-static uint32_t sym_##fn_name(Elf_Sym *sym)	\
-{						\
-	return e.sym_##fn_name(sym);		\
-}
-
-#define SYM_HALF(fn_name)			\
-static uint16_t sym64_##fn_name(Elf_Sym *sym)	\
-{						\
-	return r2(&sym->e64.st_##fn_name);	\
-}						\
-						\
-static uint16_t sym32_##fn_name(Elf_Sym *sym)	\
-{						\
-	return r2(&sym->e32.st_##fn_name);	\
-}						\
-						\
-static uint16_t sym_##fn_name(Elf_Sym *sym)	\
-{						\
-	return e.sym_##fn_name(sym);		\
-}
-
-static uint8_t sym64_type(Elf_Sym *sym)
-{
-	return ELF64_ST_TYPE(sym->e64.st_info);
-}
-
-static uint8_t sym32_type(Elf_Sym *sym)
-{
-	return ELF32_ST_TYPE(sym->e32.st_info);
-}
-
-static uint8_t sym_type(Elf_Sym *sym)
-{
-	return e.sym_type(sym);
-}
-
-SYM_ADDR(value)
-SYM_WORD(name)
-SYM_HALF(shndx)
-
-#define __maybe_unused			__attribute__((__unused__))
-
-#define RELA_ADDR(fn_name)					\
-static uint64_t rela64_##fn_name(Elf_Rela *rela)		\
-{								\
-	return r8((uint64_t *)&rela->e64.r_##fn_name);		\
-}								\
-								\
-static uint64_t rela32_##fn_name(Elf_Rela *rela)		\
-{								\
-	return r((uint32_t *)&rela->e32.r_##fn_name);		\
-}								\
-								\
-static uint64_t __maybe_unused rela_##fn_name(Elf_Rela *rela)	\
-{								\
-	return e.rela_##fn_name(rela);				\
-}
-
-RELA_ADDR(offset)
-RELA_ADDR(info)
-RELA_ADDR(addend)
-
-static void rela64_write_addend(Elf_Rela *rela, uint64_t val)
-{
-	w8(val, (uint64_t *)&rela->e64.r_addend);
-}
-
-static void rela32_write_addend(Elf_Rela *rela, uint64_t val)
-{
-	w(val, (uint32_t *)&rela->e32.r_addend);
-}
-
-/*
- * Get the whole file as a programming convenience in order to avoid
- * malloc+lseek+read+free of many pieces.  If successful, then mmap
- * avoids copying unused pieces; else just read the whole file.
- * Open for both read and write.
- */
-static void *mmap_file(char const *fname, size_t *size)
-{
-	int fd;
-	struct stat sb;
-	void *addr = NULL;
-
-	fd = open(fname, O_RDWR);
-	if (fd < 0) {
-		perror(fname);
-		return NULL;
-	}
-	if (fstat(fd, &sb) < 0) {
-		perror(fname);
-		goto out;
-	}
-	if (!S_ISREG(sb.st_mode)) {
-		fprintf(stderr, "not a regular file: %s\n", fname);
-		goto out;
-	}
-
-	addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-	if (addr == MAP_FAILED) {
-		fprintf(stderr, "Could not mmap file: %s\n", fname);
-		goto out;
-	}
-
-	*size = sb.st_size;
-
-out:
-	close(fd);
-	return addr;
-}
-
-static uint32_t rbe(const uint32_t *x)
-{
-	return get_unaligned_be32(x);
-}
-
-static uint16_t r2be(const uint16_t *x)
-{
-	return get_unaligned_be16(x);
-}
-
-static uint64_t r8be(const uint64_t *x)
-{
-	return get_unaligned_be64(x);
-}
-
-static uint32_t rle(const uint32_t *x)
-{
-	return get_unaligned_le32(x);
-}
-
-static uint16_t r2le(const uint16_t *x)
-{
-	return get_unaligned_le16(x);
-}
-
-static uint64_t r8le(const uint64_t *x)
-{
-	return get_unaligned_le64(x);
-}
-
-static void wbe(uint32_t val, uint32_t *x)
-{
-	put_unaligned_be32(val, x);
-}
-
-static void wle(uint32_t val, uint32_t *x)
-{
-	put_unaligned_le32(val, x);
-}
-
-static void w8be(uint64_t val, uint64_t *x)
-{
-	put_unaligned_be64(val, x);
-}
-
-static void w8le(uint64_t val, uint64_t *x)
-{
-	put_unaligned_le64(val, x);
-}
-
 /*
  * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
  * the way to -256..-1, to avoid conflicting with real section
@@ -415,13 +85,13 @@ static inline unsigned int get_secindex(unsigned int shndx,
 		return SPECIAL(shndx);
 	if (shndx != SHN_XINDEX)
 		return shndx;
-	return r(&symtab_shndx_start[sym_offs]);
+	return elf_parser.r(&symtab_shndx_start[sym_offs]);
 }
 
 static int compare_extable_32(const void *a, const void *b)
 {
-	Elf32_Addr av = r(a);
-	Elf32_Addr bv = r(b);
+	Elf32_Addr av = elf_parser.r(a);
+	Elf32_Addr bv = elf_parser.r(b);
 
 	if (av < bv)
 		return -1;
@@ -430,18 +100,15 @@ static int compare_extable_32(const void *a, const void *b)
 
 static int compare_extable_64(const void *a, const void *b)
 {
-	Elf64_Addr av = r8(a);
-	Elf64_Addr bv = r8(b);
+	Elf64_Addr av = elf_parser.r8(a);
+	Elf64_Addr bv = elf_parser.r8(b);
 
 	if (av < bv)
 		return -1;
 	return av > bv;
 }
 
-static int compare_extable(const void *a, const void *b)
-{
-	return e.compare_extable(a, b);
-}
+static int (*compare_extable)(const void *a, const void *b);
 
 static inline void *get_index(void *start, int entsize, int index)
 {
@@ -577,7 +244,7 @@ static int (*compare_values)(const void *a, const void *b);
 /* Only used for sorting mcount table */
 static void rela_write_addend(Elf_Rela *rela, uint64_t val)
 {
-	e.rela_write_addend(rela, val);
+	elf_parser.rela_write_addend(rela, val);
 }
 
 struct func_info {
@@ -792,9 +459,9 @@ static int fill_addrs(void *ptr, uint64_t size, void *addrs)
 
 	for (; ptr < end; ptr += long_size, addrs += long_size, count++) {
 		if (long_size == 4)
-			*(uint32_t *)ptr = r(addrs);
+			*(uint32_t *)ptr = elf_parser.r(addrs);
 		else
-			*(uint64_t *)ptr = r8(addrs);
+			*(uint64_t *)ptr = elf_parser.r8(addrs);
 	}
 	return count;
 }
@@ -805,9 +472,9 @@ static void replace_addrs(void *ptr, uint64_t size, void *addrs)
 
 	for (; ptr < end; ptr += long_size, addrs += long_size) {
 		if (long_size == 4)
-			w(*(uint32_t *)ptr, addrs);
+			elf_parser.w(*(uint32_t *)ptr, addrs);
 		else
-			w8(*(uint64_t *)ptr, addrs);
+			elf_parser.w8(*(uint64_t *)ptr, addrs);
 	}
 }
 
@@ -1111,7 +778,7 @@ static int do_sort(Elf_Ehdr *ehdr,
 		sym_value(sort_needed_sym) - shdr_addr(sort_needed_sec);
 
 	/* extable has been sorted, clear the flag */
-	w(0, sort_needed_loc);
+	elf_parser.w(0, sort_needed_loc);
 	rc = 0;
 
 out:
@@ -1155,8 +822,8 @@ static int do_sort(Elf_Ehdr *ehdr,
 
 static int compare_relative_table(const void *a, const void *b)
 {
-	int32_t av = (int32_t)r(a);
-	int32_t bv = (int32_t)r(b);
+	int32_t av = (int32_t)elf_parser.r(a);
+	int32_t bv = (int32_t)elf_parser.r(b);
 
 	if (av < bv)
 		return -1;
@@ -1175,7 +842,7 @@ static void sort_relative_table(char *extab_image, int image_size)
 	 */
 	while (i < image_size) {
 		uint32_t *loc = (uint32_t *)(extab_image + i);
-		w(r(loc) + i, loc);
+		elf_parser.w(elf_parser.r(loc) + i, loc);
 		i += 4;
 	}
 
@@ -1185,7 +852,7 @@ static void sort_relative_table(char *extab_image, int image_size)
 	i = 0;
 	while (i < image_size) {
 		uint32_t *loc = (uint32_t *)(extab_image + i);
-		w(r(loc) - i, loc);
+		elf_parser.w(elf_parser.r(loc) - i, loc);
 		i += 4;
 	}
 }
@@ -1197,8 +864,8 @@ static void sort_relative_table_with_data(char *extab_image, int image_size)
 	while (i < image_size) {
 		uint32_t *loc = (uint32_t *)(extab_image + i);
 
-		w(r(loc) + i, loc);
-		w(r(loc + 1) + i + 4, loc + 1);
+		elf_parser.w(elf_parser.r(loc) + i, loc);
+		elf_parser.w(elf_parser.r(loc + 1) + i + 4, loc + 1);
 		/* Don't touch the fixup type or data */
 
 		i += sizeof(uint32_t) * 3;
@@ -1210,8 +877,8 @@ static void sort_relative_table_with_data(char *extab_image, int image_size)
 	while (i < image_size) {
 		uint32_t *loc = (uint32_t *)(extab_image + i);
 
-		w(r(loc) - i, loc);
-		w(r(loc + 1) - (i + 4), loc + 1);
+		elf_parser.w(elf_parser.r(loc) - i, loc);
+		elf_parser.w(elf_parser.r(loc + 1) - (i + 4), loc + 1);
 		/* Don't touch the fixup type or data */
 
 		i += sizeof(uint32_t) * 3;
@@ -1223,35 +890,7 @@ static int do_file(char const *const fname, void *addr)
 	Elf_Ehdr *ehdr = addr;
 	table_sort_t custom_sort = NULL;
 
-	switch (ehdr->e32.e_ident[EI_DATA]) {
-	case ELFDATA2LSB:
-		r	= rle;
-		r2	= r2le;
-		r8	= r8le;
-		w	= wle;
-		w8	= w8le;
-		break;
-	case ELFDATA2MSB:
-		r	= rbe;
-		r2	= r2be;
-		r8	= r8be;
-		w	= wbe;
-		w8	= w8be;
-		break;
-	default:
-		fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
-			ehdr->e32.e_ident[EI_DATA], fname);
-		return -1;
-	}
-
-	if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
-	    (r2(&ehdr->e32.e_type) != ET_EXEC && r2(&ehdr->e32.e_type) != ET_DYN) ||
-	    ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
-		fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname);
-		return -1;
-	}
-
-	switch (r2(&ehdr->e32.e_machine)) {
+	switch (elf_map_machine(ehdr)) {
 	case EM_AARCH64:
 #ifdef MCOUNT_SORT_ENABLED
 		sort_reloc = true;
@@ -1281,85 +920,37 @@ static int do_file(char const *const fname, void *addr)
 		break;
 	default:
 		fprintf(stderr, "unrecognized e_machine %d %s\n",
-			r2(&ehdr->e32.e_machine), fname);
+			elf_parser.r2(&ehdr->e32.e_machine), fname);
 		return -1;
 	}
 
-	switch (ehdr->e32.e_ident[EI_CLASS]) {
-	case ELFCLASS32: {
-		struct elf_funcs efuncs = {
-			.compare_extable	= compare_extable_32,
-			.ehdr_shoff		= ehdr32_shoff,
-			.ehdr_shentsize		= ehdr32_shentsize,
-			.ehdr_shstrndx		= ehdr32_shstrndx,
-			.ehdr_shnum		= ehdr32_shnum,
-			.shdr_addr		= shdr32_addr,
-			.shdr_offset		= shdr32_offset,
-			.shdr_link		= shdr32_link,
-			.shdr_size		= shdr32_size,
-			.shdr_name		= shdr32_name,
-			.shdr_type		= shdr32_type,
-			.shdr_entsize		= shdr32_entsize,
-			.sym_type		= sym32_type,
-			.sym_name		= sym32_name,
-			.sym_value		= sym32_value,
-			.sym_shndx		= sym32_shndx,
-			.rela_offset		= rela32_offset,
-			.rela_info		= rela32_info,
-			.rela_addend		= rela32_addend,
-			.rela_write_addend	= rela32_write_addend,
-		};
-
-		e = efuncs;
+	switch (elf_map_long_size(addr)) {
+	case 4:
+		compare_extable	= compare_extable_32,
 		long_size		= 4;
 		extable_ent_size	= 8;
 
-		if (r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) ||
-		    r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) {
+		if (elf_parser.r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) ||
+		    elf_parser.r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) {
 			fprintf(stderr,
 				"unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
 			return -1;
 		}
 
-		}
 		break;
-	case ELFCLASS64: {
-		struct elf_funcs efuncs = {
-			.compare_extable	= compare_extable_64,
-			.ehdr_shoff		= ehdr64_shoff,
-			.ehdr_shentsize		= ehdr64_shentsize,
-			.ehdr_shstrndx		= ehdr64_shstrndx,
-			.ehdr_shnum		= ehdr64_shnum,
-			.shdr_addr		= shdr64_addr,
-			.shdr_offset		= shdr64_offset,
-			.shdr_link		= shdr64_link,
-			.shdr_size		= shdr64_size,
-			.shdr_name		= shdr64_name,
-			.shdr_type		= shdr64_type,
-			.shdr_entsize		= shdr64_entsize,
-			.sym_type		= sym64_type,
-			.sym_name		= sym64_name,
-			.sym_value		= sym64_value,
-			.sym_shndx		= sym64_shndx,
-			.rela_offset		= rela64_offset,
-			.rela_info		= rela64_info,
-			.rela_addend		= rela64_addend,
-			.rela_write_addend	= rela64_write_addend,
-		};
-
-		e = efuncs;
+	case 8:
+		compare_extable	= compare_extable_64,
 		long_size		= 8;
 		extable_ent_size	= 16;
 
-		if (r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) ||
-		    r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) {
+		if (elf_parser.r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) ||
+		    elf_parser.r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) {
 			fprintf(stderr,
 				"unrecognized ET_EXEC/ET_DYN file: %s\n",
 				fname);
 			return -1;
 		}
 
-		}
 		break;
 	default:
 		fprintf(stderr, "unrecognized ELF class %d %s\n",
@@ -1398,7 +989,7 @@ int main(int argc, char *argv[])
 
 	/* Process each file in turn, allowing deep failure. */
 	for (i = optind; i < argc; i++) {
-		addr = mmap_file(argv[i], &size);
+		addr = elf_map(argv[i], &size, (1 << ET_EXEC) | (1 << ET_DYN));
 		if (!addr) {
 			++n_error;
 			continue;
@@ -1407,7 +998,7 @@ int main(int argc, char *argv[])
 		if (do_file(argv[i], addr))
 			++n_error;
 
-		munmap(addr, size);
+		elf_unmap(addr, size);
 	}
 
 	return !!n_error;
-- 
2.50.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [for-next][PATCH 2/3] tracing: Add a tracepoint verification check at build time
  2025-08-28 18:27 [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused Steven Rostedt
  2025-08-28 18:27 ` [for-next][PATCH 1/3] sorttable: Move ELF parsing into scripts/elf-parse.[ch] Steven Rostedt
@ 2025-08-28 18:27 ` Steven Rostedt
  2025-08-28 18:27 ` [for-next][PATCH 3/3] tracepoint: Do not warn for unused event that is exported Steven Rostedt
  2025-08-28 21:02 ` [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused Stephen Rothwell
  3 siblings, 0 replies; 9+ messages in thread
From: Steven Rostedt @ 2025-08-28 18:27 UTC (permalink / raw)
  To: linux-kernel, Stephen Rothwell
  Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Linus Torvalds, Arnd Bergmann, Masahiro Yamada, Nathan Chancellor,
	Nicolas Schier, Nick Desaulniers, Catalin Marinas, Randy Dunlap

From: Steven Rostedt <rostedt@goodmis.org>

If a tracepoint is defined via DECLARE_TRACE() or TRACE_EVENT() but never
called (via the trace_<tracepoint>() function), its metadata is still
around in memory and not discarded.

When created via TRACE_EVENT() the situation is worse because the
TRACE_EVENT() creates metadata that can be around 5k per trace event.
Having unused trace events causes several thousand of wasted bytes.

Add a verifier that injects a string of the name of the tracepoint it
calls that is added to the discarded section "__tracepoint_check".
For every builtin tracepoint, its name (which is saved in the in-memory
section "__tracepoint_strings") will have its name also in the
"__tracepoint_check" section if it is used.

Add a new program that is run on build called tracepoint-update. This is
executed on the vmlinux.o before the __tracepoint_check section is
discarded (the section is discarded before vmlinux is created). This
program will create an array of each string in the __tracepoint_check
section and then sort it. Then it will walk the strings in the
__tracepoint_strings section and do a binary search to check if its name
is in the __tracepoint_check section. If it is not, then it is unused and
a warning is printed.

Note, this currently only handles tracepoints that are builtin and not in
modules.

Enabling this currently with a given config produces:

warning: tracepoint 'sched_move_numa' is unused.
warning: tracepoint 'sched_stick_numa' is unused.
warning: tracepoint 'sched_swap_numa' is unused.
warning: tracepoint 'pelt_hw_tp' is unused.
warning: tracepoint 'pelt_irq_tp' is unused.
warning: tracepoint 'rcu_preempt_task' is unused.
warning: tracepoint 'rcu_unlock_preempted_task' is unused.
warning: tracepoint 'xdp_bulk_tx' is unused.
warning: tracepoint 'xdp_redirect_map' is unused.
warning: tracepoint 'xdp_redirect_map_err' is unused.
warning: tracepoint 'vma_mas_szero' is unused.
warning: tracepoint 'vma_store' is unused.
warning: tracepoint 'hugepage_set_pmd' is unused.
warning: tracepoint 'hugepage_set_pud' is unused.
warning: tracepoint 'hugepage_update_pmd' is unused.
warning: tracepoint 'hugepage_update_pud' is unused.
warning: tracepoint 'block_rq_remap' is unused.
warning: tracepoint 'xhci_dbc_handle_event' is unused.
warning: tracepoint 'xhci_dbc_handle_transfer' is unused.
warning: tracepoint 'xhci_dbc_gadget_ep_queue' is unused.
warning: tracepoint 'xhci_dbc_alloc_request' is unused.
warning: tracepoint 'xhci_dbc_free_request' is unused.
warning: tracepoint 'xhci_dbc_queue_request' is unused.
warning: tracepoint 'xhci_dbc_giveback_request' is unused.
warning: tracepoint 'tcp_ao_wrong_maclen' is unused.
warning: tracepoint 'tcp_ao_mismatch' is unused.
warning: tracepoint 'tcp_ao_key_not_found' is unused.
warning: tracepoint 'tcp_ao_rnext_request' is unused.
warning: tracepoint 'tcp_ao_synack_no_key' is unused.
warning: tracepoint 'tcp_ao_snd_sne_update' is unused.
warning: tracepoint 'tcp_ao_rcv_sne_update' is unused.

Some of the above is totally unused but others are not used due to their
"trace_" functions being inside configs, in which case, the defined
tracepoints should also be inside those same configs. Others are
architecture specific but defined in generic code, where they should
either be moved to the architecture or be surrounded by #ifdef for the
architectures they are for.

This tool could be updated to process modules in the future.

I'd like to thank Mathieu Desnoyers for suggesting using strings instead
of pointers, as using pointers in vmlinux.o required handling relocations
and it required implementing almost a full feature linker to do so.

Link: https://lore.kernel.org/all/20250528114549.4d8a5e03@gandalf.local.home/

Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas.schier@linux.dev>
Cc: Nick Desaulniers <nick.desaulniers+lkml@gmail.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Link: https://lore.kernel.org/20250825231355.769343238@kernel.org
Suggested-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> # for using strings instead of pointers
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 include/asm-generic/vmlinux.lds.h |   1 +
 include/linux/tracepoint.h        |  10 ++
 kernel/trace/Kconfig              |  10 ++
 scripts/Makefile                  |   3 +
 scripts/link-vmlinux.sh           |   4 +
 scripts/tracepoint-update.c       | 232 ++++++++++++++++++++++++++++++
 6 files changed, 260 insertions(+)
 create mode 100644 scripts/tracepoint-update.c

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index ae2d2359b79e..b0aed322ccbd 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -1047,6 +1047,7 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
 	*(.modinfo)							\
 	/* ld.bfd warns about .gnu.version* even when not emitted */	\
 	*(.gnu.version*)						\
+	*(__tracepoint_check)
 
 #define DISCARDS							\
 	/DISCARD/ : {							\
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index 826ce3f8e1f8..71d2e085c49e 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -221,6 +221,14 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
 		__do_trace_##name(args);				\
 	}
 
+#ifdef CONFIG_TRACEPOINT_WARN_ON_UNUSED
+# define TRACEPOINT_CHECK(name)						\
+	static const char __used __section("__tracepoint_check") __trace_check[] = \
+		#name;
+#else
+# define TRACEPOINT_CHECK(tname)
+#endif
+
 /*
  * Make sure the alignment of the structure in the __tracepoints section will
  * not add unwanted padding between the beginning of the section and the
@@ -270,6 +278,7 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
 	__DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), PARAMS(data_proto)) \
 	static inline void __do_trace_##name(proto)			\
 	{								\
+		TRACEPOINT_CHECK(name)					\
 		if (cond) {						\
 			guard(preempt_notrace)();			\
 			__DO_TRACE_CALL(name, TP_ARGS(args));		\
@@ -289,6 +298,7 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
 	__DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), PARAMS(data_proto)) \
 	static inline void __do_trace_##name(proto)			\
 	{								\
+		TRACEPOINT_CHECK(name)					\
 		guard(rcu_tasks_trace)();				\
 		__DO_TRACE_CALL(name, TP_ARGS(args));			\
 	}								\
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index d2c79da81e4f..6dcb0fbacf0d 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -1067,6 +1067,16 @@ config GCOV_PROFILE_FTRACE
 	  Note that on a kernel compiled with this config, ftrace will
 	  run significantly slower.
 
+config TRACEPOINT_WARN_ON_UNUSED
+	bool "Warn on build if a tracepoint is defined but not used"
+	depends on TRACEPOINTS
+	help
+	  This option checks if every builtin defined tracepoint is
+	  used in the code. If a tracepoint is defined but not used,
+	  it will waste memory as its metadata is still created.
+	  This will cause a warning at build time if it detects a
+	  tracepoint created but never called.
+
 config FTRACE_SELFTEST
 	bool
 
diff --git a/scripts/Makefile b/scripts/Makefile
index f19624b3ed92..11bf1bbd8c5d 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -11,8 +11,10 @@ hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT)		+= sign-file
 hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE)	+= insert-sys-cert
 hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS)		+= rustdoc_test_builder
 hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS)		+= rustdoc_test_gen
+hostprogs-always-$(CONFIG_TRACEPOINT_WARN_ON_UNUSED)	+= tracepoint-update
 
 sorttable-objs := sorttable.o elf-parse.o
+tracepoint-update-objs := tracepoint-update.o elf-parse.o
 
 ifneq ($(or $(CONFIG_X86_64),$(CONFIG_X86_32)),)
 always-$(CONFIG_RUST)					+= target.json
@@ -27,6 +29,7 @@ generate_rust_target-rust := y
 rustdoc_test_builder-rust := y
 rustdoc_test_gen-rust := y
 
+HOSTCFLAGS_tracepoint-update.o = -I$(srctree)/tools/include
 HOSTCFLAGS_elf-parse.o = -I$(srctree)/tools/include
 HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
 HOSTLDLIBS_sorttable = -lpthread
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 51367c2bfc21..4934c5e6c0b1 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -211,6 +211,10 @@ kallsymso=
 strip_debug=
 generate_map=
 
+if is_enabled CONFIG_TRACEPOINT_WARN_ON_UNUSED; then
+	${objtree}/scripts/tracepoint-update vmlinux.o
+fi
+
 if is_enabled CONFIG_KALLSYMS; then
 	true > .tmp_vmlinux0.syms
 	kallsyms .tmp_vmlinux0.syms .tmp_vmlinux0.kallsyms
diff --git a/scripts/tracepoint-update.c b/scripts/tracepoint-update.c
new file mode 100644
index 000000000000..6ec30f39d0ad
--- /dev/null
+++ b/scripts/tracepoint-update.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include "elf-parse.h"
+
+static Elf_Shdr *check_data_sec;
+static Elf_Shdr *tracepoint_data_sec;
+
+static inline void *get_index(void *start, int entsize, int index)
+{
+	return start + (entsize * index);
+}
+
+static int compare_strings(const void *a, const void *b)
+{
+	const char *av = *(const char **)a;
+	const char *bv = *(const char **)b;
+
+	return strcmp(av, bv);
+}
+
+struct elf_tracepoint {
+	Elf_Ehdr *ehdr;
+	const char **array;
+	int count;
+};
+
+#define REALLOC_SIZE (1 << 10)
+#define REALLOC_MASK (REALLOC_SIZE - 1)
+
+static int add_string(const char *str, const char ***vals, int *count)
+{
+	const char **array = *vals;
+
+	if (!(*count & REALLOC_MASK)) {
+		int size = (*count) + REALLOC_SIZE;
+
+		array = realloc(array, sizeof(char *) * size);
+		if (!array) {
+			fprintf(stderr, "Failed memory allocation\n");
+			return -1;
+		}
+		*vals = array;
+	}
+
+	array[(*count)++] = str;
+	return 0;
+}
+
+/**
+ * for_each_shdr_str - iterator that reads strings that are in an ELF section.
+ * @len: "int" to hold the length of the current string
+ * @ehdr: A pointer to the ehdr of the ELF file
+ * @sec: The section that has the strings to iterate on
+ *
+ * This is a for loop that iterates over all the nul terminated strings
+ * that are in a given ELF section. The variable "str" will hold
+ * the current string for each iteration and the passed in @len will
+ * contain the strlen() of that string.
+ */
+#define for_each_shdr_str(len, ehdr, sec)				\
+	for (const char *str = (void *)(ehdr) + shdr_offset(sec),	\
+			*end = str + shdr_size(sec);			\
+	     len = strlen(str), str < end;				\
+	     str += (len) + 1)
+
+
+static void make_trace_array(struct elf_tracepoint *etrace)
+{
+	Elf_Ehdr *ehdr = etrace->ehdr;
+	const char **vals = NULL;
+	int count = 0;
+	int len;
+
+	etrace->array = NULL;
+
+	/*
+	 * The __tracepoint_check section is filled with strings of the
+	 * names of tracepoints (in tracepoint_strings). Create an array
+	 * that points to each string and then sort the array.
+	 */
+	for_each_shdr_str(len, ehdr, check_data_sec) {
+		if (!len)
+			continue;
+		if (add_string(str, &vals, &count) < 0)
+			return;
+	}
+
+	/* If CONFIG_TRACEPOINT_VERIFY_USED is not set, there's nothing to do */
+	if (!count)
+		return;
+
+	qsort(vals, count, sizeof(char *), compare_strings);
+
+	etrace->array = vals;
+	etrace->count = count;
+}
+
+static int find_event(const char *str, void *array, size_t size)
+{
+	return bsearch(&str, array, size, sizeof(char *), compare_strings) != NULL;
+}
+
+static void check_tracepoints(struct elf_tracepoint *etrace)
+{
+	Elf_Ehdr *ehdr = etrace->ehdr;
+	int len;
+
+	if (!etrace->array)
+		return;
+
+	/*
+	 * The __tracepoints_strings section holds all the names of the
+	 * defined tracepoints. If any of them are not in the
+	 * __tracepoint_check_section it means they are not used.
+	 */
+	for_each_shdr_str(len, ehdr, tracepoint_data_sec) {
+		if (!len)
+			continue;
+		if (!find_event(str, etrace->array, etrace->count)) {
+			fprintf(stderr, "warning: tracepoint '%s' is unused.\n", str);
+		}
+	}
+
+	free(etrace->array);
+}
+
+static void *tracepoint_check(struct elf_tracepoint *etrace)
+{
+	make_trace_array(etrace);
+	check_tracepoints(etrace);
+
+	return NULL;
+}
+
+static int process_tracepoints(void *addr, char const *const fname)
+{
+	struct elf_tracepoint etrace = {0};
+	Elf_Ehdr *ehdr = addr;
+	Elf_Shdr *shdr_start;
+	Elf_Shdr *string_sec;
+	const char *secstrings;
+	unsigned int shnum;
+	unsigned int shstrndx;
+	int shentsize;
+	int idx;
+	int done = 2;
+
+	shdr_start = (Elf_Shdr *)((char *)ehdr + ehdr_shoff(ehdr));
+	shentsize = ehdr_shentsize(ehdr);
+
+	shstrndx = ehdr_shstrndx(ehdr);
+	if (shstrndx == SHN_XINDEX)
+		shstrndx = shdr_link(shdr_start);
+	string_sec = get_index(shdr_start, shentsize, shstrndx);
+	secstrings = (const char *)ehdr + shdr_offset(string_sec);
+
+	shnum = ehdr_shnum(ehdr);
+	if (shnum == SHN_UNDEF)
+		shnum = shdr_size(shdr_start);
+
+	for (int i = 0; done && i < shnum; i++) {
+		Elf_Shdr *shdr = get_index(shdr_start, shentsize, i);
+
+		idx = shdr_name(shdr);
+
+		/* locate the __tracepoint_check in vmlinux */
+		if (!strcmp(secstrings + idx, "__tracepoint_check")) {
+			check_data_sec = shdr;
+			done--;
+		}
+
+		/* locate the __tracepoints_ptrs section in vmlinux */
+		if (!strcmp(secstrings + idx, "__tracepoints_strings")) {
+			tracepoint_data_sec = shdr;
+			done--;
+		}
+	}
+
+	if (!check_data_sec) {
+		fprintf(stderr,	"no __tracepoint_check in file: %s\n", fname);
+		return -1;
+	}
+
+	if (!tracepoint_data_sec) {
+		fprintf(stderr,	"no __tracepoint_strings in file: %s\n", fname);
+		return -1;
+	}
+
+	etrace.ehdr = ehdr;
+	tracepoint_check(&etrace);
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int n_error = 0;
+	size_t size = 0;
+	void *addr = NULL;
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: tracepoint-update vmlinux...\n");
+		return 0;
+	}
+
+	/* Process each file in turn, allowing deep failure. */
+	for (int i = 1; i < argc; i++) {
+		addr = elf_map(argv[i], &size, 1 << ET_REL);
+		if (!addr) {
+			++n_error;
+			continue;
+		}
+
+		if (process_tracepoints(addr, argv[i]))
+			++n_error;
+
+		elf_unmap(addr, size);
+	}
+
+	return !!n_error;
+}
-- 
2.50.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [for-next][PATCH 3/3] tracepoint: Do not warn for unused event that is exported
  2025-08-28 18:27 [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused Steven Rostedt
  2025-08-28 18:27 ` [for-next][PATCH 1/3] sorttable: Move ELF parsing into scripts/elf-parse.[ch] Steven Rostedt
  2025-08-28 18:27 ` [for-next][PATCH 2/3] tracing: Add a tracepoint verification check at build time Steven Rostedt
@ 2025-08-28 18:27 ` Steven Rostedt
  2025-08-28 21:02 ` [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused Stephen Rothwell
  3 siblings, 0 replies; 9+ messages in thread
From: Steven Rostedt @ 2025-08-28 18:27 UTC (permalink / raw)
  To: linux-kernel, Stephen Rothwell
  Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Linus Torvalds, Arnd Bergmann, Masahiro Yamada, Nathan Chancellor,
	Nicolas Schier, Nick Desaulniers, Catalin Marinas, Randy Dunlap

From: Steven Rostedt <rostedt@goodmis.org>

There are a few generic events that may only be used by modules. They are
defined and then set with EXPORT_TRACEPOINT*(). Mark events that are
exported as being used, even though they still waste memory in the kernel
proper.

Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nicolas.schier@linux.dev>
Cc: Nick Desaulniers <nick.desaulniers+lkml@gmail.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Link: https://lore.kernel.org/20250825231355.939259124@kernel.org
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 include/linux/tracepoint.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index 71d2e085c49e..ec6827d00d79 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -223,8 +223,8 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
 
 #ifdef CONFIG_TRACEPOINT_WARN_ON_UNUSED
 # define TRACEPOINT_CHECK(name)						\
-	static const char __used __section("__tracepoint_check") __trace_check[] = \
-		#name;
+	static const char __used __section("__tracepoint_check")	\
+	__trace_check_##name[] = #name;
 #else
 # define TRACEPOINT_CHECK(tname)
 #endif
@@ -381,10 +381,12 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
 	__DEFINE_TRACE_EXT(_name, NULL, PARAMS(_proto), PARAMS(_args));
 
 #define EXPORT_TRACEPOINT_SYMBOL_GPL(name)				\
+	TRACEPOINT_CHECK(name)						\
 	EXPORT_SYMBOL_GPL(__tracepoint_##name);				\
 	EXPORT_SYMBOL_GPL(__traceiter_##name);				\
 	EXPORT_STATIC_CALL_GPL(tp_func_##name)
 #define EXPORT_TRACEPOINT_SYMBOL(name)					\
+	TRACEPOINT_CHECK(name)						\
 	EXPORT_SYMBOL(__tracepoint_##name);				\
 	EXPORT_SYMBOL(__traceiter_##name);				\
 	EXPORT_STATIC_CALL(tp_func_##name)
-- 
2.50.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [for-next][PATCH 1/3] sorttable: Move ELF parsing into scripts/elf-parse.[ch]
  2025-08-28 18:27 ` [for-next][PATCH 1/3] sorttable: Move ELF parsing into scripts/elf-parse.[ch] Steven Rostedt
@ 2025-08-28 19:03   ` Nicolas Schier
  2025-08-28 19:36     ` Steven Rostedt
  0 siblings, 1 reply; 9+ messages in thread
From: Nicolas Schier @ 2025-08-28 19:03 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Stephen Rothwell, Masami Hiramatsu, Mark Rutland,
	Mathieu Desnoyers, Andrew Morton, Linus Torvalds, Arnd Bergmann,
	Masahiro Yamada, Nathan Chancellor, Nick Desaulniers,
	Catalin Marinas, Randy Dunlap

On Thu, Aug 28, 2025 at 02:27:55PM -0400, Steven Rostedt wrote:
> From: Steven Rostedt <rostedt@goodmis.org>
> 
> In order to share the elf parsing that is in sorttable.c so that other
> programs could use the same code, move it into elf-parse.c and
> elf-parse.h.
> 
> Cc: Masami Hiramatsu <mhiramat@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Masahiro Yamada <masahiroy@kernel.org>
> Cc: Nathan Chancellor <nathan@kernel.org>
> Cc: Nicolas Schier <nicolas.schier@linux.dev>
> Cc: Nick Desaulniers <nick.desaulniers+lkml@gmail.com>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Linus Torvalds <torvalds@linux-foundation.org>
> Cc: Randy Dunlap <rdunlap@infradead.org>
> Link: https://lore.kernel.org/20250825231355.597630284@kernel.org
> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
> ---
>  scripts/Makefile         |   3 +
>  scripts/Makefile.vmlinux |   2 +
>  scripts/elf-parse.c      | 198 ++++++++++++++++
>  scripts/elf-parse.h      | 305 +++++++++++++++++++++++++
>  scripts/sorttable.c      | 477 +++------------------------------------
>  5 files changed, 542 insertions(+), 443 deletions(-)
>  create mode 100644 scripts/elf-parse.c
>  create mode 100644 scripts/elf-parse.h
> 
> diff --git a/scripts/Makefile b/scripts/Makefile
> index 46f860529df5..f19624b3ed92 100644
> --- a/scripts/Makefile
> +++ b/scripts/Makefile
> @@ -12,6 +12,8 @@ hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE)	+= insert-sys-cert
>  hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS)		+= rustdoc_test_builder
>  hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS)		+= rustdoc_test_gen
>  
> +sorttable-objs := sorttable.o elf-parse.o
> +
>  ifneq ($(or $(CONFIG_X86_64),$(CONFIG_X86_32)),)
>  always-$(CONFIG_RUST)					+= target.json
>  filechk_rust_target = $< < include/config/auto.conf
> @@ -25,6 +27,7 @@ generate_rust_target-rust := y
>  rustdoc_test_builder-rust := y
>  rustdoc_test_gen-rust := y
>  
> +HOSTCFLAGS_elf-parse.o = -I$(srctree)/tools/include
>  HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
>  HOSTLDLIBS_sorttable = -lpthread
>  HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
> diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
> index b64862dc6f08..ebbb8b5aca83 100644
> --- a/scripts/Makefile.vmlinux
> +++ b/scripts/Makefile.vmlinux
> @@ -97,6 +97,8 @@ ifdef CONFIG_BUILDTIME_TABLE_SORT
>  $(vmlinux-final): scripts/sorttable
>  endif
>  
> +.PRECIOUS: $(vmlinux-final)

Why do you need '.PRECIOUS' here?  Does its need match to Masahiros
explanations in 
https://git.kernel.org/torvalds/c/875ef1a57f32fcb91010dc9bc8bd1166956a579e

Kind regards,
Nicolas

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [for-next][PATCH 1/3] sorttable: Move ELF parsing into scripts/elf-parse.[ch]
  2025-08-28 19:03   ` Nicolas Schier
@ 2025-08-28 19:36     ` Steven Rostedt
  0 siblings, 0 replies; 9+ messages in thread
From: Steven Rostedt @ 2025-08-28 19:36 UTC (permalink / raw)
  To: Nicolas Schier
  Cc: linux-kernel, Stephen Rothwell, Masami Hiramatsu, Mark Rutland,
	Mathieu Desnoyers, Andrew Morton, Linus Torvalds, Arnd Bergmann,
	Masahiro Yamada, Nathan Chancellor, Nick Desaulniers,
	Catalin Marinas, Randy Dunlap

On Thu, 28 Aug 2025 21:03:52 +0200
Nicolas Schier <nsc@kernel.org> wrote:

> > --- a/scripts/Makefile.vmlinux
> > +++ b/scripts/Makefile.vmlinux
> > @@ -97,6 +97,8 @@ ifdef CONFIG_BUILDTIME_TABLE_SORT
> >  $(vmlinux-final): scripts/sorttable
> >  endif
> >  
> > +.PRECIOUS: $(vmlinux-final)  
> 
> Why do you need '.PRECIOUS' here?  Does its need match to Masahiros
> explanations in 

I don't. Crap! That was from debugging where I needed to keep the
vmlinux-final around to test. I must have accidentally committed it.

Let me go and remove that.

Thanks for spotting it!

-- Steve


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused
  2025-08-28 18:27 [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused Steven Rostedt
                   ` (2 preceding siblings ...)
  2025-08-28 18:27 ` [for-next][PATCH 3/3] tracepoint: Do not warn for unused event that is exported Steven Rostedt
@ 2025-08-28 21:02 ` Stephen Rothwell
  2025-08-28 21:13   ` Steven Rostedt
  2025-08-29 12:10   ` Steven Rostedt
  3 siblings, 2 replies; 9+ messages in thread
From: Stephen Rothwell @ 2025-08-28 21:02 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers,
	Andrew Morton, Linus Torvalds

[-- Attachment #1: Type: text/plain, Size: 1237 bytes --]

Hi Steven,

On Thu, 28 Aug 2025 14:27:54 -0400 Steven Rostedt <rostedt@kernel.org> wrote:
>
> I built this against all archs in my tree (26 of them) with a allyesconfig.
> Unfortunately, only 10 build successfully with that (they all build
> successfully with defconfig and this option with tracing enabled). This
> detected 178 unique tracepoints that are defined and not used:
> 
> $ grep '^warning:' /work/autotest/cross-unused-traceevnts.log | sort -u |wc -l
> 178
> 
> Among them, 78 tracepoints were created and never referenced.
> 
> $ grep '^warning:' /work/autotest/cross-unused-traceevents.log | sort -u |cut -d"'" -f2 |
>     while read a ; do if ! git grep -q trace_$a ; then echo $a; fi ; done | wc -l
> 78
> 
> The 100 remaining are likely in strange #ifdef CONFIG combinations where an
> allyesconfig defines the tracepoint but doesn't enable the code that uses
> them.

[Pretending to be Linus :-)]

So, have you fixed up the 178 new warnings you know about?  I cannot
possibly do that, or even notify the offenders.  Please do that before
adding this code to linux-next.

But, really, these known warnings can just make it so much harder to
notice new ones.
-- 
Cheers,
Stephen Rothwell

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused
  2025-08-28 21:02 ` [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused Stephen Rothwell
@ 2025-08-28 21:13   ` Steven Rostedt
  2025-08-29 12:10   ` Steven Rostedt
  1 sibling, 0 replies; 9+ messages in thread
From: Steven Rostedt @ 2025-08-28 21:13 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: linux-kernel, Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers,
	Andrew Morton, Linus Torvalds

On Fri, 29 Aug 2025 07:02:24 +1000
Stephen Rothwell <sfr@canb.auug.org.au> wrote:

> [Pretending to be Linus :-)]
> 
> So, have you fixed up the 178 new warnings you know about?  I cannot
> possibly do that, or even notify the offenders.  Please do that before
> adding this code to linux-next.
> 
> But, really, these known warnings can just make it so much harder to
> notice new ones.

Then this won't get in. I simply don't have the time to fix the current
ones. I did 20 or so, and that took me all day (which I did on a
holiday). And this work is something I'm already doing on my own time,
as my employer has other priorities for me to work on.

But it is something that is needed as there's currently nothing that
tells you that you have a tracepoint not used, and the are growing in
numbers and wasting more memory.

There is an option that needs to be enabled. Now this will get enabled
with allmodconfig or allyesconfig, but scripts that do tests could
disable it. Or I can make it a tri op that doesn't get set by one of
those (but randconfig may set it).

As for fixing the warnings, it really belongs to whoever added the
tracepoint (git blame will give you that). And would be a great project
for an intern (which I don't have any).

-- Steve

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused
  2025-08-28 21:02 ` [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused Stephen Rothwell
  2025-08-28 21:13   ` Steven Rostedt
@ 2025-08-29 12:10   ` Steven Rostedt
  1 sibling, 0 replies; 9+ messages in thread
From: Steven Rostedt @ 2025-08-29 12:10 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: Steven Rostedt, linux-kernel, Masami Hiramatsu, Mark Rutland,
	Mathieu Desnoyers, Andrew Morton, Linus Torvalds

On Fri, 29 Aug 2025 07:02:24 +1000
Stephen Rothwell <sfr@canb.auug.org.au> wrote:

> But, really, these known warnings can just make it so much harder to
> notice new ones.

They all should be fixed. Note, this is not a compiler warning. It's a tool
that states "Your code is causing wasted memory to be allocate in the
running machine". If your tracepoint shows up in this list, then you should
fix it.

On an allyesconfig for x86_64:

warning: tracepoint 'kvm_iocsr' is unused.
warning: tracepoint 'nfs4_rename' is unused.
warning: tracepoint 'nfs4_renew' is unused.
warning: tracepoint 'xfs_metadir_link' is unused.
warning: tracepoint 'xfs_metadir_start_link' is unused.
warning: tracepoint 'xrep_rtbitmap_load_word' is unused.
warning: tracepoint 'xrep_rtbitmap_load_words' is unused.
warning: tracepoint 'xrep_rtbitmap_load' is unused.
warning: tracepoint 'xrep_nlinks_set_record' is unused.
warning: tracepoint 'xrep_cow_free_staging' is unused.
warning: tracepoint 'ocfs2_encode_fh_begin' is unused.
warning: tracepoint 'ocfs2_duplicate_clusters_by_jbd' is unused.
warning: tracepoint 'trans_restart_relock_key_cache_fill' is unused.
warning: tracepoint 'zonefs_file_dio_append' is unused.
warning: tracepoint 'edma_readb' is unused.
warning: tracepoint 'edma_readw' is unused.
warning: tracepoint 'host1x_syncpt_wait_check' is unused.
warning: tracepoint 'host1x_channel_submit_complete' is unused.
warning: tracepoint 'host1x_channel_release' is unused.
warning: tracepoint 'host1x_channel_open' is unused.
warning: tracepoint 'amdgpu_reset_reg_dumps' is unused.
warning: tracepoint 'amdgpu_dm_atomic_state_template' is unused.
warning: tracepoint 'xe_exec_queue_supress_resume' is unused.
warning: tracepoint 'xe_vm_restart' is unused.
warning: tracepoint 'xe_vma_userptr_rebind_exec' is unused.
warning: tracepoint 'xe_vma_userptr_rebind_worker' is unused.
warning: tracepoint 'xe_vma_flush' is unused.
warning: tracepoint 'dpu_rm_reserve_intf' is unused.
warning: tracepoint 'dpu_enc_atomic_check_flags' is unused.
warning: tracepoint 'dpu_crtc_runtime_resume' is unused.
warning: tracepoint 'dpu_enc_atomic_check' is unused.
warning: tracepoint 'dpu_trace_counter' is unused.
warning: tracepoint 'scsi_zone_wp_update' is unused.
warning: tracepoint 'scsi_prepare_zone_append' is unused.
warning: tracepoint 'ath12k_htt_rxdesc' is unused.
warning: tracepoint 'ath12k_htt_ppdu_stats' is unused.
warning: tracepoint 'ath12k_htt_pktlog' is unused.
warning: tracepoint 'brcms_dpc' is unused.
warning: tracepoint 'brcms_timer' is unused.
warning: tracepoint 'mt_tx_status' is unused.
warning: tracepoint 'ee_read' is unused.
warning: tracepoint 'cdns3_mapped_request' is unused.
warning: tracepoint 'cdns3_map_request' is unused.
warning: tracepoint 'cdns3_stream_transfer_split_next_part' is unused.
warning: tracepoint 'cdns3_stream_transfer_split' is unused.
warning: tracepoint 'cdnsp_handle_cmd_flush_ep' is unused.
warning: tracepoint 'cdnsp_setup_device' is unused.
warning: tracepoint 'cdnsp_free_priv_device' is unused.
warning: tracepoint 'cdnsp_defered_event' is unused.
warning: tracepoint 'cdnsp_ep0_halted' is unused.
warning: tracepoint 'cdns2_iso_out_ep_disable' is unused.
warning: tracepoint 'cdns2_mapped_request' is unused.
warning: tracepoint 'cdns2_map_request' is unused.
warning: tracepoint 'cdns2_ep0_enqueue' is unused.
warning: tracepoint 'cdns2_ep_queue' is unused.
warning: tracepoint 'cdns2_ep0_set_config' is unused.
warning: tracepoint 'cdns2_may_wakeup' is unused.
warning: tracepoint 'cdns2_lpm' is unused.
warning: tracepoint 'ucsi_reset_ppm' is unused.
warning: tracepoint 'ucsi_run_command' is unused.
warning: tracepoint 'icm_send_mra' is unused.
warning: tracepoint 'open_err_template' is unused.
warning: tracepoint 'irdma_send_cm_event_no_node' is unused.
warning: tracepoint 'hfi1_txq_xmit_stopped' is unused.
warning: tracepoint 'hfi1_mmu_invalidate' is unused.
warning: tracepoint 'rvt_mr_fmr_seg' is unused.
warning: tracepoint 'camera_debug' is unused.
warning: tracepoint 'camera_meminfo' is unused.
warning: tracepoint 'rpc_socket_reset_connection' is unused.
warning: tracepoint 'rxrpc_drop_ack' is unused.
warning: tracepoint 'cfg80211_return_u32' is unused.
warning: tracepoint 'cfg80211_return_uint' is unused.
warning: tracepoint 'cfg80211_chandef_dfs_required' is unused.
warning: tracepoint 'cfg80211_send_rx_auth' is unused.
warning: tracepoint 'rdev_return_void_tx_rx' is unused.
warning: tracepoint 'drv_offchannel_tx_cancel_wait' is unused.
warning: tracepoint 'tipc_node_dump' is unused.
warning: tracepoint '802154_new_scan_event' is unused.
warning: tracepoint '802154_drv_set_pan_coord' is unused.

Each one of those causes around 5K of wasted memory on your machine.

Most of them is because of some crazy config combinations the maintainer
has, as they are used, but for some reason an allyesconfig isn't the right
config option to enable them.

I'll push this branch up, and if it causes issues for you, I'll remove it.
But then, I'm not doing anymore work on fixing this.

-- Steve


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-08-29 12:10 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-28 18:27 [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused Steven Rostedt
2025-08-28 18:27 ` [for-next][PATCH 1/3] sorttable: Move ELF parsing into scripts/elf-parse.[ch] Steven Rostedt
2025-08-28 19:03   ` Nicolas Schier
2025-08-28 19:36     ` Steven Rostedt
2025-08-28 18:27 ` [for-next][PATCH 2/3] tracing: Add a tracepoint verification check at build time Steven Rostedt
2025-08-28 18:27 ` [for-next][PATCH 3/3] tracepoint: Do not warn for unused event that is exported Steven Rostedt
2025-08-28 21:02 ` [for-next][PATCH 0/3] tracing: Trigger a warning on build if a tracepoint is defined but unused Stephen Rothwell
2025-08-28 21:13   ` Steven Rostedt
2025-08-29 12:10   ` Steven Rostedt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).