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 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 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 */ 51 bool is_symbol_ptr(const char *name) 52 { 53 return name && !strncmp(name, SYMBOL_PTR_PREFIX, SYMBOL_PTR_PREFIX_LEN); 54 } 55 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 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 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 103 static void set_ptr(struct symbol *sym, void *data) 104 { 105 sym->ptr_die_addr = (uintptr_t)((Dwarf_Die *)data)->addr; 106 } 107 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 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 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 126 static bool is_exported(const char *name) 127 { 128 return for_each(name, NULL, NULL) > 0; 129 } 130 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 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 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 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 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 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 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 311 void symbol_read_symtab(int fd) 312 { 313 elf_for_each_global(fd, elf_set_symbol_addr, NULL); 314 } 315 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 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