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 | * | |
6402e141 | 9 | * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. |
a79f248b | 10 | * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. |
a79f248b DD |
11 | */ |
12 | ||
13 | #undef extable_ent_size | |
14 | #undef compare_extable | |
57cafdf2 | 15 | #undef do_sort |
a79f248b DD |
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 | |
57cafdf2 | 37 | # define do_sort do_sort_64 |
a79f248b DD |
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 | |
57cafdf2 | 58 | # define do_sort do_sort_32 |
a79f248b DD |
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 | ||
57cafdf2 | 90 | static int do_sort(Elf_Ehdr *ehdr, |
6402e141 SZ |
91 | char const *const fname, |
92 | table_sort_t custom_sort) | |
a79f248b | 93 | { |
57cafdf2 | 94 | Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); |
a79f248b DD |
95 | Elf_Shdr *strtab_sec = NULL; |
96 | Elf_Shdr *symtab_sec = NULL; | |
97 | Elf_Shdr *extab_sec = NULL; | |
98 | Elf_Sym *sym; | |
59c36455 | 99 | const Elf_Sym *symtab; |
57cafdf2 SZ |
100 | Elf32_Word *symtab_shndx = NULL; |
101 | Elf_Sym *sort_needed_sym = NULL; | |
a79f248b | 102 | Elf_Shdr *sort_needed_sec; |
d59a1683 | 103 | Elf_Rel *relocs = NULL; |
7cbc0ea7 | 104 | int relocs_size = 0; |
57cafdf2 SZ |
105 | uint32_t *sort_needed_loc; |
106 | const char *secstrings; | |
a79f248b | 107 | const char *strtab; |
d59a1683 DD |
108 | char *extab_image; |
109 | int extab_index = 0; | |
a79f248b DD |
110 | int i; |
111 | int idx; | |
57cafdf2 SZ |
112 | unsigned int shnum; |
113 | unsigned int shstrndx; | |
a79f248b | 114 | |
57cafdf2 SZ |
115 | shstrndx = r2(&ehdr->e_shstrndx); |
116 | if (shstrndx == SHN_XINDEX) | |
117 | shstrndx = r(&shdr[0].sh_link); | |
118 | secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset); | |
59c36455 | 119 | |
57cafdf2 SZ |
120 | shnum = r2(&ehdr->e_shnum); |
121 | if (shnum == SHN_UNDEF) | |
122 | shnum = _r(&shdr[0].sh_size); | |
59c36455 | 123 | |
57cafdf2 SZ |
124 | for (i = 0, s = shdr; s < shdr + shnum; i++, s++) { |
125 | idx = r(&s->sh_name); | |
126 | if (!strcmp(secstrings + idx, "__ex_table")) { | |
127 | extab_sec = s; | |
d59a1683 DD |
128 | extab_index = i; |
129 | } | |
57cafdf2 SZ |
130 | if (!strcmp(secstrings + idx, ".symtab")) |
131 | symtab_sec = s; | |
132 | if (!strcmp(secstrings + idx, ".strtab")) | |
133 | strtab_sec = s; | |
134 | ||
135 | if ((r(&s->sh_type) == SHT_REL || | |
136 | r(&s->sh_type) == SHT_RELA) && | |
137 | r(&s->sh_info) == extab_index) { | |
138 | relocs = (void *)ehdr + _r(&s->sh_offset); | |
139 | relocs_size = _r(&s->sh_size); | |
d59a1683 | 140 | } |
57cafdf2 SZ |
141 | if (r(&s->sh_type) == SHT_SYMTAB_SHNDX) |
142 | symtab_shndx = (Elf32_Word *)((const char *)ehdr + | |
143 | _r(&s->sh_offset)); | |
a79f248b | 144 | } |
57cafdf2 SZ |
145 | |
146 | if (!extab_sec) { | |
147 | fprintf(stderr, "no __ex_table in file: %s\n", fname); | |
3c47b787 | 148 | return -1; |
a79f248b | 149 | } |
57cafdf2 | 150 | |
6402e141 SZ |
151 | if (!symtab_sec) { |
152 | fprintf(stderr, "no .symtab in file: %s\n", fname); | |
3c47b787 | 153 | return -1; |
a79f248b | 154 | } |
57cafdf2 SZ |
155 | |
156 | if (!strtab_sec) { | |
157 | fprintf(stderr, "no .strtab in file: %s\n", fname); | |
3c47b787 | 158 | return -1; |
a79f248b | 159 | } |
a79f248b | 160 | |
d59a1683 | 161 | extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); |
57cafdf2 SZ |
162 | strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); |
163 | symtab = (const Elf_Sym *)((const char *)ehdr + | |
164 | _r(&symtab_sec->sh_offset)); | |
d59a1683 DD |
165 | |
166 | if (custom_sort) { | |
167 | custom_sort(extab_image, _r(&extab_sec->sh_size)); | |
168 | } else { | |
169 | int num_entries = _r(&extab_sec->sh_size) / extable_ent_size; | |
170 | qsort(extab_image, num_entries, | |
171 | extable_ent_size, compare_extable); | |
172 | } | |
57cafdf2 | 173 | |
d59a1683 DD |
174 | /* If there were relocations, we no longer need them. */ |
175 | if (relocs) | |
176 | memset(relocs, 0, relocs_size); | |
a79f248b | 177 | |
57cafdf2 SZ |
178 | /* find the flag main_extable_sort_needed */ |
179 | for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset); | |
180 | sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); | |
181 | sym++) { | |
a79f248b DD |
182 | if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) |
183 | continue; | |
57cafdf2 SZ |
184 | if (!strcmp(strtab + r(&sym->st_name), |
185 | "main_extable_sort_needed")) { | |
a79f248b DD |
186 | sort_needed_sym = sym; |
187 | break; | |
188 | } | |
189 | } | |
57cafdf2 | 190 | |
6402e141 | 191 | if (!sort_needed_sym) { |
a79f248b | 192 | fprintf(stderr, |
6402e141 | 193 | "no main_extable_sort_needed symbol in file: %s\n", |
a79f248b | 194 | fname); |
3c47b787 | 195 | return -1; |
a79f248b | 196 | } |
57cafdf2 | 197 | |
59c36455 JI |
198 | sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), |
199 | sort_needed_sym - symtab, | |
57cafdf2 SZ |
200 | symtab_shndx)]; |
201 | sort_needed_loc = (void *)ehdr + | |
d59a1683 DD |
202 | _r(&sort_needed_sec->sh_offset) + |
203 | _r(&sort_needed_sym->st_value) - | |
204 | _r(&sort_needed_sec->sh_addr); | |
a79f248b | 205 | |
57cafdf2 SZ |
206 | /* extable has been sorted, clear the flag */ |
207 | w(0, sort_needed_loc); | |
208 | ||
3c47b787 | 209 | return 0; |
a79f248b | 210 | } |