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