The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/scripts/sortextable.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * sortextable.c: Sort the kernel's exception table
    3  *
    4  * Copyright 2011 - 2012 Cavium, Inc.
    5  *
    6  * Based on code taken from recortmcount.c which is:
    7  *
    8  * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
    9  * Licensed under the GNU General Public License, version 2 (GPLv2).
   10  *
   11  * Restructured to fit Linux format, as well as other updates:
   12  *  Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
   13  */
   14 
   15 /*
   16  * Strategy: alter the vmlinux file in-place.
   17  */
   18 
   19 #include <sys/types.h>
   20 #include <sys/mman.h>
   21 #include <sys/stat.h>
   22 #include <getopt.h>
   23 #include <elf.h>
   24 #include <fcntl.h>
   25 #include <setjmp.h>
   26 #include <stdio.h>
   27 #include <stdlib.h>
   28 #include <string.h>
   29 #include <unistd.h>
   30 
   31 #include <tools/be_byteshift.h>
   32 #include <tools/le_byteshift.h>
   33 
   34 static int fd_map;      /* File descriptor for file being modified. */
   35 static int mmap_failed; /* Boolean flag. */
   36 static void *ehdr_curr; /* current ElfXX_Ehdr *  for resource cleanup */
   37 static struct stat sb;  /* Remember .st_size, etc. */
   38 static jmp_buf jmpenv;  /* setjmp/longjmp per-file error escape */
   39 
   40 /* setjmp() return values */
   41 enum {
   42         SJ_SETJMP = 0,  /* hardwired first return */
   43         SJ_FAIL,
   44         SJ_SUCCEED
   45 };
   46 
   47 /* Per-file resource cleanup when multiple files. */
   48 static void
   49 cleanup(void)
   50 {
   51         if (!mmap_failed)
   52                 munmap(ehdr_curr, sb.st_size);
   53         close(fd_map);
   54 }
   55 
   56 static void __attribute__((noreturn))
   57 fail_file(void)
   58 {
   59         cleanup();
   60         longjmp(jmpenv, SJ_FAIL);
   61 }
   62 
   63 static void __attribute__((noreturn))
   64 succeed_file(void)
   65 {
   66         cleanup();
   67         longjmp(jmpenv, SJ_SUCCEED);
   68 }
   69 
   70 
   71 /*
   72  * Get the whole file as a programming convenience in order to avoid
   73  * malloc+lseek+read+free of many pieces.  If successful, then mmap
   74  * avoids copying unused pieces; else just read the whole file.
   75  * Open for both read and write.
   76  */
   77 static void *mmap_file(char const *fname)
   78 {
   79         void *addr;
   80 
   81         fd_map = open(fname, O_RDWR);
   82         if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
   83                 perror(fname);
   84                 fail_file();
   85         }
   86         if (!S_ISREG(sb.st_mode)) {
   87                 fprintf(stderr, "not a regular file: %s\n", fname);
   88                 fail_file();
   89         }
   90         addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED,
   91                     fd_map, 0);
   92         if (addr == MAP_FAILED) {
   93                 mmap_failed = 1;
   94                 fprintf(stderr, "Could not mmap file: %s\n", fname);
   95                 fail_file();
   96         }
   97         return addr;
   98 }
   99 
  100 static uint64_t r8be(const uint64_t *x)
  101 {
  102         return get_unaligned_be64(x);
  103 }
  104 static uint32_t rbe(const uint32_t *x)
  105 {
  106         return get_unaligned_be32(x);
  107 }
  108 static uint16_t r2be(const uint16_t *x)
  109 {
  110         return get_unaligned_be16(x);
  111 }
  112 static uint64_t r8le(const uint64_t *x)
  113 {
  114         return get_unaligned_le64(x);
  115 }
  116 static uint32_t rle(const uint32_t *x)
  117 {
  118         return get_unaligned_le32(x);
  119 }
  120 static uint16_t r2le(const uint16_t *x)
  121 {
  122         return get_unaligned_le16(x);
  123 }
  124 
  125 static void w8be(uint64_t val, uint64_t *x)
  126 {
  127         put_unaligned_be64(val, x);
  128 }
  129 static void wbe(uint32_t val, uint32_t *x)
  130 {
  131         put_unaligned_be32(val, x);
  132 }
  133 static void w2be(uint16_t val, uint16_t *x)
  134 {
  135         put_unaligned_be16(val, x);
  136 }
  137 static void w8le(uint64_t val, uint64_t *x)
  138 {
  139         put_unaligned_le64(val, x);
  140 }
  141 static void wle(uint32_t val, uint32_t *x)
  142 {
  143         put_unaligned_le32(val, x);
  144 }
  145 static void w2le(uint16_t val, uint16_t *x)
  146 {
  147         put_unaligned_le16(val, x);
  148 }
  149 
  150 static uint64_t (*r8)(const uint64_t *);
  151 static uint32_t (*r)(const uint32_t *);
  152 static uint16_t (*r2)(const uint16_t *);
  153 static void (*w8)(uint64_t, uint64_t *);
  154 static void (*w)(uint32_t, uint32_t *);
  155 static void (*w2)(uint16_t, uint16_t *);
  156 
  157 typedef void (*table_sort_t)(char *, int);
  158 
  159 /* 32 bit and 64 bit are very similar */
  160 #include "sortextable.h"
  161 #define SORTEXTABLE_64
  162 #include "sortextable.h"
  163 
  164 static int compare_relative_table(const void *a, const void *b)
  165 {
  166         int32_t av = (int32_t)r(a);
  167         int32_t bv = (int32_t)r(b);
  168 
  169         if (av < bv)
  170                 return -1;
  171         if (av > bv)
  172                 return 1;
  173         return 0;
  174 }
  175 
  176 static void sort_relative_table(char *extab_image, int image_size)
  177 {
  178         int i;
  179 
  180         /*
  181          * Do the same thing the runtime sort does, first normalize to
  182          * being relative to the start of the section.
  183          */
  184         i = 0;
  185         while (i < image_size) {
  186                 uint32_t *loc = (uint32_t *)(extab_image + i);
  187                 w(r(loc) + i, loc);
  188                 i += 4;
  189         }
  190 
  191         qsort(extab_image, image_size / 8, 8, compare_relative_table);
  192 
  193         /* Now denormalize. */
  194         i = 0;
  195         while (i < image_size) {
  196                 uint32_t *loc = (uint32_t *)(extab_image + i);
  197                 w(r(loc) - i, loc);
  198                 i += 4;
  199         }
  200 }
  201 
  202 static void
  203 do_file(char const *const fname)
  204 {
  205         table_sort_t custom_sort;
  206         Elf32_Ehdr *ehdr = mmap_file(fname);
  207 
  208         ehdr_curr = ehdr;
  209         switch (ehdr->e_ident[EI_DATA]) {
  210         default:
  211                 fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
  212                         ehdr->e_ident[EI_DATA], fname);
  213                 fail_file();
  214                 break;
  215         case ELFDATA2LSB:
  216                 r = rle;
  217                 r2 = r2le;
  218                 r8 = r8le;
  219                 w = wle;
  220                 w2 = w2le;
  221                 w8 = w8le;
  222                 break;
  223         case ELFDATA2MSB:
  224                 r = rbe;
  225                 r2 = r2be;
  226                 r8 = r8be;
  227                 w = wbe;
  228                 w2 = w2be;
  229                 w8 = w8be;
  230                 break;
  231         }  /* end switch */
  232         if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
  233         ||  r2(&ehdr->e_type) != ET_EXEC
  234         ||  ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
  235                 fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname);
  236                 fail_file();
  237         }
  238 
  239         custom_sort = NULL;
  240         switch (r2(&ehdr->e_machine)) {
  241         default:
  242                 fprintf(stderr, "unrecognized e_machine %d %s\n",
  243                         r2(&ehdr->e_machine), fname);
  244                 fail_file();
  245                 break;
  246         case EM_386:
  247         case EM_X86_64:
  248         case EM_S390:
  249                 custom_sort = sort_relative_table;
  250                 break;
  251         case EM_ARM:
  252         case EM_MIPS:
  253                 break;
  254         }  /* end switch */
  255 
  256         switch (ehdr->e_ident[EI_CLASS]) {
  257         default:
  258                 fprintf(stderr, "unrecognized ELF class %d %s\n",
  259                         ehdr->e_ident[EI_CLASS], fname);
  260                 fail_file();
  261                 break;
  262         case ELFCLASS32:
  263                 if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
  264                 ||  r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
  265                         fprintf(stderr,
  266                                 "unrecognized ET_EXEC file: %s\n", fname);
  267                         fail_file();
  268                 }
  269                 do32(ehdr, fname, custom_sort);
  270                 break;
  271         case ELFCLASS64: {
  272                 Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
  273                 if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
  274                 ||  r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
  275                         fprintf(stderr,
  276                                 "unrecognized ET_EXEC file: %s\n", fname);
  277                         fail_file();
  278                 }
  279                 do64(ghdr, fname, custom_sort);
  280                 break;
  281         }
  282         }  /* end switch */
  283 
  284         cleanup();
  285 }
  286 
  287 int
  288 main(int argc, char *argv[])
  289 {
  290         int n_error = 0;  /* gcc-4.3.0 false positive complaint */
  291         int i;
  292 
  293         if (argc < 2) {
  294                 fprintf(stderr, "usage: sortextable vmlinux...\n");
  295                 return 0;
  296         }
  297 
  298         /* Process each file in turn, allowing deep failure. */
  299         for (i = 1; i < argc; i++) {
  300                 char *file = argv[i];
  301                 int const sjval = setjmp(jmpenv);
  302 
  303                 switch (sjval) {
  304                 default:
  305                         fprintf(stderr, "internal error: %s\n", file);
  306                         exit(1);
  307                         break;
  308                 case SJ_SETJMP:    /* normal sequence */
  309                         /* Avoid problems if early cleanup() */
  310                         fd_map = -1;
  311                         ehdr_curr = NULL;
  312                         mmap_failed = 1;
  313                         do_file(file);
  314                         break;
  315                 case SJ_FAIL:    /* error in do_file or below */
  316                         ++n_error;
  317                         break;
  318                 case SJ_SUCCEED:    /* premature success */
  319                         /* do nothing */
  320                         break;
  321                 }  /* end switch */
  322         }
  323         return !!n_error;
  324 }

Cache object: 0e8aca043ffc33d7c67554429a2fe0b4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.