Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.19 343 lines 7.8 kB view raw
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 */ 11static HASHTABLE_DEFINE(symbol_addrs, 1 << SYMBOL_HASH_BITS); 12/* name -> struct symbol */ 13static HASHTABLE_DEFINE(symbol_names, 1 << SYMBOL_HASH_BITS); 14 15static inline unsigned int symbol_addr_hash(const struct symbol_addr *addr) 16{ 17 return hash_32(addr->section ^ addr_hash(addr->address)); 18} 19 20static 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 */ 51bool is_symbol_ptr(const char *name) 52{ 53 return name && !strncmp(name, SYMBOL_PTR_PREFIX, SYMBOL_PTR_PREFIX_LEN); 54} 55 56static 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 85static 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 97void 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 103static void set_ptr(struct symbol *sym, void *data) 104{ 105 sym->ptr_die_addr = (uintptr_t)((Dwarf_Die *)data)->addr; 106} 107 108void 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 114static 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 120void 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 126static bool is_exported(const char *name) 127{ 128 return for_each(name, NULL, NULL) > 0; 129} 130 131int 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 166static 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 174struct 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 182void 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 192typedef void (*elf_symbol_callback_t)(const char *name, GElf_Sym *sym, 193 Elf32_Word xndx, void *arg); 194 195static 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 286static 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 303static 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 313void symbol_read_symtab(int fd) 314{ 315 elf_for_each_global(fd, elf_set_symbol_addr, NULL); 316} 317 318void 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 331void 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}