[RFC PATCH 09/10] extable: add undwarf table sorting ability to sorttable script

From: Josh Poimboeuf
Date: Thu Jun 01 2017 - 01:45:00 EST


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 <jpoimboe@xxxxxxxxxx>
---
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