xref: /linux/scripts/gendwarfksyms/types.c (revision ba6ec09911b805778a2fed6d626bfe77b011a717)
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