From 3c47b787b6516d2c3cbaa193fe13a83adbaaad1f Mon Sep 17 00:00:00 2001 From: Shile Zhang Date: Wed, 4 Dec 2019 08:46:27 +0800 Subject: scripts/sortextable: Rewrite error/success handling The scripts/sortextable.c code has originally copied some code from scripts/recordmount.c, which used the same setjmp/longjmp method to manage control flow. Meanwhile recordmcount has improved its error handling via: 3f1df12019f3 ("recordmcount: Rewrite error/success handling"). So rewrite this part of sortextable as well to get rid of the setjmp/longjmp kludges, with additional refactoring, to make it more readable and easier to extend. No functional changes intended. [ mingo: Rewrote the changelog. ] Signed-off-by: Shile Zhang Acked-by: Peter Zijlstra (Intel) Cc: Josh Poimboeuf Cc: Masahiro Yamada Cc: Michal Marek Cc: linux-kbuild@vger.kernel.org Link: https://lkml.kernel.org/r/20191204004633.88660-2-shile.zhang@linux.alibaba.com Signed-off-by: Ingo Molnar --- scripts/sortextable.c | 119 ++++++++++++++++++-------------------------------- scripts/sortextable.h | 11 ++--- 2 files changed, 48 insertions(+), 82 deletions(-) diff --git a/scripts/sortextable.c b/scripts/sortextable.c index 55768654e3c6..cd9762ba4467 100644 --- a/scripts/sortextable.c +++ b/scripts/sortextable.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -51,61 +50,41 @@ #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); -} - /* * 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) +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; } @@ -264,19 +243,18 @@ static void sort_relative_table(char *extab_image, int image_size) } } -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); + table_sort_t custom_sort = NULL; + Elf32_Ehdr *ehdr = addr; + int rc = -1; - 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; + return -1; case ELFDATA2LSB: r = rle; r2 = r2le; @@ -298,7 +276,7 @@ do_file(char const *const fname) || (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; @@ -306,7 +284,6 @@ do_file(char const *const fname) default: fprintf(stderr, "unrecognized e_machine %d %s\n", r2(&ehdr->e_machine), fname); - fail_file(); break; case EM_386: case EM_X86_64: @@ -333,16 +310,15 @@ do_file(char const *const fname) 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)) { fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); - fail_file(); + break; } - do32(ehdr, fname, custom_sort); + rc = do32(ehdr, fname, custom_sort); break; case ELFCLASS64: { Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; @@ -350,21 +326,22 @@ do_file(char const *const fname) || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); - fail_file(); + break; } - do64(ghdr, fname, custom_sort); + rc = do64(ghdr, fname, custom_sort); break; } } /* end switch */ - cleanup(); + return rc; } 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"); @@ -373,28 +350,16 @@ main(int argc, char *argv[]) /* 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/sortextable.h b/scripts/sortextable.h index d4b3f6c40f02..5a62e94df678 100644 --- a/scripts/sortextable.h +++ b/scripts/sortextable.h @@ -87,7 +87,7 @@ static int compare_extable(const void *a, const void *b) return 0; } -static void +static int do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) { Elf_Shdr *shdr; @@ -146,17 +146,17 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) } if (strtab_sec == NULL) { fprintf(stderr, "no .strtab in file: %s\n", fname); - fail_file(); + return -1; } if (symtab_sec == NULL) { fprintf(stderr, "no .symtab in file: %s\n", fname); - fail_file(); + return -1; } 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(); + return -1; } strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); @@ -190,7 +190,7 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) fprintf(stderr, "no main_extable_sort_needed symbol in file: %s\n", fname); - fail_file(); + return -1; } sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), sort_needed_sym - symtab, @@ -206,4 +206,5 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) #endif /* We sorted it, clear the flag. */ w(0, sort_done_location); + return 0; } -- cgit v1.2.3-59-g8ed1b From 6402e1416255a7bb94834925ba0255c750f54a2d Mon Sep 17 00:00:00 2001 From: Shile Zhang Date: Wed, 4 Dec 2019 08:46:28 +0800 Subject: scripts/sortextable: Clean up the code to meet the kernel coding style better Fix various style errors and inconsistencies, no functional changes intended. Signed-off-by: Shile Zhang Acked-by: Peter Zijlstra (Intel) Cc: Josh Poimboeuf Cc: Masahiro Yamada Cc: Michal Marek Cc: linux-kbuild@vger.kernel.org Link: https://lkml.kernel.org/r/20191204004633.88660-3-shile.zhang@linux.alibaba.com Signed-off-by: Ingo Molnar --- scripts/sortextable.c | 182 ++++++++++++++++++++++++++------------------------ scripts/sortextable.h | 31 ++++----- 2 files changed, 111 insertions(+), 102 deletions(-) diff --git a/scripts/sortextable.c b/scripts/sortextable.c index cd9762ba4467..e5384e86b58c 100644 --- a/scripts/sortextable.c +++ b/scripts/sortextable.c @@ -50,6 +50,14 @@ #define EM_ARCV2 195 #endif +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 * malloc+lseek+read+free of many pieces. If successful, then mmap @@ -75,6 +83,7 @@ static void *mmap_file(char const *fname, size_t *size) 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); @@ -88,64 +97,65 @@ out: 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 @@ -188,108 +198,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 int -do_file(char const *const fname, void *addr) +static int do_file(char const *const fname, void *addr) { - table_sort_t custom_sort = NULL; - Elf32_Ehdr *ehdr = addr; int rc = -1; + Elf32_Ehdr *ehdr = addr; + table_sort_t custom_sort = NULL; switch (ehdr->e_ident[EI_DATA]) { - default: - fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", - ehdr->e_ident[EI_DATA], fname); - return -1; 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); return -1; } - custom_sort = NULL; switch (r2(&ehdr->e_machine)) { - default: - fprintf(stderr, "unrecognized e_machine %d %s\n", - r2(&ehdr->e_machine), fname); - break; case EM_386: case EM_X86_64: custom_sort = x86_sort_relative_table; break; - case EM_S390: case EM_AARCH64: case EM_PARISC: @@ -304,40 +306,45 @@ do_file(char const *const fname, void *addr) 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); - 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); break; } rc = do32(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); + "unrecognized ET_EXEC/ET_DYN file: %s\n", + fname); break; } rc = do64(ghdr, fname, custom_sort); + } + break; + default: + fprintf(stderr, "unrecognized ELF class %d %s\n", + ehdr->e_ident[EI_CLASS], fname); break; } - } /* end switch */ return rc; } -int -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { int i, n_error = 0; /* gcc-4.3.0 false positive complaint */ size_t size = 0; @@ -361,5 +368,6 @@ main(int argc, char *argv[]) munmap(addr, size); } + return !!n_error; } diff --git a/scripts/sortextable.h b/scripts/sortextable.h index 5a62e94df678..b7e407e09f59 100644 --- a/scripts/sortextable.h +++ b/scripts/sortextable.h @@ -6,7 +6,7 @@ * * Some of this code was taken out of recordmcount.h written by: * - * Copyright 2009 John F. Reiser . All rights reserved. + * Copyright 2009 John F. Reiser . All rights reserved. * Copyright 2010 Steven Rostedt , Red Hat Inc. */ @@ -87,8 +87,9 @@ static int compare_extable(const void *a, const void *b) return 0; } -static int -do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) +static int do_func(Elf_Ehdr *ehdr, + char const *const fname, + table_sort_t custom_sort) { Elf_Shdr *shdr; Elf_Shdr *shstrtab_sec; @@ -126,7 +127,7 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) 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) { + if (!strcmp(secstrtab + idx, "__ex_table")) { extab_sec = shdr + i; extab_index = i; } @@ -136,26 +137,26 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) relocs = (void *)ehdr + _r(&shdr[i].sh_offset); relocs_size = _r(&shdr[i].sh_size); } - if (strcmp(secstrtab + idx, ".symtab") == 0) + if (!strcmp(secstrtab + idx, ".symtab")) symtab_sec = shdr + i; - if (strcmp(secstrtab + idx, ".strtab") == 0) + if (!strcmp(secstrtab + idx, ".strtab")) 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); + if (!strtab_sec) { + fprintf(stderr, "no .strtab in file: %s\n", fname); return -1; } - if (symtab_sec == NULL) { - fprintf(stderr, "no .symtab in file: %s\n", fname); + if (!symtab_sec) { + fprintf(stderr, "no .symtab in file: %s\n", fname); return -1; } 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); + if (!extab_sec) { + fprintf(stderr, "no __ex_table in file: %s\n", fname); return -1; } strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); @@ -181,14 +182,14 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) continue; idx = r(&sym->st_name); - if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { + if (!strcmp(strtab + idx, "main_extable_sort_needed")) { sort_needed_sym = sym; break; } } - if (sort_needed_sym == NULL) { + if (!sort_needed_sym) { fprintf(stderr, - "no main_extable_sort_needed symbol in file: %s\n", + "no main_extable_sort_needed symbol in file: %s\n", fname); return -1; } -- cgit v1.2.3-59-g8ed1b From abe4f92ca8948a3e04c56788354933c326909acb Mon Sep 17 00:00:00 2001 From: Shile Zhang Date: Wed, 4 Dec 2019 08:46:29 +0800 Subject: scripts/sortextable: Remove dead code Signed-off-by: Shile Zhang Acked-by: Peter Zijlstra (Intel) Cc: Josh Poimboeuf Cc: Masahiro Yamada Cc: Michal Marek Cc: linux-kbuild@vger.kernel.org Link: https://lkml.kernel.org/r/20191204004633.88660-4-shile.zhang@linux.alibaba.com Signed-off-by: Ingo Molnar --- scripts/sortextable.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/sortextable.h b/scripts/sortextable.h index b7e407e09f59..a2e3af7bf211 100644 --- a/scripts/sortextable.h +++ b/scripts/sortextable.h @@ -201,10 +201,6 @@ static int do_func(Elf_Ehdr *ehdr, _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); return 0; -- cgit v1.2.3-59-g8ed1b From 57cafdf2a04e161b9654c4ae3888a7549594c499 Mon Sep 17 00:00:00 2001 From: Shile Zhang Date: Wed, 4 Dec 2019 08:46:30 +0800 Subject: scripts/sortextable: Refactor the do_func() function Refine the loop, naming and code structure, make the code more readable and extendable. No functional changes intended. Signed-off-by: Shile Zhang Acked-by: Peter Zijlstra (Intel) Cc: Josh Poimboeuf Cc: Masahiro Yamada Cc: Michal Marek Cc: linux-kbuild@vger.kernel.org Link: https://lkml.kernel.org/r/20191204004633.88660-5-shile.zhang@linux.alibaba.com Signed-off-by: Ingo Molnar --- scripts/sortextable.c | 4 +- scripts/sortextable.h | 115 ++++++++++++++++++++++++++------------------------ 2 files changed, 61 insertions(+), 58 deletions(-) diff --git a/scripts/sortextable.c b/scripts/sortextable.c index e5384e86b58c..efa2839865cd 100644 --- a/scripts/sortextable.c +++ b/scripts/sortextable.c @@ -320,7 +320,7 @@ static int do_file(char const *const fname, void *addr) "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); break; } - rc = do32(ehdr, fname, custom_sort); + rc = do_sort_32(ehdr, fname, custom_sort); break; case ELFCLASS64: { @@ -332,7 +332,7 @@ static int do_file(char const *const fname, void *addr) fname); break; } - rc = do64(ghdr, fname, custom_sort); + rc = do_sort_64(ghdr, fname, custom_sort); } break; default: diff --git a/scripts/sortextable.h b/scripts/sortextable.h index a2e3af7bf211..6485513f7cae 100644 --- a/scripts/sortextable.h +++ b/scripts/sortextable.h @@ -12,7 +12,7 @@ #undef extable_ent_size #undef compare_extable -#undef do_func +#undef do_sort #undef Elf_Addr #undef Elf_Ehdr #undef Elf_Shdr @@ -34,7 +34,7 @@ #ifdef SORTEXTABLE_64 # define extable_ent_size 16 # define compare_extable compare_extable_64 -# define do_func do64 +# define do_sort do_sort_64 # define Elf_Addr Elf64_Addr # define Elf_Ehdr Elf64_Ehdr # define Elf_Shdr Elf64_Shdr @@ -55,7 +55,7 @@ #else # define extable_ent_size 8 # define compare_extable compare_extable_32 -# define do_func do32 +# define do_sort do_sort_32 # define Elf_Addr Elf32_Addr # define Elf_Ehdr Elf32_Ehdr # define Elf_Shdr Elf32_Shdr @@ -87,81 +87,81 @@ static int compare_extable(const void *a, const void *b) return 0; } -static int do_func(Elf_Ehdr *ehdr, +static int do_sort(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) { - Elf_Shdr *shdr; - Elf_Shdr *shstrtab_sec; + 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_start = NULL; - Elf_Sym *sort_needed_sym; + 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_done_location; - const char *secstrtab; + uint32_t *sort_needed_loc; + const char *secstrings; const char *strtab; char *extab_image; int extab_index = 0; int i; int idx; - unsigned int num_sections; - unsigned int secindex_strings; + unsigned int shnum; + unsigned int shstrndx; - shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); + shstrndx = r2(&ehdr->e_shstrndx); + if (shstrndx == SHN_XINDEX) + shstrndx = r(&shdr[0].sh_link); + secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset); - num_sections = r2(&ehdr->e_shnum); - if (num_sections == SHN_UNDEF) - num_sections = _r(&shdr[0].sh_size); + shnum = r2(&ehdr->e_shnum); + if (shnum == SHN_UNDEF) + shnum = _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")) { - extab_sec = shdr + i; + 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 ((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(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 (!strcmp(secstrtab + idx, ".symtab")) - symtab_sec = shdr + i; - if (!strcmp(secstrtab + idx, ".strtab")) - 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 (r(&s->sh_type) == SHT_SYMTAB_SHNDX) + symtab_shndx = (Elf32_Word *)((const char *)ehdr + + _r(&s->sh_offset)); } - if (!strtab_sec) { - fprintf(stderr, "no .strtab in file: %s\n", fname); + + if (!extab_sec) { + fprintf(stderr, "no __ex_table in file: %s\n", fname); return -1; } + if (!symtab_sec) { fprintf(stderr, "no .symtab in file: %s\n", fname); return -1; } - symtab = (const Elf_Sym *)((const char *)ehdr + - _r(&symtab_sec->sh_offset)); - if (!extab_sec) { - fprintf(stderr, "no __ex_table in file: %s\n", fname); + + if (!strtab_sec) { + fprintf(stderr, "no .strtab in file: %s\n", fname); return -1; } - strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); 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)); @@ -170,38 +170,41 @@ static int do_func(Elf_Ehdr *ehdr, 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; + /* 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; - idx = r(&sym->st_name); - if (!strcmp(strtab + idx, "main_extable_sort_needed")) { + 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); return -1; } + sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), sort_needed_sym - symtab, - symtab_shndx_start)]; - sort_done_location = (void *)ehdr + + 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); - /* We sorted it, clear the flag. */ - w(0, sort_done_location); + /* extable has been sorted, clear the flag */ + w(0, sort_needed_loc); + return 0; } -- cgit v1.2.3-59-g8ed1b From 1091670637be8bd34a39dd1ddcc0a10a7c88d4e2 Mon Sep 17 00:00:00 2001 From: Shile Zhang Date: Wed, 4 Dec 2019 08:46:31 +0800 Subject: scripts/sorttable: Rename 'sortextable' to 'sorttable' Use a more generic name for additional table sorting usecases, such as the upcoming ORC table sorting feature. This tool is not tied to exception table sorting anymore. No functional changes intended. [ mingo: Rewrote the changelog. ] Signed-off-by: Shile Zhang Acked-by: Peter Zijlstra (Intel) Cc: Josh Poimboeuf Cc: Masahiro Yamada Cc: Michal Marek Cc: linux-kbuild@vger.kernel.org Link: https://lkml.kernel.org/r/20191204004633.88660-6-shile.zhang@linux.alibaba.com Signed-off-by: Ingo Molnar --- arch/arc/Kconfig | 2 +- arch/arm/Kconfig | 2 +- arch/arm64/Kconfig | 2 +- arch/microblaze/Kconfig | 2 +- arch/mips/Kconfig | 2 +- arch/parisc/Kconfig | 2 +- arch/powerpc/Kconfig | 2 +- arch/s390/Kconfig | 2 +- arch/x86/Kconfig | 2 +- arch/xtensa/Kconfig | 2 +- init/Kconfig | 2 +- scripts/.gitignore | 2 +- scripts/Makefile | 4 +- scripts/link-vmlinux.sh | 10 +- scripts/sortextable.c | 373 ------------------------------------------------ scripts/sortextable.h | 210 --------------------------- scripts/sorttable.c | 373 ++++++++++++++++++++++++++++++++++++++++++++++++ scripts/sorttable.h | 210 +++++++++++++++++++++++++++ 18 files changed, 602 insertions(+), 602 deletions(-) delete mode 100644 scripts/sortextable.c delete mode 100644 scripts/sortextable.h create mode 100644 scripts/sorttable.c create mode 100644 scripts/sorttable.h diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 26108ea785c2..5f448201955b 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -13,7 +13,7 @@ config ARC select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC select ARCH_32BIT_OFF_T - select BUILDTIME_EXTABLE_SORT + select BUILDTIME_TABLE_SORT select CLONE_BACKWARDS select COMMON_CLK select DMA_DIRECT_REMAP diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ba75e3661a41..cb3493b4db83 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -36,7 +36,7 @@ config ARM select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU select ARCH_WANT_IPC_PARSE_VERSION select BINFMT_FLAT_ARGVP_ENVP_ON_STACK - select BUILDTIME_EXTABLE_SORT if MMU + select BUILDTIME_TABLE_SORT if MMU select CLONE_BACKWARDS select CPU_PM if SUSPEND || CPU_IDLE select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index b1b4476ddb83..6f360dd2b1ad 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -81,7 +81,7 @@ config ARM64 select ARM_GIC_V3 select ARM_GIC_V3_ITS if PCI select ARM_PSCI_FW - select BUILDTIME_EXTABLE_SORT + select BUILDTIME_TABLE_SORT select CLONE_BACKWARDS select COMMON_CLK select CPU_PM if (SUSPEND || CPU_IDLE) diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 5f46ebe7bfe3..a105f113fd67 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -11,7 +11,7 @@ config MICROBLAZE select ARCH_HAS_UNCACHED_SEGMENT if !MMU select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_WANT_IPC_PARSE_VERSION - select BUILDTIME_EXTABLE_SORT + select BUILDTIME_TABLE_SORT select TIMER_OF select CLONE_BACKWARDS3 select COMMON_CLK diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index add388236f4e..5531942baf5d 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -15,7 +15,7 @@ config MIPS select ARCH_USE_QUEUED_SPINLOCKS select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU select ARCH_WANT_IPC_PARSE_VERSION - select BUILDTIME_EXTABLE_SORT + select BUILDTIME_TABLE_SORT select CLONE_BACKWARDS select CPU_NO_EFFICIENT_FFS if (TARGET_ISA_REV < 1) select CPU_PM if CPU_IDLE diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index b16237c95ea3..e1ef610a5a2b 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -18,7 +18,7 @@ config PARISC select RTC_DRV_GENERIC select INIT_ALL_POSSIBLE select BUG - select BUILDTIME_EXTABLE_SORT + select BUILDTIME_TABLE_SORT select HAVE_PCI select HAVE_PERF_EVENTS select HAVE_KERNEL_BZIP2 diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1ec34e16ed65..18a21b4f3711 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -149,7 +149,7 @@ config PPC select ARCH_WANT_IPC_PARSE_VERSION select ARCH_WEAK_RELEASE_ACQUIRE select BINFMT_ELF - select BUILDTIME_EXTABLE_SORT + select BUILDTIME_TABLE_SORT select CLONE_BACKWARDS select DCACHE_WORD_ACCESS if PPC64 && CPU_LITTLE_ENDIAN select DYNAMIC_FTRACE if FUNCTION_TRACER diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index d4051e88e625..884194fab698 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -110,7 +110,7 @@ config S390 select ARCH_USE_CMPXCHG_LOCKREF select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_WANT_IPC_PARSE_VERSION - select BUILDTIME_EXTABLE_SORT + select BUILDTIME_TABLE_SORT select CLONE_BACKWARDS2 select DYNAMIC_FTRACE if FUNCTION_TRACER select GENERIC_CLOCKEVENTS diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5e8949953660..e71158af8dd5 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -96,7 +96,7 @@ config X86 select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_WANT_HUGE_PMD_SHARE select ARCH_WANTS_THP_SWAP if X86_64 - select BUILDTIME_EXTABLE_SORT + select BUILDTIME_TABLE_SORT select CLKEVT_I8253 select CLOCKSOURCE_VALIDATE_LAST_CYCLE select CLOCKSOURCE_WATCHDOG diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 4a3fa295d8fe..fb9746db0a6d 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -11,7 +11,7 @@ config XTENSA select ARCH_USE_QUEUED_SPINLOCKS select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_IPC_PARSE_VERSION - select BUILDTIME_EXTABLE_SORT + select BUILDTIME_TABLE_SORT select CLONE_BACKWARDS select COMMON_CLK select DMA_REMAP if MMU diff --git a/init/Kconfig b/init/Kconfig index a34064a031a5..ad9b6c5eaf1d 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -58,7 +58,7 @@ config CONSTRUCTORS config IRQ_WORK bool -config BUILDTIME_EXTABLE_SORT +config BUILDTIME_TABLE_SORT bool config THREAD_INFO_IN_TASK 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..7491241e3a0d 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -13,13 +13,13 @@ 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 diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 436379940356..a81aa76bbe18 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,9 @@ 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 + sorttable vmlinux fi info SYSMAP System.map diff --git a/scripts/sortextable.c b/scripts/sortextable.c deleted file mode 100644 index efa2839865cd..000000000000 --- a/scripts/sortextable.c +++ /dev/null @@ -1,373 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * sortextable.c: Sort the kernel's exception table - * - * Copyright 2011 - 2012 Cavium, Inc. - * - * Based on code taken from recortmcount.c which is: - * - * Copyright 2009 John F. Reiser . All rights reserved. - * - * Restructured to fit Linux format, as well as other updates: - * Copyright 2010 Steven Rostedt , Red Hat Inc. - */ - -/* - * Strategy: alter the vmlinux file in-place. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifndef EM_ARCOMPACT -#define EM_ARCOMPACT 93 -#endif - -#ifndef EM_XTENSA -#define EM_XTENSA 94 -#endif - -#ifndef EM_AARCH64 -#define EM_AARCH64 183 -#endif - -#ifndef EM_MICROBLAZE -#define EM_MICROBLAZE 189 -#endif - -#ifndef EM_ARCV2 -#define EM_ARCV2 195 -#endif - -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 - * 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 w2be(uint16_t val, uint16_t *x) -{ - put_unaligned_be16(val, x); -} - -static void w8be(uint64_t val, uint64_t *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 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 - * indices. - */ -#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) - -static inline int is_shndx_special(unsigned int i) -{ - return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; -} - -/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ -static inline unsigned int get_secindex(unsigned int shndx, - unsigned int sym_offs, - const Elf32_Word *symtab_shndx_start) -{ - if (is_shndx_special(shndx)) - return SPECIAL(shndx); - if (shndx != SHN_XINDEX) - return shndx; - return r(&symtab_shndx_start[sym_offs]); -} - -/* 32 bit and 64 bit are very similar */ -#include "sortextable.h" -#define SORTEXTABLE_64 -#include "sortextable.h" - -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); - - if (av < bv) - return -1; - if (av > bv) - return 1; - return 0; -} - -static void sort_relative_table(char *extab_image, int image_size) -{ - int 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); - i += 4; - } - - 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); - i += 4; - } -} - -static void x86_sort_relative_table(char *extab_image, int image_size) -{ - int 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; - } - - qsort(extab_image, image_size / 12, 12, compare_relative_table); - - 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; - } -} - -static int do_file(char const *const fname, void *addr) -{ - int rc = -1; - Elf32_Ehdr *ehdr = addr; - table_sort_t custom_sort = NULL; - - switch (ehdr->e_ident[EI_DATA]) { - case ELFDATA2LSB: - 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; - break; - 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); - return -1; - } - - switch (r2(&ehdr->e_machine)) { - case EM_386: - case EM_X86_64: - custom_sort = x86_sort_relative_table; - break; - case EM_S390: - case EM_AARCH64: - case EM_PARISC: - case EM_PPC: - case EM_PPC64: - custom_sort = sort_relative_table; - break; - case EM_ARCOMPACT: - case EM_ARCV2: - case EM_ARM: - case EM_MICROBLAZE: - case EM_MIPS: - case EM_XTENSA: - break; - default: - fprintf(stderr, "unrecognized e_machine %d %s\n", - r2(&ehdr->e_machine), fname); - return -1; - } - - switch (ehdr->e_ident[EI_CLASS]) { - case ELFCLASS32: - 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); - break; - } - rc = do_sort_32(ehdr, fname, custom_sort); - break; - case ELFCLASS64: - { - Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; - 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); - break; - } - rc = do_sort_64(ghdr, fname, custom_sort); - } - break; - default: - fprintf(stderr, "unrecognized ELF class %d %s\n", - ehdr->e_ident[EI_CLASS], fname); - break; - } - - return rc; -} - -int main(int argc, char *argv[]) -{ - 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"); - return 0; - } - - /* Process each file in turn, allowing deep failure. */ - for (i = 1; i < argc; i++) { - addr = mmap_file(argv[i], &size); - if (!addr) { - ++n_error; - continue; - } - - if (do_file(argv[i], addr)) - ++n_error; - - munmap(addr, size); - } - - return !!n_error; -} diff --git a/scripts/sortextable.h b/scripts/sortextable.h deleted file mode 100644 index 6485513f7cae..000000000000 --- a/scripts/sortextable.h +++ /dev/null @@ -1,210 +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 . All rights reserved. - * Copyright 2010 Steven Rostedt , 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 SORTEXTABLE_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 - -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) -{ - 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; - - 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 (!extab_sec) { - fprintf(stderr, "no __ex_table in file: %s\n", fname); - return -1; - } - - if (!symtab_sec) { - fprintf(stderr, "no .symtab in file: %s\n", fname); - return -1; - } - - if (!strtab_sec) { - fprintf(stderr, "no .strtab in file: %s\n", fname); - return -1; - } - - 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); - return -1; - } - - 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); - - return 0; -} diff --git a/scripts/sorttable.c b/scripts/sorttable.c new file mode 100644 index 000000000000..ff98b7db20c6 --- /dev/null +++ b/scripts/sorttable.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * sorttable.c: Sort the kernel's table + * + * Copyright 2011 - 2012 Cavium, Inc. + * + * Based on code taken from recortmcount.c which is: + * + * Copyright 2009 John F. Reiser . All rights reserved. + * + * Restructured to fit Linux format, as well as other updates: + * Copyright 2010 Steven Rostedt , Red Hat Inc. + */ + +/* + * Strategy: alter the vmlinux file in-place. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef EM_ARCOMPACT +#define EM_ARCOMPACT 93 +#endif + +#ifndef EM_XTENSA +#define EM_XTENSA 94 +#endif + +#ifndef EM_AARCH64 +#define EM_AARCH64 183 +#endif + +#ifndef EM_MICROBLAZE +#define EM_MICROBLAZE 189 +#endif + +#ifndef EM_ARCV2 +#define EM_ARCV2 195 +#endif + +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 + * 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 w2be(uint16_t val, uint16_t *x) +{ + put_unaligned_be16(val, x); +} + +static void w8be(uint64_t val, uint64_t *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 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 + * indices. + */ +#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) + +static inline int is_shndx_special(unsigned int i) +{ + return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; +} + +/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ +static inline unsigned int get_secindex(unsigned int shndx, + unsigned int sym_offs, + const Elf32_Word *symtab_shndx_start) +{ + if (is_shndx_special(shndx)) + return SPECIAL(shndx); + if (shndx != SHN_XINDEX) + return shndx; + return r(&symtab_shndx_start[sym_offs]); +} + +/* 32 bit and 64 bit are very similar */ +#include "sorttable.h" +#define SORTTABLE_64 +#include "sorttable.h" + +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); + + if (av < bv) + return -1; + if (av > bv) + return 1; + return 0; +} + +static void sort_relative_table(char *extab_image, int image_size) +{ + int 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); + i += 4; + } + + 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); + i += 4; + } +} + +static void x86_sort_relative_table(char *extab_image, int image_size) +{ + int 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; + } + + qsort(extab_image, image_size / 12, 12, compare_relative_table); + + 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; + } +} + +static int do_file(char const *const fname, void *addr) +{ + int rc = -1; + Elf32_Ehdr *ehdr = addr; + table_sort_t custom_sort = NULL; + + switch (ehdr->e_ident[EI_DATA]) { + case ELFDATA2LSB: + 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; + break; + 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); + return -1; + } + + switch (r2(&ehdr->e_machine)) { + case EM_386: + case EM_X86_64: + custom_sort = x86_sort_relative_table; + break; + case EM_S390: + case EM_AARCH64: + case EM_PARISC: + case EM_PPC: + case EM_PPC64: + custom_sort = sort_relative_table; + break; + case EM_ARCOMPACT: + case EM_ARCV2: + case EM_ARM: + case EM_MICROBLAZE: + case EM_MIPS: + case EM_XTENSA: + break; + default: + fprintf(stderr, "unrecognized e_machine %d %s\n", + r2(&ehdr->e_machine), fname); + return -1; + } + + switch (ehdr->e_ident[EI_CLASS]) { + case ELFCLASS32: + 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); + break; + } + rc = do_sort_32(ehdr, fname, custom_sort); + break; + case ELFCLASS64: + { + Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; + 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); + break; + } + rc = do_sort_64(ghdr, fname, custom_sort); + } + break; + default: + fprintf(stderr, "unrecognized ELF class %d %s\n", + ehdr->e_ident[EI_CLASS], fname); + break; + } + + return rc; +} + +int main(int argc, char *argv[]) +{ + 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: sorttable vmlinux...\n"); + return 0; + } + + /* Process each file in turn, allowing deep failure. */ + for (i = 1; i < argc; i++) { + addr = mmap_file(argv[i], &size); + if (!addr) { + ++n_error; + continue; + } + + if (do_file(argv[i], addr)) + ++n_error; + + munmap(addr, size); + } + + return !!n_error; +} diff --git a/scripts/sorttable.h b/scripts/sorttable.h new file mode 100644 index 000000000000..82589ff90e25 --- /dev/null +++ b/scripts/sorttable.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * sorttable.h + * + * Copyright 2011 - 2012 Cavium, Inc. + * + * Some of this code was taken out of recordmcount.h written by: + * + * Copyright 2009 John F. Reiser . All rights reserved. + * Copyright 2010 Steven Rostedt , 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 + +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) +{ + 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; + + 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 (!extab_sec) { + fprintf(stderr, "no __ex_table in file: %s\n", fname); + return -1; + } + + if (!symtab_sec) { + fprintf(stderr, "no .symtab in file: %s\n", fname); + return -1; + } + + if (!strtab_sec) { + fprintf(stderr, "no .strtab in file: %s\n", fname); + return -1; + } + + 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); + return -1; + } + + 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); + + return 0; +} -- cgit v1.2.3-59-g8ed1b From 57fa1899428538e314a7e0d52a5b617af082389a Mon Sep 17 00:00:00 2001 From: Shile Zhang Date: Wed, 4 Dec 2019 08:46:32 +0800 Subject: scripts/sorttable: Implement build-time ORC unwind table sorting The ORC unwinder has two tables: .orc_unwind_ip and .orc_unwind, which need to be sorted for binary search. Previously this sorting was done during bootup. Sort them at build time to speed up booting. Add the ORC tables sorting in a parallel build process to speed up the build. [ mingo: Rewrote the changelog and fixed some comments. ] Suggested-by: Andy Lutomirski Suggested-by: Peter Zijlstra Reported-by: kbuild test robot Signed-off-by: Shile Zhang Acked-by: Peter Zijlstra (Intel) Cc: Josh Poimboeuf Cc: Masahiro Yamada Cc: Michal Marek Cc: linux-kbuild@vger.kernel.org Link: https://lkml.kernel.org/r/20191204004633.88660-7-shile.zhang@linux.alibaba.com Signed-off-by: Ingo Molnar --- scripts/Makefile | 9 +++ scripts/sorttable.c | 6 +- scripts/sorttable.h | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 189 insertions(+), 6 deletions(-) diff --git a/scripts/Makefile b/scripts/Makefile index 7491241e3a0d..b0e962611d50 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -24,6 +24,15 @@ 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/sorttable.c b/scripts/sorttable.c index ff98b7db20c6..ec6b5e81eba1 100644 --- a/scripts/sorttable.c +++ b/scripts/sorttable.c @@ -2,6 +2,10 @@ /* * 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 + * * Copyright 2011 - 2012 Cavium, Inc. * * Based on code taken from recortmcount.c which is: @@ -9,7 +13,7 @@ * Copyright 2009 John F. Reiser . All rights reserved. * * Restructured to fit Linux format, as well as other updates: - * Copyright 2010 Steven Rostedt , Red Hat Inc. + * Copyright 2010 Steven Rostedt , Red Hat Inc. */ /* diff --git a/scripts/sorttable.h b/scripts/sorttable.h index 82589ff90e25..a2baa2fefb13 100644 --- a/scripts/sorttable.h +++ b/scripts/sorttable.h @@ -2,8 +2,15 @@ /* * sorttable.h * + * Added ORC unwind tables sort support and other updates: + * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by: + * Shile Zhang + * * 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 + * * Some of this code was taken out of recordmcount.h written by: * * Copyright 2009 John F. Reiser . All rights reserved. @@ -75,6 +82,104 @@ # define _w w #endif +#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) +/* ORC unwinder only support X86_64 */ +#include +#include +#include + +#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); @@ -91,6 +196,7 @@ 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; @@ -111,6 +217,11 @@ static int do_sort(Elf_Ehdr *ehdr, 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) @@ -141,21 +252,61 @@ static int do_sort(Elf_Ehdr *ehdr, 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); - return -1; + goto out; } if (!symtab_sec) { fprintf(stderr, "no .symtab in file: %s\n", fname); - return -1; + goto out; } if (!strtab_sec) { fprintf(stderr, "no .strtab in file: %s\n", fname); - return -1; + goto out; } extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); @@ -192,7 +343,7 @@ static int do_sort(Elf_Ehdr *ehdr, fprintf(stderr, "no main_extable_sort_needed symbol in file: %s\n", fname); - return -1; + goto out; } sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), @@ -205,6 +356,25 @@ static int do_sort(Elf_Ehdr *ehdr, /* extable has been sorted, clear the flag */ w(0, sort_needed_loc); + rc = 0; - return 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; } -- cgit v1.2.3-59-g8ed1b From f14bf6a350dfd6613dbf91be5b423bc7eab690da Mon Sep 17 00:00:00 2001 From: Shile Zhang Date: Wed, 4 Dec 2019 08:46:33 +0800 Subject: x86/unwind/orc: Remove boot-time ORC unwind tables sorting Now that the orc_unwind and orc_unwind_ip tables are sorted at build time, remove the boot time sorting pass. No change in functionality. [ mingo: Rewrote the changelog and code comments. ] Signed-off-by: Shile Zhang Acked-by: Peter Zijlstra (Intel) Cc: Josh Poimboeuf Cc: Masahiro Yamada Cc: Peter Zijlstra Cc: linux-kbuild@vger.kernel.org Link: https://lkml.kernel.org/r/20191204004633.88660-8-shile.zhang@linux.alibaba.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/unwind_orc.c | 8 +++++--- scripts/link-vmlinux.sh | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index 332ae6530fa8..abdf8911a1fb 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -273,9 +273,11 @@ void __init unwind_init(void) return; } - /* Sort the .orc_unwind and .orc_unwind_ip tables: */ - sort(__start_orc_unwind_ip, num_entries, sizeof(int), orc_sort_cmp, - orc_sort_swap); + /* + * Note, the orc_unwind and orc_unwind_ip tables were already + * sorted at build time via the 'sorttable' tool. + * It's ready for binary search straight away, no need to sort it. + */ /* Initialize the fast lookup table: */ lookup_num_blocks = orc_lookup_end - orc_lookup; diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index a81aa76bbe18..c287ad9b3a67 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -306,7 +306,10 @@ vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o} if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then info SORTTAB vmlinux - sorttable vmlinux + if ! sorttable vmlinux; then + echo >&2 Failed to sort kernel tables + exit 1 + fi fi info SYSMAP System.map -- cgit v1.2.3-59-g8ed1b From 22a7fa8848c5e881d87ef2f7f3c2ea77b286e6f9 Mon Sep 17 00:00:00 2001 From: Shile Zhang Date: Mon, 16 Dec 2019 11:07:29 +0800 Subject: x86/unwind/orc: Fix !CONFIG_MODULES build warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To fix follwowing warning due to ORC sort moved to build time: arch/x86/kernel/unwind_orc.c:210:12: warning: ‘orc_sort_cmp’ defined but not used [-Wunused-function] arch/x86/kernel/unwind_orc.c:190:13: warning: ‘orc_sort_swap’ defined but not used [-Wunused-function] Signed-off-by: Shile Zhang Reported-by: Stephen Rothwell Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Josh Poimboeuf Cc: Peter Zijlstra Cc: Thomas Gleixner Link: https://lkml.kernel.org/r/c9c81536-2afc-c8aa-c5f8-c7618ecd4f54@linux.alibaba.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/unwind_orc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index abdf8911a1fb..e9cc182aa97e 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -187,6 +187,8 @@ static struct orc_entry *orc_find(unsigned long ip) return orc_ftrace_find(ip); } +#ifdef CONFIG_MODULES + static void orc_sort_swap(void *_a, void *_b, int size) { struct orc_entry *orc_a, *orc_b; @@ -229,7 +231,6 @@ static int orc_sort_cmp(const void *_a, const void *_b) return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1; } -#ifdef CONFIG_MODULES void unwind_module_init(struct module *mod, void *_orc_ip, size_t orc_ip_size, void *_orc, size_t orc_size) { -- cgit v1.2.3-59-g8ed1b