File Index
Files and directories
Sign in
FILE

symbols.c

File preview with syntax highlighting.

linux-6.19.14/scripts/gendwarfksyms/symbols.c C
  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 */
 12static HASHTABLE_DEFINE(symbol_addrs, 1 << SYMBOL_HASH_BITS);
 13/* name -> struct symbol */
 14static HASHTABLE_DEFINE(symbol_names, 1 << SYMBOL_HASH_BITS);
 15
 16static inline unsigned int symbol_addr_hash(const struct symbol_addr *addr)
 17{
 18	return hash_32(addr->section ^ addr_hash(addr->address));
 19}
 20
 21static 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 */
 52bool is_symbol_ptr(const char *name)
 53{
 54	return name && !strncmp(name, SYMBOL_PTR_PREFIX, SYMBOL_PTR_PREFIX_LEN);
 55}
 56
 57static 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
 86static 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
 98void 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
104static void set_ptr(struct symbol *sym, void *data)
105{
106	sym->ptr_die_addr = (uintptr_t)((Dwarf_Die *)data)->addr;
107}
108
109void 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
115static 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
121void 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
127static bool is_exported(const char *name)
128{
129	return for_each(name, NULL, NULL) > 0;
130}
131
132int 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
167static 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
175struct 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
183void 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
193typedef void (*elf_symbol_callback_t)(const char *name, GElf_Sym *sym,
194				      Elf32_Word xndx, void *arg);
195
196static 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
287static 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
304static 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
314void symbol_read_symtab(int fd)
315{
316	elf_for_each_global(fd, elf_set_symbol_addr, NULL);
317}
318
319void 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
332void 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}
~/ Read-only file preview.