diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-05 09:37:41 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-05 09:37:41 -0800 |
| commit | 36492b7141b9abc967e92c991af32c670351dc16 (patch) | |
| tree | 7e1ea41e1bc327a1c4b028174b118050a5945ea3 /scripts/sorttable.c | |
| parent | 5779de8d36ac5a0c929f276096a499b03ae0afa7 (diff) | |
| parent | b21f90e2e4503847ffeb00a9ef4d6d390291f902 (diff) | |
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]
Diffstat (limited to 'scripts/sorttable.c')
| -rw-r--r-- | scripts/sorttable.c | 477 |
1 files changed, 34 insertions, 443 deletions
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 @@ out: 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; |