From a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 19 Apr 2012 14:59:55 -0700 Subject: scripts: Add sortextable to sort the kernel's exception table. Using this build-time sort saves time booting as we don't have to burn cycles sorting the exception table. Signed-off-by: David Daney Link: http://lkml.kernel.org/r/1334872799-14589-2-git-send-email-ddaney.cavm@gmail.com Signed-off-by: H. Peter Anvin --- scripts/.gitignore | 1 + scripts/Makefile | 1 + scripts/sortextable.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++ scripts/sortextable.h | 168 +++++++++++++++++++++++++++++++ 4 files changed, 441 insertions(+) create mode 100644 scripts/sortextable.c create mode 100644 scripts/sortextable.h (limited to 'scripts') diff --git a/scripts/.gitignore b/scripts/.gitignore index 105b21f..65f362d 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -9,3 +9,4 @@ unifdef ihex2fw recordmcount docproc +sortextable diff --git a/scripts/Makefile b/scripts/Makefile index df7678f..43e19b9 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -13,6 +13,7 @@ hostprogs-$(CONFIG_LOGO) += pnmtologo hostprogs-$(CONFIG_VT) += conmakehash hostprogs-$(CONFIG_IKCONFIG) += bin2c hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount +hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable always := $(hostprogs-y) $(hostprogs-m) diff --git a/scripts/sortextable.c b/scripts/sortextable.c new file mode 100644 index 0000000..f51f1d4 --- /dev/null +++ b/scripts/sortextable.c @@ -0,0 +1,271 @@ +/* + * sortextable.c: Sort the kernel's exception table + * + * Copyright 2011 Cavium, Inc. + * + * Based on code taken from recortmcount.c which is: + * + * Copyright 2009 John F. Reiser . All rights reserved. + * Licensed under the GNU General Public License, version 2 (GPLv2). + * + * 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 + +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); +} + +static void __attribute__((noreturn)) +succeed_file(void) +{ + cleanup(); + longjmp(jmpenv, SJ_SUCCEED); +} + + +/* + * 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) +{ + void *addr; + + fd_map = open(fname, O_RDWR); + if (fd_map < 0 || fstat(fd_map, &sb) < 0) { + perror(fname); + fail_file(); + } + if (!S_ISREG(sb.st_mode)) { + fprintf(stderr, "not a regular file: %s\n", fname); + fail_file(); + } + 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 addr; +} + +/* w8rev, w8nat, ...: Handle endianness. */ + +static uint64_t w8rev(uint64_t const x) +{ + return ((0xff & (x >> (0 * 8))) << (7 * 8)) + | ((0xff & (x >> (1 * 8))) << (6 * 8)) + | ((0xff & (x >> (2 * 8))) << (5 * 8)) + | ((0xff & (x >> (3 * 8))) << (4 * 8)) + | ((0xff & (x >> (4 * 8))) << (3 * 8)) + | ((0xff & (x >> (5 * 8))) << (2 * 8)) + | ((0xff & (x >> (6 * 8))) << (1 * 8)) + | ((0xff & (x >> (7 * 8))) << (0 * 8)); +} + +static uint32_t w4rev(uint32_t const x) +{ + return ((0xff & (x >> (0 * 8))) << (3 * 8)) + | ((0xff & (x >> (1 * 8))) << (2 * 8)) + | ((0xff & (x >> (2 * 8))) << (1 * 8)) + | ((0xff & (x >> (3 * 8))) << (0 * 8)); +} + +static uint32_t w2rev(uint16_t const x) +{ + return ((0xff & (x >> (0 * 8))) << (1 * 8)) + | ((0xff & (x >> (1 * 8))) << (0 * 8)); +} + +static uint64_t w8nat(uint64_t const x) +{ + return x; +} + +static uint32_t w4nat(uint32_t const x) +{ + return x; +} + +static uint32_t w2nat(uint16_t const x) +{ + return x; +} + +static uint64_t (*w8)(uint64_t); +static uint32_t (*w)(uint32_t); +static uint32_t (*w2)(uint16_t); + + +/* 32 bit and 64 bit are very similar */ +#include "sortextable.h" +#define SORTEXTABLE_64 +#include "sortextable.h" + + +static void +do_file(char const *const fname) +{ + Elf32_Ehdr *const ehdr = mmap_file(fname); + + ehdr_curr = ehdr; + w = w4nat; + w2 = w2nat; + w8 = w8nat; + switch (ehdr->e_ident[EI_DATA]) { + static unsigned int const endian = 1; + default: + fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", + ehdr->e_ident[EI_DATA], fname); + fail_file(); + break; + case ELFDATA2LSB: + if (*(unsigned char const *)&endian != 1) { + /* main() is big endian, file.o is little endian. */ + w = w4rev; + w2 = w2rev; + w8 = w8rev; + } + break; + case ELFDATA2MSB: + if (*(unsigned char const *)&endian != 0) { + /* main() is little endian, file.o is big endian. */ + w = w4rev; + w2 = w2rev; + w8 = w8rev; + } + break; + } /* end switch */ + if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 + || w2(ehdr->e_type) != ET_EXEC + || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { + fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname); + fail_file(); + } + + switch (w2(ehdr->e_machine)) { + default: + fprintf(stderr, "unrecognized e_machine %d %s\n", + w2(ehdr->e_machine), fname); + fail_file(); + break; + case EM_386: + case EM_MIPS: + case EM_X86_64: + break; + } /* end switch */ + + switch (ehdr->e_ident[EI_CLASS]) { + default: + fprintf(stderr, "unrecognized ELF class %d %s\n", + ehdr->e_ident[EI_CLASS], fname); + fail_file(); + break; + case ELFCLASS32: + if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr) + || w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { + fprintf(stderr, + "unrecognized ET_EXEC file: %s\n", fname); + fail_file(); + } + do32(ehdr, fname); + break; + case ELFCLASS64: { + Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; + if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr) + || w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { + fprintf(stderr, + "unrecognized ET_EXEC file: %s\n", fname); + fail_file(); + } + do64(ghdr, fname); + break; + } + } /* end switch */ + + cleanup(); +} + +int +main(int argc, char *argv[]) +{ + int n_error = 0; /* gcc-4.3.0 false positive complaint */ + int i; + + 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++) { + 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 */ + } + return !!n_error; +} diff --git a/scripts/sortextable.h b/scripts/sortextable.h new file mode 100644 index 0000000..bb6aaf1 --- /dev/null +++ b/scripts/sortextable.h @@ -0,0 +1,168 @@ +/* + * sortextable.h + * + * Copyright 2011 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. + * + * + * Licensed under the GNU General Public License, version 2 (GPLv2). + */ + +#undef extable_ent_size +#undef compare_extable +#undef do_func +#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 _w + +#ifdef SORTEXTABLE_64 +# define extable_ent_size 16 +# define compare_extable compare_extable_64 +# define do_func do64 +# 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 _w w8 +#else +# define extable_ent_size 8 +# define compare_extable compare_extable_32 +# define do_func do32 +# 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 _w w +#endif + +static int compare_extable(const void *a, const void *b) +{ + const uint_t *aa = a; + const uint_t *bb = b; + + if (_w(*aa) < _w(*bb)) + return -1; + if (_w(*aa) > _w(*bb)) + return 1; + return 0; +} + +static void +do_func(Elf_Ehdr *const ehdr, char const *const fname) +{ + Elf_Shdr *shdr; + Elf_Shdr *shstrtab_sec; + Elf_Shdr *strtab_sec = NULL; + Elf_Shdr *symtab_sec = NULL; + Elf_Shdr *extab_sec = NULL; + Elf_Sym *sym; + Elf_Sym *sort_needed_sym; + Elf_Shdr *sort_needed_sec; + uint32_t *sort_done_location; + const char *secstrtab; + const char *strtab; + int i; + int idx; + + shdr = (Elf_Shdr *)((void *)ehdr + _w(ehdr->e_shoff)); + shstrtab_sec = shdr + w2(ehdr->e_shstrndx); + secstrtab = (const char *)ehdr + _w(shstrtab_sec->sh_offset); + for (i = 0; i < w2(ehdr->e_shnum); i++) { + idx = w(shdr[i].sh_name); + if (strcmp(secstrtab + idx, "__ex_table") == 0) + extab_sec = shdr + i; + if (strcmp(secstrtab + idx, ".symtab") == 0) + symtab_sec = shdr + i; + if (strcmp(secstrtab + idx, ".strtab") == 0) + strtab_sec = shdr + i; + } + if (strtab_sec == NULL) { + fprintf(stderr, "no .strtab in file: %s\n", fname); + fail_file(); + } + if (symtab_sec == NULL) { + fprintf(stderr, "no .symtab in file: %s\n", fname); + fail_file(); + } + if (extab_sec == NULL) { + fprintf(stderr, "no __ex_table in file: %s\n", fname); + fail_file(); + } + strtab = (const char *)ehdr + _w(strtab_sec->sh_offset); + + /* Sort the table in place */ + qsort((void *)ehdr + _w(extab_sec->sh_offset), + (_w(extab_sec->sh_size) / extable_ent_size), + extable_ent_size, compare_extable); + + /* find main_extable_sort_needed */ + sort_needed_sym = NULL; + for (i = 0; i < _w(symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { + sym = (void *)ehdr + _w(symtab_sec->sh_offset); + sym += i; + if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) + continue; + idx = w(sym->st_name); + if (strcmp(strtab + idx, "main_extable_sort_needed") == 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(); + } + sort_needed_sec = &shdr[w2(sort_needed_sym->st_shndx)]; + sort_done_location = (void *)ehdr + + _w(sort_needed_sec->sh_offset) + + _w(sort_needed_sym->st_value) - + _w(sort_needed_sec->sh_addr); + + printf("sort done marker at %lx\n", + (unsigned long) (_w(sort_needed_sec->sh_offset) + + _w(sort_needed_sym->st_value) - + _w(sort_needed_sec->sh_addr))); + /* We sorted it, clear the flag. */ + *sort_done_location = 0; +} -- cgit v1.1 From d59a16836d917548cf41eda3369936684d527f5f Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 24 Apr 2012 11:23:14 -0700 Subject: scripts/sortextable: Handle relative entries, and other cleanups x86 is now using relative rather than absolute addresses in its exception table, so we add a sorter for these. If there are relocations on the __ex_table section, they are redundant and probably incorrect after the sort, so they are zeroed out leaving them valid and consistent. Also use the unaligned safe accessors from tools/{be,le}_byteshift.h Signed-off-by: David Daney Link: http://lkml.kernel.org/r/1335291795-26693-2-git-send-email-ddaney.cavm@gmail.com Signed-off-by: H. Peter Anvin --- scripts/Makefile | 2 + scripts/sortextable.c | 171 ++++++++++++++++++++++++++++++++------------------ scripts/sortextable.h | 79 ++++++++++++++--------- 3 files changed, 164 insertions(+), 88 deletions(-) (limited to 'scripts') diff --git a/scripts/Makefile b/scripts/Makefile index 43e19b9..9eace52 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -15,6 +15,8 @@ hostprogs-$(CONFIG_IKCONFIG) += bin2c hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable +HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include + always := $(hostprogs-y) $(hostprogs-m) # The following hostprogs-y programs are only build on demand diff --git a/scripts/sortextable.c b/scripts/sortextable.c index f51f1d4..1ca9ceb 100644 --- a/scripts/sortextable.c +++ b/scripts/sortextable.c @@ -1,7 +1,7 @@ /* * sortextable.c: Sort the kernel's exception table * - * Copyright 2011 Cavium, Inc. + * Copyright 2011 - 2012 Cavium, Inc. * * Based on code taken from recortmcount.c which is: * @@ -28,6 +28,9 @@ #include #include +#include +#include + 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 */ @@ -94,109 +97,157 @@ static void *mmap_file(char const *fname) return addr; } -/* w8rev, w8nat, ...: Handle endianness. */ - -static uint64_t w8rev(uint64_t const x) +static uint64_t r8be(const uint64_t *x) { - return ((0xff & (x >> (0 * 8))) << (7 * 8)) - | ((0xff & (x >> (1 * 8))) << (6 * 8)) - | ((0xff & (x >> (2 * 8))) << (5 * 8)) - | ((0xff & (x >> (3 * 8))) << (4 * 8)) - | ((0xff & (x >> (4 * 8))) << (3 * 8)) - | ((0xff & (x >> (5 * 8))) << (2 * 8)) - | ((0xff & (x >> (6 * 8))) << (1 * 8)) - | ((0xff & (x >> (7 * 8))) << (0 * 8)); + return get_unaligned_be64(x); } - -static uint32_t w4rev(uint32_t const x) +static uint32_t rbe(const uint32_t *x) { - return ((0xff & (x >> (0 * 8))) << (3 * 8)) - | ((0xff & (x >> (1 * 8))) << (2 * 8)) - | ((0xff & (x >> (2 * 8))) << (1 * 8)) - | ((0xff & (x >> (3 * 8))) << (0 * 8)); + return get_unaligned_be32(x); } - -static uint32_t w2rev(uint16_t const x) +static uint16_t r2be(const uint16_t *x) { - return ((0xff & (x >> (0 * 8))) << (1 * 8)) - | ((0xff & (x >> (1 * 8))) << (0 * 8)); + return get_unaligned_be16(x); } - -static uint64_t w8nat(uint64_t const x) +static uint64_t r8le(const uint64_t *x) { - return x; + return get_unaligned_le64(x); } - -static uint32_t w4nat(uint32_t const x) +static uint32_t rle(const uint32_t *x) +{ + return get_unaligned_le32(x); +} +static uint16_t r2le(const uint16_t *x) { - return x; + return get_unaligned_le16(x); } -static uint32_t w2nat(uint16_t const x) +static void w8be(uint64_t val, uint64_t *x) +{ + put_unaligned_be64(val, 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) +{ + put_unaligned_le64(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) { - return x; + put_unaligned_le16(val, x); } -static uint64_t (*w8)(uint64_t); -static uint32_t (*w)(uint32_t); -static uint32_t (*w2)(uint16_t); +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); /* 32 bit and 64 bit are very similar */ #include "sortextable.h" #define SORTEXTABLE_64 #include "sortextable.h" +static int compare_x86_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_x86_table(char *extab_image, int image_size) +{ + 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); + w(r(loc) + i, loc); + i += 4; + } + + qsort(extab_image, image_size / 8, 8, compare_x86_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 do_file(char const *const fname) { - Elf32_Ehdr *const ehdr = mmap_file(fname); + table_sort_t custom_sort; + Elf32_Ehdr *ehdr = mmap_file(fname); ehdr_curr = ehdr; - w = w4nat; - w2 = w2nat; - w8 = w8nat; switch (ehdr->e_ident[EI_DATA]) { - static unsigned int const endian = 1; default: fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", ehdr->e_ident[EI_DATA], fname); fail_file(); break; case ELFDATA2LSB: - if (*(unsigned char const *)&endian != 1) { - /* main() is big endian, file.o is little endian. */ - w = w4rev; - w2 = w2rev; - w8 = w8rev; - } + r = rle; + r2 = r2le; + r8 = r8le; + w = wle; + w2 = w2le; + w8 = w8le; break; case ELFDATA2MSB: - if (*(unsigned char const *)&endian != 0) { - /* main() is little endian, file.o is big endian. */ - w = w4rev; - w2 = w2rev; - w8 = w8rev; - } + r = rbe; + r2 = r2be; + r8 = r8be; + w = wbe; + w2 = w2be; + w8 = w8be; break; } /* end switch */ if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 - || w2(ehdr->e_type) != ET_EXEC + || r2(&ehdr->e_type) != ET_EXEC || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname); fail_file(); } - switch (w2(ehdr->e_machine)) { + custom_sort = NULL; + switch (r2(&ehdr->e_machine)) { default: fprintf(stderr, "unrecognized e_machine %d %s\n", - w2(ehdr->e_machine), fname); + r2(&ehdr->e_machine), fname); fail_file(); break; case EM_386: - case EM_MIPS: case EM_X86_64: + custom_sort = sort_x86_table; + break; + case EM_MIPS: break; } /* end switch */ @@ -207,23 +258,23 @@ do_file(char const *const fname) fail_file(); break; case ELFCLASS32: - if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr) - || w2(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 file: %s\n", fname); fail_file(); } - do32(ehdr, fname); + do32(ehdr, fname, custom_sort); break; case ELFCLASS64: { Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; - if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr) - || w2(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 file: %s\n", fname); fail_file(); } - do64(ghdr, fname); + do64(ghdr, fname, custom_sort); break; } } /* end switch */ diff --git a/scripts/sortextable.h b/scripts/sortextable.h index bb6aaf1..e4fd45b 100644 --- a/scripts/sortextable.h +++ b/scripts/sortextable.h @@ -1,7 +1,7 @@ /* * sortextable.h * - * Copyright 2011 Cavium, Inc. + * Copyright 2011 - 2012 Cavium, Inc. * * Some of this code was taken out of recordmcount.h written by: * @@ -30,6 +30,7 @@ #undef fn_ELF_R_SYM #undef fn_ELF_R_INFO #undef uint_t +#undef _r #undef _w #ifdef SORTEXTABLE_64 @@ -51,6 +52,7 @@ # 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 @@ -71,23 +73,24 @@ # 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) { - const uint_t *aa = a; - const uint_t *bb = b; + Elf_Addr av = _r(a); + Elf_Addr bv = _r(b); - if (_w(*aa) < _w(*bb)) + if (av < bv) return -1; - if (_w(*aa) > _w(*bb)) + if (av > bv) return 1; return 0; } static void -do_func(Elf_Ehdr *const ehdr, char const *const fname) +do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) { Elf_Shdr *shdr; Elf_Shdr *shstrtab_sec; @@ -97,19 +100,31 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname) Elf_Sym *sym; Elf_Sym *sort_needed_sym; Elf_Shdr *sort_needed_sec; + Elf_Rel *relocs = NULL; + int relocs_size; uint32_t *sort_done_location; const char *secstrtab; const char *strtab; + char *extab_image; + int extab_index = 0; int i; int idx; - shdr = (Elf_Shdr *)((void *)ehdr + _w(ehdr->e_shoff)); - shstrtab_sec = shdr + w2(ehdr->e_shstrndx); - secstrtab = (const char *)ehdr + _w(shstrtab_sec->sh_offset); - for (i = 0; i < w2(ehdr->e_shnum); i++) { - idx = w(shdr[i].sh_name); - if (strcmp(secstrtab + idx, "__ex_table") == 0) + shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); + shstrtab_sec = shdr + r2(&ehdr->e_shstrndx); + secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset); + for (i = 0; i < r2(&ehdr->e_shnum); i++) { + idx = r(&shdr[i].sh_name); + if (strcmp(secstrtab + idx, "__ex_table") == 0) { extab_sec = shdr + i; + 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(secstrtab + idx, ".symtab") == 0) symtab_sec = shdr + i; if (strcmp(secstrtab + idx, ".strtab") == 0) @@ -127,21 +142,29 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname) fprintf(stderr, "no __ex_table in file: %s\n", fname); fail_file(); } - strtab = (const char *)ehdr + _w(strtab_sec->sh_offset); + strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); - /* Sort the table in place */ - qsort((void *)ehdr + _w(extab_sec->sh_offset), - (_w(extab_sec->sh_size) / extable_ent_size), - extable_ent_size, compare_extable); + extab_image = (void *)ehdr + _r(&extab_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 main_extable_sort_needed */ sort_needed_sym = NULL; - for (i = 0; i < _w(symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { - sym = (void *)ehdr + _w(symtab_sec->sh_offset); + for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { + sym = (void *)ehdr + _r(&symtab_sec->sh_offset); sym += i; if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) continue; - idx = w(sym->st_name); + idx = r(&sym->st_name); if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { sort_needed_sym = sym; break; @@ -153,16 +176,16 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname) fname); fail_file(); } - sort_needed_sec = &shdr[w2(sort_needed_sym->st_shndx)]; + sort_needed_sec = &shdr[r2(&sort_needed_sym->st_shndx)]; sort_done_location = (void *)ehdr + - _w(sort_needed_sec->sh_offset) + - _w(sort_needed_sym->st_value) - - _w(sort_needed_sec->sh_addr); + _r(&sort_needed_sec->sh_offset) + + _r(&sort_needed_sym->st_value) - + _r(&sort_needed_sec->sh_addr); +#if 1 printf("sort done marker at %lx\n", - (unsigned long) (_w(sort_needed_sec->sh_offset) + - _w(sort_needed_sym->st_value) - - _w(sort_needed_sec->sh_addr))); + (unsigned long)((char *)sort_done_location - (char *)ehdr)); +#endif /* We sorted it, clear the flag. */ - *sort_done_location = 0; + w(0, sort_done_location); } -- cgit v1.1 From 4d53b8012f1f01ddb3f24db2031b042bb4cbd0d0 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Mon, 23 Apr 2012 12:07:02 +0200 Subject: HID: Add device group to modalias HID devices are only partially presented to userland. Hotplugged devices emit events containing a modalias based on the basic bus, vendor and product entities. However, in practise a hid device can depend on details such as a single usb interface or a particular item in a report descriptor. This patch adds a device group to the hid device id, and broadcasts it using uevent and the device modalias. The module alias generation is modified to match. As a consequence, a device with a non-zero group will be processed by the corresponding group driver instead of by the generic hid driver. Signed-off-by: Henrik Rydberg Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- scripts/mod/file2alias.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'scripts') diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 8e730cc..fe967ce 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -336,10 +336,12 @@ static int do_hid_entry(const char *filename, struct hid_device_id *id, char *alias) { id->bus = TO_NATIVE(id->bus); + id->group = TO_NATIVE(id->group); id->vendor = TO_NATIVE(id->vendor); id->product = TO_NATIVE(id->product); sprintf(alias, "hid:b%04X", id->bus); + ADD(alias, "g", id->group != HID_GROUP_ANY, id->group); ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor); ADD(alias, "p", id->product != HID_ANY_ID, id->product); -- cgit v1.1 From 7431fb767d896b7f0048039f2e17707ea057d35a Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Mon, 23 Apr 2012 12:07:04 +0200 Subject: HID: Allow bus wildcard matching Most HID drivers do not need to know what bus driver is in use. A generic group driver can drive any hid device, and the device list should not need to be duplicated for each new bus. This patch adds wildcard matching to the HID bus, simplifying device list handling for group drivers. Signed-off-by: Henrik Rydberg Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- scripts/mod/file2alias.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index fe967ce..056de31 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -340,7 +340,8 @@ static int do_hid_entry(const char *filename, id->vendor = TO_NATIVE(id->vendor); id->product = TO_NATIVE(id->product); - sprintf(alias, "hid:b%04X", id->bus); + sprintf(alias, "hid:"); + ADD(alias, "b", id->bus != HID_BUS_ANY, id->bus); ADD(alias, "g", id->group != HID_GROUP_ANY, id->group); ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor); ADD(alias, "p", id->product != HID_ANY_ID, id->product); -- cgit v1.1 From 5efe241eac80bb534fed0a965684c2d7527af5bf Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 26 Apr 2012 01:51:32 -0700 Subject: kconfig: Add error handling to KCONFIG_ALLCONFIG - Only try to read the file specified if KCONFIG_ALL_CONFIG is set to something other than the empty string or "1". - Don't use stat to check the name passed to conf_read_simple so that zconf_fopen can find the file in the current directory or in SRCTREE removing a extremely source of confusing failure, where KCONFIG_ALL_CONFIG was not interpreted with respect to the directory make was called in. - If conf_read_simple fails complain clearly and stop processing. Allowing the simple debugging of typos. - Clearly document the behavior so it is clear to users which values are treated as flags and which values are treated as filenames. Signed-off-by: Eric W. Biederman Signed-off-by: Michal Marek --- scripts/kconfig/conf.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index f208f90..0fdda91 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -574,8 +574,13 @@ int main(int ac, char **av) case alldefconfig: case randconfig: name = getenv("KCONFIG_ALLCONFIG"); - if (name && !stat(name, &tmpstat)) { - conf_read_simple(name, S_DEF_USER); + if (name && (strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { + if (conf_read_simple(name, S_DEF_USER)) { + fprintf(stderr, + _("*** Can't read seed configuration \"%s\"!\n"), + name); + exit(1); + } break; } switch (input_mode) { @@ -586,10 +591,13 @@ int main(int ac, char **av) case randconfig: name = "allrandom.config"; break; default: break; } - if (!stat(name, &tmpstat)) - conf_read_simple(name, S_DEF_USER); - else if (!stat("all.config", &tmpstat)) - conf_read_simple("all.config", S_DEF_USER); + if (conf_read_simple(name, S_DEF_USER) && + conf_read_simple("all.config", S_DEF_USER)) { + fprintf(stderr, + _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), + name); + exit(1); + } break; default: break; -- cgit v1.1 From 1f2bfbd00e466ff3489b2ca5cc75b1cccd14c123 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 5 May 2012 10:18:41 +0200 Subject: kbuild: link of vmlinux moved to a script Move the final link of vmlinux to a script to improve readability and maintainability of the code. The Makefile fragments used to link vmlinux has over the years seen far too many changes and the logic had become hard to follow. As the process by nature is serialized there was nothing gained including this in the Makefile. "um" has special link requirments - and the only way to handle this was to hard-code the linking of "um" in the script. This was better than trying to modularize it only for the benefit of "um" anyway. The shell script has been improved after input from: Arnaud Lacombe Nick Bowler Signed-off-by: Sam Ravnborg Cc: Arnaud Lacombe Cc: Nick Bowler Cc: Richard Weinberger Signed-off-by: Michal Marek --- scripts/link-vmlinux.sh | 211 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 scripts/link-vmlinux.sh (limited to 'scripts') diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh new file mode 100644 index 0000000..26c5b65 --- /dev/null +++ b/scripts/link-vmlinux.sh @@ -0,0 +1,211 @@ +#!/bin/sh +# +# link vmlinux +# +# vmlinux is linked from the objects selected by $(KBUILD_VMLINUX_INIT) and +# $(KBUILD_VMLINUX_MAIN). Most are built-in.o files from top-level directories +# in the kernel tree, others are specified in arch/$(ARCH)/Makefile. +# Ordering when linking is important, and $(KBUILD_VMLINUX_INIT) must be first. +# +# vmlinux +# ^ +# | +# +-< $(KBUILD_VMLINUX_INIT) +# | +--< init/version.o + more +# | +# +--< $(KBUILD_VMLINUX_MAIN) +# | +--< drivers/built-in.o mm/built-in.o + more +# | +# +-< ${kallsymso} (see description in KALLSYMS section) +# +# vmlinux version (uname -v) cannot be updated during normal +# descending-into-subdirs phase since we do not yet know if we need to +# update vmlinux. +# Therefore this step is delayed until just before final link of vmlinux. +# +# System.map is generated to document addresses of all kernel symbols + +# Error out on error +set -e + +# Nice output in kbuild format +# Will be supressed by "make -s" +info() +{ + if [ "${quiet}" != "silent_" ]; then + printf " %-7s %s\n" ${1} ${2} + fi +} + +# Link of vmlinux.o used for section mismatch analysis +# ${1} output file +modpost_link() +{ + ${LD} ${LDFLAGS} -r -o ${1} ${KBUILD_VMLINUX_INIT} \ + --start-group ${KBUILD_VMLINUX_MAIN} --end-group +} + +# Link of vmlinux +# ${1} - optional extra .o files +# ${2} - output file +vmlinux_link() +{ + local lds="${objtree}/${KBUILD_LDS}" + + if [ "${SRCARCH}" != "um" ]; then + ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ + -T ${lds} ${KBUILD_VMLINUX_INIT} \ + --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1} + else + ${CC} ${CFLAGS_vmlinux} -o ${2} \ + -Wl,-T,${lds} ${KBUILD_VMLINUX_INIT} \ + -Wl,--start-group \ + ${KBUILD_VMLINUX_MAIN} \ + -Wl,--end-group \ + -lutil ${1} + rm -f linux + fi +} + + +# Create ${2} .o file with all symbols from the ${1} object file +kallsyms() +{ + info KSYM ${2} + local kallsymopt; + + if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then + kallsymopt=--all-symbols + fi + + local aflags="${KBUILD_AFLAGS} ${NOSTDINC_FLAGS} \ + ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" + + ${NM} -n ${1} | \ + scripts/kallsyms ${kallsymopt} | \ + ${CC} ${aflags} -c -o ${2} -x assembler-with-cpp - +} + +# Create map file with all symbols from ${1} +# See mksymap for additional details +mksysmap() +{ + ${CONFIG_SHELL} "${srctree}/scripts/mksysmap" ${1} ${2} +} + +# Delete output files in case of error +trap cleanup SIGHUP SIGINT SIGQUIT SIGTERM ERR +cleanup() +{ + rm -f .old_version + rm -f .tmp_System.map + rm -f .tmp_kallsyms* + rm -f .tmp_version + rm -f .tmp_vmlinux* + rm -f System.map + rm -f vmlinux + rm -f vmlinux.o +} + +# +# +# Use "make V=1" to debug this script +case "${KBUILD_VERBOSE}" in +*1*) + set -x + ;; +esac + +if [ "$1" = "clean" ]; then + cleanup + exit 0 +fi + +# We need access to CONFIG_ symbols +. ./.config + +#link vmlinux.o +info LD vmlinux.o +modpost_link vmlinux.o + +# modpost vmlinux.o to check for section mismatches +${MAKE} -f "${srctree}/scripts/Makefile.modpost" vmlinux.o + +# Update version +info GEN .version +if [ ! -r .version ]; then + rm -f .version; + echo 1 >.version; +else + mv .version .old_version; + expr 0$(cat .old_version) + 1 >.version; +fi; + +# final build of init/ +${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init + +kallsymso="" +kallsyms_vmlinux="" +if [ -n "${CONFIG_KALLSYMS}" ]; then + + # kallsyms support + # Generate section listing all symbols and add it into vmlinux + # It's a three step process: + # 1) Link .tmp_vmlinux1 so it has all symbols and sections, + # but __kallsyms is empty. + # Running kallsyms on that gives us .tmp_kallsyms1.o with + # the right size + # 2) Link .tmp_vmlinux2 so it now has a __kallsyms section of + # the right size, but due to the added section, some + # addresses have shifted. + # From here, we generate a correct .tmp_kallsyms2.o + # 2a) We may use an extra pass as this has been necessary to + # woraround some alignment related bugs. + # KALLSYMS_EXTRA_PASS=1 is used to trigger this. + # 3) The correct ${kallsymso} is linked into the final vmlinux. + # + # a) Verify that the System.map from vmlinux matches the map from + # ${kallsymso}. + + kallsymso=.tmp_kallsyms2.o + kallsyms_vmlinux=.tmp_vmlinux2 + + # step 1 + vmlinux_link "" .tmp_vmlinux1 + kallsyms .tmp_vmlinux1 .tmp_kallsyms1.o + + # step 2 + vmlinux_link .tmp_kallsyms1.o .tmp_vmlinux2 + kallsyms .tmp_vmlinux2 .tmp_kallsyms2.o + + # step 2a + if [ -n "${KALLSYMS_EXTRA_PASS}" ]; then + kallsymso=.tmp_kallsyms3.o + kallsyms_vmlinux=.tmp_vmlinux3 + + vmlinux_link .tmp_kallsyms2.o .tmp_vmlinux3 + + kallsyms .tmp_vmlinux3 .tmp_kallsyms3.o + fi +fi + +info LD vmlinux +vmlinux_link "${kallsymso}" vmlinux + +info SYSMAP System.map +mksysmap vmlinux System.map + +# step a (see comment above) +if [ -n "${CONFIG_KALLSYMS}" ]; then + mksysmap ${kallsyms_vmlinux} .tmp_System.map + + if ! cmp -s System.map .tmp_System.map; then + echo Inconsistent kallsyms data + echo echo Try "make KALLSYMS_EXTRA_PASS=1" as a workaround + cleanup + exit 1 + fi +fi + +# We made a new kernel - delete old version file +rm -f .old_version -- cgit v1.1 From 9f420bf0f4a74e404b73b42b7fc3c85c20c64ea7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 7 May 2012 05:37:45 -0700 Subject: kbuild: all{no,yes,mod,def,rand}config only read files when instructed to. Prevent subtle surprises to both people working on the kconfig code and people using make allnoconfig allyesconfig allmoconfig and randconfig by only attempting to read a config file if KCONFIG_ALLCONFIG is set. Common sense suggests attempting to read the extra config files does not make sense unless requested. The documentation says the code won't attempt to read the extra config files unless requested. Current usage does not appear to include people depending on the code reading the config files without the variable being set So do the simple thing and stop reading config files when passed all{no,yes,mod,def,rand}config unless KCONFIG_ALLCONFIG environment variable is set. Signed-off-by: Eric W. Biederman Reported-by: Stephen Rothwell Signed-off-by: Michal Marek --- scripts/kconfig/conf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 0fdda91..0dc4a2c 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -574,7 +574,9 @@ int main(int ac, char **av) case alldefconfig: case randconfig: name = getenv("KCONFIG_ALLCONFIG"); - if (name && (strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { + if (!name) + break; + if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { if (conf_read_simple(name, S_DEF_USER)) { fprintf(stderr, _("*** Can't read seed configuration \"%s\"!\n"), -- cgit v1.1 From 00e6c28c6808c0ef6a3f25bb420d037fbb724d84 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Tue, 8 May 2012 19:53:46 +0200 Subject: kbuild: fix ia64 link ia64 build failed like this: CC init/version.o LD init/built-in.o KSYM .tmp_kallsyms1.o ld: .tmp_kallsyms1.o: linking constant-gp files with non-constant-gp files ld: failed to merge target specific data of file .tmp_kallsyms1.o make: *** [vmlinux] Error 1 This was introduced when link of vmlinux was migrated to a script. Add missing option to as to fix this. Reported-by: Tony Luck Tested-by: Tony Luck Signed-off-by: Sam Ravnborg Signed-off-by: Michal Marek --- 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 26c5b65..1f4c27b 100644 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -78,8 +78,8 @@ kallsyms() kallsymopt=--all-symbols fi - local aflags="${KBUILD_AFLAGS} ${NOSTDINC_FLAGS} \ - ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" + local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ + ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" ${NM} -n ${1} | \ scripts/kallsyms ${kallsymopt} | \ -- cgit v1.1 From d6686da814c884e341d3bd8aa54947c91cb678be Mon Sep 17 00:00:00 2001 From: "Yann E. MORIN" Date: Mon, 9 Apr 2012 14:49:10 +0200 Subject: scripts/config: properly report and set string options Currently, scripts/config removes the leading double-quote from string options, but leaves the trailing double-quote. Also, double-quotes in a string are escaped, but scripts/config does not unescape those when printing Finally, scripts/config does not escape double-quotes when setting string options. Eg. the current behavior: $ grep -E '^CONFIG_FOO=' .config CONFIG_FOO="Bar \"Buz\" Meh" $ ./scripts/config -s FOO Bar \"Buz\" Meh" $ ./scripts/config --set-str FOO 'Alpha "Bravo" Charlie' $ grep -E '^CONFIG_FOO=' .config CONFIG_FOO="Alpha "Bravo" Charlie" Fix those three, giving this new behavior: $ grep -E '^CONFIG_FOO=' .config CONFIG_FOO="Bar \"Buz\" Meh" $ ./scripts/config -s FOO Bar "Buz" Meh $ ./scripts/config --set-str FOO 'Alpha "Bravo" Charlie' $ grep -E '^CONFIG_FOO=' .config CONFIG_FOO="Alpha \"Bravo\" Charlie" Signed-off-by: "Yann E. MORIN" Acked-by: Andi Kleen Signed-off-by: Michal Marek --- scripts/config | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'scripts') diff --git a/scripts/config b/scripts/config index a7c7c4b..ed6653e 100755 --- a/scripts/config +++ b/scripts/config @@ -107,7 +107,8 @@ while [ "$1" != "" ] ; do ;; --set-str) - set_var "CONFIG_$ARG" "CONFIG_$ARG=\"$1\"" + # sed swallows one level of escaping, so we need double-escaping + set_var "CONFIG_$ARG" "CONFIG_$ARG=\"${1//\"/\\\\\"}\"" shift ;; @@ -124,9 +125,11 @@ while [ "$1" != "" ] ; do if [ $? != 0 ] ; then echo undef else - V="${V/CONFIG_$ARG=/}" - V="${V/\"/}" - echo "$V" + V="${V/#CONFIG_$ARG=/}" + V="${V/#\"/}" + V="${V/%\"/}" + V="${V/\\\"/\"}" + echo "${V}" fi fi ;; -- cgit v1.1 From bb8187d35f820671d6dd76700d77a6b55f95e2c5 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 17 May 2012 19:06:13 -0400 Subject: MCA: delete all remaining traces of microchannel bus support. Hardware with MCA bus is limited to 386 and 486 class machines that are now 20+ years old and typically with less than 32MB of memory. A quick search on the internet, and you see that even the MCA hobbyist/enthusiast community has lost interest in the early 2000 era and never really even moved ahead from the 2.4 kernels to the 2.6 series. This deletes anything remaining related to CONFIG_MCA from core kernel code and from the x86 architecture. There is no point in carrying this any further into the future. One complication to watch for is inadvertently scooping up stuff relating to machine check, since there is overlap in the TLA name space (e.g. arch/x86/boot/mca.c). Cc: Thomas Gleixner Cc: James Bottomley Cc: x86@kernel.org Acked-by: Ingo Molnar Acked-by: H. Peter Anvin Signed-off-by: Paul Gortmaker --- scripts/kconfig/mconf.c | 2 +- scripts/kconfig/nconf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 2c6286c..f606738 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -240,7 +240,7 @@ search_help[] = N_( "Defined at drivers/pci/Kconfig:47\n" "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" "Location:\n" - " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" + " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" " -> PCI support (PCI [=y])\n" " -> PCI access mode ( [=y])\n" "Selects: LIBCRC32\n" diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 73070cb..8c0eb659 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -223,7 +223,7 @@ search_help[] = N_( "Defined at drivers/pci/Kconfig:47\n" "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" "Location:\n" -" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" +" -> Bus options (PCI, PCMCIA, EISA, ISA)\n" " -> PCI support (PCI [ = y])\n" " -> PCI access mode ( [ = y])\n" "Selects: LIBCRC32\n" -- cgit v1.1 From 6520fe5564acf07ade7b18a1272db1184835c487 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 8 May 2012 21:22:24 +0300 Subject: x86, realmode: 16-bit real-mode code support for relocs tool A new option is added to the relocs tool called '--realmode'. This option causes the generation of 16-bit segment relocations and 32-bit linear relocations for the real-mode code. When the real-mode code is moved to the low-memory during kernel initialization, these relocation entries can be used to relocate the code properly. In the assembly code 16-bit segment relocations must be relative to the 'real_mode_seg' absolute symbol. Linear relocations must be relative to a symbol prefixed with 'pa_'. 16-bit segment relocation is used to load cs:ip in 16-bit code. Linear relocations are used in the 32-bit code for relocatable data references. They are declared in the linker script of the real-mode code. The relocs tool is moved to arch/x86/tools/relocs.c, and added new target archscripts that can be used to build scripts needed building an architecture. be compiled before building the arch/x86 tree. [ hpa: accelerating this because it detects invalid absolute relocations, a serious bug in binutils 2.22.52.0.x which currently produces bad kernels. ] Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1336501366-28617-2-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: Jarkko Sakkinen Signed-off-by: H. Peter Anvin Cc: --- scripts/Makefile | 2 ++ 1 file changed, 2 insertions(+) (limited to 'scripts') diff --git a/scripts/Makefile b/scripts/Makefile index df7678f..3626666 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -8,6 +8,8 @@ # conmakehash: Create arrays for initializing the kernel console tables # docproc: Used in Documentation/DocBook +HOST_EXTRACFLAGS += -I$(srctree)/tools/include + hostprogs-$(CONFIG_KALLSYMS) += kallsyms hostprogs-$(CONFIG_LOGO) += pnmtologo hostprogs-$(CONFIG_VT) += conmakehash -- cgit v1.1 From eb3d5cc67a525df5115c1dc1c0ff8a111bda70e4 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 23 May 2012 22:28:49 +0930 Subject: modpost: Stop grab_file() from leaking filedescriptors if fstat() fails In case the open() call succeeds but the subsequent fstat() call fails, then we'll return without close()'ing the filedescriptor. Signed-off-by: Jesper Juhl Signed-off-by: Rusty Russell --- scripts/mod/modpost.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index c4e7d15..ea0eaca 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -337,17 +337,20 @@ static void sym_update_crc(const char *name, struct module *mod, void *grab_file(const char *filename, unsigned long *size) { struct stat st; - void *map; + void *map = MAP_FAILED; int fd; fd = open(filename, O_RDONLY); - if (fd < 0 || fstat(fd, &st) != 0) + if (fd < 0) return NULL; + if (fstat(fd, &st)) + goto failed; *size = st.st_size; map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); - close(fd); +failed: + close(fd); if (map == MAP_FAILED) return NULL; return map; -- cgit v1.1 From 3c7ec94d2c4a67d9663a080aa5080134308261c4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Apr 2012 11:10:15 -0700 Subject: modpost: use proper kernel style for autogenerated files If the kernel build process is creating files automatically, the least it can do is create them in a properly formatted manner. Sure, it's a minor issue, but being consistent is nice. Cc: Rusty Russell Cc: Alessio Igor Bogani Cc: Tony Lindgren Cc: Ben Hutchings Cc: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Rusty Russell --- scripts/mod/modpost.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'scripts') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index ea0eaca..0f84bb3 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1853,14 +1853,14 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "\n"); buf_printf(b, "struct module __this_module\n"); buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); - buf_printf(b, " .name = KBUILD_MODNAME,\n"); + buf_printf(b, "\t.name = KBUILD_MODNAME,\n"); if (mod->has_init) - buf_printf(b, " .init = init_module,\n"); + buf_printf(b, "\t.init = init_module,\n"); if (mod->has_cleanup) buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" - " .exit = cleanup_module,\n" + "\t.exit = cleanup_module,\n" "#endif\n"); - buf_printf(b, " .arch = MODULE_ARCH_INIT,\n"); + buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); buf_printf(b, "};\n"); } -- cgit v1.1 From 4619c2b8304a0751d9ec2ba89e11f387977c8cb4 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 Apr 2012 20:14:58 +0200 Subject: scripts/coccinelle: address test is always true Signed-off-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/misc/ifaddr.cocci | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 scripts/coccinelle/misc/ifaddr.cocci (limited to 'scripts') diff --git a/scripts/coccinelle/misc/ifaddr.cocci b/scripts/coccinelle/misc/ifaddr.cocci new file mode 100644 index 0000000..3e4089a --- /dev/null +++ b/scripts/coccinelle/misc/ifaddr.cocci @@ -0,0 +1,35 @@ +/// the address of a variable or field is non-zero is likely always to bo +/// non-zero +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual org +virtual report +virtual context + +@r@ +expression x; +statement S1,S2; +position p; +@@ + +*if@p (&x) + S1 else S2 + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("test of a variable/field address",p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "ERROR: test of a variable/field address" +coccilib.report.print_report(p[0],msg) -- cgit v1.1 From 2cbd08253a011bd9db9a51f15a974df3a779224b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 Apr 2012 20:23:48 +0200 Subject: scripts/coccinelle: sizeof of pointer Signed-off-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/misc/noderef.cocci | 65 +++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 scripts/coccinelle/misc/noderef.cocci (limited to 'scripts') diff --git a/scripts/coccinelle/misc/noderef.cocci b/scripts/coccinelle/misc/noderef.cocci new file mode 100644 index 0000000..c170721 --- /dev/null +++ b/scripts/coccinelle/misc/noderef.cocci @@ -0,0 +1,65 @@ +/// sizeof when applied to a pointer typed expression gives the size of +/// the pointer +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual org +virtual report +virtual context +virtual patch + +@depends on patch@ +expression *x; +expression f; +type T; +@@ + +( +x = <+... sizeof( +- x ++ *x + ) ...+> +| +f(...,(T)(x),...,sizeof( +- x ++ *x + ),...) +| +f(...,sizeof(x),...,(T)( +- x ++ *x + ),...) +) + +@r depends on !patch@ +expression *x; +expression f; +position p; +type T; +@@ + +( +*x = <+... sizeof@p(x) ...+> +| +*f(...,(T)(x),...,sizeof@p(x),...) +| +*f(...,sizeof@p(x),...,(T)(x),...) +) + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("application of sizeof to pointer",p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "ERROR: application of sizeof to pointer" +coccilib.report.print_report(p[0],msg) -- cgit v1.1 From 19a4b988955bc1d838a55c89d3d927f3d788a7dd Mon Sep 17 00:00:00 2001 From: Lekensteyn Date: Fri, 18 May 2012 10:22:43 +0200 Subject: builddeb: include autogenerated header files After 303395ac3bf3e2cb488435537d416bc840438fcb, some headers are autogenerated. Include these autogenerated headers (mainly unistd_32_ia32.h) in out-of-tree builds to allow DKMS modules to be built succesfully. Signed-off-by: Peter Lekensteyn Signed-off-by: Michal Marek --- scripts/package/builddeb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/package/builddeb b/scripts/package/builddeb index eee5f8e..c95fdda 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -245,7 +245,7 @@ fi # Build header package (cd $srctree; find . -name Makefile -o -name Kconfig\* -o -name \*.pl > "$objtree/debian/hdrsrcfiles") (cd $srctree; find arch/$SRCARCH/include include scripts -type f >> "$objtree/debian/hdrsrcfiles") -(cd $objtree; find .config Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles") +(cd $objtree; find arch/$SRCARCH/include .config Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles") destdir=$kernel_headers_dir/usr/src/linux-headers-$version mkdir -p "$destdir" (cd $srctree; tar -c -f - -T "$objtree/debian/hdrsrcfiles") | (cd $destdir; tar -xf -) -- cgit v1.1 From 9a4cad4e25b91f48494f13fce3d25ea44bec7472 Mon Sep 17 00:00:00 2001 From: Eric Nelson Date: Thu, 31 May 2012 16:26:09 -0700 Subject: checkpatch: check for whitespace before semicolon at EOL Requires --strict option during invocation: ~/linux$ scripts/checkpatch --strict foo.patch This tests for a bad habits of mine like this: return 0 ; Note that it does allow a special case of a bare semicolon for empty loops: while (foo()) ; Signed-off-by: Eric Nelson Cc: Andy Whitcroft Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index faea0ec..2262e1f 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2448,6 +2448,13 @@ sub process { "space prohibited between function name and open parenthesis '('\n" . $herecurr); } } + +# check for whitespace before a non-naked semicolon + if ($line =~ /^\+.*\S\s+;/) { + CHK("SPACING", + "space prohibited before semicolon\n" . $herecurr); + } + # Check operator spacing. if (!($line=~/\#\s*include/)) { my $ops = qr{ -- cgit v1.1 From 243f3803cf2a3665092c5fd6f924f453694681a6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 31 May 2012 16:26:09 -0700 Subject: checkpatch: suggest pr_ over printk(KERN_ Suggest the shorter pr_ instead of printk(KERN_. Prefer to use pr_ over bare printks. Prefer to use pr_warn over pr_warning. Signed-off-by: Joe Perches Cc: Andy Whitcroft Cc: Theodore Ts'o Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 2262e1f..e5bd60f 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2382,6 +2382,19 @@ sub process { } } + if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) { + my $orig = $1; + my $level = lc($orig); + $level = "warn" if ($level eq "warning"); + WARN("PREFER_PR_LEVEL", + "Prefer pr_$level(... to printk(KERN_$1, ...\n" . $herecurr); + } + + if ($line =~ /\bpr_warning\s*\(/) { + WARN("PREFER_PR_LEVEL", + "Prefer pr_warn(... to pr_warning(...\n" . $herecurr); + } + # function brace can't be on same line, except for #defines of do while, # or if closed on same line if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and -- cgit v1.1