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