Commit d59a16836d917548cf41eda3369936684d527f5f
Committed by
H. Peter Anvin
1 parent
706276543b
Exists in
master
and in
20 other branches
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 <david.daney@cavium.com> Link: http://lkml.kernel.org/r/1335291795-26693-2-git-send-email-ddaney.cavm@gmail.com Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Showing 3 changed files with 164 additions and 88 deletions Inline Diff
scripts/Makefile
1 | ### | 1 | ### |
2 | # scripts contains sources for various helper programs used throughout | 2 | # scripts contains sources for various helper programs used throughout |
3 | # the kernel for the build process. | 3 | # the kernel for the build process. |
4 | # --------------------------------------------------------------------------- | 4 | # --------------------------------------------------------------------------- |
5 | # kallsyms: Find all symbols in vmlinux | 5 | # kallsyms: Find all symbols in vmlinux |
6 | # pnmttologo: Convert pnm files to logo files | 6 | # pnmttologo: Convert pnm files to logo files |
7 | # conmakehash: Create chartable | 7 | # conmakehash: Create chartable |
8 | # conmakehash: Create arrays for initializing the kernel console tables | 8 | # conmakehash: Create arrays for initializing the kernel console tables |
9 | # docproc: Used in Documentation/DocBook | 9 | # docproc: Used in Documentation/DocBook |
10 | 10 | ||
11 | hostprogs-$(CONFIG_KALLSYMS) += kallsyms | 11 | hostprogs-$(CONFIG_KALLSYMS) += kallsyms |
12 | hostprogs-$(CONFIG_LOGO) += pnmtologo | 12 | hostprogs-$(CONFIG_LOGO) += pnmtologo |
13 | hostprogs-$(CONFIG_VT) += conmakehash | 13 | hostprogs-$(CONFIG_VT) += conmakehash |
14 | hostprogs-$(CONFIG_IKCONFIG) += bin2c | 14 | hostprogs-$(CONFIG_IKCONFIG) += bin2c |
15 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount | 15 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount |
16 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable | 16 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable |
17 | 17 | ||
18 | HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include | ||
19 | |||
18 | always := $(hostprogs-y) $(hostprogs-m) | 20 | always := $(hostprogs-y) $(hostprogs-m) |
19 | 21 | ||
20 | # The following hostprogs-y programs are only build on demand | 22 | # The following hostprogs-y programs are only build on demand |
21 | hostprogs-y += unifdef docproc | 23 | hostprogs-y += unifdef docproc |
22 | 24 | ||
23 | # These targets are used internally to avoid "is up to date" messages | 25 | # These targets are used internally to avoid "is up to date" messages |
24 | PHONY += build_unifdef | 26 | PHONY += build_unifdef |
25 | build_unifdef: scripts/unifdef FORCE | 27 | build_unifdef: scripts/unifdef FORCE |
26 | @: | 28 | @: |
27 | build_docproc: scripts/docproc FORCE | 29 | build_docproc: scripts/docproc FORCE |
28 | @: | 30 | @: |
29 | 31 | ||
30 | subdir-$(CONFIG_MODVERSIONS) += genksyms | 32 | subdir-$(CONFIG_MODVERSIONS) += genksyms |
31 | subdir-y += mod | 33 | subdir-y += mod |
32 | subdir-$(CONFIG_SECURITY_SELINUX) += selinux | 34 | subdir-$(CONFIG_SECURITY_SELINUX) += selinux |
33 | subdir-$(CONFIG_DTC) += dtc | 35 | subdir-$(CONFIG_DTC) += dtc |
34 | 36 | ||
35 | # Let clean descend into subdirs | 37 | # Let clean descend into subdirs |
36 | subdir- += basic kconfig package selinux | 38 | subdir- += basic kconfig package selinux |
37 | 39 |
scripts/sortextable.c
1 | /* | 1 | /* |
2 | * sortextable.c: Sort the kernel's exception table | 2 | * sortextable.c: Sort the kernel's exception table |
3 | * | 3 | * |
4 | * Copyright 2011 Cavium, Inc. | 4 | * Copyright 2011 - 2012 Cavium, Inc. |
5 | * | 5 | * |
6 | * Based on code taken from recortmcount.c which is: | 6 | * Based on code taken from recortmcount.c which is: |
7 | * | 7 | * |
8 | * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. | 8 | * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. |
9 | * Licensed under the GNU General Public License, version 2 (GPLv2). | 9 | * Licensed under the GNU General Public License, version 2 (GPLv2). |
10 | * | 10 | * |
11 | * Restructured to fit Linux format, as well as other updates: | 11 | * Restructured to fit Linux format, as well as other updates: |
12 | * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. | 12 | * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | /* | 15 | /* |
16 | * Strategy: alter the vmlinux file in-place. | 16 | * Strategy: alter the vmlinux file in-place. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <sys/types.h> | 19 | #include <sys/types.h> |
20 | #include <sys/mman.h> | 20 | #include <sys/mman.h> |
21 | #include <sys/stat.h> | 21 | #include <sys/stat.h> |
22 | #include <getopt.h> | 22 | #include <getopt.h> |
23 | #include <elf.h> | 23 | #include <elf.h> |
24 | #include <fcntl.h> | 24 | #include <fcntl.h> |
25 | #include <setjmp.h> | 25 | #include <setjmp.h> |
26 | #include <stdio.h> | 26 | #include <stdio.h> |
27 | #include <stdlib.h> | 27 | #include <stdlib.h> |
28 | #include <string.h> | 28 | #include <string.h> |
29 | #include <unistd.h> | 29 | #include <unistd.h> |
30 | 30 | ||
31 | #include <tools/be_byteshift.h> | ||
32 | #include <tools/le_byteshift.h> | ||
33 | |||
31 | static int fd_map; /* File descriptor for file being modified. */ | 34 | static int fd_map; /* File descriptor for file being modified. */ |
32 | static int mmap_failed; /* Boolean flag. */ | 35 | static int mmap_failed; /* Boolean flag. */ |
33 | static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ | 36 | static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ |
34 | static struct stat sb; /* Remember .st_size, etc. */ | 37 | static struct stat sb; /* Remember .st_size, etc. */ |
35 | static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ | 38 | static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ |
36 | 39 | ||
37 | /* setjmp() return values */ | 40 | /* setjmp() return values */ |
38 | enum { | 41 | enum { |
39 | SJ_SETJMP = 0, /* hardwired first return */ | 42 | SJ_SETJMP = 0, /* hardwired first return */ |
40 | SJ_FAIL, | 43 | SJ_FAIL, |
41 | SJ_SUCCEED | 44 | SJ_SUCCEED |
42 | }; | 45 | }; |
43 | 46 | ||
44 | /* Per-file resource cleanup when multiple files. */ | 47 | /* Per-file resource cleanup when multiple files. */ |
45 | static void | 48 | static void |
46 | cleanup(void) | 49 | cleanup(void) |
47 | { | 50 | { |
48 | if (!mmap_failed) | 51 | if (!mmap_failed) |
49 | munmap(ehdr_curr, sb.st_size); | 52 | munmap(ehdr_curr, sb.st_size); |
50 | close(fd_map); | 53 | close(fd_map); |
51 | } | 54 | } |
52 | 55 | ||
53 | static void __attribute__((noreturn)) | 56 | static void __attribute__((noreturn)) |
54 | fail_file(void) | 57 | fail_file(void) |
55 | { | 58 | { |
56 | cleanup(); | 59 | cleanup(); |
57 | longjmp(jmpenv, SJ_FAIL); | 60 | longjmp(jmpenv, SJ_FAIL); |
58 | } | 61 | } |
59 | 62 | ||
60 | static void __attribute__((noreturn)) | 63 | static void __attribute__((noreturn)) |
61 | succeed_file(void) | 64 | succeed_file(void) |
62 | { | 65 | { |
63 | cleanup(); | 66 | cleanup(); |
64 | longjmp(jmpenv, SJ_SUCCEED); | 67 | longjmp(jmpenv, SJ_SUCCEED); |
65 | } | 68 | } |
66 | 69 | ||
67 | 70 | ||
68 | /* | 71 | /* |
69 | * Get the whole file as a programming convenience in order to avoid | 72 | * Get the whole file as a programming convenience in order to avoid |
70 | * malloc+lseek+read+free of many pieces. If successful, then mmap | 73 | * malloc+lseek+read+free of many pieces. If successful, then mmap |
71 | * avoids copying unused pieces; else just read the whole file. | 74 | * avoids copying unused pieces; else just read the whole file. |
72 | * Open for both read and write. | 75 | * Open for both read and write. |
73 | */ | 76 | */ |
74 | static void *mmap_file(char const *fname) | 77 | static void *mmap_file(char const *fname) |
75 | { | 78 | { |
76 | void *addr; | 79 | void *addr; |
77 | 80 | ||
78 | fd_map = open(fname, O_RDWR); | 81 | fd_map = open(fname, O_RDWR); |
79 | if (fd_map < 0 || fstat(fd_map, &sb) < 0) { | 82 | if (fd_map < 0 || fstat(fd_map, &sb) < 0) { |
80 | perror(fname); | 83 | perror(fname); |
81 | fail_file(); | 84 | fail_file(); |
82 | } | 85 | } |
83 | if (!S_ISREG(sb.st_mode)) { | 86 | if (!S_ISREG(sb.st_mode)) { |
84 | fprintf(stderr, "not a regular file: %s\n", fname); | 87 | fprintf(stderr, "not a regular file: %s\n", fname); |
85 | fail_file(); | 88 | fail_file(); |
86 | } | 89 | } |
87 | addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, | 90 | addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, |
88 | fd_map, 0); | 91 | fd_map, 0); |
89 | if (addr == MAP_FAILED) { | 92 | if (addr == MAP_FAILED) { |
90 | mmap_failed = 1; | 93 | mmap_failed = 1; |
91 | fprintf(stderr, "Could not mmap file: %s\n", fname); | 94 | fprintf(stderr, "Could not mmap file: %s\n", fname); |
92 | fail_file(); | 95 | fail_file(); |
93 | } | 96 | } |
94 | return addr; | 97 | return addr; |
95 | } | 98 | } |
96 | 99 | ||
97 | /* w8rev, w8nat, ...: Handle endianness. */ | 100 | static uint64_t r8be(const uint64_t *x) |
98 | |||
99 | static uint64_t w8rev(uint64_t const x) | ||
100 | { | 101 | { |
101 | return ((0xff & (x >> (0 * 8))) << (7 * 8)) | 102 | return get_unaligned_be64(x); |
102 | | ((0xff & (x >> (1 * 8))) << (6 * 8)) | ||
103 | | ((0xff & (x >> (2 * 8))) << (5 * 8)) | ||
104 | | ((0xff & (x >> (3 * 8))) << (4 * 8)) | ||
105 | | ((0xff & (x >> (4 * 8))) << (3 * 8)) | ||
106 | | ((0xff & (x >> (5 * 8))) << (2 * 8)) | ||
107 | | ((0xff & (x >> (6 * 8))) << (1 * 8)) | ||
108 | | ((0xff & (x >> (7 * 8))) << (0 * 8)); | ||
109 | } | 103 | } |
110 | 104 | static uint32_t rbe(const uint32_t *x) | |
111 | static uint32_t w4rev(uint32_t const x) | ||
112 | { | 105 | { |
113 | return ((0xff & (x >> (0 * 8))) << (3 * 8)) | 106 | return get_unaligned_be32(x); |
114 | | ((0xff & (x >> (1 * 8))) << (2 * 8)) | ||
115 | | ((0xff & (x >> (2 * 8))) << (1 * 8)) | ||
116 | | ((0xff & (x >> (3 * 8))) << (0 * 8)); | ||
117 | } | 107 | } |
118 | 108 | static uint16_t r2be(const uint16_t *x) | |
119 | static uint32_t w2rev(uint16_t const x) | ||
120 | { | 109 | { |
121 | return ((0xff & (x >> (0 * 8))) << (1 * 8)) | 110 | return get_unaligned_be16(x); |
122 | | ((0xff & (x >> (1 * 8))) << (0 * 8)); | ||
123 | } | 111 | } |
124 | 112 | static uint64_t r8le(const uint64_t *x) | |
125 | static uint64_t w8nat(uint64_t const x) | ||
126 | { | 113 | { |
127 | return x; | 114 | return get_unaligned_le64(x); |
128 | } | 115 | } |
129 | 116 | static uint32_t rle(const uint32_t *x) | |
130 | static uint32_t w4nat(uint32_t const x) | ||
131 | { | 117 | { |
132 | return x; | 118 | return get_unaligned_le32(x); |
133 | } | 119 | } |
120 | static uint16_t r2le(const uint16_t *x) | ||
121 | { | ||
122 | return get_unaligned_le16(x); | ||
123 | } | ||
134 | 124 | ||
135 | static uint32_t w2nat(uint16_t const x) | 125 | static void w8be(uint64_t val, uint64_t *x) |
136 | { | 126 | { |
137 | return x; | 127 | put_unaligned_be64(val, x); |
138 | } | 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 | } | ||
139 | 149 | ||
140 | static uint64_t (*w8)(uint64_t); | 150 | static uint64_t (*r8)(const uint64_t *); |
141 | static uint32_t (*w)(uint32_t); | 151 | static uint32_t (*r)(const uint32_t *); |
142 | static uint32_t (*w2)(uint16_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 *); | ||
143 | 156 | ||
157 | typedef void (*table_sort_t)(char *, int); | ||
144 | 158 | ||
145 | /* 32 bit and 64 bit are very similar */ | 159 | /* 32 bit and 64 bit are very similar */ |
146 | #include "sortextable.h" | 160 | #include "sortextable.h" |
147 | #define SORTEXTABLE_64 | 161 | #define SORTEXTABLE_64 |
148 | #include "sortextable.h" | 162 | #include "sortextable.h" |
149 | 163 | ||
164 | static 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); | ||
150 | 168 | ||
169 | if (av < bv) | ||
170 | return -1; | ||
171 | if (av > bv) | ||
172 | return 1; | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static 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 | |||
151 | static void | 202 | static void |
152 | do_file(char const *const fname) | 203 | do_file(char const *const fname) |
153 | { | 204 | { |
154 | Elf32_Ehdr *const ehdr = mmap_file(fname); | 205 | table_sort_t custom_sort; |
206 | Elf32_Ehdr *ehdr = mmap_file(fname); | ||
155 | 207 | ||
156 | ehdr_curr = ehdr; | 208 | ehdr_curr = ehdr; |
157 | w = w4nat; | ||
158 | w2 = w2nat; | ||
159 | w8 = w8nat; | ||
160 | switch (ehdr->e_ident[EI_DATA]) { | 209 | switch (ehdr->e_ident[EI_DATA]) { |
161 | static unsigned int const endian = 1; | ||
162 | default: | 210 | default: |
163 | fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", | 211 | fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", |
164 | ehdr->e_ident[EI_DATA], fname); | 212 | ehdr->e_ident[EI_DATA], fname); |
165 | fail_file(); | 213 | fail_file(); |
166 | break; | 214 | break; |
167 | case ELFDATA2LSB: | 215 | case ELFDATA2LSB: |
168 | if (*(unsigned char const *)&endian != 1) { | 216 | r = rle; |
169 | /* main() is big endian, file.o is little endian. */ | 217 | r2 = r2le; |
170 | w = w4rev; | 218 | r8 = r8le; |
171 | w2 = w2rev; | 219 | w = wle; |
172 | w8 = w8rev; | 220 | w2 = w2le; |
173 | } | 221 | w8 = w8le; |
174 | break; | 222 | break; |
175 | case ELFDATA2MSB: | 223 | case ELFDATA2MSB: |
176 | if (*(unsigned char const *)&endian != 0) { | 224 | r = rbe; |
177 | /* main() is little endian, file.o is big endian. */ | 225 | r2 = r2be; |
178 | w = w4rev; | 226 | r8 = r8be; |
179 | w2 = w2rev; | 227 | w = wbe; |
180 | w8 = w8rev; | 228 | w2 = w2be; |
181 | } | 229 | w8 = w8be; |
182 | break; | 230 | break; |
183 | } /* end switch */ | 231 | } /* end switch */ |
184 | if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 | 232 | if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 |
185 | || w2(ehdr->e_type) != ET_EXEC | 233 | || r2(&ehdr->e_type) != ET_EXEC |
186 | || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { | 234 | || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { |
187 | fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname); | 235 | fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname); |
188 | fail_file(); | 236 | fail_file(); |
189 | } | 237 | } |
190 | 238 | ||
191 | switch (w2(ehdr->e_machine)) { | 239 | custom_sort = NULL; |
240 | switch (r2(&ehdr->e_machine)) { | ||
192 | default: | 241 | default: |
193 | fprintf(stderr, "unrecognized e_machine %d %s\n", | 242 | fprintf(stderr, "unrecognized e_machine %d %s\n", |
194 | w2(ehdr->e_machine), fname); | 243 | r2(&ehdr->e_machine), fname); |
195 | fail_file(); | 244 | fail_file(); |
196 | break; | 245 | break; |
197 | case EM_386: | 246 | case EM_386: |
198 | case EM_MIPS: | ||
199 | case EM_X86_64: | 247 | case EM_X86_64: |
248 | custom_sort = sort_x86_table; | ||
200 | break; | 249 | break; |
250 | case EM_MIPS: | ||
251 | break; | ||
201 | } /* end switch */ | 252 | } /* end switch */ |
202 | 253 | ||
203 | switch (ehdr->e_ident[EI_CLASS]) { | 254 | switch (ehdr->e_ident[EI_CLASS]) { |
204 | default: | 255 | default: |
205 | fprintf(stderr, "unrecognized ELF class %d %s\n", | 256 | fprintf(stderr, "unrecognized ELF class %d %s\n", |
206 | ehdr->e_ident[EI_CLASS], fname); | 257 | ehdr->e_ident[EI_CLASS], fname); |
207 | fail_file(); | 258 | fail_file(); |
208 | break; | 259 | break; |
209 | case ELFCLASS32: | 260 | case ELFCLASS32: |
210 | if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr) | 261 | if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) |
211 | || w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { | 262 | || r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { |
212 | fprintf(stderr, | 263 | fprintf(stderr, |
213 | "unrecognized ET_EXEC file: %s\n", fname); | 264 | "unrecognized ET_EXEC file: %s\n", fname); |
214 | fail_file(); | 265 | fail_file(); |
215 | } | 266 | } |
216 | do32(ehdr, fname); | 267 | do32(ehdr, fname, custom_sort); |
217 | break; | 268 | break; |
218 | case ELFCLASS64: { | 269 | case ELFCLASS64: { |
219 | Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; | 270 | Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; |
220 | if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr) | 271 | if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) |
221 | || w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { | 272 | || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { |
222 | fprintf(stderr, | 273 | fprintf(stderr, |
223 | "unrecognized ET_EXEC file: %s\n", fname); | 274 | "unrecognized ET_EXEC file: %s\n", fname); |
224 | fail_file(); | 275 | fail_file(); |
225 | } | 276 | } |
226 | do64(ghdr, fname); | 277 | do64(ghdr, fname, custom_sort); |
227 | break; | 278 | break; |
228 | } | 279 | } |
229 | } /* end switch */ | 280 | } /* end switch */ |
230 | 281 | ||
231 | cleanup(); | 282 | cleanup(); |
232 | } | 283 | } |
233 | 284 | ||
234 | int | 285 | int |
235 | main(int argc, char *argv[]) | 286 | main(int argc, char *argv[]) |
236 | { | 287 | { |
237 | int n_error = 0; /* gcc-4.3.0 false positive complaint */ | 288 | int n_error = 0; /* gcc-4.3.0 false positive complaint */ |
238 | int i; | 289 | int i; |
239 | 290 | ||
240 | if (argc < 2) { | 291 | if (argc < 2) { |
241 | fprintf(stderr, "usage: sortextable vmlinux...\n"); | 292 | fprintf(stderr, "usage: sortextable vmlinux...\n"); |
242 | return 0; | 293 | return 0; |
243 | } | 294 | } |
244 | 295 | ||
245 | /* Process each file in turn, allowing deep failure. */ | 296 | /* Process each file in turn, allowing deep failure. */ |
246 | for (i = 1; i < argc; i++) { | 297 | for (i = 1; i < argc; i++) { |
247 | char *file = argv[i]; | 298 | char *file = argv[i]; |
248 | int const sjval = setjmp(jmpenv); | 299 | int const sjval = setjmp(jmpenv); |
249 | 300 | ||
250 | switch (sjval) { | 301 | switch (sjval) { |
scripts/sortextable.h
1 | /* | 1 | /* |
2 | * sortextable.h | 2 | * sortextable.h |
3 | * | 3 | * |
4 | * Copyright 2011 Cavium, Inc. | 4 | * Copyright 2011 - 2012 Cavium, Inc. |
5 | * | 5 | * |
6 | * Some of this code was taken out of recordmcount.h written by: | 6 | * Some of this code was taken out of recordmcount.h written by: |
7 | * | 7 | * |
8 | * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. | 8 | * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. |
9 | * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. | 9 | * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. |
10 | * | 10 | * |
11 | * | 11 | * |
12 | * Licensed under the GNU General Public License, version 2 (GPLv2). | 12 | * Licensed under the GNU General Public License, version 2 (GPLv2). |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #undef extable_ent_size | 15 | #undef extable_ent_size |
16 | #undef compare_extable | 16 | #undef compare_extable |
17 | #undef do_func | 17 | #undef do_func |
18 | #undef Elf_Addr | 18 | #undef Elf_Addr |
19 | #undef Elf_Ehdr | 19 | #undef Elf_Ehdr |
20 | #undef Elf_Shdr | 20 | #undef Elf_Shdr |
21 | #undef Elf_Rel | 21 | #undef Elf_Rel |
22 | #undef Elf_Rela | 22 | #undef Elf_Rela |
23 | #undef Elf_Sym | 23 | #undef Elf_Sym |
24 | #undef ELF_R_SYM | 24 | #undef ELF_R_SYM |
25 | #undef Elf_r_sym | 25 | #undef Elf_r_sym |
26 | #undef ELF_R_INFO | 26 | #undef ELF_R_INFO |
27 | #undef Elf_r_info | 27 | #undef Elf_r_info |
28 | #undef ELF_ST_BIND | 28 | #undef ELF_ST_BIND |
29 | #undef ELF_ST_TYPE | 29 | #undef ELF_ST_TYPE |
30 | #undef fn_ELF_R_SYM | 30 | #undef fn_ELF_R_SYM |
31 | #undef fn_ELF_R_INFO | 31 | #undef fn_ELF_R_INFO |
32 | #undef uint_t | 32 | #undef uint_t |
33 | #undef _r | ||
33 | #undef _w | 34 | #undef _w |
34 | 35 | ||
35 | #ifdef SORTEXTABLE_64 | 36 | #ifdef SORTEXTABLE_64 |
36 | # define extable_ent_size 16 | 37 | # define extable_ent_size 16 |
37 | # define compare_extable compare_extable_64 | 38 | # define compare_extable compare_extable_64 |
38 | # define do_func do64 | 39 | # define do_func do64 |
39 | # define Elf_Addr Elf64_Addr | 40 | # define Elf_Addr Elf64_Addr |
40 | # define Elf_Ehdr Elf64_Ehdr | 41 | # define Elf_Ehdr Elf64_Ehdr |
41 | # define Elf_Shdr Elf64_Shdr | 42 | # define Elf_Shdr Elf64_Shdr |
42 | # define Elf_Rel Elf64_Rel | 43 | # define Elf_Rel Elf64_Rel |
43 | # define Elf_Rela Elf64_Rela | 44 | # define Elf_Rela Elf64_Rela |
44 | # define Elf_Sym Elf64_Sym | 45 | # define Elf_Sym Elf64_Sym |
45 | # define ELF_R_SYM ELF64_R_SYM | 46 | # define ELF_R_SYM ELF64_R_SYM |
46 | # define Elf_r_sym Elf64_r_sym | 47 | # define Elf_r_sym Elf64_r_sym |
47 | # define ELF_R_INFO ELF64_R_INFO | 48 | # define ELF_R_INFO ELF64_R_INFO |
48 | # define Elf_r_info Elf64_r_info | 49 | # define Elf_r_info Elf64_r_info |
49 | # define ELF_ST_BIND ELF64_ST_BIND | 50 | # define ELF_ST_BIND ELF64_ST_BIND |
50 | # define ELF_ST_TYPE ELF64_ST_TYPE | 51 | # define ELF_ST_TYPE ELF64_ST_TYPE |
51 | # define fn_ELF_R_SYM fn_ELF64_R_SYM | 52 | # define fn_ELF_R_SYM fn_ELF64_R_SYM |
52 | # define fn_ELF_R_INFO fn_ELF64_R_INFO | 53 | # define fn_ELF_R_INFO fn_ELF64_R_INFO |
53 | # define uint_t uint64_t | 54 | # define uint_t uint64_t |
55 | # define _r r8 | ||
54 | # define _w w8 | 56 | # define _w w8 |
55 | #else | 57 | #else |
56 | # define extable_ent_size 8 | 58 | # define extable_ent_size 8 |
57 | # define compare_extable compare_extable_32 | 59 | # define compare_extable compare_extable_32 |
58 | # define do_func do32 | 60 | # define do_func do32 |
59 | # define Elf_Addr Elf32_Addr | 61 | # define Elf_Addr Elf32_Addr |
60 | # define Elf_Ehdr Elf32_Ehdr | 62 | # define Elf_Ehdr Elf32_Ehdr |
61 | # define Elf_Shdr Elf32_Shdr | 63 | # define Elf_Shdr Elf32_Shdr |
62 | # define Elf_Rel Elf32_Rel | 64 | # define Elf_Rel Elf32_Rel |
63 | # define Elf_Rela Elf32_Rela | 65 | # define Elf_Rela Elf32_Rela |
64 | # define Elf_Sym Elf32_Sym | 66 | # define Elf_Sym Elf32_Sym |
65 | # define ELF_R_SYM ELF32_R_SYM | 67 | # define ELF_R_SYM ELF32_R_SYM |
66 | # define Elf_r_sym Elf32_r_sym | 68 | # define Elf_r_sym Elf32_r_sym |
67 | # define ELF_R_INFO ELF32_R_INFO | 69 | # define ELF_R_INFO ELF32_R_INFO |
68 | # define Elf_r_info Elf32_r_info | 70 | # define Elf_r_info Elf32_r_info |
69 | # define ELF_ST_BIND ELF32_ST_BIND | 71 | # define ELF_ST_BIND ELF32_ST_BIND |
70 | # define ELF_ST_TYPE ELF32_ST_TYPE | 72 | # define ELF_ST_TYPE ELF32_ST_TYPE |
71 | # define fn_ELF_R_SYM fn_ELF32_R_SYM | 73 | # define fn_ELF_R_SYM fn_ELF32_R_SYM |
72 | # define fn_ELF_R_INFO fn_ELF32_R_INFO | 74 | # define fn_ELF_R_INFO fn_ELF32_R_INFO |
73 | # define uint_t uint32_t | 75 | # define uint_t uint32_t |
76 | # define _r r | ||
74 | # define _w w | 77 | # define _w w |
75 | #endif | 78 | #endif |
76 | 79 | ||
77 | static int compare_extable(const void *a, const void *b) | 80 | static int compare_extable(const void *a, const void *b) |
78 | { | 81 | { |
79 | const uint_t *aa = a; | 82 | Elf_Addr av = _r(a); |
80 | const uint_t *bb = b; | 83 | Elf_Addr bv = _r(b); |
81 | 84 | ||
82 | if (_w(*aa) < _w(*bb)) | 85 | if (av < bv) |
83 | return -1; | 86 | return -1; |
84 | if (_w(*aa) > _w(*bb)) | 87 | if (av > bv) |
85 | return 1; | 88 | return 1; |
86 | return 0; | 89 | return 0; |
87 | } | 90 | } |
88 | 91 | ||
89 | static void | 92 | static void |
90 | do_func(Elf_Ehdr *const ehdr, char const *const fname) | 93 | do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) |
91 | { | 94 | { |
92 | Elf_Shdr *shdr; | 95 | Elf_Shdr *shdr; |
93 | Elf_Shdr *shstrtab_sec; | 96 | Elf_Shdr *shstrtab_sec; |
94 | Elf_Shdr *strtab_sec = NULL; | 97 | Elf_Shdr *strtab_sec = NULL; |
95 | Elf_Shdr *symtab_sec = NULL; | 98 | Elf_Shdr *symtab_sec = NULL; |
96 | Elf_Shdr *extab_sec = NULL; | 99 | Elf_Shdr *extab_sec = NULL; |
97 | Elf_Sym *sym; | 100 | Elf_Sym *sym; |
98 | Elf_Sym *sort_needed_sym; | 101 | Elf_Sym *sort_needed_sym; |
99 | Elf_Shdr *sort_needed_sec; | 102 | Elf_Shdr *sort_needed_sec; |
103 | Elf_Rel *relocs = NULL; | ||
104 | int relocs_size; | ||
100 | uint32_t *sort_done_location; | 105 | uint32_t *sort_done_location; |
101 | const char *secstrtab; | 106 | const char *secstrtab; |
102 | const char *strtab; | 107 | const char *strtab; |
108 | char *extab_image; | ||
109 | int extab_index = 0; | ||
103 | int i; | 110 | int i; |
104 | int idx; | 111 | int idx; |
105 | 112 | ||
106 | shdr = (Elf_Shdr *)((void *)ehdr + _w(ehdr->e_shoff)); | 113 | shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); |
107 | shstrtab_sec = shdr + w2(ehdr->e_shstrndx); | 114 | shstrtab_sec = shdr + r2(&ehdr->e_shstrndx); |
108 | secstrtab = (const char *)ehdr + _w(shstrtab_sec->sh_offset); | 115 | secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset); |
109 | for (i = 0; i < w2(ehdr->e_shnum); i++) { | 116 | for (i = 0; i < r2(&ehdr->e_shnum); i++) { |
110 | idx = w(shdr[i].sh_name); | 117 | idx = r(&shdr[i].sh_name); |
111 | if (strcmp(secstrtab + idx, "__ex_table") == 0) | 118 | if (strcmp(secstrtab + idx, "__ex_table") == 0) { |
112 | extab_sec = shdr + i; | 119 | extab_sec = shdr + i; |
120 | extab_index = i; | ||
121 | } | ||
122 | if ((r(&shdr[i].sh_type) == SHT_REL || | ||
123 | r(&shdr[i].sh_type) == SHT_RELA) && | ||
124 | r(&shdr[i].sh_info) == extab_index) { | ||
125 | relocs = (void *)ehdr + _r(&shdr[i].sh_offset); | ||
126 | relocs_size = _r(&shdr[i].sh_size); | ||
127 | } | ||
113 | if (strcmp(secstrtab + idx, ".symtab") == 0) | 128 | if (strcmp(secstrtab + idx, ".symtab") == 0) |
114 | symtab_sec = shdr + i; | 129 | symtab_sec = shdr + i; |
115 | if (strcmp(secstrtab + idx, ".strtab") == 0) | 130 | if (strcmp(secstrtab + idx, ".strtab") == 0) |
116 | strtab_sec = shdr + i; | 131 | strtab_sec = shdr + i; |
117 | } | 132 | } |
118 | if (strtab_sec == NULL) { | 133 | if (strtab_sec == NULL) { |
119 | fprintf(stderr, "no .strtab in file: %s\n", fname); | 134 | fprintf(stderr, "no .strtab in file: %s\n", fname); |
120 | fail_file(); | 135 | fail_file(); |
121 | } | 136 | } |
122 | if (symtab_sec == NULL) { | 137 | if (symtab_sec == NULL) { |
123 | fprintf(stderr, "no .symtab in file: %s\n", fname); | 138 | fprintf(stderr, "no .symtab in file: %s\n", fname); |
124 | fail_file(); | 139 | fail_file(); |
125 | } | 140 | } |
126 | if (extab_sec == NULL) { | 141 | if (extab_sec == NULL) { |
127 | fprintf(stderr, "no __ex_table in file: %s\n", fname); | 142 | fprintf(stderr, "no __ex_table in file: %s\n", fname); |
128 | fail_file(); | 143 | fail_file(); |
129 | } | 144 | } |
130 | strtab = (const char *)ehdr + _w(strtab_sec->sh_offset); | 145 | strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); |
131 | 146 | ||
132 | /* Sort the table in place */ | 147 | extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); |
133 | qsort((void *)ehdr + _w(extab_sec->sh_offset), | ||
134 | (_w(extab_sec->sh_size) / extable_ent_size), | ||
135 | extable_ent_size, compare_extable); | ||
136 | 148 | ||
149 | if (custom_sort) { | ||
150 | custom_sort(extab_image, _r(&extab_sec->sh_size)); | ||
151 | } else { | ||
152 | int num_entries = _r(&extab_sec->sh_size) / extable_ent_size; | ||
153 | qsort(extab_image, num_entries, | ||
154 | extable_ent_size, compare_extable); | ||
155 | } | ||
156 | /* If there were relocations, we no longer need them. */ | ||
157 | if (relocs) | ||
158 | memset(relocs, 0, relocs_size); | ||
159 | |||
137 | /* find main_extable_sort_needed */ | 160 | /* find main_extable_sort_needed */ |
138 | sort_needed_sym = NULL; | 161 | sort_needed_sym = NULL; |
139 | for (i = 0; i < _w(symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { | 162 | for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { |
140 | sym = (void *)ehdr + _w(symtab_sec->sh_offset); | 163 | sym = (void *)ehdr + _r(&symtab_sec->sh_offset); |
141 | sym += i; | 164 | sym += i; |
142 | if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) | 165 | if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) |
143 | continue; | 166 | continue; |
144 | idx = w(sym->st_name); | 167 | idx = r(&sym->st_name); |
145 | if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { | 168 | if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { |
146 | sort_needed_sym = sym; | 169 | sort_needed_sym = sym; |
147 | break; | 170 | break; |
148 | } | 171 | } |
149 | } | 172 | } |
150 | if (sort_needed_sym == NULL) { | 173 | if (sort_needed_sym == NULL) { |
151 | fprintf(stderr, | 174 | fprintf(stderr, |
152 | "no main_extable_sort_needed symbol in file: %s\n", | 175 | "no main_extable_sort_needed symbol in file: %s\n", |
153 | fname); | 176 | fname); |
154 | fail_file(); | 177 | fail_file(); |
155 | } | 178 | } |
156 | sort_needed_sec = &shdr[w2(sort_needed_sym->st_shndx)]; | 179 | sort_needed_sec = &shdr[r2(&sort_needed_sym->st_shndx)]; |
157 | sort_done_location = (void *)ehdr + | 180 | sort_done_location = (void *)ehdr + |
158 | _w(sort_needed_sec->sh_offset) + | 181 | _r(&sort_needed_sec->sh_offset) + |
159 | _w(sort_needed_sym->st_value) - | 182 | _r(&sort_needed_sym->st_value) - |
160 | _w(sort_needed_sec->sh_addr); | 183 | _r(&sort_needed_sec->sh_addr); |
161 | 184 | ||
185 | #if 1 | ||
162 | printf("sort done marker at %lx\n", | 186 | printf("sort done marker at %lx\n", |
163 | (unsigned long) (_w(sort_needed_sec->sh_offset) + | 187 | (unsigned long)((char *)sort_done_location - (char *)ehdr)); |
164 | _w(sort_needed_sym->st_value) - | 188 | #endif |
165 | _w(sort_needed_sec->sh_addr))); |