From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751429AbdFAFo4 (ORCPT ); Thu, 1 Jun 2017 01:44:56 -0400 Received: from mx1.redhat.com ([209.132.183.28]:52424 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751209AbdFAFok (ORCPT ); Thu, 1 Jun 2017 01:44:40 -0400 DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 549B58553D Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=jpoimboe@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 549B58553D From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org, Linus Torvalds , Andy Lutomirski , Jiri Slaby , Ingo Molnar , "H. Peter Anvin" , Peter Zijlstra Subject: [RFC PATCH 09/10] extable: add undwarf table sorting ability to sorttable script Date: Thu, 1 Jun 2017 00:44:15 -0500 Message-Id: <4c7615464ae6fd09a3ef2a80f2ed32bc07a0b6f7.1496293620.git.jpoimboe@redhat.com> In-Reply-To: References: X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Thu, 01 Jun 2017 05:44:30 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The undwarf table needs to be sorted at vmlinux link time, just like the extable. Extend sorttable's functionality to do so. Signed-off-by: Josh Poimboeuf --- init/Kconfig | 4 ++ scripts/Makefile | 2 +- scripts/link-vmlinux.sh | 7 +- scripts/sorttable.c | 178 +++++++++++++++++++++++++----------------------- scripts/sorttable.h | 71 ++++++++++--------- 5 files changed, 142 insertions(+), 120 deletions(-) diff --git a/init/Kconfig b/init/Kconfig index 1d3475f..4c096f0 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -25,6 +25,10 @@ config IRQ_WORK config BUILDTIME_EXTABLE_SORT bool + select SORTTABLE + +config SORTTABLE + bool config THREAD_INFO_IN_TASK bool diff --git a/scripts/Makefile b/scripts/Makefile index a7b700f..99c05de 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -15,7 +15,7 @@ hostprogs-$(CONFIG_KALLSYMS) += kallsyms hostprogs-$(CONFIG_LOGO) += pnmtologo hostprogs-$(CONFIG_VT) += conmakehash hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount -hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sorttable +hostprogs-$(CONFIG_SORTTABLE) += sorttable hostprogs-$(CONFIG_ASN1) += asn1_compiler hostprogs-$(CONFIG_MODULE_SIG) += sign-file hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 18dd369..f4eb9dc 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -154,7 +154,12 @@ mksysmap() sortextable() { - ${objtree}/scripts/sorttable ${1} + ${objtree}/scripts/sorttable ${1} extable +} + +sortundwarf() +{ + ${objtree}/scripts/sorttable ${1} undwarf } # Delete output files in case of error diff --git a/scripts/sorttable.c b/scripts/sorttable.c index 17324dd..299db227 100644 --- a/scripts/sorttable.c +++ b/scripts/sorttable.c @@ -1,5 +1,5 @@ /* - * sorttable.c: Sort the kernel's exception table + * sorttable.c: Sort vmlinux tables * * Copyright 2011 - 2012 Cavium, Inc. * @@ -51,11 +51,10 @@ #define EM_ARCV2 195 #endif -static int fd_map; /* File descriptor for file being modified. */ -static int mmap_failed; /* Boolean flag. */ +static int fd_map = -1; /* File descriptor for file being modified. */ +static int mmap_succeeded; /* 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 { @@ -64,20 +63,19 @@ enum { SJ_SUCCEED }; +enum sectype { + SEC_TYPE_EXTABLE, + SEC_TYPE_UNDWARF, +}; + /* Per-file resource cleanup when multiple files. */ static void cleanup(void) { - if (!mmap_failed) + if (mmap_succeeded) munmap(ehdr_curr, sb.st_size); - close(fd_map); -} - -static void __attribute__((noreturn)) -fail_file(void) -{ - cleanup(); - longjmp(jmpenv, SJ_FAIL); + if (fd_map >= 0) + close(fd_map); } /* @@ -93,19 +91,20 @@ static void *mmap_file(char const *fname) fd_map = open(fname, O_RDWR); if (fd_map < 0 || fstat(fd_map, &sb) < 0) { perror(fname); - fail_file(); + return NULL; } if (!S_ISREG(sb.st_mode)) { fprintf(stderr, "not a regular file: %s\n", fname); - fail_file(); + return NULL; } addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd_map, 0); if (addr == MAP_FAILED) { - mmap_failed = 1; fprintf(stderr, "Could not mmap file: %s\n", fname); - fail_file(); + return NULL; } + mmap_succeeded = 1; + return addr; } @@ -166,7 +165,7 @@ 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); +typedef void (*table_sort_t)(char *, size_t, size_t); /* * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of @@ -194,7 +193,7 @@ static inline unsigned int get_secindex(unsigned int shndx, /* 32 bit and 64 bit are very similar */ #include "sorttable.h" -#define SORTEXTABLE_64 +#define SORTTABLE_64 #include "sorttable.h" static int compare_relative_table(const void *a, const void *b) @@ -209,36 +208,33 @@ 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_extable(char *image, size_t image_size, size_t entsize) { int i; + /* + * 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); - + uint32_t *loc = (uint32_t *)(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(image, image_size / entsize, entsize, compare_relative_table); + /* Now denormalize. */ i = 0; while (i < image_size) { - uint32_t *loc = (uint32_t *)(extab_image + i); - + uint32_t *loc = (uint32_t *)(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 sort_undwarf_table(char *image, size_t image_size, size_t entsize) { int i; @@ -248,34 +244,39 @@ static void sort_relative_table(char *extab_image, int image_size) */ i = 0; while (i < image_size) { - uint32_t *loc = (uint32_t *)(extab_image + i); + uint32_t *loc = (uint32_t *)(image + i); w(r(loc) + i, loc); - i += 4; + i += entsize; } - qsort(extab_image, image_size / 8, 8, compare_relative_table); + qsort(image, image_size / entsize, entsize, compare_relative_table); /* Now denormalize. */ i = 0; while (i < image_size) { - uint32_t *loc = (uint32_t *)(extab_image + i); + uint32_t *loc = (uint32_t *)(image + i); w(r(loc) - i, loc); - i += 4; + i += entsize; } } -static void -do_file(char const *const fname) +static int do_file(char const *const fname, enum sectype sectype) { table_sort_t custom_sort; - Elf32_Ehdr *ehdr = mmap_file(fname); + Elf32_Ehdr *ehdr; + const char *secname, *sort_needed_var; + size_t entsize_32, entsize_64; + + ehdr = mmap_file(fname); + if (!ehdr) + return -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(); + return -1; break; case ELFDATA2LSB: r = rle; @@ -298,7 +299,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,11 +307,13 @@ do_file(char const *const fname) default: fprintf(stderr, "unrecognized e_machine %d %s\n", r2(&ehdr->e_machine), fname); - fail_file(); - break; + return -1; case EM_386: case EM_X86_64: - custom_sort = x86_sort_relative_table; + if (sectype == SEC_TYPE_EXTABLE) { + custom_sort = sort_relative_extable; + entsize_32 = entsize_64 = 12; + } break; case EM_S390: @@ -318,7 +321,10 @@ do_file(char const *const fname) case EM_PARISC: case EM_PPC: case EM_PPC64: - custom_sort = sort_relative_table; + if (sectype == SEC_TYPE_EXTABLE) { + custom_sort = sort_relative_extable; + entsize_32 = entsize_64 = 8; + } break; case EM_ARCOMPACT: case EM_ARCV2: @@ -326,23 +332,38 @@ do_file(char const *const fname) case EM_MICROBLAZE: case EM_MIPS: case EM_XTENSA: + entsize_32 = 8; + entsize_64 = 16; break; } /* end switch */ + switch (sectype) { + case SEC_TYPE_EXTABLE: + secname = "__ex_table"; + sort_needed_var = "main_extable_sort_needed"; + break; + case SEC_TYPE_UNDWARF: + secname = ".undwarf"; + custom_sort = sort_undwarf_table; + entsize_32 = entsize_64 = 16; + sort_needed_var = NULL; + break; + } + switch (ehdr->e_ident[EI_CLASS]) { default: fprintf(stderr, "unrecognized ELF class %d %s\n", ehdr->e_ident[EI_CLASS], fname); - fail_file(); - break; + return -1; 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(); + return -1; } - do32(ehdr, fname, custom_sort); + if (do32(ehdr, fname, secname, entsize_32, custom_sort, sort_needed_var)) + return -1; break; case ELFCLASS64: { Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; @@ -350,51 +371,40 @@ 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(); + return -1; } - do64(ghdr, fname, custom_sort); + if (do64(ghdr, fname, secname, entsize_64, custom_sort, sort_needed_var)) + return -1; break; } } /* end switch */ cleanup(); + + return 0; } int main(int argc, char *argv[]) { - int n_error = 0; /* gcc-4.3.0 false positive complaint */ - int i; + char *file; + enum sectype sectype; - if (argc < 2) { - fprintf(stderr, "usage: sorttable vmlinux...\n"); - return 0; + if (argc != 3) { + fprintf(stderr, "usage: sorttable \n"); + return -1; } - /* Process each file in turn, allowing deep failure. */ - for (i = 1; i < argc; i++) { - char *file = argv[i]; - int const sjval = setjmp(jmpenv); - - 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 */ - ++n_error; - break; - case SJ_SUCCEED: /* premature success */ - /* do nothing */ - break; - } /* end switch */ + file = argv[1]; + + if (!strcmp(argv[2], "extable")) + sectype = SEC_TYPE_EXTABLE; + else if (!strcmp(argv[2], "undwarf")) + sectype = SEC_TYPE_UNDWARF; + else { + fprintf(stderr, "unsupported section type %s\n", argv[2]); + return -1; } - return !!n_error; + + return do_file(file, sectype); } diff --git a/scripts/sorttable.h b/scripts/sorttable.h index 0de9488..68f7200 100644 --- a/scripts/sorttable.h +++ b/scripts/sorttable.h @@ -1,5 +1,5 @@ /* - * sorttable.h + * sortextable.h * * Copyright 2011 - 2012 Cavium, Inc. * @@ -13,7 +13,7 @@ */ #undef extable_ent_size -#undef compare_extable +#undef generic_compare #undef do_func #undef Elf_Addr #undef Elf_Ehdr @@ -33,9 +33,8 @@ #undef _r #undef _w -#ifdef SORTEXTABLE_64 -# define extable_ent_size 16 -# define compare_extable compare_extable_64 +#ifdef SORTTABLE_64 +# define generic_compare generic_compare_64 # define do_func do64 # define Elf_Addr Elf64_Addr # define Elf_Ehdr Elf64_Ehdr @@ -55,8 +54,7 @@ # define _r r8 # define _w w8 #else -# define extable_ent_size 8 -# define compare_extable compare_extable_32 +# define generic_compare generic_compare_32 # define do_func do32 # define Elf_Addr Elf32_Addr # define Elf_Ehdr Elf32_Ehdr @@ -77,7 +75,7 @@ # define _w w #endif -static int compare_extable(const void *a, const void *b) +static int generic_compare(const void *a, const void *b) { Elf_Addr av = _r(a); Elf_Addr bv = _r(b); @@ -89,14 +87,16 @@ static int compare_extable(const void *a, const void *b) return 0; } -static void -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, char const *const secname, + size_t entsize, table_sort_t custom_sort, + char const *const sort_needed_var) { Elf_Shdr *shdr; Elf_Shdr *shstrtab_sec; Elf_Shdr *strtab_sec = NULL; Elf_Shdr *symtab_sec = NULL; - Elf_Shdr *extab_sec = NULL; + Elf_Shdr *table_sec = NULL; Elf_Sym *sym; const Elf_Sym *symtab; Elf32_Word *symtab_shndx_start = NULL; @@ -107,8 +107,8 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) uint32_t *sort_done_location; const char *secstrtab; const char *strtab; - char *extab_image; - int extab_index = 0; + char *table_image; + int table_index = 0; int i; int idx; unsigned int num_sections; @@ -128,13 +128,13 @@ 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) { - extab_sec = shdr + i; - extab_index = i; + if (strcmp(secstrtab + idx, secname) == 0) { + table_sec = shdr + i; + table_index = i; } if ((r(&shdr[i].sh_type) == SHT_REL || r(&shdr[i].sh_type) == SHT_RELA) && - r(&shdr[i].sh_info) == extab_index) { + r(&shdr[i].sh_info) == table_index) { relocs = (void *)ehdr + _r(&shdr[i].sh_offset); relocs_size = _r(&shdr[i].sh_size); } @@ -147,35 +147,37 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) (const char *)ehdr + _r(&shdr[i].sh_offset)); } if (strtab_sec == NULL) { - fprintf(stderr, "no .strtab in file: %s\n", fname); - fail_file(); + fprintf(stderr, "no .strtab in file: %s\n", fname); + return -1; } if (symtab_sec == NULL) { - fprintf(stderr, "no .symtab in file: %s\n", fname); - fail_file(); + 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); - fail_file(); + if (table_sec == NULL) { + fprintf(stderr, "no %s section in file: %s\n", secname, fname); + return -1; } strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); - extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); + table_image = (void *)ehdr + _r(&table_sec->sh_offset); if (custom_sort) { - custom_sort(extab_image, _r(&extab_sec->sh_size)); + custom_sort(table_image, _r(&table_sec->sh_size), entsize); } else { - int num_entries = _r(&extab_sec->sh_size) / extable_ent_size; - qsort(extab_image, num_entries, - extable_ent_size, compare_extable); + int num_entries = _r(&table_sec->sh_size) / entsize; + qsort(table_image, num_entries, entsize, generic_compare); } /* If there were relocations, we no longer need them. */ if (relocs) memset(relocs, 0, relocs_size); - /* find main_extable_sort_needed */ + if (!sort_needed_var) + return 0; + + /* find sort needed variable so we can clear it */ 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); @@ -183,16 +185,16 @@ 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, sort_needed_var) == 0) { sort_needed_sym = sym; break; } } if (sort_needed_sym == NULL) { fprintf(stderr, - "no main_extable_sort_needed symbol in file: %s\n", - fname); - fail_file(); + "no %s symbol in file: %s\n", + sort_needed_var, fname); + return -1; } sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), sort_needed_sym - symtab, @@ -208,4 +210,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; } -- 2.7.4