]>
Commit | Line | Data |
---|---|---|
a79f248b DD |
1 | /* |
2 | * sortextable.h | |
3 | * | |
d59a1683 | 4 | * Copyright 2011 - 2012 Cavium, Inc. |
a79f248b DD |
5 | * |
6 | * Some of this code was taken out of recordmcount.h written by: | |
7 | * | |
8 | * Copyright 2009 John F. Reiser <[email protected]>. All rights reserved. | |
9 | * Copyright 2010 Steven Rostedt <[email protected]>, 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 | |
d59a1683 | 33 | #undef _r |
a79f248b DD |
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 | |
d59a1683 | 55 | # define _r r8 |
a79f248b DD |
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 | |
d59a1683 | 76 | # define _r r |
a79f248b DD |
77 | # define _w w |
78 | #endif | |
79 | ||
80 | static int compare_extable(const void *a, const void *b) | |
81 | { | |
d59a1683 DD |
82 | Elf_Addr av = _r(a); |
83 | Elf_Addr bv = _r(b); | |
a79f248b | 84 | |
d59a1683 | 85 | if (av < bv) |
a79f248b | 86 | return -1; |
d59a1683 | 87 | if (av > bv) |
a79f248b DD |
88 | return 1; |
89 | return 0; | |
90 | } | |
91 | ||
92 | static void | |
d59a1683 | 93 | do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) |
a79f248b DD |
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; | |
59c36455 JI |
101 | const Elf_Sym *symtab; |
102 | Elf32_Word *symtab_shndx_start = NULL; | |
a79f248b DD |
103 | Elf_Sym *sort_needed_sym; |
104 | Elf_Shdr *sort_needed_sec; | |
d59a1683 | 105 | Elf_Rel *relocs = NULL; |
7cbc0ea7 | 106 | int relocs_size = 0; |
a79f248b DD |
107 | uint32_t *sort_done_location; |
108 | const char *secstrtab; | |
109 | const char *strtab; | |
d59a1683 DD |
110 | char *extab_image; |
111 | int extab_index = 0; | |
a79f248b DD |
112 | int i; |
113 | int idx; | |
59c36455 JI |
114 | unsigned int num_sections; |
115 | unsigned int secindex_strings; | |
a79f248b | 116 | |
d59a1683 | 117 | shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); |
59c36455 JI |
118 | |
119 | num_sections = r2(&ehdr->e_shnum); | |
120 | if (num_sections == SHN_UNDEF) | |
121 | num_sections = _r(&shdr[0].sh_size); | |
122 | ||
123 | secindex_strings = r2(&ehdr->e_shstrndx); | |
124 | if (secindex_strings == SHN_XINDEX) | |
125 | secindex_strings = r(&shdr[0].sh_link); | |
126 | ||
127 | shstrtab_sec = shdr + secindex_strings; | |
d59a1683 | 128 | secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset); |
59c36455 | 129 | for (i = 0; i < num_sections; i++) { |
d59a1683 DD |
130 | idx = r(&shdr[i].sh_name); |
131 | if (strcmp(secstrtab + idx, "__ex_table") == 0) { | |
a79f248b | 132 | extab_sec = shdr + i; |
d59a1683 DD |
133 | extab_index = i; |
134 | } | |
135 | if ((r(&shdr[i].sh_type) == SHT_REL || | |
136 | r(&shdr[i].sh_type) == SHT_RELA) && | |
137 | r(&shdr[i].sh_info) == extab_index) { | |
138 | relocs = (void *)ehdr + _r(&shdr[i].sh_offset); | |
139 | relocs_size = _r(&shdr[i].sh_size); | |
140 | } | |
a79f248b DD |
141 | if (strcmp(secstrtab + idx, ".symtab") == 0) |
142 | symtab_sec = shdr + i; | |
143 | if (strcmp(secstrtab + idx, ".strtab") == 0) | |
144 | strtab_sec = shdr + i; | |
59c36455 JI |
145 | if (r(&shdr[i].sh_type) == SHT_SYMTAB_SHNDX) |
146 | symtab_shndx_start = (Elf32_Word *)( | |
147 | (const char *)ehdr + _r(&shdr[i].sh_offset)); | |
a79f248b DD |
148 | } |
149 | if (strtab_sec == NULL) { | |
150 | fprintf(stderr, "no .strtab in file: %s\n", fname); | |
151 | fail_file(); | |
152 | } | |
153 | if (symtab_sec == NULL) { | |
154 | fprintf(stderr, "no .symtab in file: %s\n", fname); | |
155 | fail_file(); | |
156 | } | |
59c36455 JI |
157 | symtab = (const Elf_Sym *)((const char *)ehdr + |
158 | _r(&symtab_sec->sh_offset)); | |
a79f248b DD |
159 | if (extab_sec == NULL) { |
160 | fprintf(stderr, "no __ex_table in file: %s\n", fname); | |
161 | fail_file(); | |
162 | } | |
d59a1683 | 163 | strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); |
a79f248b | 164 | |
d59a1683 DD |
165 | extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); |
166 | ||
167 | if (custom_sort) { | |
168 | custom_sort(extab_image, _r(&extab_sec->sh_size)); | |
169 | } else { | |
170 | int num_entries = _r(&extab_sec->sh_size) / extable_ent_size; | |
171 | qsort(extab_image, num_entries, | |
172 | extable_ent_size, compare_extable); | |
173 | } | |
174 | /* If there were relocations, we no longer need them. */ | |
175 | if (relocs) | |
176 | memset(relocs, 0, relocs_size); | |
a79f248b DD |
177 | |
178 | /* find main_extable_sort_needed */ | |
179 | sort_needed_sym = NULL; | |
d59a1683 DD |
180 | for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { |
181 | sym = (void *)ehdr + _r(&symtab_sec->sh_offset); | |
a79f248b DD |
182 | sym += i; |
183 | if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) | |
184 | continue; | |
d59a1683 | 185 | idx = r(&sym->st_name); |
a79f248b DD |
186 | if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { |
187 | sort_needed_sym = sym; | |
188 | break; | |
189 | } | |
190 | } | |
191 | if (sort_needed_sym == NULL) { | |
192 | fprintf(stderr, | |
193 | "no main_extable_sort_needed symbol in file: %s\n", | |
194 | fname); | |
195 | fail_file(); | |
196 | } | |
59c36455 JI |
197 | sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), |
198 | sort_needed_sym - symtab, | |
199 | symtab_shndx_start)]; | |
a79f248b | 200 | sort_done_location = (void *)ehdr + |
d59a1683 DD |
201 | _r(&sort_needed_sec->sh_offset) + |
202 | _r(&sort_needed_sym->st_value) - | |
203 | _r(&sort_needed_sec->sh_addr); | |
a79f248b | 204 | |
8c0c774d | 205 | #if 0 |
a79f248b | 206 | printf("sort done marker at %lx\n", |
d59a1683 DD |
207 | (unsigned long)((char *)sort_done_location - (char *)ehdr)); |
208 | #endif | |
a79f248b | 209 | /* We sorted it, clear the flag. */ |
d59a1683 | 210 | w(0, sort_done_location); |
a79f248b | 211 | } |