sortextable.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * sortextable.c: Sort the kernel's exception table
  3. *
  4. * Copyright 2011 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. * Strategy: alter the vmlinux file in-place.
  16. */
  17. #include <sys/types.h>
  18. #include <sys/mman.h>
  19. #include <sys/stat.h>
  20. #include <getopt.h>
  21. #include <elf.h>
  22. #include <fcntl.h>
  23. #include <setjmp.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <unistd.h>
  28. static int fd_map; /* File descriptor for file being modified. */
  29. static int mmap_failed; /* Boolean flag. */
  30. static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */
  31. static struct stat sb; /* Remember .st_size, etc. */
  32. static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
  33. /* setjmp() return values */
  34. enum {
  35. SJ_SETJMP = 0, /* hardwired first return */
  36. SJ_FAIL,
  37. SJ_SUCCEED
  38. };
  39. /* Per-file resource cleanup when multiple files. */
  40. static void
  41. cleanup(void)
  42. {
  43. if (!mmap_failed)
  44. munmap(ehdr_curr, sb.st_size);
  45. close(fd_map);
  46. }
  47. static void __attribute__((noreturn))
  48. fail_file(void)
  49. {
  50. cleanup();
  51. longjmp(jmpenv, SJ_FAIL);
  52. }
  53. static void __attribute__((noreturn))
  54. succeed_file(void)
  55. {
  56. cleanup();
  57. longjmp(jmpenv, SJ_SUCCEED);
  58. }
  59. /*
  60. * Get the whole file as a programming convenience in order to avoid
  61. * malloc+lseek+read+free of many pieces. If successful, then mmap
  62. * avoids copying unused pieces; else just read the whole file.
  63. * Open for both read and write.
  64. */
  65. static void *mmap_file(char const *fname)
  66. {
  67. void *addr;
  68. fd_map = open(fname, O_RDWR);
  69. if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
  70. perror(fname);
  71. fail_file();
  72. }
  73. if (!S_ISREG(sb.st_mode)) {
  74. fprintf(stderr, "not a regular file: %s\n", fname);
  75. fail_file();
  76. }
  77. addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED,
  78. fd_map, 0);
  79. if (addr == MAP_FAILED) {
  80. mmap_failed = 1;
  81. fprintf(stderr, "Could not mmap file: %s\n", fname);
  82. fail_file();
  83. }
  84. return addr;
  85. }
  86. /* w8rev, w8nat, ...: Handle endianness. */
  87. static uint64_t w8rev(uint64_t const x)
  88. {
  89. return ((0xff & (x >> (0 * 8))) << (7 * 8))
  90. | ((0xff & (x >> (1 * 8))) << (6 * 8))
  91. | ((0xff & (x >> (2 * 8))) << (5 * 8))
  92. | ((0xff & (x >> (3 * 8))) << (4 * 8))
  93. | ((0xff & (x >> (4 * 8))) << (3 * 8))
  94. | ((0xff & (x >> (5 * 8))) << (2 * 8))
  95. | ((0xff & (x >> (6 * 8))) << (1 * 8))
  96. | ((0xff & (x >> (7 * 8))) << (0 * 8));
  97. }
  98. static uint32_t w4rev(uint32_t const x)
  99. {
  100. return ((0xff & (x >> (0 * 8))) << (3 * 8))
  101. | ((0xff & (x >> (1 * 8))) << (2 * 8))
  102. | ((0xff & (x >> (2 * 8))) << (1 * 8))
  103. | ((0xff & (x >> (3 * 8))) << (0 * 8));
  104. }
  105. static uint32_t w2rev(uint16_t const x)
  106. {
  107. return ((0xff & (x >> (0 * 8))) << (1 * 8))
  108. | ((0xff & (x >> (1 * 8))) << (0 * 8));
  109. }
  110. static uint64_t w8nat(uint64_t const x)
  111. {
  112. return x;
  113. }
  114. static uint32_t w4nat(uint32_t const x)
  115. {
  116. return x;
  117. }
  118. static uint32_t w2nat(uint16_t const x)
  119. {
  120. return x;
  121. }
  122. static uint64_t (*w8)(uint64_t);
  123. static uint32_t (*w)(uint32_t);
  124. static uint32_t (*w2)(uint16_t);
  125. /* 32 bit and 64 bit are very similar */
  126. #include "sortextable.h"
  127. #define SORTEXTABLE_64
  128. #include "sortextable.h"
  129. static void
  130. do_file(char const *const fname)
  131. {
  132. Elf32_Ehdr *const ehdr = mmap_file(fname);
  133. ehdr_curr = ehdr;
  134. w = w4nat;
  135. w2 = w2nat;
  136. w8 = w8nat;
  137. switch (ehdr->e_ident[EI_DATA]) {
  138. static unsigned int const endian = 1;
  139. default:
  140. fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
  141. ehdr->e_ident[EI_DATA], fname);
  142. fail_file();
  143. break;
  144. case ELFDATA2LSB:
  145. if (*(unsigned char const *)&endian != 1) {
  146. /* main() is big endian, file.o is little endian. */
  147. w = w4rev;
  148. w2 = w2rev;
  149. w8 = w8rev;
  150. }
  151. break;
  152. case ELFDATA2MSB:
  153. if (*(unsigned char const *)&endian != 0) {
  154. /* main() is little endian, file.o is big endian. */
  155. w = w4rev;
  156. w2 = w2rev;
  157. w8 = w8rev;
  158. }
  159. break;
  160. } /* end switch */
  161. if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
  162. || w2(ehdr->e_type) != ET_EXEC
  163. || ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
  164. fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname);
  165. fail_file();
  166. }
  167. switch (w2(ehdr->e_machine)) {
  168. default:
  169. fprintf(stderr, "unrecognized e_machine %d %s\n",
  170. w2(ehdr->e_machine), fname);
  171. fail_file();
  172. break;
  173. case EM_386:
  174. case EM_MIPS:
  175. case EM_X86_64:
  176. break;
  177. } /* end switch */
  178. switch (ehdr->e_ident[EI_CLASS]) {
  179. default:
  180. fprintf(stderr, "unrecognized ELF class %d %s\n",
  181. ehdr->e_ident[EI_CLASS], fname);
  182. fail_file();
  183. break;
  184. case ELFCLASS32:
  185. if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
  186. || w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
  187. fprintf(stderr,
  188. "unrecognized ET_EXEC file: %s\n", fname);
  189. fail_file();
  190. }
  191. do32(ehdr, fname);
  192. break;
  193. case ELFCLASS64: {
  194. Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
  195. if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
  196. || w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
  197. fprintf(stderr,
  198. "unrecognized ET_EXEC file: %s\n", fname);
  199. fail_file();
  200. }
  201. do64(ghdr, fname);
  202. break;
  203. }
  204. } /* end switch */
  205. cleanup();
  206. }
  207. int
  208. main(int argc, char *argv[])
  209. {
  210. int n_error = 0; /* gcc-4.3.0 false positive complaint */
  211. int i;
  212. if (argc < 2) {
  213. fprintf(stderr, "usage: sortextable vmlinux...\n");
  214. return 0;
  215. }
  216. /* Process each file in turn, allowing deep failure. */
  217. for (i = 1; i < argc; i++) {
  218. char *file = argv[i];
  219. int const sjval = setjmp(jmpenv);
  220. switch (sjval) {
  221. default:
  222. fprintf(stderr, "internal error: %s\n", file);
  223. exit(1);
  224. break;
  225. case SJ_SETJMP: /* normal sequence */
  226. /* Avoid problems if early cleanup() */
  227. fd_map = -1;
  228. ehdr_curr = NULL;
  229. mmap_failed = 1;
  230. do_file(file);
  231. break;
  232. case SJ_FAIL: /* error in do_file or below */
  233. ++n_error;
  234. break;
  235. case SJ_SUCCEED: /* premature success */
  236. /* do nothing */
  237. break;
  238. } /* end switch */
  239. }
  240. return !!n_error;
  241. }