aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/sortextable.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-23 13:44:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-23 13:44:35 -0400
commit269af9a1a08d368b46d72e74126564d04c354f7e (patch)
treef0f2a8dd54075edebbb728602822e2b7378588d0 /scripts/sortextable.c
parent8ca038dc10eec80f280d9d483f1835ac2763a787 (diff)
parent8b5ad472991796b2347464922c72de2ca5a028f3 (diff)
Merge branch 'x86-extable-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull exception table generation updates from Ingo Molnar: "The biggest change here is to allow the build-time sorting of the exception table, to speed up booting. This is achieved by the architecture enabling BUILDTIME_EXTABLE_SORT. This option is enabled for x86 and MIPS currently. On x86 a number of fixes and changes were needed to allow build-time sorting of the exception table, in particular a relocation invariant exception table format was needed. This required the abstracting out of exception table protocol and the removal of 20 years of accumulated assumptions about the x86 exception table format. While at it, this tree also cleans up various other aspects of exception handling, such as early(er) exception handling for rdmsr_safe() et al. All in one, as the result of these changes the x86 exception code is now pretty nice and modern. As an added bonus any regressions in this code will be early and violent crashes, so if you see any of those, you'll know whom to blame!" Fix up trivial conflicts in arch/{mips,x86}/Kconfig files due to nearby modifications of other core architecture options. * 'x86-extable-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (35 commits) Revert "x86, extable: Disable presorted exception table for now" scripts/sortextable: Handle relative entries, and other cleanups x86, extable: Switch to relative exception table entries x86, extable: Disable presorted exception table for now x86, extable: Add _ASM_EXTABLE_EX() macro x86, extable: Remove open-coded exception table entries in arch/x86/ia32/ia32entry.S x86, extable: Remove open-coded exception table entries in arch/x86/include/asm/xsave.h x86, extable: Remove open-coded exception table entries in arch/x86/include/asm/kvm_host.h x86, extable: Remove the now-unused __ASM_EX_SEC macros x86, extable: Remove open-coded exception table entries in arch/x86/xen/xen-asm_32.S x86, extable: Remove open-coded exception table entries in arch/x86/um/checksum_32.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/usercopy_32.c x86, extable: Remove open-coded exception table entries in arch/x86/lib/putuser.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/getuser.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/csum-copy_64.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/copy_user_nocache_64.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/copy_user_64.S x86, extable: Remove open-coded exception table entries in arch/x86/lib/checksum_32.S x86, extable: Remove open-coded exception table entries in arch/x86/kernel/test_rodata.c x86, extable: Remove open-coded exception table entries in arch/x86/kernel/entry_64.S ...
Diffstat (limited to 'scripts/sortextable.c')
-rw-r--r--scripts/sortextable.c322
1 files changed, 322 insertions, 0 deletions
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
new file mode 100644
index 000000000000..1ca9ceb95eb6
--- /dev/null
+++ b/scripts/sortextable.c
@@ -0,0 +1,322 @@
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
34static int fd_map; /* File descriptor for file being modified. */
35static int mmap_failed; /* Boolean flag. */
36static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */
37static struct stat sb; /* Remember .st_size, etc. */
38static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
39
40/* setjmp() return values */
41enum {
42 SJ_SETJMP = 0, /* hardwired first return */
43 SJ_FAIL,
44 SJ_SUCCEED
45};
46
47/* Per-file resource cleanup when multiple files. */
48static void
49cleanup(void)
50{
51 if (!mmap_failed)
52 munmap(ehdr_curr, sb.st_size);
53 close(fd_map);
54}
55
56static void __attribute__((noreturn))
57fail_file(void)
58{
59 cleanup();
60 longjmp(jmpenv, SJ_FAIL);
61}
62
63static void __attribute__((noreturn))
64succeed_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 */
77static 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
100static uint64_t r8be(const uint64_t *x)
101{
102 return get_unaligned_be64(x);
103}
104static uint32_t rbe(const uint32_t *x)
105{
106 return get_unaligned_be32(x);
107}
108static uint16_t r2be(const uint16_t *x)
109{
110 return get_unaligned_be16(x);
111}
112static uint64_t r8le(const uint64_t *x)
113{
114 return get_unaligned_le64(x);
115}
116static uint32_t rle(const uint32_t *x)
117{
118 return get_unaligned_le32(x);
119}
120static uint16_t r2le(const uint16_t *x)
121{
122 return get_unaligned_le16(x);
123}
124
125static void w8be(uint64_t val, uint64_t *x)
126{
127 put_unaligned_be64(val, x);
128}
129static void wbe(uint32_t val, uint32_t *x)
130{
131 put_unaligned_be32(val, x);
132}
133static void w2be(uint16_t val, uint16_t *x)
134{
135 put_unaligned_be16(val, x);
136}
137static void w8le(uint64_t val, uint64_t *x)
138{
139 put_unaligned_le64(val, x);
140}
141static void wle(uint32_t val, uint32_t *x)
142{
143 put_unaligned_le32(val, x);
144}
145static void w2le(uint16_t val, uint16_t *x)
146{
147 put_unaligned_le16(val, x);
148}
149
150static uint64_t (*r8)(const uint64_t *);
151static uint32_t (*r)(const uint32_t *);
152static uint16_t (*r2)(const uint16_t *);
153static void (*w8)(uint64_t, uint64_t *);
154static void (*w)(uint32_t, uint32_t *);
155static void (*w2)(uint16_t, uint16_t *);
156
157typedef 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
164static int compare_x86_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
176static void sort_x86_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_x86_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
202static void
203do_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 custom_sort = sort_x86_table;
249 break;
250 case EM_MIPS:
251 break;
252 } /* end switch */
253
254 switch (ehdr->e_ident[EI_CLASS]) {
255 default:
256 fprintf(stderr, "unrecognized ELF class %d %s\n",
257 ehdr->e_ident[EI_CLASS], fname);
258 fail_file();
259 break;
260 case ELFCLASS32:
261 if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
262 || r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
263 fprintf(stderr,
264 "unrecognized ET_EXEC file: %s\n", fname);
265 fail_file();
266 }
267 do32(ehdr, fname, custom_sort);
268 break;
269 case ELFCLASS64: {
270 Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
271 if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
272 || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
273 fprintf(stderr,
274 "unrecognized ET_EXEC file: %s\n", fname);
275 fail_file();
276 }
277 do64(ghdr, fname, custom_sort);
278 break;
279 }
280 } /* end switch */
281
282 cleanup();
283}
284
285int
286main(int argc, char *argv[])
287{
288 int n_error = 0; /* gcc-4.3.0 false positive complaint */
289 int i;
290
291 if (argc < 2) {
292 fprintf(stderr, "usage: sortextable vmlinux...\n");
293 return 0;
294 }
295
296 /* Process each file in turn, allowing deep failure. */
297 for (i = 1; i < argc; i++) {
298 char *file = argv[i];
299 int const sjval = setjmp(jmpenv);
300
301 switch (sjval) {
302 default:
303 fprintf(stderr, "internal error: %s\n", file);
304 exit(1);
305 break;
306 case SJ_SETJMP: /* normal sequence */
307 /* Avoid problems if early cleanup() */
308 fd_map = -1;
309 ehdr_curr = NULL;
310 mmap_failed = 1;
311 do_file(file);
312 break;
313 case SJ_FAIL: /* error in do_file or below */
314 ++n_error;
315 break;
316 case SJ_SUCCEED: /* premature success */
317 /* do nothing */
318 break;
319 } /* end switch */
320 }
321 return !!n_error;
322}