]>
Commit | Line | Data |
---|---|---|
4317cf95 | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
a79f248b DD |
2 | /* |
3 | * sortextable.h | |
4 | * | |
d59a1683 | 5 | * Copyright 2011 - 2012 Cavium, Inc. |
a79f248b DD |
6 | * |
7 | * Some of this code was taken out of recordmcount.h written by: | |
8 | * | |
9 | * Copyright 2009 John F. Reiser <[email protected]>. All rights reserved. | |
10 | * Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc. | |
a79f248b DD |
11 | */ |
12 | ||
13 | #undef extable_ent_size | |
14 | #undef compare_extable | |
15 | #undef do_func | |
16 | #undef Elf_Addr | |
17 | #undef Elf_Ehdr | |
18 | #undef Elf_Shdr | |
19 | #undef Elf_Rel | |
20 | #undef Elf_Rela | |
21 | #undef Elf_Sym | |
22 | #undef ELF_R_SYM | |
23 | #undef Elf_r_sym | |
24 | #undef ELF_R_INFO | |
25 | #undef Elf_r_info | |
26 | #undef ELF_ST_BIND | |
27 | #undef ELF_ST_TYPE | |
28 | #undef fn_ELF_R_SYM | |
29 | #undef fn_ELF_R_INFO | |
30 | #undef uint_t | |
d59a1683 | 31 | #undef _r |
a79f248b DD |
32 | #undef _w |
33 | ||
34 | #ifdef SORTEXTABLE_64 | |
35 | # define extable_ent_size 16 | |
36 | # define compare_extable compare_extable_64 | |
37 | # define do_func do64 | |
38 | # define Elf_Addr Elf64_Addr | |
39 | # define Elf_Ehdr Elf64_Ehdr | |
40 | # define Elf_Shdr Elf64_Shdr | |
41 | # define Elf_Rel Elf64_Rel | |
42 | # define Elf_Rela Elf64_Rela | |
43 | # define Elf_Sym Elf64_Sym | |
44 | # define ELF_R_SYM ELF64_R_SYM | |
45 | # define Elf_r_sym Elf64_r_sym | |
46 | # define ELF_R_INFO ELF64_R_INFO | |
47 | # define Elf_r_info Elf64_r_info | |
48 | # define ELF_ST_BIND ELF64_ST_BIND | |
49 | # define ELF_ST_TYPE ELF64_ST_TYPE | |
50 | # define fn_ELF_R_SYM fn_ELF64_R_SYM | |
51 | # define fn_ELF_R_INFO fn_ELF64_R_INFO | |
52 | # define uint_t uint64_t | |
d59a1683 | 53 | # define _r r8 |
a79f248b DD |
54 | # define _w w8 |
55 | #else | |
56 | # define extable_ent_size 8 | |
57 | # define compare_extable compare_extable_32 | |
58 | # define do_func do32 | |
59 | # define Elf_Addr Elf32_Addr | |
60 | # define Elf_Ehdr Elf32_Ehdr | |
61 | # define Elf_Shdr Elf32_Shdr | |
62 | # define Elf_Rel Elf32_Rel | |
63 | # define Elf_Rela Elf32_Rela | |
64 | # define Elf_Sym Elf32_Sym | |
65 | # define ELF_R_SYM ELF32_R_SYM | |
66 | # define Elf_r_sym Elf32_r_sym | |
67 | # define ELF_R_INFO ELF32_R_INFO | |
68 | # define Elf_r_info Elf32_r_info | |
69 | # define ELF_ST_BIND ELF32_ST_BIND | |
70 | # define ELF_ST_TYPE ELF32_ST_TYPE | |
71 | # define fn_ELF_R_SYM fn_ELF32_R_SYM | |
72 | # define fn_ELF_R_INFO fn_ELF32_R_INFO | |
73 | # define uint_t uint32_t | |
d59a1683 | 74 | # define _r r |
a79f248b DD |
75 | # define _w w |
76 | #endif | |
77 | ||
78 | static int compare_extable(const void *a, const void *b) | |
79 | { | |
d59a1683 DD |
80 | Elf_Addr av = _r(a); |
81 | Elf_Addr bv = _r(b); | |
a79f248b | 82 | |
d59a1683 | 83 | if (av < bv) |
a79f248b | 84 | return -1; |
d59a1683 | 85 | if (av > bv) |
a79f248b DD |
86 | return 1; |
87 | return 0; | |
88 | } | |
89 | ||
90 | static void | |
d59a1683 | 91 | do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) |
a79f248b DD |
92 | { |
93 | Elf_Shdr *shdr; | |
94 | Elf_Shdr *shstrtab_sec; | |
95 | Elf_Shdr *strtab_sec = NULL; | |
96 | Elf_Shdr *symtab_sec = NULL; | |
97 | Elf_Shdr *extab_sec = NULL; | |
98 | Elf_Sym *sym; | |
59c36455 JI |
99 | const Elf_Sym *symtab; |
100 | Elf32_Word *symtab_shndx_start = NULL; | |
a79f248b DD |
101 | Elf_Sym *sort_needed_sym; |
102 | Elf_Shdr *sort_needed_sec; | |
d59a1683 | 103 | Elf_Rel *relocs = NULL; |
7cbc0ea7 | 104 | int relocs_size = 0; |
a79f248b DD |
105 | uint32_t *sort_done_location; |
106 | const char *secstrtab; | |
107 | const char *strtab; | |
d59a1683 DD |
108 | char *extab_image; |
109 | int extab_index = 0; | |
a79f248b DD |
110 | int i; |
111 | int idx; | |
59c36455 JI |
112 | unsigned int num_sections; |
113 | unsigned int secindex_strings; | |
a79f248b | 114 | |
d59a1683 | 115 | shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); |
59c36455 JI |
116 | |
117 | num_sections = r2(&ehdr->e_shnum); | |
118 | if (num_sections == SHN_UNDEF) | |
119 | num_sections = _r(&shdr[0].sh_size); | |
120 | ||
121 | secindex_strings = r2(&ehdr->e_shstrndx); | |
122 | if (secindex_strings == SHN_XINDEX) | |
123 | secindex_strings = r(&shdr[0].sh_link); | |
124 | ||
125 | shstrtab_sec = shdr + secindex_strings; | |
d59a1683 | 126 | secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset); |
59c36455 | 127 | for (i = 0; i < num_sections; i++) { |
d59a1683 DD |
128 | idx = r(&shdr[i].sh_name); |
129 | if (strcmp(secstrtab + idx, "__ex_table") == 0) { | |
a79f248b | 130 | extab_sec = shdr + i; |
d59a1683 DD |
131 | extab_index = i; |
132 | } | |
133 | if ((r(&shdr[i].sh_type) == SHT_REL || | |
134 | r(&shdr[i].sh_type) == SHT_RELA) && | |
135 | r(&shdr[i].sh_info) == extab_index) { | |
136 | relocs = (void *)ehdr + _r(&shdr[i].sh_offset); | |
137 | relocs_size = _r(&shdr[i].sh_size); | |
138 | } | |
a79f248b DD |
139 | if (strcmp(secstrtab + idx, ".symtab") == 0) |
140 | symtab_sec = shdr + i; | |
141 | if (strcmp(secstrtab + idx, ".strtab") == 0) | |
142 | strtab_sec = shdr + i; | |
59c36455 JI |
143 | if (r(&shdr[i].sh_type) == SHT_SYMTAB_SHNDX) |
144 | symtab_shndx_start = (Elf32_Word *)( | |
145 | (const char *)ehdr + _r(&shdr[i].sh_offset)); | |
a79f248b DD |
146 | } |
147 | if (strtab_sec == NULL) { | |
148 | fprintf(stderr, "no .strtab in file: %s\n", fname); | |
149 | fail_file(); | |
150 | } | |
151 | if (symtab_sec == NULL) { | |
152 | fprintf(stderr, "no .symtab in file: %s\n", fname); | |
153 | fail_file(); | |
154 | } | |
59c36455 JI |
155 | symtab = (const Elf_Sym *)((const char *)ehdr + |
156 | _r(&symtab_sec->sh_offset)); | |
a79f248b DD |
157 | if (extab_sec == NULL) { |
158 | fprintf(stderr, "no __ex_table in file: %s\n", fname); | |
159 | fail_file(); | |
160 | } | |
d59a1683 | 161 | strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); |
a79f248b | 162 | |
d59a1683 DD |
163 | extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); |
164 | ||
165 | if (custom_sort) { | |
166 | custom_sort(extab_image, _r(&extab_sec->sh_size)); | |
167 | } else { | |
168 | int num_entries = _r(&extab_sec->sh_size) / extable_ent_size; | |
169 | qsort(extab_image, num_entries, | |
170 | extable_ent_size, compare_extable); | |
171 | } | |
172 | /* If there were relocations, we no longer need them. */ | |
173 | if (relocs) | |
174 | memset(relocs, 0, relocs_size); | |
a79f248b DD |
175 | |
176 | /* find main_extable_sort_needed */ | |
177 | sort_needed_sym = NULL; | |
d59a1683 DD |
178 | for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { |
179 | sym = (void *)ehdr + _r(&symtab_sec->sh_offset); | |
a79f248b DD |
180 | sym += i; |
181 | if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) | |
182 | continue; | |
d59a1683 | 183 | idx = r(&sym->st_name); |
a79f248b DD |
184 | if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { |
185 | sort_needed_sym = sym; | |
186 | break; | |
187 | } | |
188 | } | |
189 | if (sort_needed_sym == NULL) { | |
190 | fprintf(stderr, | |
191 | "no main_extable_sort_needed symbol in file: %s\n", | |
192 | fname); | |
193 | fail_file(); | |
194 | } | |
59c36455 JI |
195 | sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), |
196 | sort_needed_sym - symtab, | |
197 | symtab_shndx_start)]; | |
a79f248b | 198 | sort_done_location = (void *)ehdr + |
d59a1683 DD |
199 | _r(&sort_needed_sec->sh_offset) + |
200 | _r(&sort_needed_sym->st_value) - | |
201 | _r(&sort_needed_sec->sh_addr); | |
a79f248b | 202 | |
8c0c774d | 203 | #if 0 |
a79f248b | 204 | printf("sort done marker at %lx\n", |
d59a1683 DD |
205 | (unsigned long)((char *)sort_done_location - (char *)ehdr)); |
206 | #endif | |
a79f248b | 207 | /* We sorted it, clear the flag. */ |
d59a1683 | 208 | w(0, sort_done_location); |
a79f248b | 209 | } |