Root/scripts/sortextable.c

Source at commit cdde9cf73945d547acd3e96f9508c79e84ad0bf1 created 9 years 4 months ago.
By Maarten ter Huurne, MMC: JZ4740: Added support for CPU frequency changing
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_S390:
251    case EM_MIPS:
252        break;
253    } /* end switch */
254
255    switch (ehdr->e_ident[EI_CLASS]) {
256    default:
257        fprintf(stderr, "unrecognized ELF class %d %s\n",
258            ehdr->e_ident[EI_CLASS], fname);
259        fail_file();
260        break;
261    case ELFCLASS32:
262        if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
263        || r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
264            fprintf(stderr,
265                "unrecognized ET_EXEC file: %s\n", fname);
266            fail_file();
267        }
268        do32(ehdr, fname, custom_sort);
269        break;
270    case ELFCLASS64: {
271        Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
272        if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
273        || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
274            fprintf(stderr,
275                "unrecognized ET_EXEC file: %s\n", fname);
276            fail_file();
277        }
278        do64(ghdr, fname, custom_sort);
279        break;
280    }
281    } /* end switch */
282
283    cleanup();
284}
285
286int
287main(int argc, char *argv[])
288{
289    int n_error = 0; /* gcc-4.3.0 false positive complaint */
290    int i;
291
292    if (argc < 2) {
293        fprintf(stderr, "usage: sortextable vmlinux...\n");
294        return 0;
295    }
296
297    /* Process each file in turn, allowing deep failure. */
298    for (i = 1; i < argc; i++) {
299        char *file = argv[i];
300        int const sjval = setjmp(jmpenv);
301
302        switch (sjval) {
303        default:
304            fprintf(stderr, "internal error: %s\n", file);
305            exit(1);
306            break;
307        case SJ_SETJMP: /* normal sequence */
308            /* Avoid problems if early cleanup() */
309            fd_map = -1;
310            ehdr_curr = NULL;
311            mmap_failed = 1;
312            do_file(file);
313            break;
314        case SJ_FAIL: /* error in do_file or below */
315            ++n_error;
316            break;
317        case SJ_SUCCEED: /* premature success */
318            /* do nothing */
319            break;
320        } /* end switch */
321    }
322    return !!n_error;
323}
324

Archive Download this file



interactive