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