xref: /linux/scripts/gendwarfksyms/die.c (revision f4d2ef48250ad057e4f00087967b5ff366da9f39)
10c1c7627SSami Tolvanen // SPDX-License-Identifier: GPL-2.0
20c1c7627SSami Tolvanen /*
30c1c7627SSami Tolvanen  * Copyright (C) 2024 Google LLC
40c1c7627SSami Tolvanen  */
50c1c7627SSami Tolvanen 
60c1c7627SSami Tolvanen #include <string.h>
70c1c7627SSami Tolvanen #include "gendwarfksyms.h"
80c1c7627SSami Tolvanen 
9*10e9510aSSami Tolvanen #define DIE_HASH_BITS 16
100c1c7627SSami Tolvanen 
110c1c7627SSami Tolvanen /* {die->addr, state} -> struct die * */
120c1c7627SSami Tolvanen static HASHTABLE_DEFINE(die_map, 1 << DIE_HASH_BITS);
130c1c7627SSami Tolvanen 
140c1c7627SSami Tolvanen static unsigned int map_hits;
150c1c7627SSami Tolvanen static unsigned int map_misses;
160c1c7627SSami Tolvanen 
170c1c7627SSami Tolvanen static inline unsigned int die_hash(uintptr_t addr, enum die_state state)
180c1c7627SSami Tolvanen {
190c1c7627SSami Tolvanen 	return hash_32(addr_hash(addr) ^ (unsigned int)state);
200c1c7627SSami Tolvanen }
210c1c7627SSami Tolvanen 
220c1c7627SSami Tolvanen static void init_die(struct die *cd)
230c1c7627SSami Tolvanen {
240c1c7627SSami Tolvanen 	cd->state = DIE_INCOMPLETE;
25ab443998SSami Tolvanen 	cd->mapped = false;
260c1c7627SSami Tolvanen 	cd->fqn = NULL;
270c1c7627SSami Tolvanen 	cd->tag = -1;
280c1c7627SSami Tolvanen 	cd->addr = 0;
290c1c7627SSami Tolvanen 	INIT_LIST_HEAD(&cd->fragments);
300c1c7627SSami Tolvanen }
310c1c7627SSami Tolvanen 
320c1c7627SSami Tolvanen static struct die *create_die(Dwarf_Die *die, enum die_state state)
330c1c7627SSami Tolvanen {
340c1c7627SSami Tolvanen 	struct die *cd;
350c1c7627SSami Tolvanen 
360c1c7627SSami Tolvanen 	cd = xmalloc(sizeof(struct die));
370c1c7627SSami Tolvanen 	init_die(cd);
380c1c7627SSami Tolvanen 	cd->addr = (uintptr_t)die->addr;
390c1c7627SSami Tolvanen 
400c1c7627SSami Tolvanen 	hash_add(die_map, &cd->hash, die_hash(cd->addr, state));
410c1c7627SSami Tolvanen 	return cd;
420c1c7627SSami Tolvanen }
430c1c7627SSami Tolvanen 
440c1c7627SSami Tolvanen int __die_map_get(uintptr_t addr, enum die_state state, struct die **res)
450c1c7627SSami Tolvanen {
460c1c7627SSami Tolvanen 	struct die *cd;
470c1c7627SSami Tolvanen 
480c1c7627SSami Tolvanen 	hash_for_each_possible(die_map, cd, hash, die_hash(addr, state)) {
490c1c7627SSami Tolvanen 		if (cd->addr == addr && cd->state == state) {
500c1c7627SSami Tolvanen 			*res = cd;
510c1c7627SSami Tolvanen 			return 0;
520c1c7627SSami Tolvanen 		}
530c1c7627SSami Tolvanen 	}
540c1c7627SSami Tolvanen 
550c1c7627SSami Tolvanen 	return -1;
560c1c7627SSami Tolvanen }
570c1c7627SSami Tolvanen 
580c1c7627SSami Tolvanen struct die *die_map_get(Dwarf_Die *die, enum die_state state)
590c1c7627SSami Tolvanen {
600c1c7627SSami Tolvanen 	struct die *cd;
610c1c7627SSami Tolvanen 
620c1c7627SSami Tolvanen 	if (__die_map_get((uintptr_t)die->addr, state, &cd) == 0) {
630c1c7627SSami Tolvanen 		map_hits++;
640c1c7627SSami Tolvanen 		return cd;
650c1c7627SSami Tolvanen 	}
660c1c7627SSami Tolvanen 
670c1c7627SSami Tolvanen 	map_misses++;
680c1c7627SSami Tolvanen 	return create_die(die, state);
690c1c7627SSami Tolvanen }
700c1c7627SSami Tolvanen 
710c1c7627SSami Tolvanen static void reset_die(struct die *cd)
720c1c7627SSami Tolvanen {
730c1c7627SSami Tolvanen 	struct die_fragment *tmp;
740c1c7627SSami Tolvanen 	struct die_fragment *df;
750c1c7627SSami Tolvanen 
760c1c7627SSami Tolvanen 	list_for_each_entry_safe(df, tmp, &cd->fragments, list) {
770c1c7627SSami Tolvanen 		if (df->type == FRAGMENT_STRING)
780c1c7627SSami Tolvanen 			free(df->data.str);
790c1c7627SSami Tolvanen 		free(df);
800c1c7627SSami Tolvanen 	}
810c1c7627SSami Tolvanen 
820c1c7627SSami Tolvanen 	if (cd->fqn && *cd->fqn)
830c1c7627SSami Tolvanen 		free(cd->fqn);
840c1c7627SSami Tolvanen 	init_die(cd);
850c1c7627SSami Tolvanen }
860c1c7627SSami Tolvanen 
87ab443998SSami Tolvanen void die_map_for_each(die_map_callback_t func, void *arg)
88ab443998SSami Tolvanen {
89ab443998SSami Tolvanen 	struct hlist_node *tmp;
90ab443998SSami Tolvanen 	struct die *cd;
91ab443998SSami Tolvanen 
92ab443998SSami Tolvanen 	hash_for_each_safe(die_map, cd, tmp, hash) {
93ab443998SSami Tolvanen 		func(cd, arg);
94ab443998SSami Tolvanen 	}
95ab443998SSami Tolvanen }
96ab443998SSami Tolvanen 
970c1c7627SSami Tolvanen void die_map_free(void)
980c1c7627SSami Tolvanen {
990c1c7627SSami Tolvanen 	struct hlist_node *tmp;
1000c1c7627SSami Tolvanen 	unsigned int stats[DIE_LAST + 1];
1010c1c7627SSami Tolvanen 	struct die *cd;
1020c1c7627SSami Tolvanen 	int i;
1030c1c7627SSami Tolvanen 
1040c1c7627SSami Tolvanen 	memset(stats, 0, sizeof(stats));
1050c1c7627SSami Tolvanen 
1060c1c7627SSami Tolvanen 	hash_for_each_safe(die_map, cd, tmp, hash) {
1070c1c7627SSami Tolvanen 		stats[cd->state]++;
1080c1c7627SSami Tolvanen 		reset_die(cd);
1090c1c7627SSami Tolvanen 		free(cd);
1100c1c7627SSami Tolvanen 	}
1110c1c7627SSami Tolvanen 	hash_init(die_map);
1120c1c7627SSami Tolvanen 
1130c1c7627SSami Tolvanen 	if (map_hits + map_misses > 0)
1140c1c7627SSami Tolvanen 		debug("hits %u, misses %u (hit rate %.02f%%)", map_hits,
1150c1c7627SSami Tolvanen 		      map_misses,
1160c1c7627SSami Tolvanen 		      (100.0f * map_hits) / (map_hits + map_misses));
1170c1c7627SSami Tolvanen 
1180c1c7627SSami Tolvanen 	for (i = 0; i <= DIE_LAST; i++)
1190c1c7627SSami Tolvanen 		debug("%s: %u entries", die_state_name(i), stats[i]);
1200c1c7627SSami Tolvanen }
1210c1c7627SSami Tolvanen 
1220c1c7627SSami Tolvanen static struct die_fragment *append_item(struct die *cd)
1230c1c7627SSami Tolvanen {
1240c1c7627SSami Tolvanen 	struct die_fragment *df;
1250c1c7627SSami Tolvanen 
1260c1c7627SSami Tolvanen 	df = xmalloc(sizeof(struct die_fragment));
1270c1c7627SSami Tolvanen 	df->type = FRAGMENT_EMPTY;
1280c1c7627SSami Tolvanen 	list_add_tail(&df->list, &cd->fragments);
1290c1c7627SSami Tolvanen 	return df;
1300c1c7627SSami Tolvanen }
1310c1c7627SSami Tolvanen 
1320c1c7627SSami Tolvanen void die_map_add_string(struct die *cd, const char *str)
1330c1c7627SSami Tolvanen {
1340c1c7627SSami Tolvanen 	struct die_fragment *df;
1350c1c7627SSami Tolvanen 
1360c1c7627SSami Tolvanen 	if (!cd)
1370c1c7627SSami Tolvanen 		return;
1380c1c7627SSami Tolvanen 
1390c1c7627SSami Tolvanen 	df = append_item(cd);
1400c1c7627SSami Tolvanen 	df->data.str = xstrdup(str);
1410c1c7627SSami Tolvanen 	df->type = FRAGMENT_STRING;
1420c1c7627SSami Tolvanen }
1430c1c7627SSami Tolvanen 
14406b8b036SSami Tolvanen void die_map_add_linebreak(struct die *cd, int linebreak)
14506b8b036SSami Tolvanen {
14606b8b036SSami Tolvanen 	struct die_fragment *df;
14706b8b036SSami Tolvanen 
14806b8b036SSami Tolvanen 	if (!cd)
14906b8b036SSami Tolvanen 		return;
15006b8b036SSami Tolvanen 
15106b8b036SSami Tolvanen 	df = append_item(cd);
15206b8b036SSami Tolvanen 	df->data.linebreak = linebreak;
15306b8b036SSami Tolvanen 	df->type = FRAGMENT_LINEBREAK;
15406b8b036SSami Tolvanen }
15506b8b036SSami Tolvanen 
1560c1c7627SSami Tolvanen void die_map_add_die(struct die *cd, struct die *child)
1570c1c7627SSami Tolvanen {
1580c1c7627SSami Tolvanen 	struct die_fragment *df;
1590c1c7627SSami Tolvanen 
1600c1c7627SSami Tolvanen 	if (!cd)
1610c1c7627SSami Tolvanen 		return;
1620c1c7627SSami Tolvanen 
1630c1c7627SSami Tolvanen 	df = append_item(cd);
1640c1c7627SSami Tolvanen 	df->data.addr = child->addr;
1650c1c7627SSami Tolvanen 	df->type = FRAGMENT_DIE;
1660c1c7627SSami Tolvanen }
167