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 <jpoim...@redhat.com>
---
 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 <object file> 
<extable|undwarf>\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

Reply via email to