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(-) (limited to 'scripts') 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 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(-) (limited to 'scripts') 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 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(-) (limited to 'scripts') 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 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(-) (limited to 'scripts') 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 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 (limited to 'scripts') 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 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(-) (limited to 'scripts') 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 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(-) (limited to 'scripts') 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 From 292e1d73b125d7a3fd7ff382557e003ece3c0d65 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sun, 12 Jan 2020 23:31:39 -0800 Subject: libbpf: Clean up bpf_helper_defs.h generation output bpf_helpers_doc.py script, used to generate bpf_helper_defs.h, unconditionally emits one informational message to stderr. Remove it and preserve stderr to contain only relevant errors. Also make sure script invocations command is muted by default in libbpf's Makefile. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20200113073143.1779940-3-andriin@fb.com --- scripts/bpf_helpers_doc.py | 2 -- tools/lib/bpf/Makefile | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/bpf_helpers_doc.py b/scripts/bpf_helpers_doc.py index 7548569e8076..90baf7d70911 100755 --- a/scripts/bpf_helpers_doc.py +++ b/scripts/bpf_helpers_doc.py @@ -158,8 +158,6 @@ class HeaderParser(object): break self.reader.close() - print('Parsed description of %d helper function(s)' % len(self.helpers), - file=sys.stderr) ############################################################################### diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index db2afccde757..aee7f1a83c77 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -183,7 +183,7 @@ $(BPF_IN_STATIC): force elfdep zdep bpfdep $(BPF_HELPER_DEFS) $(Q)$(MAKE) $(build)=libbpf OUTPUT=$(STATIC_OBJDIR) $(BPF_HELPER_DEFS): $(srctree)/tools/include/uapi/linux/bpf.h - $(Q)$(srctree)/scripts/bpf_helpers_doc.py --header \ + $(QUIET_GEN)$(srctree)/scripts/bpf_helpers_doc.py --header \ --file $(srctree)/tools/include/uapi/linux/bpf.h > $(BPF_HELPER_DEFS) $(OUTPUT)libbpf.so: $(OUTPUT)libbpf.so.$(LIBBPF_VERSION) -- cgit v1.2.3 From 2a67a6ccb01f21b854715d86ff6432a18b97adb3 Mon Sep 17 00:00:00 2001 From: Chris Down Date: Wed, 22 Jan 2020 00:01:10 +0000 Subject: bpf, btf: Always output invariant hit in pahole DWARF to BTF transform When trying to compile with CONFIG_DEBUG_INFO_BTF enabled, I got this error: % make -s Failed to generate BTF for vmlinux Try to disable CONFIG_DEBUG_INFO_BTF make[3]: *** [vmlinux] Error 1 Compiling again without -s shows the true error (that pahole is missing), but since this is fatal, we should show the error unconditionally on stderr as well, not silence it using the `info` function. With this patch: % make -s BTF: .tmp_vmlinux.btf: pahole (pahole) is not available Failed to generate BTF for vmlinux Try to disable CONFIG_DEBUG_INFO_BTF make[3]: *** [vmlinux] Error 1 Signed-off-by: Chris Down Signed-off-by: Daniel Borkmann Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20200122000110.GA310073@chrisdown.name --- scripts/link-vmlinux.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 436379940356..408b5c0b99b1 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -108,13 +108,13 @@ gen_btf() local bin_arch if ! [ -x "$(command -v ${PAHOLE})" ]; then - info "BTF" "${1}: pahole (${PAHOLE}) is not available" + echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available" return 1 fi pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/') if [ "${pahole_ver}" -lt "113" ]; then - info "BTF" "${1}: pahole version $(${PAHOLE} --version) is too old, need at least v1.13" + echo >&2 "BTF: ${1}: pahole version $(${PAHOLE} --version) is too old, need at least v1.13" return 1 fi -- cgit v1.2.3