diff options
Diffstat (limited to 'scripts/sortextable.h')
-rw-r--r-- | scripts/sortextable.h | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/scripts/sortextable.h b/scripts/sortextable.h new file mode 100644 index 000000000000..e4fd45b7e456 --- /dev/null +++ b/scripts/sortextable.h | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * sortextable.h | ||
3 | * | ||
4 | * Copyright 2011 - 2012 Cavium, Inc. | ||
5 | * | ||
6 | * Some of this code was taken out of recordmcount.h written by: | ||
7 | * | ||
8 | * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. | ||
9 | * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. | ||
10 | * | ||
11 | * | ||
12 | * Licensed under the GNU General Public License, version 2 (GPLv2). | ||
13 | */ | ||
14 | |||
15 | #undef extable_ent_size | ||
16 | #undef compare_extable | ||
17 | #undef do_func | ||
18 | #undef Elf_Addr | ||
19 | #undef Elf_Ehdr | ||
20 | #undef Elf_Shdr | ||
21 | #undef Elf_Rel | ||
22 | #undef Elf_Rela | ||
23 | #undef Elf_Sym | ||
24 | #undef ELF_R_SYM | ||
25 | #undef Elf_r_sym | ||
26 | #undef ELF_R_INFO | ||
27 | #undef Elf_r_info | ||
28 | #undef ELF_ST_BIND | ||
29 | #undef ELF_ST_TYPE | ||
30 | #undef fn_ELF_R_SYM | ||
31 | #undef fn_ELF_R_INFO | ||
32 | #undef uint_t | ||
33 | #undef _r | ||
34 | #undef _w | ||
35 | |||
36 | #ifdef SORTEXTABLE_64 | ||
37 | # define extable_ent_size 16 | ||
38 | # define compare_extable compare_extable_64 | ||
39 | # define do_func do64 | ||
40 | # define Elf_Addr Elf64_Addr | ||
41 | # define Elf_Ehdr Elf64_Ehdr | ||
42 | # define Elf_Shdr Elf64_Shdr | ||
43 | # define Elf_Rel Elf64_Rel | ||
44 | # define Elf_Rela Elf64_Rela | ||
45 | # define Elf_Sym Elf64_Sym | ||
46 | # define ELF_R_SYM ELF64_R_SYM | ||
47 | # define Elf_r_sym Elf64_r_sym | ||
48 | # define ELF_R_INFO ELF64_R_INFO | ||
49 | # define Elf_r_info Elf64_r_info | ||
50 | # define ELF_ST_BIND ELF64_ST_BIND | ||
51 | # define ELF_ST_TYPE ELF64_ST_TYPE | ||
52 | # define fn_ELF_R_SYM fn_ELF64_R_SYM | ||
53 | # define fn_ELF_R_INFO fn_ELF64_R_INFO | ||
54 | # define uint_t uint64_t | ||
55 | # define _r r8 | ||
56 | # define _w w8 | ||
57 | #else | ||
58 | # define extable_ent_size 8 | ||
59 | # define compare_extable compare_extable_32 | ||
60 | # define do_func do32 | ||
61 | # define Elf_Addr Elf32_Addr | ||
62 | # define Elf_Ehdr Elf32_Ehdr | ||
63 | # define Elf_Shdr Elf32_Shdr | ||
64 | # define Elf_Rel Elf32_Rel | ||
65 | # define Elf_Rela Elf32_Rela | ||
66 | # define Elf_Sym Elf32_Sym | ||
67 | # define ELF_R_SYM ELF32_R_SYM | ||
68 | # define Elf_r_sym Elf32_r_sym | ||
69 | # define ELF_R_INFO ELF32_R_INFO | ||
70 | # define Elf_r_info Elf32_r_info | ||
71 | # define ELF_ST_BIND ELF32_ST_BIND | ||
72 | # define ELF_ST_TYPE ELF32_ST_TYPE | ||
73 | # define fn_ELF_R_SYM fn_ELF32_R_SYM | ||
74 | # define fn_ELF_R_INFO fn_ELF32_R_INFO | ||
75 | # define uint_t uint32_t | ||
76 | # define _r r | ||
77 | # define _w w | ||
78 | #endif | ||
79 | |||
80 | static int compare_extable(const void *a, const void *b) | ||
81 | { | ||
82 | Elf_Addr av = _r(a); | ||
83 | Elf_Addr bv = _r(b); | ||
84 | |||
85 | if (av < bv) | ||
86 | return -1; | ||
87 | if (av > bv) | ||
88 | return 1; | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static void | ||
93 | do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) | ||
94 | { | ||
95 | Elf_Shdr *shdr; | ||
96 | Elf_Shdr *shstrtab_sec; | ||
97 | Elf_Shdr *strtab_sec = NULL; | ||
98 | Elf_Shdr *symtab_sec = NULL; | ||
99 | Elf_Shdr *extab_sec = NULL; | ||
100 | Elf_Sym *sym; | ||
101 | Elf_Sym *sort_needed_sym; | ||
102 | Elf_Shdr *sort_needed_sec; | ||
103 | Elf_Rel *relocs = NULL; | ||
104 | int relocs_size; | ||
105 | uint32_t *sort_done_location; | ||
106 | const char *secstrtab; | ||
107 | const char *strtab; | ||
108 | char *extab_image; | ||
109 | int extab_index = 0; | ||
110 | int i; | ||
111 | int idx; | ||
112 | |||
113 | shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); | ||
114 | shstrtab_sec = shdr + r2(&ehdr->e_shstrndx); | ||
115 | secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset); | ||
116 | for (i = 0; i < r2(&ehdr->e_shnum); i++) { | ||
117 | idx = r(&shdr[i].sh_name); | ||
118 | if (strcmp(secstrtab + idx, "__ex_table") == 0) { | ||
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 | } | ||
128 | if (strcmp(secstrtab + idx, ".symtab") == 0) | ||
129 | symtab_sec = shdr + i; | ||
130 | if (strcmp(secstrtab + idx, ".strtab") == 0) | ||
131 | strtab_sec = shdr + i; | ||
132 | } | ||
133 | if (strtab_sec == NULL) { | ||
134 | fprintf(stderr, "no .strtab in file: %s\n", fname); | ||
135 | fail_file(); | ||
136 | } | ||
137 | if (symtab_sec == NULL) { | ||
138 | fprintf(stderr, "no .symtab in file: %s\n", fname); | ||
139 | fail_file(); | ||
140 | } | ||
141 | if (extab_sec == NULL) { | ||
142 | fprintf(stderr, "no __ex_table in file: %s\n", fname); | ||
143 | fail_file(); | ||
144 | } | ||
145 | strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); | ||
146 | |||
147 | extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); | ||
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 | |||
160 | /* find main_extable_sort_needed */ | ||
161 | sort_needed_sym = NULL; | ||
162 | for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { | ||
163 | sym = (void *)ehdr + _r(&symtab_sec->sh_offset); | ||
164 | sym += i; | ||
165 | if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) | ||
166 | continue; | ||
167 | idx = r(&sym->st_name); | ||
168 | if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { | ||
169 | sort_needed_sym = sym; | ||
170 | break; | ||
171 | } | ||
172 | } | ||
173 | if (sort_needed_sym == NULL) { | ||
174 | fprintf(stderr, | ||
175 | "no main_extable_sort_needed symbol in file: %s\n", | ||
176 | fname); | ||
177 | fail_file(); | ||
178 | } | ||
179 | sort_needed_sec = &shdr[r2(&sort_needed_sym->st_shndx)]; | ||
180 | sort_done_location = (void *)ehdr + | ||
181 | _r(&sort_needed_sec->sh_offset) + | ||
182 | _r(&sort_needed_sym->st_value) - | ||
183 | _r(&sort_needed_sec->sh_addr); | ||
184 | |||
185 | #if 1 | ||
186 | printf("sort done marker at %lx\n", | ||
187 | (unsigned long)((char *)sort_done_location - (char *)ehdr)); | ||
188 | #endif | ||
189 | /* We sorted it, clear the flag. */ | ||
190 | w(0, sort_done_location); | ||
191 | } | ||