Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'tracepoints-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull unused tracepoints update from Steven Rostedt:
"Detect unused tracepoints.

If a tracepoint is defined but never used (TRACE_EVENT() created but
no trace_<tracepoint>() called), it can take up to or more than 5K of
memory each. This can add up as there are around a hundred unused
tracepoints with various configs. That is 500K of wasted memory.

Add a make build parameter of "UT=1" to have the build warn if an
unused tracepoint is detected in the build. This allows detection of
unused tracepoints to be upstream so that outreachy and the mentoring
project can have new developers look for fixing them, without having
these warnings suddenly show up when someone upgrades their kernel.

When all known unused tracepoints are removed, then the "UT=1" build
parameter can be removed and unused tracepoints will always warn. This
will catch new unused tracepoints after the current ones have been
removed.

Summary:

- Separate out elf functions from sorttable.c

Move out the ELF parsing functions from sorttable.c so that the
tracing tooling can use it.

- Add a tracepoint verifier tool to the build process

If "UT=1" is added to the kernel command line, any unused
tracepoints will trigger a warning at build time.

- Do not warn about unused tracepoints for tracepoints that are
exported

There are sever cases where a tracepoint is created by the kernel
and used by modules. Since there's no easy way to detect if these
are truly unused since the users are in modules, if a tracepoint is
exported, assume it will eventually be used by a module. Note,
there's not many exported tracepoints so this should not be a
problem to ignore them.

- Have building of modules also detect unused tracepoints

Do not only check the main vmlinux for unused tracepoints, also
check modules. If a module is defining a tracepoint it should be
using it.

- Add the tracepoint-update program to the ignore file

The new tracepoint-update program needs to be ignored by git"

* tag 'tracepoints-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
scripts: add tracepoint-update to the list of ignores files
tracing: Add warnings for unused tracepoints for modules
tracing: Allow tracepoint-update.c to work with modules
tracepoint: Do not warn for unused event that is exported
tracing: Add a tracepoint verification check at build time
sorttable: Move ELF parsing into scripts/elf-parse.[ch]

+852 -443
+21
Makefile
··· 810 810 CC_FLAGS_FTRACE := -pg 811 811 endif 812 812 813 + ifdef CONFIG_TRACEPOINTS 814 + # To check for unused tracepoints (tracepoints that are defined but never 815 + # called), run with: 816 + # 817 + # make UT=1 818 + # 819 + # Each unused tracepoints can take up to 5KB of memory in the running kernel. 820 + # It is best to remove any that are not used. 821 + # 822 + # This command line option will be removed when all current unused 823 + # tracepoints are removed. 824 + 825 + ifeq ("$(origin UT)", "command line") 826 + WARN_ON_UNUSED_TRACEPOINTS := $(UT) 827 + endif 828 + endif # CONFIG_TRACEPOINTS 829 + 830 + export WARN_ON_UNUSED_TRACEPOINTS 831 + 813 832 include $(srctree)/arch/$(SRCARCH)/Makefile 814 833 815 834 ifdef need-config ··· 1806 1787 @echo ' c: extra checks in the configuration stage (Kconfig)' 1807 1788 @echo ' e: warnings are being treated as errors' 1808 1789 @echo ' Multiple levels can be combined with W=12 or W=123' 1790 + @echo ' make UT=1 [targets] Warn if a tracepoint is defined but not used.' 1791 + @echo ' [ This will be removed when all current unused tracepoints are eliminated. ]' 1809 1792 @$(if $(dtstree), \ 1810 1793 echo ' make CHECK_DTBS=1 [targets] Check all generated dtb files against schema'; \ 1811 1794 echo ' This can be applied both to "dtbs" and to individual "foo.dtb" targets' ; \
+1
include/asm-generic/vmlinux.lds.h
··· 1065 1065 *(.no_trim_symbol) \ 1066 1066 /* ld.bfd warns about .gnu.version* even when not emitted */ \ 1067 1067 *(.gnu.version*) \ 1068 + *(__tracepoint_check) \ 1068 1069 1069 1070 #define DISCARDS \ 1070 1071 /DISCARD/ : { \
+13
include/linux/tracepoint.h
··· 222 222 } 223 223 224 224 /* 225 + * When a tracepoint is used, it's name is added to the __tracepoint_check 226 + * section. This section is only used at build time to make sure all 227 + * defined tracepoints are used. It is discarded after the build. 228 + */ 229 + # define TRACEPOINT_CHECK(name) \ 230 + static const char __used __section("__tracepoint_check") \ 231 + __trace_check_##name[] = #name; 232 + 233 + /* 225 234 * Make sure the alignment of the structure in the __tracepoints section will 226 235 * not add unwanted padding between the beginning of the section and the 227 236 * structure. Force alignment to the same alignment as the section start. ··· 279 270 __DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), PARAMS(data_proto)) \ 280 271 static inline void __do_trace_##name(proto) \ 281 272 { \ 273 + TRACEPOINT_CHECK(name) \ 282 274 if (cond) { \ 283 275 guard(preempt_notrace)(); \ 284 276 __DO_TRACE_CALL(name, TP_ARGS(args)); \ ··· 299 289 __DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), PARAMS(data_proto)) \ 300 290 static inline void __do_trace_##name(proto) \ 301 291 { \ 292 + TRACEPOINT_CHECK(name) \ 302 293 guard(rcu_tasks_trace)(); \ 303 294 __DO_TRACE_CALL(name, TP_ARGS(args)); \ 304 295 } \ ··· 382 371 __DEFINE_TRACE_EXT(_name, NULL, PARAMS(_proto), PARAMS(_args)); 383 372 384 373 #define EXPORT_TRACEPOINT_SYMBOL_GPL(name) \ 374 + TRACEPOINT_CHECK(name) \ 385 375 EXPORT_SYMBOL_GPL(__tracepoint_##name); \ 386 376 EXPORT_SYMBOL_GPL(__traceiter_##name); \ 387 377 EXPORT_STATIC_CALL_GPL(tp_func_##name) 388 378 #define EXPORT_TRACEPOINT_SYMBOL(name) \ 379 + TRACEPOINT_CHECK(name) \ 389 380 EXPORT_SYMBOL(__tracepoint_##name); \ 390 381 EXPORT_SYMBOL(__traceiter_##name); \ 391 382 EXPORT_STATIC_CALL(tp_func_##name)
+1
scripts/.gitignore
··· 11 11 /sign-file 12 12 /sorttable 13 13 /target.json 14 + /tracepoint-update 14 15 /unifdef
+6
scripts/Makefile
··· 11 11 hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert 12 12 hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_builder 13 13 hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_gen 14 + hostprogs-always-$(CONFIG_TRACEPOINTS) += tracepoint-update 15 + 16 + sorttable-objs := sorttable.o elf-parse.o 17 + tracepoint-update-objs := tracepoint-update.o elf-parse.o 14 18 15 19 ifneq ($(or $(CONFIG_X86_64),$(CONFIG_X86_32)),) 16 20 always-$(CONFIG_RUST) += target.json ··· 29 25 rustdoc_test_builder-rust := y 30 26 rustdoc_test_gen-rust := y 31 27 28 + HOSTCFLAGS_tracepoint-update.o = -I$(srctree)/tools/include 29 + HOSTCFLAGS_elf-parse.o = -I$(srctree)/tools/include 32 30 HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include 33 31 HOSTLDLIBS_sorttable = -lpthread 34 32 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
+5
scripts/Makefile.modfinal
··· 28 28 .module-common.o: $(srctree)/scripts/module-common.c FORCE 29 29 $(call if_changed_rule,cc_o_c) 30 30 31 + ifneq ($(WARN_ON_UNUSED_TRACEPOINTS),) 32 + cmd_check_tracepoint = $(objtree)/scripts/tracepoint-update --module $<; 33 + endif 34 + 31 35 quiet_cmd_ld_ko_o = LD [M] $@ 32 36 cmd_ld_ko_o = \ 33 37 $(LD) -r $(KBUILD_LDFLAGS) \ ··· 61 57 ifdef CONFIG_DEBUG_INFO_BTF_MODULES 62 58 +$(if $(newer-prereqs),$(call cmd,btf_ko)) 63 59 endif 60 + +$(call cmd,check_tracepoint) 64 61 65 62 targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o) .module-common.o 66 63
+198
scripts/elf-parse.c
··· 1 + #include <sys/types.h> 2 + #include <sys/mman.h> 3 + #include <sys/stat.h> 4 + #include <fcntl.h> 5 + #include <stdio.h> 6 + #include <stdlib.h> 7 + #include <stdbool.h> 8 + #include <string.h> 9 + #include <unistd.h> 10 + #include <errno.h> 11 + 12 + #include "elf-parse.h" 13 + 14 + struct elf_funcs elf_parser; 15 + 16 + /* 17 + * Get the whole file as a programming convenience in order to avoid 18 + * malloc+lseek+read+free of many pieces. If successful, then mmap 19 + * avoids copying unused pieces; else just read the whole file. 20 + * Open for both read and write. 21 + */ 22 + static void *map_file(char const *fname, size_t *size) 23 + { 24 + int fd; 25 + struct stat sb; 26 + void *addr = NULL; 27 + 28 + fd = open(fname, O_RDWR); 29 + if (fd < 0) { 30 + perror(fname); 31 + return NULL; 32 + } 33 + if (fstat(fd, &sb) < 0) { 34 + perror(fname); 35 + goto out; 36 + } 37 + if (!S_ISREG(sb.st_mode)) { 38 + fprintf(stderr, "not a regular file: %s\n", fname); 39 + goto out; 40 + } 41 + 42 + addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 43 + if (addr == MAP_FAILED) { 44 + fprintf(stderr, "Could not mmap file: %s\n", fname); 45 + goto out; 46 + } 47 + 48 + *size = sb.st_size; 49 + 50 + out: 51 + close(fd); 52 + return addr; 53 + } 54 + 55 + static int elf_parse(const char *fname, void *addr, uint32_t types) 56 + { 57 + Elf_Ehdr *ehdr = addr; 58 + uint16_t type; 59 + 60 + switch (ehdr->e32.e_ident[EI_DATA]) { 61 + case ELFDATA2LSB: 62 + elf_parser.r = rle; 63 + elf_parser.r2 = r2le; 64 + elf_parser.r8 = r8le; 65 + elf_parser.w = wle; 66 + elf_parser.w8 = w8le; 67 + break; 68 + case ELFDATA2MSB: 69 + elf_parser.r = rbe; 70 + elf_parser.r2 = r2be; 71 + elf_parser.r8 = r8be; 72 + elf_parser.w = wbe; 73 + elf_parser.w8 = w8be; 74 + break; 75 + default: 76 + fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", 77 + ehdr->e32.e_ident[EI_DATA], fname); 78 + return -1; 79 + } 80 + 81 + if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 || 82 + ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) { 83 + fprintf(stderr, "unrecognized ELF file %s\n", fname); 84 + return -1; 85 + } 86 + 87 + type = elf_parser.r2(&ehdr->e32.e_type); 88 + if (!((1 << type) & types)) { 89 + fprintf(stderr, "Invalid ELF type file %s\n", fname); 90 + return -1; 91 + } 92 + 93 + switch (ehdr->e32.e_ident[EI_CLASS]) { 94 + case ELFCLASS32: { 95 + elf_parser.ehdr_shoff = ehdr32_shoff; 96 + elf_parser.ehdr_shentsize = ehdr32_shentsize; 97 + elf_parser.ehdr_shstrndx = ehdr32_shstrndx; 98 + elf_parser.ehdr_shnum = ehdr32_shnum; 99 + elf_parser.shdr_addr = shdr32_addr; 100 + elf_parser.shdr_offset = shdr32_offset; 101 + elf_parser.shdr_link = shdr32_link; 102 + elf_parser.shdr_size = shdr32_size; 103 + elf_parser.shdr_name = shdr32_name; 104 + elf_parser.shdr_type = shdr32_type; 105 + elf_parser.shdr_entsize = shdr32_entsize; 106 + elf_parser.sym_type = sym32_type; 107 + elf_parser.sym_name = sym32_name; 108 + elf_parser.sym_value = sym32_value; 109 + elf_parser.sym_shndx = sym32_shndx; 110 + elf_parser.rela_offset = rela32_offset; 111 + elf_parser.rela_info = rela32_info; 112 + elf_parser.rela_addend = rela32_addend; 113 + elf_parser.rela_write_addend = rela32_write_addend; 114 + 115 + if (elf_parser.r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) || 116 + elf_parser.r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) { 117 + fprintf(stderr, 118 + "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); 119 + return -1; 120 + } 121 + 122 + } 123 + break; 124 + case ELFCLASS64: { 125 + elf_parser.ehdr_shoff = ehdr64_shoff; 126 + elf_parser.ehdr_shentsize = ehdr64_shentsize; 127 + elf_parser.ehdr_shstrndx = ehdr64_shstrndx; 128 + elf_parser.ehdr_shnum = ehdr64_shnum; 129 + elf_parser.shdr_addr = shdr64_addr; 130 + elf_parser.shdr_offset = shdr64_offset; 131 + elf_parser.shdr_link = shdr64_link; 132 + elf_parser.shdr_size = shdr64_size; 133 + elf_parser.shdr_name = shdr64_name; 134 + elf_parser.shdr_type = shdr64_type; 135 + elf_parser.shdr_entsize = shdr64_entsize; 136 + elf_parser.sym_type = sym64_type; 137 + elf_parser.sym_name = sym64_name; 138 + elf_parser.sym_value = sym64_value; 139 + elf_parser.sym_shndx = sym64_shndx; 140 + elf_parser.rela_offset = rela64_offset; 141 + elf_parser.rela_info = rela64_info; 142 + elf_parser.rela_addend = rela64_addend; 143 + elf_parser.rela_write_addend = rela64_write_addend; 144 + 145 + if (elf_parser.r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) || 146 + elf_parser.r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) { 147 + fprintf(stderr, 148 + "unrecognized ET_EXEC/ET_DYN file: %s\n", 149 + fname); 150 + return -1; 151 + } 152 + 153 + } 154 + break; 155 + default: 156 + fprintf(stderr, "unrecognized ELF class %d %s\n", 157 + ehdr->e32.e_ident[EI_CLASS], fname); 158 + return -1; 159 + } 160 + return 0; 161 + } 162 + 163 + int elf_map_machine(void *addr) 164 + { 165 + Elf_Ehdr *ehdr = addr; 166 + 167 + return elf_parser.r2(&ehdr->e32.e_machine); 168 + } 169 + 170 + int elf_map_long_size(void *addr) 171 + { 172 + Elf_Ehdr *ehdr = addr; 173 + 174 + return ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; 175 + } 176 + 177 + void *elf_map(char const *fname, size_t *size, uint32_t types) 178 + { 179 + void *addr; 180 + int ret; 181 + 182 + addr = map_file(fname, size); 183 + if (!addr) 184 + return NULL; 185 + 186 + ret = elf_parse(fname, addr, types); 187 + if (ret < 0) { 188 + elf_unmap(addr, *size); 189 + return NULL; 190 + } 191 + 192 + return addr; 193 + } 194 + 195 + void elf_unmap(void *addr, size_t size) 196 + { 197 + munmap(addr, size); 198 + }
+305
scripts/elf-parse.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #ifndef _SCRIPTS_ELF_PARSE_H 3 + #define _SCRIPTS_ELF_PARSE_H 4 + 5 + #include <elf.h> 6 + 7 + #include <tools/be_byteshift.h> 8 + #include <tools/le_byteshift.h> 9 + 10 + typedef union { 11 + Elf32_Ehdr e32; 12 + Elf64_Ehdr e64; 13 + } Elf_Ehdr; 14 + 15 + typedef union { 16 + Elf32_Shdr e32; 17 + Elf64_Shdr e64; 18 + } Elf_Shdr; 19 + 20 + typedef union { 21 + Elf32_Sym e32; 22 + Elf64_Sym e64; 23 + } Elf_Sym; 24 + 25 + typedef union { 26 + Elf32_Rela e32; 27 + Elf64_Rela e64; 28 + } Elf_Rela; 29 + 30 + struct elf_funcs { 31 + int (*compare_extable)(const void *a, const void *b); 32 + uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr); 33 + uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr); 34 + uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr); 35 + uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr); 36 + uint64_t (*shdr_addr)(Elf_Shdr *shdr); 37 + uint64_t (*shdr_offset)(Elf_Shdr *shdr); 38 + uint64_t (*shdr_size)(Elf_Shdr *shdr); 39 + uint64_t (*shdr_entsize)(Elf_Shdr *shdr); 40 + uint32_t (*shdr_link)(Elf_Shdr *shdr); 41 + uint32_t (*shdr_name)(Elf_Shdr *shdr); 42 + uint32_t (*shdr_type)(Elf_Shdr *shdr); 43 + uint8_t (*sym_type)(Elf_Sym *sym); 44 + uint32_t (*sym_name)(Elf_Sym *sym); 45 + uint64_t (*sym_value)(Elf_Sym *sym); 46 + uint16_t (*sym_shndx)(Elf_Sym *sym); 47 + uint64_t (*rela_offset)(Elf_Rela *rela); 48 + uint64_t (*rela_info)(Elf_Rela *rela); 49 + uint64_t (*rela_addend)(Elf_Rela *rela); 50 + void (*rela_write_addend)(Elf_Rela *rela, uint64_t val); 51 + uint32_t (*r)(const uint32_t *); 52 + uint16_t (*r2)(const uint16_t *); 53 + uint64_t (*r8)(const uint64_t *); 54 + void (*w)(uint32_t, uint32_t *); 55 + void (*w8)(uint64_t, uint64_t *); 56 + }; 57 + 58 + extern struct elf_funcs elf_parser; 59 + 60 + static inline uint64_t ehdr64_shoff(Elf_Ehdr *ehdr) 61 + { 62 + return elf_parser.r8(&ehdr->e64.e_shoff); 63 + } 64 + 65 + static inline uint64_t ehdr32_shoff(Elf_Ehdr *ehdr) 66 + { 67 + return elf_parser.r(&ehdr->e32.e_shoff); 68 + } 69 + 70 + static inline uint64_t ehdr_shoff(Elf_Ehdr *ehdr) 71 + { 72 + return elf_parser.ehdr_shoff(ehdr); 73 + } 74 + 75 + #define EHDR_HALF(fn_name) \ 76 + static inline uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr) \ 77 + { \ 78 + return elf_parser.r2(&ehdr->e64.e_##fn_name); \ 79 + } \ 80 + \ 81 + static inline uint16_t ehdr32_##fn_name(Elf_Ehdr *ehdr) \ 82 + { \ 83 + return elf_parser.r2(&ehdr->e32.e_##fn_name); \ 84 + } \ 85 + \ 86 + static inline uint16_t ehdr_##fn_name(Elf_Ehdr *ehdr) \ 87 + { \ 88 + return elf_parser.ehdr_##fn_name(ehdr); \ 89 + } 90 + 91 + EHDR_HALF(shentsize) 92 + EHDR_HALF(shstrndx) 93 + EHDR_HALF(shnum) 94 + 95 + #define SHDR_WORD(fn_name) \ 96 + static inline uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \ 97 + { \ 98 + return elf_parser.r(&shdr->e64.sh_##fn_name); \ 99 + } \ 100 + \ 101 + static inline uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \ 102 + { \ 103 + return elf_parser.r(&shdr->e32.sh_##fn_name); \ 104 + } \ 105 + \ 106 + static inline uint32_t shdr_##fn_name(Elf_Shdr *shdr) \ 107 + { \ 108 + return elf_parser.shdr_##fn_name(shdr); \ 109 + } 110 + 111 + #define SHDR_ADDR(fn_name) \ 112 + static inline uint64_t shdr64_##fn_name(Elf_Shdr *shdr) \ 113 + { \ 114 + return elf_parser.r8(&shdr->e64.sh_##fn_name); \ 115 + } \ 116 + \ 117 + static inline uint64_t shdr32_##fn_name(Elf_Shdr *shdr) \ 118 + { \ 119 + return elf_parser.r(&shdr->e32.sh_##fn_name); \ 120 + } \ 121 + \ 122 + static inline uint64_t shdr_##fn_name(Elf_Shdr *shdr) \ 123 + { \ 124 + return elf_parser.shdr_##fn_name(shdr); \ 125 + } 126 + 127 + #define SHDR_WORD(fn_name) \ 128 + static inline uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \ 129 + { \ 130 + return elf_parser.r(&shdr->e64.sh_##fn_name); \ 131 + } \ 132 + \ 133 + static inline uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \ 134 + { \ 135 + return elf_parser.r(&shdr->e32.sh_##fn_name); \ 136 + } \ 137 + static inline uint32_t shdr_##fn_name(Elf_Shdr *shdr) \ 138 + { \ 139 + return elf_parser.shdr_##fn_name(shdr); \ 140 + } 141 + 142 + SHDR_ADDR(addr) 143 + SHDR_ADDR(offset) 144 + SHDR_ADDR(size) 145 + SHDR_ADDR(entsize) 146 + 147 + SHDR_WORD(link) 148 + SHDR_WORD(name) 149 + SHDR_WORD(type) 150 + 151 + #define SYM_ADDR(fn_name) \ 152 + static inline uint64_t sym64_##fn_name(Elf_Sym *sym) \ 153 + { \ 154 + return elf_parser.r8(&sym->e64.st_##fn_name); \ 155 + } \ 156 + \ 157 + static inline uint64_t sym32_##fn_name(Elf_Sym *sym) \ 158 + { \ 159 + return elf_parser.r(&sym->e32.st_##fn_name); \ 160 + } \ 161 + \ 162 + static inline uint64_t sym_##fn_name(Elf_Sym *sym) \ 163 + { \ 164 + return elf_parser.sym_##fn_name(sym); \ 165 + } 166 + 167 + #define SYM_WORD(fn_name) \ 168 + static inline uint32_t sym64_##fn_name(Elf_Sym *sym) \ 169 + { \ 170 + return elf_parser.r(&sym->e64.st_##fn_name); \ 171 + } \ 172 + \ 173 + static inline uint32_t sym32_##fn_name(Elf_Sym *sym) \ 174 + { \ 175 + return elf_parser.r(&sym->e32.st_##fn_name); \ 176 + } \ 177 + \ 178 + static inline uint32_t sym_##fn_name(Elf_Sym *sym) \ 179 + { \ 180 + return elf_parser.sym_##fn_name(sym); \ 181 + } 182 + 183 + #define SYM_HALF(fn_name) \ 184 + static inline uint16_t sym64_##fn_name(Elf_Sym *sym) \ 185 + { \ 186 + return elf_parser.r2(&sym->e64.st_##fn_name); \ 187 + } \ 188 + \ 189 + static inline uint16_t sym32_##fn_name(Elf_Sym *sym) \ 190 + { \ 191 + return elf_parser.r2(&sym->e32.st_##fn_name); \ 192 + } \ 193 + \ 194 + static inline uint16_t sym_##fn_name(Elf_Sym *sym) \ 195 + { \ 196 + return elf_parser.sym_##fn_name(sym); \ 197 + } 198 + 199 + static inline uint8_t sym64_type(Elf_Sym *sym) 200 + { 201 + return ELF64_ST_TYPE(sym->e64.st_info); 202 + } 203 + 204 + static inline uint8_t sym32_type(Elf_Sym *sym) 205 + { 206 + return ELF32_ST_TYPE(sym->e32.st_info); 207 + } 208 + 209 + static inline uint8_t sym_type(Elf_Sym *sym) 210 + { 211 + return elf_parser.sym_type(sym); 212 + } 213 + 214 + SYM_ADDR(value) 215 + SYM_WORD(name) 216 + SYM_HALF(shndx) 217 + 218 + #define __maybe_unused __attribute__((__unused__)) 219 + 220 + #define RELA_ADDR(fn_name) \ 221 + static inline uint64_t rela64_##fn_name(Elf_Rela *rela) \ 222 + { \ 223 + return elf_parser.r8((uint64_t *)&rela->e64.r_##fn_name); \ 224 + } \ 225 + \ 226 + static inline uint64_t rela32_##fn_name(Elf_Rela *rela) \ 227 + { \ 228 + return elf_parser.r((uint32_t *)&rela->e32.r_##fn_name); \ 229 + } \ 230 + \ 231 + static inline uint64_t __maybe_unused rela_##fn_name(Elf_Rela *rela) \ 232 + { \ 233 + return elf_parser.rela_##fn_name(rela); \ 234 + } 235 + 236 + RELA_ADDR(offset) 237 + RELA_ADDR(info) 238 + RELA_ADDR(addend) 239 + 240 + static inline void rela64_write_addend(Elf_Rela *rela, uint64_t val) 241 + { 242 + elf_parser.w8(val, (uint64_t *)&rela->e64.r_addend); 243 + } 244 + 245 + static inline void rela32_write_addend(Elf_Rela *rela, uint64_t val) 246 + { 247 + elf_parser.w(val, (uint32_t *)&rela->e32.r_addend); 248 + } 249 + 250 + static inline uint32_t rbe(const uint32_t *x) 251 + { 252 + return get_unaligned_be32(x); 253 + } 254 + 255 + static inline uint16_t r2be(const uint16_t *x) 256 + { 257 + return get_unaligned_be16(x); 258 + } 259 + 260 + static inline uint64_t r8be(const uint64_t *x) 261 + { 262 + return get_unaligned_be64(x); 263 + } 264 + 265 + static inline uint32_t rle(const uint32_t *x) 266 + { 267 + return get_unaligned_le32(x); 268 + } 269 + 270 + static inline uint16_t r2le(const uint16_t *x) 271 + { 272 + return get_unaligned_le16(x); 273 + } 274 + 275 + static inline uint64_t r8le(const uint64_t *x) 276 + { 277 + return get_unaligned_le64(x); 278 + } 279 + 280 + static inline void wbe(uint32_t val, uint32_t *x) 281 + { 282 + put_unaligned_be32(val, x); 283 + } 284 + 285 + static inline void wle(uint32_t val, uint32_t *x) 286 + { 287 + put_unaligned_le32(val, x); 288 + } 289 + 290 + static inline void w8be(uint64_t val, uint64_t *x) 291 + { 292 + put_unaligned_be64(val, x); 293 + } 294 + 295 + static inline void w8le(uint64_t val, uint64_t *x) 296 + { 297 + put_unaligned_le64(val, x); 298 + } 299 + 300 + void *elf_map(char const *fname, size_t *size, uint32_t types); 301 + void elf_unmap(void *addr, size_t size); 302 + int elf_map_machine(void *addr); 303 + int elf_map_long_size(void *addr); 304 + 305 + #endif /* _SCRIPTS_ELF_PARSE_H */
+34 -443
scripts/sorttable.c
··· 21 21 */ 22 22 23 23 #include <sys/types.h> 24 - #include <sys/mman.h> 25 24 #include <sys/stat.h> 26 25 #include <getopt.h> 27 - #include <elf.h> 28 26 #include <fcntl.h> 29 27 #include <stdio.h> 30 28 #include <stdlib.h> ··· 32 34 #include <errno.h> 33 35 #include <pthread.h> 34 36 35 - #include <tools/be_byteshift.h> 36 - #include <tools/le_byteshift.h> 37 + #include "elf-parse.h" 37 38 38 39 #ifndef EM_ARCOMPACT 39 40 #define EM_ARCOMPACT 93 ··· 62 65 #define EM_LOONGARCH 258 63 66 #endif 64 67 65 - typedef union { 66 - Elf32_Ehdr e32; 67 - Elf64_Ehdr e64; 68 - } Elf_Ehdr; 69 - 70 - typedef union { 71 - Elf32_Shdr e32; 72 - Elf64_Shdr e64; 73 - } Elf_Shdr; 74 - 75 - typedef union { 76 - Elf32_Sym e32; 77 - Elf64_Sym e64; 78 - } Elf_Sym; 79 - 80 - typedef union { 81 - Elf32_Rela e32; 82 - Elf64_Rela e64; 83 - } Elf_Rela; 84 - 85 - static uint32_t (*r)(const uint32_t *); 86 - static uint16_t (*r2)(const uint16_t *); 87 - static uint64_t (*r8)(const uint64_t *); 88 - static void (*w)(uint32_t, uint32_t *); 89 - static void (*w8)(uint64_t, uint64_t *); 90 68 typedef void (*table_sort_t)(char *, int); 91 - 92 - static struct elf_funcs { 93 - int (*compare_extable)(const void *a, const void *b); 94 - uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr); 95 - uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr); 96 - uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr); 97 - uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr); 98 - uint64_t (*shdr_addr)(Elf_Shdr *shdr); 99 - uint64_t (*shdr_offset)(Elf_Shdr *shdr); 100 - uint64_t (*shdr_size)(Elf_Shdr *shdr); 101 - uint64_t (*shdr_entsize)(Elf_Shdr *shdr); 102 - uint32_t (*shdr_link)(Elf_Shdr *shdr); 103 - uint32_t (*shdr_name)(Elf_Shdr *shdr); 104 - uint32_t (*shdr_type)(Elf_Shdr *shdr); 105 - uint8_t (*sym_type)(Elf_Sym *sym); 106 - uint32_t (*sym_name)(Elf_Sym *sym); 107 - uint64_t (*sym_value)(Elf_Sym *sym); 108 - uint16_t (*sym_shndx)(Elf_Sym *sym); 109 - uint64_t (*rela_offset)(Elf_Rela *rela); 110 - uint64_t (*rela_info)(Elf_Rela *rela); 111 - uint64_t (*rela_addend)(Elf_Rela *rela); 112 - void (*rela_write_addend)(Elf_Rela *rela, uint64_t val); 113 - } e; 114 - 115 - static uint64_t ehdr64_shoff(Elf_Ehdr *ehdr) 116 - { 117 - return r8(&ehdr->e64.e_shoff); 118 - } 119 - 120 - static uint64_t ehdr32_shoff(Elf_Ehdr *ehdr) 121 - { 122 - return r(&ehdr->e32.e_shoff); 123 - } 124 - 125 - static uint64_t ehdr_shoff(Elf_Ehdr *ehdr) 126 - { 127 - return e.ehdr_shoff(ehdr); 128 - } 129 - 130 - #define EHDR_HALF(fn_name) \ 131 - static uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr) \ 132 - { \ 133 - return r2(&ehdr->e64.e_##fn_name); \ 134 - } \ 135 - \ 136 - static uint16_t ehdr32_##fn_name(Elf_Ehdr *ehdr) \ 137 - { \ 138 - return r2(&ehdr->e32.e_##fn_name); \ 139 - } \ 140 - \ 141 - static uint16_t ehdr_##fn_name(Elf_Ehdr *ehdr) \ 142 - { \ 143 - return e.ehdr_##fn_name(ehdr); \ 144 - } 145 - 146 - EHDR_HALF(shentsize) 147 - EHDR_HALF(shstrndx) 148 - EHDR_HALF(shnum) 149 - 150 - #define SHDR_WORD(fn_name) \ 151 - static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \ 152 - { \ 153 - return r(&shdr->e64.sh_##fn_name); \ 154 - } \ 155 - \ 156 - static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \ 157 - { \ 158 - return r(&shdr->e32.sh_##fn_name); \ 159 - } \ 160 - \ 161 - static uint32_t shdr_##fn_name(Elf_Shdr *shdr) \ 162 - { \ 163 - return e.shdr_##fn_name(shdr); \ 164 - } 165 - 166 - #define SHDR_ADDR(fn_name) \ 167 - static uint64_t shdr64_##fn_name(Elf_Shdr *shdr) \ 168 - { \ 169 - return r8(&shdr->e64.sh_##fn_name); \ 170 - } \ 171 - \ 172 - static uint64_t shdr32_##fn_name(Elf_Shdr *shdr) \ 173 - { \ 174 - return r(&shdr->e32.sh_##fn_name); \ 175 - } \ 176 - \ 177 - static uint64_t shdr_##fn_name(Elf_Shdr *shdr) \ 178 - { \ 179 - return e.shdr_##fn_name(shdr); \ 180 - } 181 - 182 - #define SHDR_WORD(fn_name) \ 183 - static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \ 184 - { \ 185 - return r(&shdr->e64.sh_##fn_name); \ 186 - } \ 187 - \ 188 - static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \ 189 - { \ 190 - return r(&shdr->e32.sh_##fn_name); \ 191 - } \ 192 - static uint32_t shdr_##fn_name(Elf_Shdr *shdr) \ 193 - { \ 194 - return e.shdr_##fn_name(shdr); \ 195 - } 196 - 197 - SHDR_ADDR(addr) 198 - SHDR_ADDR(offset) 199 - SHDR_ADDR(size) 200 - SHDR_ADDR(entsize) 201 - 202 - SHDR_WORD(link) 203 - SHDR_WORD(name) 204 - SHDR_WORD(type) 205 - 206 - #define SYM_ADDR(fn_name) \ 207 - static uint64_t sym64_##fn_name(Elf_Sym *sym) \ 208 - { \ 209 - return r8(&sym->e64.st_##fn_name); \ 210 - } \ 211 - \ 212 - static uint64_t sym32_##fn_name(Elf_Sym *sym) \ 213 - { \ 214 - return r(&sym->e32.st_##fn_name); \ 215 - } \ 216 - \ 217 - static uint64_t sym_##fn_name(Elf_Sym *sym) \ 218 - { \ 219 - return e.sym_##fn_name(sym); \ 220 - } 221 - 222 - #define SYM_WORD(fn_name) \ 223 - static uint32_t sym64_##fn_name(Elf_Sym *sym) \ 224 - { \ 225 - return r(&sym->e64.st_##fn_name); \ 226 - } \ 227 - \ 228 - static uint32_t sym32_##fn_name(Elf_Sym *sym) \ 229 - { \ 230 - return r(&sym->e32.st_##fn_name); \ 231 - } \ 232 - \ 233 - static uint32_t sym_##fn_name(Elf_Sym *sym) \ 234 - { \ 235 - return e.sym_##fn_name(sym); \ 236 - } 237 - 238 - #define SYM_HALF(fn_name) \ 239 - static uint16_t sym64_##fn_name(Elf_Sym *sym) \ 240 - { \ 241 - return r2(&sym->e64.st_##fn_name); \ 242 - } \ 243 - \ 244 - static uint16_t sym32_##fn_name(Elf_Sym *sym) \ 245 - { \ 246 - return r2(&sym->e32.st_##fn_name); \ 247 - } \ 248 - \ 249 - static uint16_t sym_##fn_name(Elf_Sym *sym) \ 250 - { \ 251 - return e.sym_##fn_name(sym); \ 252 - } 253 - 254 - static uint8_t sym64_type(Elf_Sym *sym) 255 - { 256 - return ELF64_ST_TYPE(sym->e64.st_info); 257 - } 258 - 259 - static uint8_t sym32_type(Elf_Sym *sym) 260 - { 261 - return ELF32_ST_TYPE(sym->e32.st_info); 262 - } 263 - 264 - static uint8_t sym_type(Elf_Sym *sym) 265 - { 266 - return e.sym_type(sym); 267 - } 268 - 269 - SYM_ADDR(value) 270 - SYM_WORD(name) 271 - SYM_HALF(shndx) 272 - 273 - #define __maybe_unused __attribute__((__unused__)) 274 - 275 - #define RELA_ADDR(fn_name) \ 276 - static uint64_t rela64_##fn_name(Elf_Rela *rela) \ 277 - { \ 278 - return r8((uint64_t *)&rela->e64.r_##fn_name); \ 279 - } \ 280 - \ 281 - static uint64_t rela32_##fn_name(Elf_Rela *rela) \ 282 - { \ 283 - return r((uint32_t *)&rela->e32.r_##fn_name); \ 284 - } \ 285 - \ 286 - static uint64_t __maybe_unused rela_##fn_name(Elf_Rela *rela) \ 287 - { \ 288 - return e.rela_##fn_name(rela); \ 289 - } 290 - 291 - RELA_ADDR(offset) 292 - RELA_ADDR(info) 293 - RELA_ADDR(addend) 294 - 295 - static void rela64_write_addend(Elf_Rela *rela, uint64_t val) 296 - { 297 - w8(val, (uint64_t *)&rela->e64.r_addend); 298 - } 299 - 300 - static void rela32_write_addend(Elf_Rela *rela, uint64_t val) 301 - { 302 - w(val, (uint32_t *)&rela->e32.r_addend); 303 - } 304 - 305 - /* 306 - * Get the whole file as a programming convenience in order to avoid 307 - * malloc+lseek+read+free of many pieces. If successful, then mmap 308 - * avoids copying unused pieces; else just read the whole file. 309 - * Open for both read and write. 310 - */ 311 - static void *mmap_file(char const *fname, size_t *size) 312 - { 313 - int fd; 314 - struct stat sb; 315 - void *addr = NULL; 316 - 317 - fd = open(fname, O_RDWR); 318 - if (fd < 0) { 319 - perror(fname); 320 - return NULL; 321 - } 322 - if (fstat(fd, &sb) < 0) { 323 - perror(fname); 324 - goto out; 325 - } 326 - if (!S_ISREG(sb.st_mode)) { 327 - fprintf(stderr, "not a regular file: %s\n", fname); 328 - goto out; 329 - } 330 - 331 - addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 332 - if (addr == MAP_FAILED) { 333 - fprintf(stderr, "Could not mmap file: %s\n", fname); 334 - goto out; 335 - } 336 - 337 - *size = sb.st_size; 338 - 339 - out: 340 - close(fd); 341 - return addr; 342 - } 343 - 344 - static uint32_t rbe(const uint32_t *x) 345 - { 346 - return get_unaligned_be32(x); 347 - } 348 - 349 - static uint16_t r2be(const uint16_t *x) 350 - { 351 - return get_unaligned_be16(x); 352 - } 353 - 354 - static uint64_t r8be(const uint64_t *x) 355 - { 356 - return get_unaligned_be64(x); 357 - } 358 - 359 - static uint32_t rle(const uint32_t *x) 360 - { 361 - return get_unaligned_le32(x); 362 - } 363 - 364 - static uint16_t r2le(const uint16_t *x) 365 - { 366 - return get_unaligned_le16(x); 367 - } 368 - 369 - static uint64_t r8le(const uint64_t *x) 370 - { 371 - return get_unaligned_le64(x); 372 - } 373 - 374 - static void wbe(uint32_t val, uint32_t *x) 375 - { 376 - put_unaligned_be32(val, x); 377 - } 378 - 379 - static void wle(uint32_t val, uint32_t *x) 380 - { 381 - put_unaligned_le32(val, x); 382 - } 383 - 384 - static void w8be(uint64_t val, uint64_t *x) 385 - { 386 - put_unaligned_be64(val, x); 387 - } 388 - 389 - static void w8le(uint64_t val, uint64_t *x) 390 - { 391 - put_unaligned_le64(val, x); 392 - } 393 69 394 70 /* 395 71 * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of ··· 85 415 return SPECIAL(shndx); 86 416 if (shndx != SHN_XINDEX) 87 417 return shndx; 88 - return r(&symtab_shndx_start[sym_offs]); 418 + return elf_parser.r(&symtab_shndx_start[sym_offs]); 89 419 } 90 420 91 421 static int compare_extable_32(const void *a, const void *b) 92 422 { 93 - Elf32_Addr av = r(a); 94 - Elf32_Addr bv = r(b); 423 + Elf32_Addr av = elf_parser.r(a); 424 + Elf32_Addr bv = elf_parser.r(b); 95 425 96 426 if (av < bv) 97 427 return -1; ··· 100 430 101 431 static int compare_extable_64(const void *a, const void *b) 102 432 { 103 - Elf64_Addr av = r8(a); 104 - Elf64_Addr bv = r8(b); 433 + Elf64_Addr av = elf_parser.r8(a); 434 + Elf64_Addr bv = elf_parser.r8(b); 105 435 106 436 if (av < bv) 107 437 return -1; 108 438 return av > bv; 109 439 } 110 440 111 - static int compare_extable(const void *a, const void *b) 112 - { 113 - return e.compare_extable(a, b); 114 - } 441 + static int (*compare_extable)(const void *a, const void *b); 115 442 116 443 static inline void *get_index(void *start, int entsize, int index) 117 444 { ··· 244 577 /* Only used for sorting mcount table */ 245 578 static void rela_write_addend(Elf_Rela *rela, uint64_t val) 246 579 { 247 - e.rela_write_addend(rela, val); 580 + elf_parser.rela_write_addend(rela, val); 248 581 } 249 582 250 583 struct func_info { ··· 459 792 460 793 for (; ptr < end; ptr += long_size, addrs += long_size, count++) { 461 794 if (long_size == 4) 462 - *(uint32_t *)ptr = r(addrs); 795 + *(uint32_t *)ptr = elf_parser.r(addrs); 463 796 else 464 - *(uint64_t *)ptr = r8(addrs); 797 + *(uint64_t *)ptr = elf_parser.r8(addrs); 465 798 } 466 799 return count; 467 800 } ··· 472 805 473 806 for (; ptr < end; ptr += long_size, addrs += long_size) { 474 807 if (long_size == 4) 475 - w(*(uint32_t *)ptr, addrs); 808 + elf_parser.w(*(uint32_t *)ptr, addrs); 476 809 else 477 - w8(*(uint64_t *)ptr, addrs); 810 + elf_parser.w8(*(uint64_t *)ptr, addrs); 478 811 } 479 812 } 480 813 ··· 778 1111 sym_value(sort_needed_sym) - shdr_addr(sort_needed_sec); 779 1112 780 1113 /* extable has been sorted, clear the flag */ 781 - w(0, sort_needed_loc); 1114 + elf_parser.w(0, sort_needed_loc); 782 1115 rc = 0; 783 1116 784 1117 out: ··· 822 1155 823 1156 static int compare_relative_table(const void *a, const void *b) 824 1157 { 825 - int32_t av = (int32_t)r(a); 826 - int32_t bv = (int32_t)r(b); 1158 + int32_t av = (int32_t)elf_parser.r(a); 1159 + int32_t bv = (int32_t)elf_parser.r(b); 827 1160 828 1161 if (av < bv) 829 1162 return -1; ··· 842 1175 */ 843 1176 while (i < image_size) { 844 1177 uint32_t *loc = (uint32_t *)(extab_image + i); 845 - w(r(loc) + i, loc); 1178 + elf_parser.w(elf_parser.r(loc) + i, loc); 846 1179 i += 4; 847 1180 } 848 1181 ··· 852 1185 i = 0; 853 1186 while (i < image_size) { 854 1187 uint32_t *loc = (uint32_t *)(extab_image + i); 855 - w(r(loc) - i, loc); 1188 + elf_parser.w(elf_parser.r(loc) - i, loc); 856 1189 i += 4; 857 1190 } 858 1191 } ··· 864 1197 while (i < image_size) { 865 1198 uint32_t *loc = (uint32_t *)(extab_image + i); 866 1199 867 - w(r(loc) + i, loc); 868 - w(r(loc + 1) + i + 4, loc + 1); 1200 + elf_parser.w(elf_parser.r(loc) + i, loc); 1201 + elf_parser.w(elf_parser.r(loc + 1) + i + 4, loc + 1); 869 1202 /* Don't touch the fixup type or data */ 870 1203 871 1204 i += sizeof(uint32_t) * 3; ··· 877 1210 while (i < image_size) { 878 1211 uint32_t *loc = (uint32_t *)(extab_image + i); 879 1212 880 - w(r(loc) - i, loc); 881 - w(r(loc + 1) - (i + 4), loc + 1); 1213 + elf_parser.w(elf_parser.r(loc) - i, loc); 1214 + elf_parser.w(elf_parser.r(loc + 1) - (i + 4), loc + 1); 882 1215 /* Don't touch the fixup type or data */ 883 1216 884 1217 i += sizeof(uint32_t) * 3; ··· 890 1223 Elf_Ehdr *ehdr = addr; 891 1224 table_sort_t custom_sort = NULL; 892 1225 893 - switch (ehdr->e32.e_ident[EI_DATA]) { 894 - case ELFDATA2LSB: 895 - r = rle; 896 - r2 = r2le; 897 - r8 = r8le; 898 - w = wle; 899 - w8 = w8le; 900 - break; 901 - case ELFDATA2MSB: 902 - r = rbe; 903 - r2 = r2be; 904 - r8 = r8be; 905 - w = wbe; 906 - w8 = w8be; 907 - break; 908 - default: 909 - fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", 910 - ehdr->e32.e_ident[EI_DATA], fname); 911 - return -1; 912 - } 913 - 914 - if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 || 915 - (r2(&ehdr->e32.e_type) != ET_EXEC && r2(&ehdr->e32.e_type) != ET_DYN) || 916 - ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) { 917 - fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname); 918 - return -1; 919 - } 920 - 921 - switch (r2(&ehdr->e32.e_machine)) { 1226 + switch (elf_map_machine(ehdr)) { 922 1227 case EM_AARCH64: 923 1228 #ifdef MCOUNT_SORT_ENABLED 924 1229 sort_reloc = true; ··· 920 1281 break; 921 1282 default: 922 1283 fprintf(stderr, "unrecognized e_machine %d %s\n", 923 - r2(&ehdr->e32.e_machine), fname); 1284 + elf_parser.r2(&ehdr->e32.e_machine), fname); 924 1285 return -1; 925 1286 } 926 1287 927 - switch (ehdr->e32.e_ident[EI_CLASS]) { 928 - case ELFCLASS32: { 929 - struct elf_funcs efuncs = { 930 - .compare_extable = compare_extable_32, 931 - .ehdr_shoff = ehdr32_shoff, 932 - .ehdr_shentsize = ehdr32_shentsize, 933 - .ehdr_shstrndx = ehdr32_shstrndx, 934 - .ehdr_shnum = ehdr32_shnum, 935 - .shdr_addr = shdr32_addr, 936 - .shdr_offset = shdr32_offset, 937 - .shdr_link = shdr32_link, 938 - .shdr_size = shdr32_size, 939 - .shdr_name = shdr32_name, 940 - .shdr_type = shdr32_type, 941 - .shdr_entsize = shdr32_entsize, 942 - .sym_type = sym32_type, 943 - .sym_name = sym32_name, 944 - .sym_value = sym32_value, 945 - .sym_shndx = sym32_shndx, 946 - .rela_offset = rela32_offset, 947 - .rela_info = rela32_info, 948 - .rela_addend = rela32_addend, 949 - .rela_write_addend = rela32_write_addend, 950 - }; 951 - 952 - e = efuncs; 1288 + switch (elf_map_long_size(addr)) { 1289 + case 4: 1290 + compare_extable = compare_extable_32, 953 1291 long_size = 4; 954 1292 extable_ent_size = 8; 955 1293 956 - if (r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) || 957 - r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) { 1294 + if (elf_parser.r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) || 1295 + elf_parser.r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) { 958 1296 fprintf(stderr, 959 1297 "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); 960 1298 return -1; 961 1299 } 962 1300 963 - } 964 1301 break; 965 - case ELFCLASS64: { 966 - struct elf_funcs efuncs = { 967 - .compare_extable = compare_extable_64, 968 - .ehdr_shoff = ehdr64_shoff, 969 - .ehdr_shentsize = ehdr64_shentsize, 970 - .ehdr_shstrndx = ehdr64_shstrndx, 971 - .ehdr_shnum = ehdr64_shnum, 972 - .shdr_addr = shdr64_addr, 973 - .shdr_offset = shdr64_offset, 974 - .shdr_link = shdr64_link, 975 - .shdr_size = shdr64_size, 976 - .shdr_name = shdr64_name, 977 - .shdr_type = shdr64_type, 978 - .shdr_entsize = shdr64_entsize, 979 - .sym_type = sym64_type, 980 - .sym_name = sym64_name, 981 - .sym_value = sym64_value, 982 - .sym_shndx = sym64_shndx, 983 - .rela_offset = rela64_offset, 984 - .rela_info = rela64_info, 985 - .rela_addend = rela64_addend, 986 - .rela_write_addend = rela64_write_addend, 987 - }; 988 - 989 - e = efuncs; 1302 + case 8: 1303 + compare_extable = compare_extable_64, 990 1304 long_size = 8; 991 1305 extable_ent_size = 16; 992 1306 993 - if (r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) || 994 - r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) { 1307 + if (elf_parser.r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) || 1308 + elf_parser.r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) { 995 1309 fprintf(stderr, 996 1310 "unrecognized ET_EXEC/ET_DYN file: %s\n", 997 1311 fname); 998 1312 return -1; 999 1313 } 1000 1314 1001 - } 1002 1315 break; 1003 1316 default: 1004 1317 fprintf(stderr, "unrecognized ELF class %d %s\n", ··· 989 1398 990 1399 /* Process each file in turn, allowing deep failure. */ 991 1400 for (i = optind; i < argc; i++) { 992 - addr = mmap_file(argv[i], &size); 1401 + addr = elf_map(argv[i], &size, (1 << ET_EXEC) | (1 << ET_DYN)); 993 1402 if (!addr) { 994 1403 ++n_error; 995 1404 continue; ··· 998 1407 if (do_file(argv[i], addr)) 999 1408 ++n_error; 1000 1409 1001 - munmap(addr, size); 1410 + elf_unmap(addr, size); 1002 1411 } 1003 1412 1004 1413 return !!n_error;
+261
scripts/tracepoint-update.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <sys/types.h> 4 + #include <sys/stat.h> 5 + #include <getopt.h> 6 + #include <fcntl.h> 7 + #include <stdio.h> 8 + #include <stdlib.h> 9 + #include <stdbool.h> 10 + #include <string.h> 11 + #include <unistd.h> 12 + #include <errno.h> 13 + #include <pthread.h> 14 + 15 + #include "elf-parse.h" 16 + 17 + static Elf_Shdr *check_data_sec; 18 + static Elf_Shdr *tracepoint_data_sec; 19 + 20 + static inline void *get_index(void *start, int entsize, int index) 21 + { 22 + return start + (entsize * index); 23 + } 24 + 25 + static int compare_strings(const void *a, const void *b) 26 + { 27 + const char *av = *(const char **)a; 28 + const char *bv = *(const char **)b; 29 + 30 + return strcmp(av, bv); 31 + } 32 + 33 + struct elf_tracepoint { 34 + Elf_Ehdr *ehdr; 35 + const char **array; 36 + int count; 37 + }; 38 + 39 + #define REALLOC_SIZE (1 << 10) 40 + #define REALLOC_MASK (REALLOC_SIZE - 1) 41 + 42 + static int add_string(const char *str, const char ***vals, int *count) 43 + { 44 + const char **array = *vals; 45 + 46 + if (!(*count & REALLOC_MASK)) { 47 + int size = (*count) + REALLOC_SIZE; 48 + 49 + array = realloc(array, sizeof(char *) * size); 50 + if (!array) { 51 + fprintf(stderr, "Failed memory allocation\n"); 52 + return -1; 53 + } 54 + *vals = array; 55 + } 56 + 57 + array[(*count)++] = str; 58 + return 0; 59 + } 60 + 61 + /** 62 + * for_each_shdr_str - iterator that reads strings that are in an ELF section. 63 + * @len: "int" to hold the length of the current string 64 + * @ehdr: A pointer to the ehdr of the ELF file 65 + * @sec: The section that has the strings to iterate on 66 + * 67 + * This is a for loop that iterates over all the nul terminated strings 68 + * that are in a given ELF section. The variable "str" will hold 69 + * the current string for each iteration and the passed in @len will 70 + * contain the strlen() of that string. 71 + */ 72 + #define for_each_shdr_str(len, ehdr, sec) \ 73 + for (const char *str = (void *)(ehdr) + shdr_offset(sec), \ 74 + *end = str + shdr_size(sec); \ 75 + len = strlen(str), str < end; \ 76 + str += (len) + 1) 77 + 78 + 79 + static void make_trace_array(struct elf_tracepoint *etrace) 80 + { 81 + Elf_Ehdr *ehdr = etrace->ehdr; 82 + const char **vals = NULL; 83 + int count = 0; 84 + int len; 85 + 86 + etrace->array = NULL; 87 + 88 + /* 89 + * The __tracepoint_check section is filled with strings of the 90 + * names of tracepoints (in tracepoint_strings). Create an array 91 + * that points to each string and then sort the array. 92 + */ 93 + for_each_shdr_str(len, ehdr, check_data_sec) { 94 + if (!len) 95 + continue; 96 + if (add_string(str, &vals, &count) < 0) 97 + return; 98 + } 99 + 100 + /* If CONFIG_TRACEPOINT_VERIFY_USED is not set, there's nothing to do */ 101 + if (!count) 102 + return; 103 + 104 + qsort(vals, count, sizeof(char *), compare_strings); 105 + 106 + etrace->array = vals; 107 + etrace->count = count; 108 + } 109 + 110 + static int find_event(const char *str, void *array, size_t size) 111 + { 112 + return bsearch(&str, array, size, sizeof(char *), compare_strings) != NULL; 113 + } 114 + 115 + static void check_tracepoints(struct elf_tracepoint *etrace, const char *fname) 116 + { 117 + Elf_Ehdr *ehdr = etrace->ehdr; 118 + int len; 119 + 120 + if (!etrace->array) 121 + return; 122 + 123 + /* 124 + * The __tracepoints_strings section holds all the names of the 125 + * defined tracepoints. If any of them are not in the 126 + * __tracepoint_check_section it means they are not used. 127 + */ 128 + for_each_shdr_str(len, ehdr, tracepoint_data_sec) { 129 + if (!len) 130 + continue; 131 + if (!find_event(str, etrace->array, etrace->count)) { 132 + fprintf(stderr, "warning: tracepoint '%s' is unused", str); 133 + if (fname) 134 + fprintf(stderr, " in module %s\n", fname); 135 + else 136 + fprintf(stderr, "\n"); 137 + } 138 + } 139 + 140 + free(etrace->array); 141 + } 142 + 143 + static void *tracepoint_check(struct elf_tracepoint *etrace, const char *fname) 144 + { 145 + make_trace_array(etrace); 146 + check_tracepoints(etrace, fname); 147 + 148 + return NULL; 149 + } 150 + 151 + static int process_tracepoints(bool mod, void *addr, const char *fname) 152 + { 153 + struct elf_tracepoint etrace = {0}; 154 + Elf_Ehdr *ehdr = addr; 155 + Elf_Shdr *shdr_start; 156 + Elf_Shdr *string_sec; 157 + const char *secstrings; 158 + unsigned int shnum; 159 + unsigned int shstrndx; 160 + int shentsize; 161 + int idx; 162 + int done = 2; 163 + 164 + shdr_start = (Elf_Shdr *)((char *)ehdr + ehdr_shoff(ehdr)); 165 + shentsize = ehdr_shentsize(ehdr); 166 + 167 + shstrndx = ehdr_shstrndx(ehdr); 168 + if (shstrndx == SHN_XINDEX) 169 + shstrndx = shdr_link(shdr_start); 170 + string_sec = get_index(shdr_start, shentsize, shstrndx); 171 + secstrings = (const char *)ehdr + shdr_offset(string_sec); 172 + 173 + shnum = ehdr_shnum(ehdr); 174 + if (shnum == SHN_UNDEF) 175 + shnum = shdr_size(shdr_start); 176 + 177 + for (int i = 0; done && i < shnum; i++) { 178 + Elf_Shdr *shdr = get_index(shdr_start, shentsize, i); 179 + 180 + idx = shdr_name(shdr); 181 + 182 + /* locate the __tracepoint_check in vmlinux */ 183 + if (!strcmp(secstrings + idx, "__tracepoint_check")) { 184 + check_data_sec = shdr; 185 + done--; 186 + } 187 + 188 + /* locate the __tracepoints_ptrs section in vmlinux */ 189 + if (!strcmp(secstrings + idx, "__tracepoints_strings")) { 190 + tracepoint_data_sec = shdr; 191 + done--; 192 + } 193 + } 194 + 195 + /* 196 + * Modules may not have either section. But if it has one section, 197 + * it should have both of them. 198 + */ 199 + if (mod && !check_data_sec && !tracepoint_data_sec) 200 + return 0; 201 + 202 + if (!check_data_sec) { 203 + if (mod) { 204 + fprintf(stderr, "warning: Module %s has only unused tracepoints\n", fname); 205 + /* Do not fail build */ 206 + return 0; 207 + } 208 + fprintf(stderr, "no __tracepoint_check in file: %s\n", fname); 209 + return -1; 210 + } 211 + 212 + if (!tracepoint_data_sec) { 213 + fprintf(stderr, "no __tracepoint_strings in file: %s\n", fname); 214 + return -1; 215 + } 216 + 217 + if (!mod) 218 + fname = NULL; 219 + 220 + etrace.ehdr = ehdr; 221 + tracepoint_check(&etrace, fname); 222 + return 0; 223 + } 224 + 225 + int main(int argc, char *argv[]) 226 + { 227 + int n_error = 0; 228 + size_t size = 0; 229 + void *addr = NULL; 230 + bool mod = false; 231 + 232 + if (argc > 1 && strcmp(argv[1], "--module") == 0) { 233 + mod = true; 234 + argc--; 235 + argv++; 236 + } 237 + 238 + if (argc < 2) { 239 + if (mod) 240 + fprintf(stderr, "usage: tracepoint-update --module module...\n"); 241 + else 242 + fprintf(stderr, "usage: tracepoint-update vmlinux...\n"); 243 + return 0; 244 + } 245 + 246 + /* Process each file in turn, allowing deep failure. */ 247 + for (int i = 1; i < argc; i++) { 248 + addr = elf_map(argv[i], &size, 1 << ET_REL); 249 + if (!addr) { 250 + ++n_error; 251 + continue; 252 + } 253 + 254 + if (process_tracepoints(mod, addr, argv[i])) 255 + ++n_error; 256 + 257 + elf_unmap(addr, size); 258 + } 259 + 260 + return !!n_error; 261 + }