1a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney/*
2a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney * sortextable.c: Sort the kernel's exception table
3a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney *
4d59a16836d917548cf41eda3369936684d527f5fDavid Daney * Copyright 2011 - 2012 Cavium, Inc.
5a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney *
6a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney * Based on code taken from recortmcount.c which is:
7a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney *
8a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
9a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney * Licensed under the GNU General Public License, version 2 (GPLv2).
10a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney *
11a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney * Restructured to fit Linux format, as well as other updates:
12a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney *  Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
13a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney */
14a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
15a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney/*
16a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney * Strategy: alter the vmlinux file in-place.
17a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney */
18a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
19a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include <sys/types.h>
20a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include <sys/mman.h>
21a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include <sys/stat.h>
22a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include <getopt.h>
23a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include <elf.h>
24a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include <fcntl.h>
25a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include <setjmp.h>
26a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include <stdio.h>
27a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include <stdlib.h>
28a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include <string.h>
29a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include <unistd.h>
30a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
31d59a16836d917548cf41eda3369936684d527f5fDavid Daney#include <tools/be_byteshift.h>
32d59a16836d917548cf41eda3369936684d527f5fDavid Daney#include <tools/le_byteshift.h>
33d59a16836d917548cf41eda3369936684d527f5fDavid Daney
34f06d19e460cdd326eff955ca614cb8064bd0a5f2Vineet Gupta#ifndef EM_ARCOMPACT
35f06d19e460cdd326eff955ca614cb8064bd0a5f2Vineet Gupta#define EM_ARCOMPACT	93
36f06d19e460cdd326eff955ca614cb8064bd0a5f2Vineet Gupta#endif
37f06d19e460cdd326eff955ca614cb8064bd0a5f2Vineet Gupta
3825df8198f4b257cf6db4d4f000c53accfa9c28f8Max Filippov#ifndef EM_XTENSA
3925df8198f4b257cf6db4d4f000c53accfa9c28f8Max Filippov#define EM_XTENSA	94
4025df8198f4b257cf6db4d4f000c53accfa9c28f8Max Filippov#endif
4125df8198f4b257cf6db4d4f000c53accfa9c28f8Max Filippov
42adace89562c7a9645b8dc84f6e1ac7ba8756094eWill Deacon#ifndef EM_AARCH64
43adace89562c7a9645b8dc84f6e1ac7ba8756094eWill Deacon#define EM_AARCH64	183
44adace89562c7a9645b8dc84f6e1ac7ba8756094eWill Deacon#endif
45adace89562c7a9645b8dc84f6e1ac7ba8756094eWill Deacon
46372c7209d6a05130b9d867f7ba350dec19e54030Michal Simek#ifndef EM_MICROBLAZE
47372c7209d6a05130b9d867f7ba350dec19e54030Michal Simek#define EM_MICROBLAZE	189
48372c7209d6a05130b9d867f7ba350dec19e54030Michal Simek#endif
49372c7209d6a05130b9d867f7ba350dec19e54030Michal Simek
50a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneystatic int fd_map;	/* File descriptor for file being modified. */
51a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneystatic int mmap_failed; /* Boolean flag. */
52a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneystatic void *ehdr_curr; /* current ElfXX_Ehdr *  for resource cleanup */
53a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneystatic struct stat sb;	/* Remember .st_size, etc. */
54a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneystatic jmp_buf jmpenv;	/* setjmp/longjmp per-file error escape */
55a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
56a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney/* setjmp() return values */
57a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneyenum {
58a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	SJ_SETJMP = 0,  /* hardwired first return */
59a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	SJ_FAIL,
60a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	SJ_SUCCEED
61a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney};
62a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
63a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney/* Per-file resource cleanup when multiple files. */
64a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneystatic void
65a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneycleanup(void)
66a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney{
67a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	if (!mmap_failed)
68a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		munmap(ehdr_curr, sb.st_size);
69a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	close(fd_map);
70a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney}
71a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
72a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneystatic void __attribute__((noreturn))
73a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneyfail_file(void)
74a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney{
75a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	cleanup();
76a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	longjmp(jmpenv, SJ_FAIL);
77a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney}
78a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
79a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney/*
80a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney * Get the whole file as a programming convenience in order to avoid
81a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney * malloc+lseek+read+free of many pieces.  If successful, then mmap
82a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney * avoids copying unused pieces; else just read the whole file.
83a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney * Open for both read and write.
84a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney */
85a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneystatic void *mmap_file(char const *fname)
86a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney{
87a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	void *addr;
88a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
89a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	fd_map = open(fname, O_RDWR);
90a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
91a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		perror(fname);
92a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fail_file();
93a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	}
94a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	if (!S_ISREG(sb.st_mode)) {
95a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fprintf(stderr, "not a regular file: %s\n", fname);
96a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fail_file();
97a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	}
98a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED,
99a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		    fd_map, 0);
100a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	if (addr == MAP_FAILED) {
101a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		mmap_failed = 1;
102a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fprintf(stderr, "Could not mmap file: %s\n", fname);
103a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fail_file();
104a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	}
105a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	return addr;
106a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney}
107a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
108d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic uint64_t r8be(const uint64_t *x)
109a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney{
110d59a16836d917548cf41eda3369936684d527f5fDavid Daney	return get_unaligned_be64(x);
111a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney}
112d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic uint32_t rbe(const uint32_t *x)
113a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney{
114d59a16836d917548cf41eda3369936684d527f5fDavid Daney	return get_unaligned_be32(x);
115a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney}
116d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic uint16_t r2be(const uint16_t *x)
117a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney{
118d59a16836d917548cf41eda3369936684d527f5fDavid Daney	return get_unaligned_be16(x);
119a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney}
120d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic uint64_t r8le(const uint64_t *x)
121a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney{
122d59a16836d917548cf41eda3369936684d527f5fDavid Daney	return get_unaligned_le64(x);
123a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney}
124d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic uint32_t rle(const uint32_t *x)
125d59a16836d917548cf41eda3369936684d527f5fDavid Daney{
126d59a16836d917548cf41eda3369936684d527f5fDavid Daney	return get_unaligned_le32(x);
127d59a16836d917548cf41eda3369936684d527f5fDavid Daney}
128d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic uint16_t r2le(const uint16_t *x)
129a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney{
130d59a16836d917548cf41eda3369936684d527f5fDavid Daney	return get_unaligned_le16(x);
131a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney}
132a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
133d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic void w8be(uint64_t val, uint64_t *x)
134d59a16836d917548cf41eda3369936684d527f5fDavid Daney{
135d59a16836d917548cf41eda3369936684d527f5fDavid Daney	put_unaligned_be64(val, x);
136d59a16836d917548cf41eda3369936684d527f5fDavid Daney}
137d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic void wbe(uint32_t val, uint32_t *x)
138d59a16836d917548cf41eda3369936684d527f5fDavid Daney{
139d59a16836d917548cf41eda3369936684d527f5fDavid Daney	put_unaligned_be32(val, x);
140d59a16836d917548cf41eda3369936684d527f5fDavid Daney}
141d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic void w2be(uint16_t val, uint16_t *x)
142d59a16836d917548cf41eda3369936684d527f5fDavid Daney{
143d59a16836d917548cf41eda3369936684d527f5fDavid Daney	put_unaligned_be16(val, x);
144d59a16836d917548cf41eda3369936684d527f5fDavid Daney}
145d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic void w8le(uint64_t val, uint64_t *x)
146d59a16836d917548cf41eda3369936684d527f5fDavid Daney{
147d59a16836d917548cf41eda3369936684d527f5fDavid Daney	put_unaligned_le64(val, x);
148d59a16836d917548cf41eda3369936684d527f5fDavid Daney}
149d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic void wle(uint32_t val, uint32_t *x)
150d59a16836d917548cf41eda3369936684d527f5fDavid Daney{
151d59a16836d917548cf41eda3369936684d527f5fDavid Daney	put_unaligned_le32(val, x);
152d59a16836d917548cf41eda3369936684d527f5fDavid Daney}
153d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic void w2le(uint16_t val, uint16_t *x)
154a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney{
155d59a16836d917548cf41eda3369936684d527f5fDavid Daney	put_unaligned_le16(val, x);
156a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney}
157a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
158d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic uint64_t (*r8)(const uint64_t *);
159d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic uint32_t (*r)(const uint32_t *);
160d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic uint16_t (*r2)(const uint16_t *);
161d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic void (*w8)(uint64_t, uint64_t *);
162d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic void (*w)(uint32_t, uint32_t *);
163d59a16836d917548cf41eda3369936684d527f5fDavid Daneystatic void (*w2)(uint16_t, uint16_t *);
164a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
165d59a16836d917548cf41eda3369936684d527f5fDavid Daneytypedef void (*table_sort_t)(char *, int);
166a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
16759c36455d061e200f386e1817362f6afd6265b6aJamie Iles/*
16859c36455d061e200f386e1817362f6afd6265b6aJamie Iles * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
16959c36455d061e200f386e1817362f6afd6265b6aJamie Iles * the way to -256..-1, to avoid conflicting with real section
17059c36455d061e200f386e1817362f6afd6265b6aJamie Iles * indices.
17159c36455d061e200f386e1817362f6afd6265b6aJamie Iles */
17259c36455d061e200f386e1817362f6afd6265b6aJamie Iles#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))
17359c36455d061e200f386e1817362f6afd6265b6aJamie Iles
17459c36455d061e200f386e1817362f6afd6265b6aJamie Ilesstatic inline int is_shndx_special(unsigned int i)
17559c36455d061e200f386e1817362f6afd6265b6aJamie Iles{
17659c36455d061e200f386e1817362f6afd6265b6aJamie Iles	return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
17759c36455d061e200f386e1817362f6afd6265b6aJamie Iles}
17859c36455d061e200f386e1817362f6afd6265b6aJamie Iles
17959c36455d061e200f386e1817362f6afd6265b6aJamie Iles/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
18059c36455d061e200f386e1817362f6afd6265b6aJamie Ilesstatic inline unsigned int get_secindex(unsigned int shndx,
18159c36455d061e200f386e1817362f6afd6265b6aJamie Iles					unsigned int sym_offs,
18259c36455d061e200f386e1817362f6afd6265b6aJamie Iles					const Elf32_Word *symtab_shndx_start)
18359c36455d061e200f386e1817362f6afd6265b6aJamie Iles{
18459c36455d061e200f386e1817362f6afd6265b6aJamie Iles	if (is_shndx_special(shndx))
18559c36455d061e200f386e1817362f6afd6265b6aJamie Iles		return SPECIAL(shndx);
18659c36455d061e200f386e1817362f6afd6265b6aJamie Iles	if (shndx != SHN_XINDEX)
18759c36455d061e200f386e1817362f6afd6265b6aJamie Iles		return shndx;
18859c36455d061e200f386e1817362f6afd6265b6aJamie Iles	return r(&symtab_shndx_start[sym_offs]);
18959c36455d061e200f386e1817362f6afd6265b6aJamie Iles}
19059c36455d061e200f386e1817362f6afd6265b6aJamie Iles
191a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney/* 32 bit and 64 bit are very similar */
192a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include "sortextable.h"
193a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#define SORTEXTABLE_64
194a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney#include "sortextable.h"
195a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
196eb608fb366de123a97227437e5306f731f4a63c5Heiko Carstensstatic int compare_relative_table(const void *a, const void *b)
197d59a16836d917548cf41eda3369936684d527f5fDavid Daney{
198d59a16836d917548cf41eda3369936684d527f5fDavid Daney	int32_t av = (int32_t)r(a);
199d59a16836d917548cf41eda3369936684d527f5fDavid Daney	int32_t bv = (int32_t)r(b);
200d59a16836d917548cf41eda3369936684d527f5fDavid Daney
201d59a16836d917548cf41eda3369936684d527f5fDavid Daney	if (av < bv)
202d59a16836d917548cf41eda3369936684d527f5fDavid Daney		return -1;
203d59a16836d917548cf41eda3369936684d527f5fDavid Daney	if (av > bv)
204d59a16836d917548cf41eda3369936684d527f5fDavid Daney		return 1;
205d59a16836d917548cf41eda3369936684d527f5fDavid Daney	return 0;
206d59a16836d917548cf41eda3369936684d527f5fDavid Daney}
207d59a16836d917548cf41eda3369936684d527f5fDavid Daney
208eb608fb366de123a97227437e5306f731f4a63c5Heiko Carstensstatic void sort_relative_table(char *extab_image, int image_size)
209d59a16836d917548cf41eda3369936684d527f5fDavid Daney{
210d59a16836d917548cf41eda3369936684d527f5fDavid Daney	int i;
211d59a16836d917548cf41eda3369936684d527f5fDavid Daney
212d59a16836d917548cf41eda3369936684d527f5fDavid Daney	/*
213d59a16836d917548cf41eda3369936684d527f5fDavid Daney	 * Do the same thing the runtime sort does, first normalize to
214d59a16836d917548cf41eda3369936684d527f5fDavid Daney	 * being relative to the start of the section.
215d59a16836d917548cf41eda3369936684d527f5fDavid Daney	 */
216d59a16836d917548cf41eda3369936684d527f5fDavid Daney	i = 0;
217d59a16836d917548cf41eda3369936684d527f5fDavid Daney	while (i < image_size) {
218d59a16836d917548cf41eda3369936684d527f5fDavid Daney		uint32_t *loc = (uint32_t *)(extab_image + i);
219d59a16836d917548cf41eda3369936684d527f5fDavid Daney		w(r(loc) + i, loc);
220d59a16836d917548cf41eda3369936684d527f5fDavid Daney		i += 4;
221d59a16836d917548cf41eda3369936684d527f5fDavid Daney	}
222d59a16836d917548cf41eda3369936684d527f5fDavid Daney
223eb608fb366de123a97227437e5306f731f4a63c5Heiko Carstens	qsort(extab_image, image_size / 8, 8, compare_relative_table);
224d59a16836d917548cf41eda3369936684d527f5fDavid Daney
225d59a16836d917548cf41eda3369936684d527f5fDavid Daney	/* Now denormalize. */
226d59a16836d917548cf41eda3369936684d527f5fDavid Daney	i = 0;
227d59a16836d917548cf41eda3369936684d527f5fDavid Daney	while (i < image_size) {
228d59a16836d917548cf41eda3369936684d527f5fDavid Daney		uint32_t *loc = (uint32_t *)(extab_image + i);
229d59a16836d917548cf41eda3369936684d527f5fDavid Daney		w(r(loc) - i, loc);
230d59a16836d917548cf41eda3369936684d527f5fDavid Daney		i += 4;
231d59a16836d917548cf41eda3369936684d527f5fDavid Daney	}
232d59a16836d917548cf41eda3369936684d527f5fDavid Daney}
233a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
234a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneystatic void
235a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneydo_file(char const *const fname)
236a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney{
237d59a16836d917548cf41eda3369936684d527f5fDavid Daney	table_sort_t custom_sort;
238d59a16836d917548cf41eda3369936684d527f5fDavid Daney	Elf32_Ehdr *ehdr = mmap_file(fname);
239a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
240a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	ehdr_curr = ehdr;
241a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	switch (ehdr->e_ident[EI_DATA]) {
242a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	default:
243a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
244a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			ehdr->e_ident[EI_DATA], fname);
245a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fail_file();
246a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		break;
247a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	case ELFDATA2LSB:
248d59a16836d917548cf41eda3369936684d527f5fDavid Daney		r = rle;
249d59a16836d917548cf41eda3369936684d527f5fDavid Daney		r2 = r2le;
250d59a16836d917548cf41eda3369936684d527f5fDavid Daney		r8 = r8le;
251d59a16836d917548cf41eda3369936684d527f5fDavid Daney		w = wle;
252d59a16836d917548cf41eda3369936684d527f5fDavid Daney		w2 = w2le;
253d59a16836d917548cf41eda3369936684d527f5fDavid Daney		w8 = w8le;
254a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		break;
255a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	case ELFDATA2MSB:
256d59a16836d917548cf41eda3369936684d527f5fDavid Daney		r = rbe;
257d59a16836d917548cf41eda3369936684d527f5fDavid Daney		r2 = r2be;
258d59a16836d917548cf41eda3369936684d527f5fDavid Daney		r8 = r8be;
259d59a16836d917548cf41eda3369936684d527f5fDavid Daney		w = wbe;
260d59a16836d917548cf41eda3369936684d527f5fDavid Daney		w2 = w2be;
261d59a16836d917548cf41eda3369936684d527f5fDavid Daney		w8 = w8be;
262a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		break;
263a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	}  /* end switch */
264a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
265d59a16836d917548cf41eda3369936684d527f5fDavid Daney	||  r2(&ehdr->e_type) != ET_EXEC
266a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	||  ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
267a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname);
268a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fail_file();
269a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	}
270a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
271d59a16836d917548cf41eda3369936684d527f5fDavid Daney	custom_sort = NULL;
272d59a16836d917548cf41eda3369936684d527f5fDavid Daney	switch (r2(&ehdr->e_machine)) {
273a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	default:
274a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fprintf(stderr, "unrecognized e_machine %d %s\n",
275d59a16836d917548cf41eda3369936684d527f5fDavid Daney			r2(&ehdr->e_machine), fname);
276a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fail_file();
277a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		break;
278a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	case EM_386:
279a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	case EM_X86_64:
2803193a98dc8777815803738fdae654c6ba0feee76Heiko Carstens	case EM_S390:
281eb608fb366de123a97227437e5306f731f4a63c5Heiko Carstens		custom_sort = sort_relative_table;
282eb608fb366de123a97227437e5306f731f4a63c5Heiko Carstens		break;
283f06d19e460cdd326eff955ca614cb8064bd0a5f2Vineet Gupta	case EM_ARCOMPACT:
284ee951c630c5ce5108f8014ce1c9d738b5bbfea60Stephen Boyd	case EM_ARM:
285adace89562c7a9645b8dc84f6e1ac7ba8756094eWill Deacon	case EM_AARCH64:
286372c7209d6a05130b9d867f7ba350dec19e54030Michal Simek	case EM_MICROBLAZE:
287d59a16836d917548cf41eda3369936684d527f5fDavid Daney	case EM_MIPS:
28825df8198f4b257cf6db4d4f000c53accfa9c28f8Max Filippov	case EM_XTENSA:
289a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		break;
290a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	}  /* end switch */
291a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
292a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	switch (ehdr->e_ident[EI_CLASS]) {
293a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	default:
294a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fprintf(stderr, "unrecognized ELF class %d %s\n",
295a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			ehdr->e_ident[EI_CLASS], fname);
296a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fail_file();
297a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		break;
298a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	case ELFCLASS32:
299d59a16836d917548cf41eda3369936684d527f5fDavid Daney		if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
300d59a16836d917548cf41eda3369936684d527f5fDavid Daney		||  r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
301a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			fprintf(stderr,
302a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney				"unrecognized ET_EXEC file: %s\n", fname);
303a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			fail_file();
304a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		}
305d59a16836d917548cf41eda3369936684d527f5fDavid Daney		do32(ehdr, fname, custom_sort);
306a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		break;
307a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	case ELFCLASS64: {
308a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
309d59a16836d917548cf41eda3369936684d527f5fDavid Daney		if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
310d59a16836d917548cf41eda3369936684d527f5fDavid Daney		||  r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
311a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			fprintf(stderr,
312a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney				"unrecognized ET_EXEC file: %s\n", fname);
313a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			fail_file();
314a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		}
315d59a16836d917548cf41eda3369936684d527f5fDavid Daney		do64(ghdr, fname, custom_sort);
316a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		break;
317a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	}
318a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	}  /* end switch */
319a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
320a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	cleanup();
321a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney}
322a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
323a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneyint
324a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daneymain(int argc, char *argv[])
325a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney{
326a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	int n_error = 0;  /* gcc-4.3.0 false positive complaint */
327a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	int i;
328a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
329a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	if (argc < 2) {
330a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		fprintf(stderr, "usage: sortextable vmlinux...\n");
331a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		return 0;
332a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	}
333a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
334a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	/* Process each file in turn, allowing deep failure. */
335a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	for (i = 1; i < argc; i++) {
336a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		char *file = argv[i];
337a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		int const sjval = setjmp(jmpenv);
338a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney
339a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		switch (sjval) {
340a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		default:
341a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			fprintf(stderr, "internal error: %s\n", file);
342a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			exit(1);
343a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			break;
344a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		case SJ_SETJMP:    /* normal sequence */
345a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			/* Avoid problems if early cleanup() */
346a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			fd_map = -1;
347a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			ehdr_curr = NULL;
348a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			mmap_failed = 1;
349a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			do_file(file);
350a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			break;
351a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		case SJ_FAIL:    /* error in do_file or below */
352a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			++n_error;
353a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			break;
354a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		case SJ_SUCCEED:    /* premature success */
355a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			/* do nothing */
356a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney			break;
357a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney		}  /* end switch */
358a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	}
359a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney	return !!n_error;
360a79f248b9b309ebb5f34ca6a8fd1eb9e18db5720David Daney}
361