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 void 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(struct symbol));
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
get_symbol(struct symbol * sym,void * arg)164 static void get_symbol(struct symbol *sym, void *arg)
165 {
166 struct symbol **res = arg;
167
168 if (sym->state == SYMBOL_UNPROCESSED)
169 *res = sym;
170 }
171
symbol_get(const char * name)172 struct symbol *symbol_get(const char *name)
173 {
174 struct symbol *sym = NULL;
175
176 for_each(name, get_symbol, &sym);
177 return sym;
178 }
179
symbol_for_each(symbol_callback_t func,void * arg)180 void symbol_for_each(symbol_callback_t func, void *arg)
181 {
182 struct hlist_node *tmp;
183 struct symbol *sym;
184
185 hash_for_each_safe(symbol_names, sym, tmp, name_hash) {
186 func(sym, arg);
187 }
188 }
189
190 typedef void (*elf_symbol_callback_t)(const char *name, GElf_Sym *sym,
191 Elf32_Word xndx, void *arg);
192
elf_for_each_global(int fd,elf_symbol_callback_t func,void * arg)193 static void elf_for_each_global(int fd, elf_symbol_callback_t func, void *arg)
194 {
195 size_t sym_size;
196 GElf_Shdr shdr_mem;
197 GElf_Shdr *shdr;
198 Elf_Data *xndx_data = NULL;
199 Elf_Scn *scn;
200 Elf *elf;
201
202 if (elf_version(EV_CURRENT) != EV_CURRENT)
203 error("elf_version failed: %s", elf_errmsg(-1));
204
205 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
206 if (!elf)
207 error("elf_begin failed: %s", elf_errmsg(-1));
208
209 scn = elf_nextscn(elf, NULL);
210
211 while (scn) {
212 shdr = gelf_getshdr(scn, &shdr_mem);
213 if (!shdr)
214 error("gelf_getshdr failed: %s", elf_errmsg(-1));
215
216 if (shdr->sh_type == SHT_SYMTAB_SHNDX) {
217 xndx_data = elf_getdata(scn, NULL);
218 if (!xndx_data)
219 error("elf_getdata failed: %s", elf_errmsg(-1));
220 break;
221 }
222
223 scn = elf_nextscn(elf, scn);
224 }
225
226 sym_size = gelf_fsize(elf, ELF_T_SYM, 1, EV_CURRENT);
227 scn = elf_nextscn(elf, NULL);
228
229 while (scn) {
230 shdr = gelf_getshdr(scn, &shdr_mem);
231 if (!shdr)
232 error("gelf_getshdr failed: %s", elf_errmsg(-1));
233
234 if (shdr->sh_type == SHT_SYMTAB) {
235 unsigned int nsyms;
236 unsigned int n;
237 Elf_Data *data = elf_getdata(scn, NULL);
238
239 if (!data)
240 error("elf_getdata failed: %s", elf_errmsg(-1));
241
242 if (shdr->sh_entsize != sym_size)
243 error("expected sh_entsize (%lu) to be %zu",
244 shdr->sh_entsize, sym_size);
245
246 nsyms = shdr->sh_size / shdr->sh_entsize;
247
248 for (n = 1; n < nsyms; ++n) {
249 const char *name = NULL;
250 Elf32_Word xndx = 0;
251 GElf_Sym sym_mem;
252 GElf_Sym *sym;
253
254 sym = gelf_getsymshndx(data, xndx_data, n,
255 &sym_mem, &xndx);
256 if (!sym)
257 error("gelf_getsymshndx failed: %s",
258 elf_errmsg(-1));
259
260 if (GELF_ST_BIND(sym->st_info) == STB_LOCAL)
261 continue;
262
263 if (sym->st_shndx != SHN_XINDEX)
264 xndx = sym->st_shndx;
265
266 name = elf_strptr(elf, shdr->sh_link,
267 sym->st_name);
268 if (!name)
269 error("elf_strptr failed: %s",
270 elf_errmsg(-1));
271
272 /* Skip empty symbol names */
273 if (*name)
274 func(name, sym, xndx, arg);
275 }
276 }
277
278 scn = elf_nextscn(elf, scn);
279 }
280
281 check(elf_end(elf));
282 }
283
set_symbol_addr(struct symbol * sym,void * arg)284 static void set_symbol_addr(struct symbol *sym, void *arg)
285 {
286 struct symbol_addr *addr = arg;
287
288 if (sym->addr.section == SHN_UNDEF) {
289 sym->addr = *addr;
290 hash_add(symbol_addrs, &sym->addr_hash,
291 symbol_addr_hash(&sym->addr));
292
293 debug("%s -> { %u, %lx }", sym->name, sym->addr.section,
294 sym->addr.address);
295 } else if (sym->addr.section != addr->section ||
296 sym->addr.address != addr->address) {
297 warn("multiple addresses for symbol %s?", sym->name);
298 }
299 }
300
elf_set_symbol_addr(const char * name,GElf_Sym * sym,Elf32_Word xndx,void * arg)301 static void elf_set_symbol_addr(const char *name, GElf_Sym *sym,
302 Elf32_Word xndx, void *arg)
303 {
304 struct symbol_addr addr = { .section = xndx, .address = sym->st_value };
305
306 /* Set addresses for exported symbols */
307 if (addr.section != SHN_UNDEF)
308 for_each(name, set_symbol_addr, &addr);
309 }
310
symbol_read_symtab(int fd)311 void symbol_read_symtab(int fd)
312 {
313 elf_for_each_global(fd, elf_set_symbol_addr, NULL);
314 }
315
symbol_print_versions(void)316 void symbol_print_versions(void)
317 {
318 struct hlist_node *tmp;
319 struct symbol *sym;
320
321 hash_for_each_safe(symbol_names, sym, tmp, name_hash) {
322 if (sym->state != SYMBOL_PROCESSED)
323 warn("no information for symbol %s", sym->name);
324
325 printf("#SYMVER %s 0x%08lx\n", sym->name, sym->crc);
326 }
327 }
328
symbol_free(void)329 void symbol_free(void)
330 {
331 struct hlist_node *tmp;
332 struct symbol *sym;
333
334 hash_for_each_safe(symbol_names, sym, tmp, name_hash) {
335 free((void *)sym->name);
336 free(sym);
337 }
338
339 hash_init(symbol_addrs);
340 hash_init(symbol_names);
341 }
342