diff options
| -rw-r--r-- | Makefile | 21 | ||||
| -rw-r--r-- | include/asm-generic/vmlinux.lds.h | 1 | ||||
| -rw-r--r-- | include/linux/tracepoint.h | 13 | ||||
| -rw-r--r-- | scripts/.gitignore | 1 | ||||
| -rw-r--r-- | scripts/Makefile | 6 | ||||
| -rw-r--r-- | scripts/Makefile.modfinal | 5 | ||||
| -rw-r--r-- | scripts/elf-parse.c | 198 | ||||
| -rw-r--r-- | scripts/elf-parse.h | 305 | ||||
| -rwxr-xr-x | scripts/link-vmlinux.sh | 7 | ||||
| -rw-r--r-- | scripts/sorttable.c | 477 | ||||
| -rw-r--r-- | scripts/tracepoint-update.c | 261 |
11 files changed, 852 insertions, 443 deletions
@@ -810,6 +810,25 @@ ifdef CONFIG_FUNCTION_TRACER CC_FLAGS_FTRACE := -pg endif +ifdef CONFIG_TRACEPOINTS +# To check for unused tracepoints (tracepoints that are defined but never +# called), run with: +# +# make UT=1 +# +# Each unused tracepoints can take up to 5KB of memory in the running kernel. +# It is best to remove any that are not used. +# +# This command line option will be removed when all current unused +# tracepoints are removed. + +ifeq ("$(origin UT)", "command line") + WARN_ON_UNUSED_TRACEPOINTS := $(UT) +endif +endif # CONFIG_TRACEPOINTS + +export WARN_ON_UNUSED_TRACEPOINTS + include $(srctree)/arch/$(SRCARCH)/Makefile ifdef need-config @@ -1787,6 +1806,8 @@ help: @echo ' c: extra checks in the configuration stage (Kconfig)' @echo ' e: warnings are being treated as errors' @echo ' Multiple levels can be combined with W=12 or W=123' + @echo ' make UT=1 [targets] Warn if a tracepoint is defined but not used.' + @echo ' [ This will be removed when all current unused tracepoints are eliminated. ]' @$(if $(dtstree), \ echo ' make CHECK_DTBS=1 [targets] Check all generated dtb files against schema'; \ echo ' This can be applied both to "dtbs" and to individual "foo.dtb" targets' ; \ diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index a464ff6c1a61..8ca130af301f 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -1065,6 +1065,7 @@ *(.no_trim_symbol) \ /* 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..8a56f3278b1b 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -222,6 +222,15 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) } /* + * When a tracepoint is used, it's name is added to the __tracepoint_check + * section. This section is only used at build time to make sure all + * defined tracepoints are used. It is discarded after the build. + */ +# define TRACEPOINT_CHECK(name) \ + static const char __used __section("__tracepoint_check") \ + __trace_check_##name[] = #name; + +/* * Make sure the alignment of the structure in the __tracepoints section will * not add unwanted padding between the beginning of the section and the * structure. Force alignment to the same alignment as the section start. @@ -270,6 +279,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 +299,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)); \ } \ @@ -371,10 +382,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) diff --git a/scripts/.gitignore b/scripts/.gitignore index c2ef68848da5..4215c2208f7e 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -11,4 +11,5 @@ /sign-file /sorttable /target.json +/tracepoint-update /unifdef diff --git a/scripts/Makefile b/scripts/Makefile index 46f860529df5..0941e5ce7b57 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -11,6 +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_TRACEPOINTS) += 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 @@ -25,6 +29,8 @@ 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 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 542ba462ed3e..149e12ff5700 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -28,6 +28,10 @@ ccflags-remove-y := $(CC_FLAGS_CFI) .module-common.o: $(srctree)/scripts/module-common.c FORCE $(call if_changed_rule,cc_o_c) +ifneq ($(WARN_ON_UNUSED_TRACEPOINTS),) +cmd_check_tracepoint = $(objtree)/scripts/tracepoint-update --module $<; +endif + quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o = \ $(LD) -r $(KBUILD_LDFLAGS) \ @@ -57,6 +61,7 @@ if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \ ifdef CONFIG_DEBUG_INFO_BTF_MODULES +$(if $(newer-prereqs),$(call cmd,btf_ko)) endif + +$(call cmd,check_tracepoint) targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o) .module-common.o 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/link-vmlinux.sh b/scripts/link-vmlinux.sh index 2df714ba51a9..4ab44c73da4d 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -209,6 +209,13 @@ kallsymso= strip_debug= generate_map= +# Use "make UT=1" to trigger warnings on unused tracepoints +case "${WARN_ON_UNUSED_TRACEPOINTS}" in +*1*) + ${objtree}/scripts/tracepoint-update vmlinux.o + ;; +esac + if is_enabled CONFIG_KALLSYMS; then true > .tmp_vmlinux0.syms kallsyms .tmp_vmlinux0.syms .tmp_vmlinux0.kallsyms 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 |
