diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-01-28 19:38:25 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-01-28 19:38:25 +0300 |
commit | 8b561778f29766675e88566215aa835fff9dc1f7 (patch) | |
tree | 5965981d200f6ff0d99b7ba828140ee4044c0ce0 /scripts | |
parent | 9f2a43019edc097347900daade277571834a3e2c (diff) | |
parent | 22a7fa8848c5e881d87ef2f7f3c2ea77b286e6f9 (diff) | |
download | linux-8b561778f29766675e88566215aa835fff9dc1f7.tar.xz |
Merge branch 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull objtool updates from Ingo Molnar:
"The main changes are to move the ORC unwind table sorting from early
init to build-time - this speeds up booting.
No change in functionality intended"
* 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/unwind/orc: Fix !CONFIG_MODULES build warning
x86/unwind/orc: Remove boot-time ORC unwind tables sorting
scripts/sorttable: Implement build-time ORC unwind table sorting
scripts/sorttable: Rename 'sortextable' to 'sorttable'
scripts/sortextable: Refactor the do_func() function
scripts/sortextable: Remove dead code
scripts/sortextable: Clean up the code to meet the kernel coding style better
scripts/sortextable: Rewrite error/success handling
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/.gitignore | 2 | ||||
-rw-r--r-- | scripts/Makefile | 13 | ||||
-rwxr-xr-x | scripts/link-vmlinux.sh | 13 | ||||
-rw-r--r-- | scripts/sortextable.h | 209 | ||||
-rw-r--r-- | scripts/sorttable.c (renamed from scripts/sortextable.c) | 305 | ||||
-rw-r--r-- | scripts/sorttable.h | 380 |
6 files changed, 541 insertions, 381 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore index 4aa1806c59c2..306054ef340f 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -6,7 +6,7 @@ conmakehash kallsyms unifdef recordmcount -sortextable +sorttable asn1_compiler extract-cert sign-file diff --git a/scripts/Makefile b/scripts/Makefile index 00c47901cb06..b0e962611d50 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -13,17 +13,26 @@ hostprogs-$(CONFIG_BUILD_BIN2C) += bin2c hostprogs-$(CONFIG_KALLSYMS) += kallsyms hostprogs-$(CONFIG_VT) += conmakehash hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount -hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable +hostprogs-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable hostprogs-$(CONFIG_ASN1) += asn1_compiler hostprogs-$(CONFIG_MODULE_SIG_FORMAT) += sign-file hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert hostprogs-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert -HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include +HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include HOSTLDLIBS_sign-file = -lcrypto HOSTLDLIBS_extract-cert = -lcrypto +ifdef CONFIG_UNWINDER_ORC +ifeq ($(ARCH),x86_64) +ARCH := x86 +endif +HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include +HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED +HOSTLDLIBS_sorttable = -lpthread +endif + always := $(hostprogs-y) $(hostprogs-m) # The following hostprogs-y programs are only build on demand diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 436379940356..c287ad9b3a67 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -180,9 +180,9 @@ mksysmap() ${CONFIG_SHELL} "${srctree}/scripts/mksysmap" ${1} ${2} } -sortextable() +sorttable() { - ${objtree}/scripts/sortextable ${1} + ${objtree}/scripts/sorttable ${1} } # Delete output files in case of error @@ -304,9 +304,12 @@ fi vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o} -if [ -n "${CONFIG_BUILDTIME_EXTABLE_SORT}" ]; then - info SORTEX vmlinux - sortextable vmlinux +if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then + info SORTTAB vmlinux + if ! sorttable vmlinux; then + echo >&2 Failed to sort kernel tables + exit 1 + fi fi info SYSMAP System.map diff --git a/scripts/sortextable.h b/scripts/sortextable.h deleted file mode 100644 index d4b3f6c40f02..000000000000 --- a/scripts/sortextable.h +++ /dev/null @@ -1,209 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * sortextable.h - * - * Copyright 2011 - 2012 Cavium, Inc. - * - * Some of this code was taken out of recordmcount.h written by: - * - * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. - * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. - */ - -#undef extable_ent_size -#undef compare_extable -#undef do_func -#undef Elf_Addr -#undef Elf_Ehdr -#undef Elf_Shdr -#undef Elf_Rel -#undef Elf_Rela -#undef Elf_Sym -#undef ELF_R_SYM -#undef Elf_r_sym -#undef ELF_R_INFO -#undef Elf_r_info -#undef ELF_ST_BIND -#undef ELF_ST_TYPE -#undef fn_ELF_R_SYM -#undef fn_ELF_R_INFO -#undef uint_t -#undef _r -#undef _w - -#ifdef SORTEXTABLE_64 -# define extable_ent_size 16 -# define compare_extable compare_extable_64 -# define do_func do64 -# define Elf_Addr Elf64_Addr -# define Elf_Ehdr Elf64_Ehdr -# define Elf_Shdr Elf64_Shdr -# define Elf_Rel Elf64_Rel -# define Elf_Rela Elf64_Rela -# define Elf_Sym Elf64_Sym -# define ELF_R_SYM ELF64_R_SYM -# define Elf_r_sym Elf64_r_sym -# define ELF_R_INFO ELF64_R_INFO -# define Elf_r_info Elf64_r_info -# define ELF_ST_BIND ELF64_ST_BIND -# define ELF_ST_TYPE ELF64_ST_TYPE -# define fn_ELF_R_SYM fn_ELF64_R_SYM -# define fn_ELF_R_INFO fn_ELF64_R_INFO -# define uint_t uint64_t -# define _r r8 -# define _w w8 -#else -# define extable_ent_size 8 -# define compare_extable compare_extable_32 -# define do_func do32 -# define Elf_Addr Elf32_Addr -# define Elf_Ehdr Elf32_Ehdr -# define Elf_Shdr Elf32_Shdr -# define Elf_Rel Elf32_Rel -# define Elf_Rela Elf32_Rela -# define Elf_Sym Elf32_Sym -# define ELF_R_SYM ELF32_R_SYM -# define Elf_r_sym Elf32_r_sym -# define ELF_R_INFO ELF32_R_INFO -# define Elf_r_info Elf32_r_info -# define ELF_ST_BIND ELF32_ST_BIND -# define ELF_ST_TYPE ELF32_ST_TYPE -# define fn_ELF_R_SYM fn_ELF32_R_SYM -# define fn_ELF_R_INFO fn_ELF32_R_INFO -# define uint_t uint32_t -# define _r r -# define _w w -#endif - -static int compare_extable(const void *a, const void *b) -{ - Elf_Addr av = _r(a); - Elf_Addr bv = _r(b); - - if (av < bv) - return -1; - if (av > bv) - return 1; - return 0; -} - -static void -do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) -{ - Elf_Shdr *shdr; - Elf_Shdr *shstrtab_sec; - Elf_Shdr *strtab_sec = NULL; - Elf_Shdr *symtab_sec = NULL; - Elf_Shdr *extab_sec = NULL; - Elf_Sym *sym; - const Elf_Sym *symtab; - Elf32_Word *symtab_shndx_start = NULL; - Elf_Sym *sort_needed_sym; - Elf_Shdr *sort_needed_sec; - Elf_Rel *relocs = NULL; - int relocs_size = 0; - uint32_t *sort_done_location; - const char *secstrtab; - const char *strtab; - char *extab_image; - int extab_index = 0; - int i; - int idx; - unsigned int num_sections; - unsigned int secindex_strings; - - shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); - - num_sections = r2(&ehdr->e_shnum); - if (num_sections == SHN_UNDEF) - num_sections = _r(&shdr[0].sh_size); - - secindex_strings = r2(&ehdr->e_shstrndx); - if (secindex_strings == SHN_XINDEX) - secindex_strings = r(&shdr[0].sh_link); - - shstrtab_sec = shdr + secindex_strings; - secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset); - for (i = 0; i < num_sections; i++) { - idx = r(&shdr[i].sh_name); - if (strcmp(secstrtab + idx, "__ex_table") == 0) { - extab_sec = shdr + i; - extab_index = i; - } - if ((r(&shdr[i].sh_type) == SHT_REL || - r(&shdr[i].sh_type) == SHT_RELA) && - r(&shdr[i].sh_info) == extab_index) { - relocs = (void *)ehdr + _r(&shdr[i].sh_offset); - relocs_size = _r(&shdr[i].sh_size); - } - if (strcmp(secstrtab + idx, ".symtab") == 0) - symtab_sec = shdr + i; - if (strcmp(secstrtab + idx, ".strtab") == 0) - strtab_sec = shdr + i; - if (r(&shdr[i].sh_type) == SHT_SYMTAB_SHNDX) - symtab_shndx_start = (Elf32_Word *)( - (const char *)ehdr + _r(&shdr[i].sh_offset)); - } - if (strtab_sec == NULL) { - fprintf(stderr, "no .strtab in file: %s\n", fname); - fail_file(); - } - if (symtab_sec == NULL) { - fprintf(stderr, "no .symtab in file: %s\n", fname); - fail_file(); - } - symtab = (const Elf_Sym *)((const char *)ehdr + - _r(&symtab_sec->sh_offset)); - if (extab_sec == NULL) { - fprintf(stderr, "no __ex_table in file: %s\n", fname); - fail_file(); - } - strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); - - extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); - - if (custom_sort) { - custom_sort(extab_image, _r(&extab_sec->sh_size)); - } else { - int num_entries = _r(&extab_sec->sh_size) / extable_ent_size; - qsort(extab_image, num_entries, - extable_ent_size, compare_extable); - } - /* If there were relocations, we no longer need them. */ - if (relocs) - memset(relocs, 0, relocs_size); - - /* find main_extable_sort_needed */ - sort_needed_sym = NULL; - for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { - sym = (void *)ehdr + _r(&symtab_sec->sh_offset); - sym += i; - if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) - continue; - idx = r(&sym->st_name); - if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { - sort_needed_sym = sym; - break; - } - } - if (sort_needed_sym == NULL) { - fprintf(stderr, - "no main_extable_sort_needed symbol in file: %s\n", - fname); - fail_file(); - } - sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), - sort_needed_sym - symtab, - symtab_shndx_start)]; - sort_done_location = (void *)ehdr + - _r(&sort_needed_sec->sh_offset) + - _r(&sort_needed_sym->st_value) - - _r(&sort_needed_sec->sh_addr); - -#if 0 - printf("sort done marker at %lx\n", - (unsigned long)((char *)sort_done_location - (char *)ehdr)); -#endif - /* We sorted it, clear the flag. */ - w(0, sort_done_location); -} diff --git a/scripts/sortextable.c b/scripts/sorttable.c index 55768654e3c6..ec6b5e81eba1 100644 --- a/scripts/sortextable.c +++ b/scripts/sorttable.c @@ -1,6 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * sortextable.c: Sort the kernel's exception table + * sorttable.c: Sort the kernel's table + * + * Added ORC unwind tables sort support and other updates: + * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by: + * Shile Zhang <shile.zhang@linux.alibaba.com> * * Copyright 2011 - 2012 Cavium, Inc. * @@ -9,7 +13,7 @@ * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. * * Restructured to fit Linux format, as well as other updates: - * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. + * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. */ /* @@ -22,7 +26,6 @@ #include <getopt.h> #include <elf.h> #include <fcntl.h> -#include <setjmp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -51,34 +54,13 @@ #define EM_ARCV2 195 #endif -static int fd_map; /* File descriptor for file being modified. */ -static int mmap_failed; /* Boolean flag. */ -static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ -static struct stat sb; /* Remember .st_size, etc. */ -static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ - -/* setjmp() return values */ -enum { - SJ_SETJMP = 0, /* hardwired first return */ - SJ_FAIL, - SJ_SUCCEED -}; - -/* Per-file resource cleanup when multiple files. */ -static void -cleanup(void) -{ - if (!mmap_failed) - munmap(ehdr_curr, sb.st_size); - close(fd_map); -} - -static void __attribute__((noreturn)) -fail_file(void) -{ - cleanup(); - longjmp(jmpenv, SJ_FAIL); -} +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 (*w2)(uint16_t, uint16_t *); +static void (*w8)(uint64_t, uint64_t *); +typedef void (*table_sort_t)(char *, int); /* * Get the whole file as a programming convenience in order to avoid @@ -86,87 +68,98 @@ fail_file(void) * avoids copying unused pieces; else just read the whole file. * Open for both read and write. */ -static void *mmap_file(char const *fname) +static void *mmap_file(char const *fname, size_t *size) { - void *addr; + int fd; + struct stat sb; + void *addr = NULL; - fd_map = open(fname, O_RDWR); - if (fd_map < 0 || fstat(fd_map, &sb) < 0) { + fd = open(fname, O_RDWR); + if (fd < 0) { perror(fname); - fail_file(); + 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); - fail_file(); + goto out; } - addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, - fd_map, 0); + + addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { - mmap_failed = 1; fprintf(stderr, "Could not mmap file: %s\n", fname); - fail_file(); + goto out; } + + *size = sb.st_size; + +out: + close(fd); return addr; } -static uint64_t r8be(const uint64_t *x) -{ - return get_unaligned_be64(x); -} 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 r8le(const uint64_t *x) + +static uint64_t r8be(const uint64_t *x) { - return get_unaligned_le64(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 void w8be(uint64_t val, uint64_t *x) +static uint64_t r8le(const uint64_t *x) { - put_unaligned_be64(val, x); + return get_unaligned_le64(x); } + static void wbe(uint32_t val, uint32_t *x) { put_unaligned_be32(val, x); } + static void w2be(uint16_t val, uint16_t *x) { put_unaligned_be16(val, x); } -static void w8le(uint64_t val, uint64_t *x) + +static void w8be(uint64_t val, uint64_t *x) { - put_unaligned_le64(val, x); + put_unaligned_be64(val, x); } + static void wle(uint32_t val, uint32_t *x) { put_unaligned_le32(val, x); } + static void w2le(uint16_t val, uint16_t *x) { put_unaligned_le16(val, x); } -static uint64_t (*r8)(const uint64_t *); -static uint32_t (*r)(const uint32_t *); -static uint16_t (*r2)(const uint16_t *); -static void (*w8)(uint64_t, uint64_t *); -static void (*w)(uint32_t, uint32_t *); -static void (*w2)(uint16_t, uint16_t *); - -typedef void (*table_sort_t)(char *, int); +static void w8le(uint64_t val, uint64_t *x) +{ + put_unaligned_le64(val, x); +} /* * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of @@ -193,9 +186,9 @@ static inline unsigned int get_secindex(unsigned int shndx, } /* 32 bit and 64 bit are very similar */ -#include "sortextable.h" -#define SORTEXTABLE_64 -#include "sortextable.h" +#include "sorttable.h" +#define SORTTABLE_64 +#include "sorttable.h" static int compare_relative_table(const void *a, const void *b) { @@ -209,110 +202,100 @@ static int compare_relative_table(const void *a, const void *b) return 0; } -static void x86_sort_relative_table(char *extab_image, int image_size) +static void sort_relative_table(char *extab_image, int image_size) { - int i; + int i = 0; - i = 0; + /* + * Do the same thing the runtime sort does, first normalize to + * being relative to the start of the section. + */ 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); - w(r(loc + 2) + i + 8, loc + 2); - - i += sizeof(uint32_t) * 3; + i += 4; } - qsort(extab_image, image_size / 12, 12, compare_relative_table); + qsort(extab_image, image_size / 8, 8, compare_relative_table); + /* Now denormalize. */ i = 0; 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); - w(r(loc + 2) - (i + 8), loc + 2); - - i += sizeof(uint32_t) * 3; + i += 4; } } -static void sort_relative_table(char *extab_image, int image_size) +static void x86_sort_relative_table(char *extab_image, int image_size) { - int i; + int i = 0; - /* - * Do the same thing the runtime sort does, first normalize to - * being relative to the start of the section. - */ - i = 0; while (i < image_size) { uint32_t *loc = (uint32_t *)(extab_image + i); + w(r(loc) + i, loc); - i += 4; + w(r(loc + 1) + i + 4, loc + 1); + w(r(loc + 2) + i + 8, loc + 2); + + i += sizeof(uint32_t) * 3; } - qsort(extab_image, image_size / 8, 8, compare_relative_table); + qsort(extab_image, image_size / 12, 12, compare_relative_table); - /* Now denormalize. */ i = 0; while (i < image_size) { uint32_t *loc = (uint32_t *)(extab_image + i); + w(r(loc) - i, loc); - i += 4; + w(r(loc + 1) - (i + 4), loc + 1); + w(r(loc + 2) - (i + 8), loc + 2); + + i += sizeof(uint32_t) * 3; } } -static void -do_file(char const *const fname) +static int do_file(char const *const fname, void *addr) { - table_sort_t custom_sort; - Elf32_Ehdr *ehdr = mmap_file(fname); + int rc = -1; + Elf32_Ehdr *ehdr = addr; + table_sort_t custom_sort = NULL; - ehdr_curr = ehdr; switch (ehdr->e_ident[EI_DATA]) { - default: - fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", - ehdr->e_ident[EI_DATA], fname); - fail_file(); - break; case ELFDATA2LSB: - r = rle; - r2 = r2le; - r8 = r8le; - w = wle; - w2 = w2le; - w8 = w8le; + r = rle; + r2 = r2le; + r8 = r8le; + w = wle; + w2 = w2le; + w8 = w8le; break; case ELFDATA2MSB: - r = rbe; - r2 = r2be; - r8 = r8be; - w = wbe; - w2 = w2be; - w8 = w8be; + r = rbe; + r2 = r2be; + r8 = r8be; + w = wbe; + w2 = w2be; + w8 = w8be; break; - } /* end switch */ - if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 - || (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN) - || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { + default: + fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", + ehdr->e_ident[EI_DATA], fname); + return -1; + } + + if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 || + (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN) || + ehdr->e_ident[EI_VERSION] != EV_CURRENT) { fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname); - fail_file(); + return -1; } - custom_sort = NULL; switch (r2(&ehdr->e_machine)) { - default: - fprintf(stderr, "unrecognized e_machine %d %s\n", - r2(&ehdr->e_machine), fname); - fail_file(); - break; case EM_386: case EM_X86_64: custom_sort = x86_sort_relative_table; break; - case EM_S390: case EM_AARCH64: case EM_PARISC: @@ -327,74 +310,68 @@ do_file(char const *const fname) case EM_MIPS: case EM_XTENSA: break; - } /* end switch */ + default: + fprintf(stderr, "unrecognized e_machine %d %s\n", + r2(&ehdr->e_machine), fname); + return -1; + } switch (ehdr->e_ident[EI_CLASS]) { - default: - fprintf(stderr, "unrecognized ELF class %d %s\n", - ehdr->e_ident[EI_CLASS], fname); - fail_file(); - break; case ELFCLASS32: - if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) - || r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { + if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) || + r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); - fail_file(); + break; } - do32(ehdr, fname, custom_sort); + rc = do_sort_32(ehdr, fname, custom_sort); break; - case ELFCLASS64: { + case ELFCLASS64: + { Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; - if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) - || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { + if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) || + r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { fprintf(stderr, - "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); - fail_file(); + "unrecognized ET_EXEC/ET_DYN file: %s\n", + fname); + break; + } + rc = do_sort_64(ghdr, fname, custom_sort); } - do64(ghdr, fname, custom_sort); + break; + default: + fprintf(stderr, "unrecognized ELF class %d %s\n", + ehdr->e_ident[EI_CLASS], fname); break; } - } /* end switch */ - cleanup(); + return rc; } -int -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { - int n_error = 0; /* gcc-4.3.0 false positive complaint */ - int i; + int i, n_error = 0; /* gcc-4.3.0 false positive complaint */ + size_t size = 0; + void *addr = NULL; if (argc < 2) { - fprintf(stderr, "usage: sortextable vmlinux...\n"); + fprintf(stderr, "usage: sorttable vmlinux...\n"); return 0; } /* Process each file in turn, allowing deep failure. */ for (i = 1; i < argc; i++) { - char *file = argv[i]; - int const sjval = setjmp(jmpenv); + addr = mmap_file(argv[i], &size); + if (!addr) { + ++n_error; + continue; + } - switch (sjval) { - default: - fprintf(stderr, "internal error: %s\n", file); - exit(1); - break; - case SJ_SETJMP: /* normal sequence */ - /* Avoid problems if early cleanup() */ - fd_map = -1; - ehdr_curr = NULL; - mmap_failed = 1; - do_file(file); - break; - case SJ_FAIL: /* error in do_file or below */ + if (do_file(argv[i], addr)) ++n_error; - break; - case SJ_SUCCEED: /* premature success */ - /* do nothing */ - break; - } /* end switch */ + + munmap(addr, size); } + return !!n_error; } diff --git a/scripts/sorttable.h b/scripts/sorttable.h new file mode 100644 index 000000000000..a2baa2fefb13 --- /dev/null +++ b/scripts/sorttable.h @@ -0,0 +1,380 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * sorttable.h + * + * Added ORC unwind tables sort support and other updates: + * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by: + * Shile Zhang <shile.zhang@linux.alibaba.com> + * + * Copyright 2011 - 2012 Cavium, Inc. + * + * Some of code was taken out of arch/x86/kernel/unwind_orc.c, written by: + * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> + * + * Some of this code was taken out of recordmcount.h written by: + * + * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. + * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. + */ + +#undef extable_ent_size +#undef compare_extable +#undef do_sort +#undef Elf_Addr +#undef Elf_Ehdr +#undef Elf_Shdr +#undef Elf_Rel +#undef Elf_Rela +#undef Elf_Sym +#undef ELF_R_SYM +#undef Elf_r_sym +#undef ELF_R_INFO +#undef Elf_r_info +#undef ELF_ST_BIND +#undef ELF_ST_TYPE +#undef fn_ELF_R_SYM +#undef fn_ELF_R_INFO +#undef uint_t +#undef _r +#undef _w + +#ifdef SORTTABLE_64 +# define extable_ent_size 16 +# define compare_extable compare_extable_64 +# define do_sort do_sort_64 +# define Elf_Addr Elf64_Addr +# define Elf_Ehdr Elf64_Ehdr +# define Elf_Shdr Elf64_Shdr +# define Elf_Rel Elf64_Rel +# define Elf_Rela Elf64_Rela +# define Elf_Sym Elf64_Sym +# define ELF_R_SYM ELF64_R_SYM +# define Elf_r_sym Elf64_r_sym +# define ELF_R_INFO ELF64_R_INFO +# define Elf_r_info Elf64_r_info +# define ELF_ST_BIND ELF64_ST_BIND +# define ELF_ST_TYPE ELF64_ST_TYPE +# define fn_ELF_R_SYM fn_ELF64_R_SYM +# define fn_ELF_R_INFO fn_ELF64_R_INFO +# define uint_t uint64_t +# define _r r8 +# define _w w8 +#else +# define extable_ent_size 8 +# define compare_extable compare_extable_32 +# define do_sort do_sort_32 +# define Elf_Addr Elf32_Addr +# define Elf_Ehdr Elf32_Ehdr +# define Elf_Shdr Elf32_Shdr +# define Elf_Rel Elf32_Rel +# define Elf_Rela Elf32_Rela +# define Elf_Sym Elf32_Sym +# define ELF_R_SYM ELF32_R_SYM +# define Elf_r_sym Elf32_r_sym +# define ELF_R_INFO ELF32_R_INFO +# define Elf_r_info Elf32_r_info +# define ELF_ST_BIND ELF32_ST_BIND +# define ELF_ST_TYPE ELF32_ST_TYPE +# define fn_ELF_R_SYM fn_ELF32_R_SYM +# define fn_ELF_R_INFO fn_ELF32_R_INFO +# define uint_t uint32_t +# define _r r +# define _w w +#endif + +#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) +/* ORC unwinder only support X86_64 */ +#include <errno.h> +#include <pthread.h> +#include <asm/orc_types.h> + +#define ERRSTR_MAXSZ 256 + +char g_err[ERRSTR_MAXSZ]; +int *g_orc_ip_table; +struct orc_entry *g_orc_table; + +pthread_t orc_sort_thread; + +static inline unsigned long orc_ip(const int *ip) +{ + return (unsigned long)ip + *ip; +} + +static int orc_sort_cmp(const void *_a, const void *_b) +{ + struct orc_entry *orc_a; + const int *a = g_orc_ip_table + *(int *)_a; + const int *b = g_orc_ip_table + *(int *)_b; + unsigned long a_val = orc_ip(a); + unsigned long b_val = orc_ip(b); + + if (a_val > b_val) + return 1; + if (a_val < b_val) + return -1; + + /* + * The "weak" section terminator entries need to always be on the left + * to ensure the lookup code skips them in favor of real entries. + * These terminator entries exist to handle any gaps created by + * whitelisted .o files which didn't get objtool generation. + */ + orc_a = g_orc_table + (a - g_orc_ip_table); + return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1; +} + +static void *sort_orctable(void *arg) +{ + int i; + int *idxs = NULL; + int *tmp_orc_ip_table = NULL; + struct orc_entry *tmp_orc_table = NULL; + unsigned int *orc_ip_size = (unsigned int *)arg; + unsigned int num_entries = *orc_ip_size / sizeof(int); + unsigned int orc_size = num_entries * sizeof(struct orc_entry); + + idxs = (int *)malloc(*orc_ip_size); + if (!idxs) { + snprintf(g_err, ERRSTR_MAXSZ, "malloc idxs: %s", + strerror(errno)); + pthread_exit(g_err); + } + + tmp_orc_ip_table = (int *)malloc(*orc_ip_size); + if (!tmp_orc_ip_table) { + snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_ip_table: %s", + strerror(errno)); + pthread_exit(g_err); + } + + tmp_orc_table = (struct orc_entry *)malloc(orc_size); + if (!tmp_orc_table) { + snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_table: %s", + strerror(errno)); + pthread_exit(g_err); + } + + /* initialize indices array, convert ip_table to absolute address */ + for (i = 0; i < num_entries; i++) { + idxs[i] = i; + tmp_orc_ip_table[i] = g_orc_ip_table[i] + i * sizeof(int); + } + memcpy(tmp_orc_table, g_orc_table, orc_size); + + qsort(idxs, num_entries, sizeof(int), orc_sort_cmp); + + for (i = 0; i < num_entries; i++) { + if (idxs[i] == i) + continue; + + /* convert back to relative address */ + g_orc_ip_table[i] = tmp_orc_ip_table[idxs[i]] - i * sizeof(int); + g_orc_table[i] = tmp_orc_table[idxs[i]]; + } + + free(idxs); + free(tmp_orc_ip_table); + free(tmp_orc_table); + pthread_exit(NULL); +} +#endif + +static int compare_extable(const void *a, const void *b) +{ + Elf_Addr av = _r(a); + Elf_Addr bv = _r(b); + + if (av < bv) + return -1; + if (av > bv) + return 1; + return 0; +} + +static int do_sort(Elf_Ehdr *ehdr, + char const *const fname, + table_sort_t custom_sort) +{ + int rc = -1; + Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); + Elf_Shdr *strtab_sec = NULL; + Elf_Shdr *symtab_sec = NULL; + Elf_Shdr *extab_sec = NULL; + Elf_Sym *sym; + const Elf_Sym *symtab; + Elf32_Word *symtab_shndx = NULL; + Elf_Sym *sort_needed_sym = NULL; + Elf_Shdr *sort_needed_sec; + Elf_Rel *relocs = NULL; + int relocs_size = 0; + uint32_t *sort_needed_loc; + const char *secstrings; + const char *strtab; + char *extab_image; + int extab_index = 0; + int i; + int idx; + unsigned int shnum; + unsigned int shstrndx; +#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) + unsigned int orc_ip_size = 0; + unsigned int orc_size = 0; + unsigned int orc_num_entries = 0; +#endif + + shstrndx = r2(&ehdr->e_shstrndx); + if (shstrndx == SHN_XINDEX) + shstrndx = r(&shdr[0].sh_link); + secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset); + + shnum = r2(&ehdr->e_shnum); + if (shnum == SHN_UNDEF) + shnum = _r(&shdr[0].sh_size); + + for (i = 0, s = shdr; s < shdr + shnum; i++, s++) { + idx = r(&s->sh_name); + if (!strcmp(secstrings + idx, "__ex_table")) { + extab_sec = s; + extab_index = i; + } + if (!strcmp(secstrings + idx, ".symtab")) + symtab_sec = s; + if (!strcmp(secstrings + idx, ".strtab")) + strtab_sec = s; + + if ((r(&s->sh_type) == SHT_REL || + r(&s->sh_type) == SHT_RELA) && + r(&s->sh_info) == extab_index) { + relocs = (void *)ehdr + _r(&s->sh_offset); + relocs_size = _r(&s->sh_size); + } + if (r(&s->sh_type) == SHT_SYMTAB_SHNDX) + symtab_shndx = (Elf32_Word *)((const char *)ehdr + + _r(&s->sh_offset)); + +#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) + /* locate the ORC unwind tables */ + if (!strcmp(secstrings + idx, ".orc_unwind_ip")) { + orc_ip_size = s->sh_size; + g_orc_ip_table = (int *)((void *)ehdr + + s->sh_offset); + } + if (!strcmp(secstrings + idx, ".orc_unwind")) { + orc_size = s->sh_size; + g_orc_table = (struct orc_entry *)((void *)ehdr + + s->sh_offset); + } +#endif + } /* for loop */ + +#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) + if (!g_orc_ip_table || !g_orc_table) { + fprintf(stderr, + "incomplete ORC unwind tables in file: %s\n", fname); + goto out; + } + + orc_num_entries = orc_ip_size / sizeof(int); + if (orc_ip_size % sizeof(int) != 0 || + orc_size % sizeof(struct orc_entry) != 0 || + orc_num_entries != orc_size / sizeof(struct orc_entry)) { + fprintf(stderr, + "inconsistent ORC unwind table entries in file: %s\n", + fname); + goto out; + } + + /* create thread to sort ORC unwind tables concurrently */ + if (pthread_create(&orc_sort_thread, NULL, + sort_orctable, &orc_ip_size)) { + fprintf(stderr, + "pthread_create orc_sort_thread failed '%s': %s\n", + strerror(errno), fname); + goto out; + } +#endif + if (!extab_sec) { + fprintf(stderr, "no __ex_table in file: %s\n", fname); + goto out; + } + + if (!symtab_sec) { + fprintf(stderr, "no .symtab in file: %s\n", fname); + goto out; + } + + if (!strtab_sec) { + fprintf(stderr, "no .strtab in file: %s\n", fname); + goto out; + } + + extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); + strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); + symtab = (const Elf_Sym *)((const char *)ehdr + + _r(&symtab_sec->sh_offset)); + + if (custom_sort) { + custom_sort(extab_image, _r(&extab_sec->sh_size)); + } else { + int num_entries = _r(&extab_sec->sh_size) / extable_ent_size; + qsort(extab_image, num_entries, + extable_ent_size, compare_extable); + } + + /* If there were relocations, we no longer need them. */ + if (relocs) + memset(relocs, 0, relocs_size); + + /* find the flag main_extable_sort_needed */ + for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset); + sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); + sym++) { + if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) + continue; + if (!strcmp(strtab + r(&sym->st_name), + "main_extable_sort_needed")) { + sort_needed_sym = sym; + break; + } + } + + if (!sort_needed_sym) { + fprintf(stderr, + "no main_extable_sort_needed symbol in file: %s\n", + fname); + goto out; + } + + sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), + sort_needed_sym - symtab, + symtab_shndx)]; + sort_needed_loc = (void *)ehdr + + _r(&sort_needed_sec->sh_offset) + + _r(&sort_needed_sym->st_value) - + _r(&sort_needed_sec->sh_addr); + + /* extable has been sorted, clear the flag */ + w(0, sort_needed_loc); + rc = 0; + +out: +#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) + if (orc_sort_thread) { + void *retval = NULL; + /* wait for ORC tables sort done */ + rc = pthread_join(orc_sort_thread, &retval); + if (rc) + fprintf(stderr, + "pthread_join failed '%s': %s\n", + strerror(errno), fname); + else if (retval) { + rc = -1; + fprintf(stderr, + "failed to sort ORC tables '%s': %s\n", + (char *)retval, fname); + } + } +#endif + return rc; +} |