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 int 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 166 static 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 174 struct 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 182 void 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 192 typedef void (*elf_symbol_callback_t)(const char *name, GElf_Sym *sym, 193 Elf32_Word xndx, void *arg); 194 195 static 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 286 static 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 303 static 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 313 void symbol_read_symtab(int fd) 314 { 315 elf_for_each_global(fd, elf_set_symbol_addr, NULL); 316 } 317 318 void 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 331 void 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 } 344