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