1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2024 Google LLC 4 */ 5 6 #define _GNU_SOURCE 7 #include <inttypes.h> 8 #include <stdio.h> 9 #include <zlib.h> 10 11 #include "gendwarfksyms.h" 12 13 static struct cache expansion_cache; 14 15 /* 16 * A simple linked list of shared or owned strings to avoid copying strings 17 * around when not necessary. 18 */ 19 struct type_list_entry { 20 const char *str; 21 void *owned; 22 struct list_head list; 23 }; 24 25 static void type_list_free(struct list_head *list) 26 { 27 struct type_list_entry *entry; 28 struct type_list_entry *tmp; 29 30 list_for_each_entry_safe(entry, tmp, list, list) { 31 if (entry->owned) 32 free(entry->owned); 33 free(entry); 34 } 35 36 INIT_LIST_HEAD(list); 37 } 38 39 static int type_list_append(struct list_head *list, const char *s, void *owned) 40 { 41 struct type_list_entry *entry; 42 43 if (!s) 44 return 0; 45 46 entry = xmalloc(sizeof(struct type_list_entry)); 47 entry->str = s; 48 entry->owned = owned; 49 list_add_tail(&entry->list, list); 50 51 return strlen(entry->str); 52 } 53 54 static void type_list_write(struct list_head *list, FILE *file) 55 { 56 struct type_list_entry *entry; 57 58 list_for_each_entry(entry, list, list) { 59 if (entry->str) 60 checkp(fputs(entry->str, file)); 61 } 62 } 63 64 /* 65 * An expanded type string in symtypes format. 66 */ 67 struct type_expansion { 68 char *name; 69 size_t len; 70 struct list_head expanded; 71 struct hlist_node hash; 72 }; 73 74 static void type_expansion_init(struct type_expansion *type) 75 { 76 type->name = NULL; 77 type->len = 0; 78 INIT_LIST_HEAD(&type->expanded); 79 } 80 81 static inline void type_expansion_free(struct type_expansion *type) 82 { 83 free(type->name); 84 type->name = NULL; 85 type->len = 0; 86 type_list_free(&type->expanded); 87 } 88 89 static void type_expansion_append(struct type_expansion *type, const char *s, 90 void *owned) 91 { 92 type->len += type_list_append(&type->expanded, s, owned); 93 } 94 95 /* 96 * type_map -- the longest expansions for each type. 97 * 98 * const char *name -> struct type_expansion * 99 */ 100 #define TYPE_HASH_BITS 12 101 static HASHTABLE_DEFINE(type_map, 1 << TYPE_HASH_BITS); 102 103 static int type_map_get(const char *name, struct type_expansion **res) 104 { 105 struct type_expansion *e; 106 107 hash_for_each_possible(type_map, e, hash, hash_str(name)) { 108 if (!strcmp(name, e->name)) { 109 *res = e; 110 return 0; 111 } 112 } 113 114 return -1; 115 } 116 117 static void type_map_add(const char *name, struct type_expansion *type) 118 { 119 struct type_expansion *e; 120 121 if (type_map_get(name, &e)) { 122 e = xmalloc(sizeof(struct type_expansion)); 123 type_expansion_init(e); 124 e->name = xstrdup(name); 125 126 hash_add(type_map, &e->hash, hash_str(e->name)); 127 128 if (dump_types) 129 debug("adding %s", e->name); 130 } else { 131 /* Use the longest available expansion */ 132 if (type->len <= e->len) 133 return; 134 135 type_list_free(&e->expanded); 136 137 if (dump_types) 138 debug("replacing %s", e->name); 139 } 140 141 /* Take ownership of type->expanded */ 142 list_replace_init(&type->expanded, &e->expanded); 143 e->len = type->len; 144 145 if (dump_types) { 146 checkp(fputs(e->name, stderr)); 147 checkp(fputs(" ", stderr)); 148 type_list_write(&e->expanded, stderr); 149 checkp(fputs("\n", stderr)); 150 } 151 } 152 153 static void type_map_write(FILE *file) 154 { 155 struct type_expansion *e; 156 struct hlist_node *tmp; 157 158 if (!file) 159 return; 160 161 hash_for_each_safe(type_map, e, tmp, hash) { 162 checkp(fputs(e->name, file)); 163 checkp(fputs(" ", file)); 164 type_list_write(&e->expanded, file); 165 checkp(fputs("\n", file)); 166 } 167 } 168 169 static void type_map_free(void) 170 { 171 struct type_expansion *e; 172 struct hlist_node *tmp; 173 174 hash_for_each_safe(type_map, e, tmp, hash) { 175 type_expansion_free(e); 176 free(e); 177 } 178 179 hash_init(type_map); 180 } 181 182 /* 183 * CRC for a type, with an optional fully expanded type string for 184 * debugging. 185 */ 186 struct version { 187 struct type_expansion type; 188 unsigned long crc; 189 }; 190 191 static void version_init(struct version *version) 192 { 193 version->crc = crc32(0, NULL, 0); 194 type_expansion_init(&version->type); 195 } 196 197 static void version_free(struct version *version) 198 { 199 type_expansion_free(&version->type); 200 } 201 202 static void version_add(struct version *version, const char *s) 203 { 204 version->crc = crc32(version->crc, (void *)s, strlen(s)); 205 if (dump_versions) 206 type_expansion_append(&version->type, s, NULL); 207 } 208 209 /* 210 * Type reference format: <prefix>#<name>, where prefix: 211 * s -> structure 212 * u -> union 213 * e -> enum 214 * t -> typedef 215 * 216 * Names with spaces are additionally wrapped in single quotes. 217 */ 218 static inline bool is_type_prefix(const char *s) 219 { 220 return (s[0] == 's' || s[0] == 'u' || s[0] == 'e' || s[0] == 't') && 221 s[1] == '#'; 222 } 223 224 static char get_type_prefix(int tag) 225 { 226 switch (tag) { 227 case DW_TAG_class_type: 228 case DW_TAG_structure_type: 229 return 's'; 230 case DW_TAG_union_type: 231 return 'u'; 232 case DW_TAG_enumeration_type: 233 return 'e'; 234 case DW_TAG_typedef_type: 235 return 't'; 236 default: 237 return 0; 238 } 239 } 240 241 static char *get_type_name(struct die *cache) 242 { 243 const char *quote; 244 char prefix; 245 char *name; 246 247 if (cache->state == DIE_INCOMPLETE) { 248 warn("found incomplete cache entry: %p", cache); 249 return NULL; 250 } 251 if (cache->state == DIE_SYMBOL || cache->state == DIE_FQN) 252 return NULL; 253 if (!cache->fqn || !*cache->fqn) 254 return NULL; 255 256 prefix = get_type_prefix(cache->tag); 257 if (!prefix) 258 return NULL; 259 260 /* Wrap names with spaces in single quotes */ 261 quote = strstr(cache->fqn, " ") ? "'" : ""; 262 263 /* <prefix>#<type_name>\0 */ 264 if (asprintf(&name, "%c#%s%s%s", prefix, quote, cache->fqn, quote) < 0) 265 error("asprintf failed for '%s'", cache->fqn); 266 267 return name; 268 } 269 270 static void __calculate_version(struct version *version, struct list_head *list) 271 { 272 struct type_list_entry *entry; 273 struct type_expansion *e; 274 275 /* Calculate a CRC over an expanded type string */ 276 list_for_each_entry(entry, list, list) { 277 if (is_type_prefix(entry->str)) { 278 check(type_map_get(entry->str, &e)); 279 280 /* 281 * It's sufficient to expand each type reference just 282 * once to detect changes. 283 */ 284 if (cache_was_expanded(&expansion_cache, e)) { 285 version_add(version, entry->str); 286 } else { 287 cache_mark_expanded(&expansion_cache, e); 288 __calculate_version(version, &e->expanded); 289 } 290 } else { 291 version_add(version, entry->str); 292 } 293 } 294 } 295 296 static void calculate_version(struct version *version, struct list_head *list) 297 { 298 version_init(version); 299 __calculate_version(version, list); 300 cache_free(&expansion_cache); 301 } 302 303 static void __type_expand(struct die *cache, struct type_expansion *type, 304 bool recursive); 305 306 static void type_expand_child(struct die *cache, struct type_expansion *type, 307 bool recursive) 308 { 309 struct type_expansion child; 310 char *name; 311 312 name = get_type_name(cache); 313 if (!name) { 314 __type_expand(cache, type, recursive); 315 return; 316 } 317 318 if (recursive && !__cache_was_expanded(&expansion_cache, cache->addr)) { 319 __cache_mark_expanded(&expansion_cache, cache->addr); 320 type_expansion_init(&child); 321 __type_expand(cache, &child, true); 322 type_map_add(name, &child); 323 type_expansion_free(&child); 324 } 325 326 type_expansion_append(type, name, name); 327 } 328 329 static void __type_expand(struct die *cache, struct type_expansion *type, 330 bool recursive) 331 { 332 struct die_fragment *df; 333 struct die *child; 334 335 list_for_each_entry(df, &cache->fragments, list) { 336 switch (df->type) { 337 case FRAGMENT_STRING: 338 type_expansion_append(type, df->data.str, NULL); 339 break; 340 case FRAGMENT_DIE: 341 /* Use a complete die_map expansion if available */ 342 if (__die_map_get(df->data.addr, DIE_COMPLETE, 343 &child) && 344 __die_map_get(df->data.addr, DIE_UNEXPANDED, 345 &child)) 346 error("unknown child: %" PRIxPTR, 347 df->data.addr); 348 349 type_expand_child(child, type, recursive); 350 break; 351 case FRAGMENT_LINEBREAK: 352 /* 353 * Keep whitespace in the symtypes format, but avoid 354 * repeated spaces. 355 */ 356 if (list_is_last(&df->list, &cache->fragments) || 357 list_next_entry(df, list)->type != 358 FRAGMENT_LINEBREAK) 359 type_expansion_append(type, " ", NULL); 360 break; 361 default: 362 error("empty die_fragment in %p", cache); 363 } 364 } 365 } 366 367 static void type_expand(struct die *cache, struct type_expansion *type, 368 bool recursive) 369 { 370 type_expansion_init(type); 371 __type_expand(cache, type, recursive); 372 cache_free(&expansion_cache); 373 } 374 375 static void expand_type(struct die *cache, void *arg) 376 { 377 struct type_expansion type; 378 char *name; 379 380 if (cache->mapped) 381 return; 382 383 cache->mapped = true; 384 385 /* 386 * Skip unexpanded die_map entries if there's a complete 387 * expansion available for this DIE. 388 */ 389 if (cache->state == DIE_UNEXPANDED && 390 !__die_map_get(cache->addr, DIE_COMPLETE, &cache)) { 391 if (cache->mapped) 392 return; 393 394 cache->mapped = true; 395 } 396 397 name = get_type_name(cache); 398 if (!name) 399 return; 400 401 debug("%s", name); 402 type_expand(cache, &type, true); 403 type_map_add(name, &type); 404 405 type_expansion_free(&type); 406 free(name); 407 } 408 409 static void expand_symbol(struct symbol *sym, void *arg) 410 { 411 struct type_expansion type; 412 struct version version; 413 struct die *cache; 414 415 /* 416 * No need to expand again unless we want a symtypes file entry 417 * for the symbol. Note that this means `sym` has the same address 418 * as another symbol that was already processed. 419 */ 420 if (!symtypes && sym->state == SYMBOL_PROCESSED) 421 return; 422 423 if (__die_map_get(sym->die_addr, DIE_SYMBOL, &cache)) 424 return; /* We'll warn about missing CRCs later. */ 425 426 type_expand(cache, &type, false); 427 428 /* If the symbol already has a version, don't calculate it again. */ 429 if (sym->state != SYMBOL_PROCESSED) { 430 calculate_version(&version, &type.expanded); 431 symbol_set_crc(sym, version.crc); 432 debug("%s = %lx", sym->name, version.crc); 433 434 if (dump_versions) { 435 checkp(fputs(sym->name, stderr)); 436 checkp(fputs(" ", stderr)); 437 type_list_write(&version.type.expanded, stderr); 438 checkp(fputs("\n", stderr)); 439 } 440 441 version_free(&version); 442 } 443 444 /* These aren't needed in type_map unless we want a symtypes file. */ 445 if (symtypes) 446 type_map_add(sym->name, &type); 447 448 type_expansion_free(&type); 449 } 450 451 void generate_symtypes_and_versions(FILE *file) 452 { 453 cache_init(&expansion_cache); 454 455 /* 456 * die_map processing: 457 * 458 * 1. die_map contains all types referenced in exported symbol 459 * signatures, but can contain duplicates just like the original 460 * DWARF, and some references may not be fully expanded depending 461 * on how far we processed the DIE tree for that specific symbol. 462 * 463 * For each die_map entry, find the longest available expansion, 464 * and add it to type_map. 465 */ 466 die_map_for_each(expand_type, NULL); 467 468 /* 469 * 2. For each exported symbol, expand the die_map type, and use 470 * type_map expansions to calculate a symbol version from the 471 * fully expanded type string. 472 */ 473 symbol_for_each(expand_symbol, NULL); 474 475 /* 476 * 3. If a symtypes file is requested, write type_map contents to 477 * the file. 478 */ 479 type_map_write(file); 480 type_map_free(); 481 } 482