1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2024 Google LLC
4 */
5
6 #include <inttypes.h>
7 #include "gendwarfksyms.h"
8
9 #define SYMBOL_HASH_BITS 12
10
11 /* struct symbol_addr -> struct symbol */
12 static HASHTABLE_DEFINE(symbol_addrs, 1 << SYMBOL_HASH_BITS);
13 /* name -> struct symbol */
14 static HASHTABLE_DEFINE(symbol_names, 1 << SYMBOL_HASH_BITS);
15
symbol_addr_hash(const struct symbol_addr * addr)16 static inline unsigned int symbol_addr_hash(const struct symbol_addr *addr)
17 {
18 return hash_32(addr->section ^ addr_hash(addr->address));
19 }
20
__for_each_addr(struct symbol * sym,symbol_callback_t func,void * data)21 static unsigned int __for_each_addr(struct symbol *sym, symbol_callback_t func,
22 void *data)
23 {
24 struct hlist_node *tmp;
25 struct symbol *match = NULL;
26 unsigned int processed = 0;
27
28 hash_for_each_possible_safe(symbol_addrs, match, tmp, addr_hash,
29 symbol_addr_hash(&sym->addr)) {
30 if (match == sym)
31 continue; /* Already processed */
32
33 if (match->addr.section == sym->addr.section &&
34 match->addr.address == sym->addr.address) {
35 func(match, data);
36 ++processed;
37 }
38 }
39
40 return processed;
41 }
42
43 /*
44 * For symbols without debugging information (e.g. symbols defined in other
45 * TUs), we also match __gendwarfksyms_ptr_<symbol_name> symbols, which the
46 * kernel uses to ensure type information is present in the TU that exports
47 * the symbol. A __gendwarfksyms_ptr pointer must have the same type as the
48 * exported symbol, e.g.:
49 *
50 * typeof(symname) *__gendwarf_ptr_symname = &symname;
51 */
is_symbol_ptr(const char * name)52 bool is_symbol_ptr(const char *name)
53 {
54 return name && !strncmp(name, SYMBOL_PTR_PREFIX, SYMBOL_PTR_PREFIX_LEN);
55 }
56
for_each(const char * name,symbol_callback_t func,void * data)57 static unsigned int for_each(const char *name, symbol_callback_t func,
58 void *data)
59 {
60 struct hlist_node *tmp;
61 struct symbol *match;
62
63 if (!name || !*name)
64 return 0;
65 if (is_symbol_ptr(name))
66 name += SYMBOL_PTR_PREFIX_LEN;
67
68 hash_for_each_possible_safe(symbol_names, match, tmp, name_hash,
69 hash_str(name)) {
70 if (strcmp(match->name, name))
71 continue;
72
73 /* Call func for the match, and all address matches */
74 if (func)
75 func(match, data);
76
77 if (match->addr.section != SHN_UNDEF)
78 return __for_each_addr(match, func, data) + 1;
79
80 return 1;
81 }
82
83 return 0;
84 }
85
set_crc(struct symbol * sym,void * data)86 static void set_crc(struct symbol *sym, void *data)
87 {
88 unsigned long *crc = data;
89
90 if (sym->state == SYMBOL_PROCESSED && sym->crc != *crc)
91 warn("overriding version for symbol %s (crc %lx vs. %lx)",
92 sym->name, sym->crc, *crc);
93
94 sym->state = SYMBOL_PROCESSED;
95 sym->crc = *crc;
96 }
97
symbol_set_crc(struct symbol * sym,unsigned long crc)98 void symbol_set_crc(struct symbol *sym, unsigned long crc)
99 {
100 if (for_each(sym->name, set_crc, &crc) == 0)
101 error("no matching symbols: '%s'", sym->name);
102 }
103
set_ptr(struct symbol * sym,void * data)104 static void set_ptr(struct symbol *sym, void *data)
105 {
106 sym->ptr_die_addr = (uintptr_t)((Dwarf_Die *)data)->addr;
107 }
108
symbol_set_ptr(struct symbol * sym,Dwarf_Die * ptr)109 void symbol_set_ptr(struct symbol *sym, Dwarf_Die *ptr)
110 {
111 if (for_each(sym->name, set_ptr, ptr) == 0)
112 error("no matching symbols: '%s'", sym->name);
113 }
114
set_die(struct symbol * sym,void * data)115 static void set_die(struct symbol *sym, void *data)
116 {
117 sym->die_addr = (uintptr_t)((Dwarf_Die *)data)->addr;
118 sym->state = SYMBOL_MAPPED;
119 }
120
symbol_set_die(struct symbol * sym,Dwarf_Die * die)121 void symbol_set_die(struct symbol *sym, Dwarf_Die *die)
122 {
123 if (for_each(sym->name, set_die, die) == 0)
124 error("no matching symbols: '%s'", sym->name);
125 }
126
is_exported(const char * name)127 static bool is_exported(const char *name)
128 {
129 return for_each(name, NULL, NULL) > 0;
130 }
131
symbol_read_exports(FILE * file)132 int symbol_read_exports(FILE *file)
133 {
134 struct symbol *sym;
135 char *line = NULL;
136 char *name = NULL;
137 size_t size = 0;
138 int nsym = 0;
139
140 while (getline(&line, &size, file) > 0) {
141 if (sscanf(line, "%ms\n", &name) != 1)
142 error("malformed input line: %s", line);
143
144 if (is_exported(name)) {
145 /* Ignore duplicates */
146 free(name);
147 continue;
148 }
149
150 sym = xcalloc(1, sizeof(*sym));
151 sym->name = name;
152 sym->addr.section = SHN_UNDEF;
153 sym->state = SYMBOL_UNPROCESSED;
154
155 hash_add(symbol_names, &sym->name_hash, hash_str(sym->name));
156 ++nsym;
157
158 debug("%s", sym->name);
159 }
160
161 free(line);
162 debug("%d exported symbols", nsym);
163
164 return nsym;
165 }
166
get_symbol(struct symbol * sym,void * arg)167 static void get_symbol(struct symbol *sym, void *arg)
168 {
169 struct symbol **res = arg;
170
171 if (sym->state == SYMBOL_UNPROCESSED)
172 *res = sym;
173 }
174
symbol_get(const char * name)175 struct symbol *symbol_get(const char *name)
176 {
177 struct symbol *sym = NULL;
178
179 for_each(name, get_symbol, &sym);
180 return sym;
181 }
182
symbol_for_each(symbol_callback_t func,void * arg)183 void symbol_for_each(symbol_callback_t func, void *arg)
184 {
185 struct hlist_node *tmp;
186 struct symbol *sym;
187
188 hash_for_each_safe(symbol_names, sym, tmp, name_hash) {
189 func(sym, arg);
190 }
191 }
192
193 typedef void (*elf_symbol_callback_t)(const char *name, GElf_Sym *sym,
194 Elf32_Word xndx, void *arg);
195
elf_for_each_global(int fd,elf_symbol_callback_t func,void * arg)196 static void elf_for_each_global(int fd, elf_symbol_callback_t func, void *arg)
197 {
198 size_t sym_size;
199 GElf_Shdr shdr_mem;
200 GElf_Shdr *shdr;
201 Elf_Data *xndx_data = NULL;
202 Elf_Scn *scn;
203 Elf *elf;
204
205 if (elf_version(EV_CURRENT) != EV_CURRENT)
206 error("elf_version failed: %s", elf_errmsg(-1));
207
208 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
209 if (!elf)
210 error("elf_begin failed: %s", elf_errmsg(-1));
211
212 scn = elf_nextscn(elf, NULL);
213
214 while (scn) {
215 shdr = gelf_getshdr(scn, &shdr_mem);
216 if (!shdr)
217 error("gelf_getshdr failed: %s", elf_errmsg(-1));
218
219 if (shdr->sh_type == SHT_SYMTAB_SHNDX) {
220 xndx_data = elf_getdata(scn, NULL);
221 if (!xndx_data)
222 error("elf_getdata failed: %s", elf_errmsg(-1));
223 break;
224 }
225
226 scn = elf_nextscn(elf, scn);
227 }
228
229 sym_size = gelf_fsize(elf, ELF_T_SYM, 1, EV_CURRENT);
230 scn = elf_nextscn(elf, NULL);
231
232 while (scn) {
233 shdr = gelf_getshdr(scn, &shdr_mem);
234 if (!shdr)
235 error("gelf_getshdr failed: %s", elf_errmsg(-1));
236
237 if (shdr->sh_type == SHT_SYMTAB) {
238 unsigned int nsyms;
239 unsigned int n;
240 Elf_Data *data = elf_getdata(scn, NULL);
241
242 if (!data)
243 error("elf_getdata failed: %s", elf_errmsg(-1));
244
245 if (shdr->sh_entsize != sym_size)
246 error("expected sh_entsize (%" PRIu64 ") to be %zu",
247 shdr->sh_entsize, sym_size);
248
249 nsyms = shdr->sh_size / shdr->sh_entsize;
250
251 for (n = 1; n < nsyms; ++n) {
252 const char *name = NULL;
253 Elf32_Word xndx = 0;
254 GElf_Sym sym_mem;
255 GElf_Sym *sym;
256
257 sym = gelf_getsymshndx(data, xndx_data, n,
258 &sym_mem, &xndx);
259 if (!sym)
260 error("gelf_getsymshndx failed: %s",
261 elf_errmsg(-1));
262
263 if (GELF_ST_BIND(sym->st_info) == STB_LOCAL)
264 continue;
265
266 if (sym->st_shndx != SHN_XINDEX)
267 xndx = sym->st_shndx;
268
269 name = elf_strptr(elf, shdr->sh_link,
270 sym->st_name);
271 if (!name)
272 error("elf_strptr failed: %s",
273 elf_errmsg(-1));
274
275 /* Skip empty symbol names */
276 if (*name)
277 func(name, sym, xndx, arg);
278 }
279 }
280
281 scn = elf_nextscn(elf, scn);
282 }
283
284 check(elf_end(elf));
285 }
286
set_symbol_addr(struct symbol * sym,void * arg)287 static void set_symbol_addr(struct symbol *sym, void *arg)
288 {
289 struct symbol_addr *addr = arg;
290
291 if (sym->addr.section == SHN_UNDEF) {
292 sym->addr = *addr;
293 hash_add(symbol_addrs, &sym->addr_hash,
294 symbol_addr_hash(&sym->addr));
295
296 debug("%s -> { %u, %" PRIx64 " }", sym->name, sym->addr.section,
297 sym->addr.address);
298 } else if (sym->addr.section != addr->section ||
299 sym->addr.address != addr->address) {
300 warn("multiple addresses for symbol %s?", sym->name);
301 }
302 }
303
elf_set_symbol_addr(const char * name,GElf_Sym * sym,Elf32_Word xndx,void * arg)304 static void elf_set_symbol_addr(const char *name, GElf_Sym *sym,
305 Elf32_Word xndx, void *arg)
306 {
307 struct symbol_addr addr = { .section = xndx, .address = sym->st_value };
308
309 /* Set addresses for exported symbols */
310 if (addr.section != SHN_UNDEF)
311 for_each(name, set_symbol_addr, &addr);
312 }
313
symbol_read_symtab(int fd)314 void symbol_read_symtab(int fd)
315 {
316 elf_for_each_global(fd, elf_set_symbol_addr, NULL);
317 }
318
symbol_print_versions(void)319 void symbol_print_versions(void)
320 {
321 struct hlist_node *tmp;
322 struct symbol *sym;
323
324 hash_for_each_safe(symbol_names, sym, tmp, name_hash) {
325 if (sym->state != SYMBOL_PROCESSED)
326 warn("no information for symbol %s", sym->name);
327
328 printf("#SYMVER %s 0x%08lx\n", sym->name, sym->crc);
329 }
330 }
331
symbol_free(void)332 void symbol_free(void)
333 {
334 struct hlist_node *tmp;
335 struct symbol *sym;
336
337 hash_for_each_safe(symbol_names, sym, tmp, name_hash) {
338 free((void *)sym->name);
339 free(sym);
340 }
341
342 hash_init(symbol_addrs);
343 hash_init(symbol_names);
344 }
345