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
type_list_free(struct list_head * list)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
type_list_append(struct list_head * list,const char * s,void * owned)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
type_list_write(struct list_head * list,FILE * file)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
type_expansion_init(struct type_expansion * type)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
type_expansion_free(struct type_expansion * type)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
type_expansion_append(struct type_expansion * type,const char * s,void * owned)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
__type_map_get(const char * name,struct type_expansion ** res)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
type_map_add(const char * name,struct type_expansion * type)117 static struct type_expansion *type_map_add(const char *name,
118 struct type_expansion *type)
119 {
120 struct type_expansion *e;
121
122 if (__type_map_get(name, &e)) {
123 e = xmalloc(sizeof(struct type_expansion));
124 type_expansion_init(e);
125 e->name = xstrdup(name);
126
127 hash_add(type_map, &e->hash, hash_str(e->name));
128
129 if (dump_types)
130 debug("adding %s", e->name);
131 } else {
132 /* Use the longest available expansion */
133 if (type->len <= e->len)
134 return e;
135
136 type_list_free(&e->expanded);
137
138 if (dump_types)
139 debug("replacing %s", e->name);
140 }
141
142 /* Take ownership of type->expanded */
143 list_replace_init(&type->expanded, &e->expanded);
144 e->len = type->len;
145
146 if (dump_types) {
147 checkp(fputs(e->name, stderr));
148 checkp(fputs(" ", stderr));
149 type_list_write(&e->expanded, stderr);
150 checkp(fputs("\n", stderr));
151 }
152
153 return e;
154 }
155
156 static void type_parse(const char *name, const char *str,
157 struct type_expansion *type);
158
type_map_get(const char * name,struct type_expansion ** res)159 static int type_map_get(const char *name, struct type_expansion **res)
160 {
161 struct type_expansion type;
162 const char *override;
163
164 if (!__type_map_get(name, res))
165 return 0;
166
167 /*
168 * If die_map didn't contain a type, we might still have
169 * a type_string kABI rule that defines it.
170 */
171 if (stable && kabi_get_type_string(name, &override)) {
172 type_expansion_init(&type);
173 type_parse(name, override, &type);
174 *res = type_map_add(name, &type);
175 type_expansion_free(&type);
176 return 0;
177 }
178
179 return -1;
180 }
181
type_map_write(FILE * file)182 static void type_map_write(FILE *file)
183 {
184 struct type_expansion *e;
185 struct hlist_node *tmp;
186
187 if (!file)
188 return;
189
190 hash_for_each_safe(type_map, e, tmp, hash) {
191 checkp(fputs(e->name, file));
192 checkp(fputs(" ", file));
193 type_list_write(&e->expanded, file);
194 checkp(fputs("\n", file));
195 }
196 }
197
type_map_free(void)198 static void type_map_free(void)
199 {
200 struct type_expansion *e;
201 struct hlist_node *tmp;
202
203 hash_for_each_safe(type_map, e, tmp, hash) {
204 type_expansion_free(e);
205 free(e);
206 }
207
208 hash_init(type_map);
209 }
210
211 /*
212 * CRC for a type, with an optional fully expanded type string for
213 * debugging.
214 */
215 struct version {
216 struct type_expansion type;
217 unsigned long crc;
218 };
219
version_init(struct version * version)220 static void version_init(struct version *version)
221 {
222 version->crc = crc32(0, NULL, 0);
223 type_expansion_init(&version->type);
224 }
225
version_free(struct version * version)226 static void version_free(struct version *version)
227 {
228 type_expansion_free(&version->type);
229 }
230
version_add(struct version * version,const char * s)231 static void version_add(struct version *version, const char *s)
232 {
233 version->crc = crc32(version->crc, (void *)s, strlen(s));
234 if (dump_versions)
235 type_expansion_append(&version->type, s, NULL);
236 }
237
238 /*
239 * Type reference format: <prefix>#<name>, where prefix:
240 * s -> structure
241 * u -> union
242 * e -> enum
243 * t -> typedef
244 *
245 * Names with spaces are additionally wrapped in single quotes.
246 */
is_type_prefix(const char * s)247 static inline bool is_type_prefix(const char *s)
248 {
249 return (s[0] == 's' || s[0] == 'u' || s[0] == 'e' || s[0] == 't') &&
250 s[1] == '#';
251 }
252
get_type_prefix(int tag)253 static char get_type_prefix(int tag)
254 {
255 switch (tag) {
256 case DW_TAG_class_type:
257 case DW_TAG_structure_type:
258 return 's';
259 case DW_TAG_union_type:
260 return 'u';
261 case DW_TAG_enumeration_type:
262 return 'e';
263 case DW_TAG_typedef_type:
264 return 't';
265 default:
266 return 0;
267 }
268 }
269
get_type_name(struct die * cache)270 static char *get_type_name(struct die *cache)
271 {
272 const char *quote;
273 char prefix;
274 char *name;
275
276 if (cache->state == DIE_INCOMPLETE) {
277 warn("found incomplete cache entry: %p", cache);
278 return NULL;
279 }
280 if (cache->state == DIE_SYMBOL || cache->state == DIE_FQN)
281 return NULL;
282 if (!cache->fqn || !*cache->fqn)
283 return NULL;
284
285 prefix = get_type_prefix(cache->tag);
286 if (!prefix)
287 return NULL;
288
289 /* Wrap names with spaces in single quotes */
290 quote = strstr(cache->fqn, " ") ? "'" : "";
291
292 /* <prefix>#<type_name>\0 */
293 if (asprintf(&name, "%c#%s%s%s", prefix, quote, cache->fqn, quote) < 0)
294 error("asprintf failed for '%s'", cache->fqn);
295
296 return name;
297 }
298
__calculate_version(struct version * version,struct type_expansion * type)299 static void __calculate_version(struct version *version,
300 struct type_expansion *type)
301 {
302 struct type_list_entry *entry;
303 struct type_expansion *e;
304
305 /* Calculate a CRC over an expanded type string */
306 list_for_each_entry(entry, &type->expanded, list) {
307 if (is_type_prefix(entry->str)) {
308 if (type_map_get(entry->str, &e))
309 error("unknown type reference to '%s' when expanding '%s'",
310 entry->str, type->name);
311
312 /*
313 * It's sufficient to expand each type reference just
314 * once to detect changes.
315 */
316 if (cache_was_expanded(&expansion_cache, e)) {
317 version_add(version, entry->str);
318 } else {
319 cache_mark_expanded(&expansion_cache, e);
320 __calculate_version(version, e);
321 }
322 } else {
323 version_add(version, entry->str);
324 }
325 }
326 }
327
calculate_version(struct version * version,struct type_expansion * type)328 static void calculate_version(struct version *version,
329 struct type_expansion *type)
330 {
331 version_init(version);
332 __calculate_version(version, type);
333 cache_free(&expansion_cache);
334 }
335
__type_expand(struct die * cache,struct type_expansion * type)336 static void __type_expand(struct die *cache, struct type_expansion *type)
337 {
338 struct die_fragment *df;
339 struct die *child;
340 char *name;
341
342 list_for_each_entry(df, &cache->fragments, list) {
343 switch (df->type) {
344 case FRAGMENT_STRING:
345 type_expansion_append(type, df->data.str, NULL);
346 break;
347 case FRAGMENT_DIE:
348 /* Use a complete die_map expansion if available */
349 if (__die_map_get(df->data.addr, DIE_COMPLETE,
350 &child) &&
351 __die_map_get(df->data.addr, DIE_UNEXPANDED,
352 &child))
353 error("unknown child: %" PRIxPTR,
354 df->data.addr);
355
356 name = get_type_name(child);
357 if (name)
358 type_expansion_append(type, name, name);
359 else
360 __type_expand(child, type);
361
362 break;
363 case FRAGMENT_LINEBREAK:
364 /*
365 * Keep whitespace in the symtypes format, but avoid
366 * repeated spaces.
367 */
368 if (list_is_last(&df->list, &cache->fragments) ||
369 list_next_entry(df, list)->type !=
370 FRAGMENT_LINEBREAK)
371 type_expansion_append(type, " ", NULL);
372 break;
373 default:
374 error("empty die_fragment in %p", cache);
375 }
376 }
377 }
378
type_expand(const char * name,struct die * cache,struct type_expansion * type)379 static void type_expand(const char *name, struct die *cache,
380 struct type_expansion *type)
381 {
382 const char *override;
383
384 type_expansion_init(type);
385
386 if (stable && kabi_get_type_string(name, &override))
387 type_parse(name, override, type);
388 else
389 __type_expand(cache, type);
390 }
391
type_parse(const char * name,const char * str,struct type_expansion * type)392 static void type_parse(const char *name, const char *str,
393 struct type_expansion *type)
394 {
395 char *fragment;
396 size_t start = 0;
397 size_t end;
398 size_t pos;
399
400 if (!*str)
401 error("empty type string override for '%s'", name);
402
403 for (pos = 0; str[pos]; ++pos) {
404 bool empty;
405 char marker = ' ';
406
407 if (!is_type_prefix(&str[pos]))
408 continue;
409
410 end = pos + 2;
411
412 /*
413 * Find the end of the type reference. If the type name contains
414 * spaces, it must be in single quotes.
415 */
416 if (str[end] == '\'') {
417 marker = '\'';
418 ++end;
419 }
420 while (str[end] && str[end] != marker)
421 ++end;
422
423 /* Check that we have a non-empty type name */
424 if (marker == '\'') {
425 if (str[end] != marker)
426 error("incomplete %c# type reference for '%s' (string : '%s')",
427 str[pos], name, str);
428 empty = end == pos + 3;
429 ++end;
430 } else {
431 empty = end == pos + 2;
432 }
433 if (empty)
434 error("empty %c# type name for '%s' (string: '%s')",
435 str[pos], name, str);
436
437 /* Append the part of the string before the type reference */
438 if (pos > start) {
439 fragment = xstrndup(&str[start], pos - start);
440 type_expansion_append(type, fragment, fragment);
441 }
442
443 /*
444 * Append the type reference -- note that if the reference
445 * is invalid, i.e. points to a non-existent type, we will
446 * print out an error when calculating versions.
447 */
448 fragment = xstrndup(&str[pos], end - pos);
449 type_expansion_append(type, fragment, fragment);
450
451 start = end;
452 pos = end - 1;
453 }
454
455 /* Append the rest of the type string, if there's any left */
456 if (str[start])
457 type_expansion_append(type, &str[start], NULL);
458 }
459
expand_type(struct die * cache,void * arg)460 static void expand_type(struct die *cache, void *arg)
461 {
462 struct type_expansion type;
463 char *name;
464
465 if (cache->mapped)
466 return;
467
468 cache->mapped = true;
469
470 /*
471 * Skip unexpanded die_map entries if there's a complete
472 * expansion available for this DIE.
473 */
474 if (cache->state == DIE_UNEXPANDED &&
475 !__die_map_get(cache->addr, DIE_COMPLETE, &cache)) {
476 if (cache->mapped)
477 return;
478
479 cache->mapped = true;
480 }
481
482 name = get_type_name(cache);
483 if (!name)
484 return;
485
486 debug("%s", name);
487
488 type_expand(name, cache, &type);
489 type_map_add(name, &type);
490 type_expansion_free(&type);
491 free(name);
492 }
493
expand_symbol(struct symbol * sym,void * arg)494 static void expand_symbol(struct symbol *sym, void *arg)
495 {
496 struct type_expansion type;
497 struct version version;
498 struct die *cache;
499
500 /*
501 * No need to expand again unless we want a symtypes file entry
502 * for the symbol. Note that this means `sym` has the same address
503 * as another symbol that was already processed.
504 */
505 if (!symtypes && sym->state == SYMBOL_PROCESSED)
506 return;
507
508 if (__die_map_get(sym->die_addr, DIE_SYMBOL, &cache))
509 return; /* We'll warn about missing CRCs later. */
510
511 type_expand(sym->name, cache, &type);
512
513 /* If the symbol already has a version, don't calculate it again. */
514 if (sym->state != SYMBOL_PROCESSED) {
515 calculate_version(&version, &type);
516 symbol_set_crc(sym, version.crc);
517 debug("%s = %lx", sym->name, version.crc);
518
519 if (dump_versions) {
520 checkp(fputs(sym->name, stderr));
521 checkp(fputs(" ", stderr));
522 type_list_write(&version.type.expanded, stderr);
523 checkp(fputs("\n", stderr));
524 }
525
526 version_free(&version);
527 }
528
529 /* These aren't needed in type_map unless we want a symtypes file. */
530 if (symtypes)
531 type_map_add(sym->name, &type);
532
533 type_expansion_free(&type);
534 }
535
generate_symtypes_and_versions(FILE * file)536 void generate_symtypes_and_versions(FILE *file)
537 {
538 cache_init(&expansion_cache);
539
540 /*
541 * die_map processing:
542 *
543 * 1. die_map contains all types referenced in exported symbol
544 * signatures, but can contain duplicates just like the original
545 * DWARF, and some references may not be fully expanded depending
546 * on how far we processed the DIE tree for that specific symbol.
547 *
548 * For each die_map entry, find the longest available expansion,
549 * and add it to type_map.
550 */
551 die_map_for_each(expand_type, NULL);
552
553 /*
554 * 2. For each exported symbol, expand the die_map type, and use
555 * type_map expansions to calculate a symbol version from the
556 * fully expanded type string.
557 */
558 symbol_for_each(expand_symbol, NULL);
559
560 /*
561 * 3. If a symtypes file is requested, write type_map contents to
562 * the file.
563 */
564 type_map_write(file);
565 type_map_free();
566 }
567