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