xref: /linux/scripts/gendwarfksyms/die.c (revision 06b8b036ab9c1e70a562705a398bcd271e0b5ebf)
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 
90c1c7627SSami Tolvanen #define DIE_HASH_BITS 15
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;
250c1c7627SSami Tolvanen 	cd->fqn = NULL;
260c1c7627SSami Tolvanen 	cd->tag = -1;
270c1c7627SSami Tolvanen 	cd->addr = 0;
280c1c7627SSami Tolvanen 	INIT_LIST_HEAD(&cd->fragments);
290c1c7627SSami Tolvanen }
300c1c7627SSami Tolvanen 
310c1c7627SSami Tolvanen static struct die *create_die(Dwarf_Die *die, enum die_state state)
320c1c7627SSami Tolvanen {
330c1c7627SSami Tolvanen 	struct die *cd;
340c1c7627SSami Tolvanen 
350c1c7627SSami Tolvanen 	cd = xmalloc(sizeof(struct die));
360c1c7627SSami Tolvanen 	init_die(cd);
370c1c7627SSami Tolvanen 	cd->addr = (uintptr_t)die->addr;
380c1c7627SSami Tolvanen 
390c1c7627SSami Tolvanen 	hash_add(die_map, &cd->hash, die_hash(cd->addr, state));
400c1c7627SSami Tolvanen 	return cd;
410c1c7627SSami Tolvanen }
420c1c7627SSami Tolvanen 
430c1c7627SSami Tolvanen int __die_map_get(uintptr_t addr, enum die_state state, struct die **res)
440c1c7627SSami Tolvanen {
450c1c7627SSami Tolvanen 	struct die *cd;
460c1c7627SSami Tolvanen 
470c1c7627SSami Tolvanen 	hash_for_each_possible(die_map, cd, hash, die_hash(addr, state)) {
480c1c7627SSami Tolvanen 		if (cd->addr == addr && cd->state == state) {
490c1c7627SSami Tolvanen 			*res = cd;
500c1c7627SSami Tolvanen 			return 0;
510c1c7627SSami Tolvanen 		}
520c1c7627SSami Tolvanen 	}
530c1c7627SSami Tolvanen 
540c1c7627SSami Tolvanen 	return -1;
550c1c7627SSami Tolvanen }
560c1c7627SSami Tolvanen 
570c1c7627SSami Tolvanen struct die *die_map_get(Dwarf_Die *die, enum die_state state)
580c1c7627SSami Tolvanen {
590c1c7627SSami Tolvanen 	struct die *cd;
600c1c7627SSami Tolvanen 
610c1c7627SSami Tolvanen 	if (__die_map_get((uintptr_t)die->addr, state, &cd) == 0) {
620c1c7627SSami Tolvanen 		map_hits++;
630c1c7627SSami Tolvanen 		return cd;
640c1c7627SSami Tolvanen 	}
650c1c7627SSami Tolvanen 
660c1c7627SSami Tolvanen 	map_misses++;
670c1c7627SSami Tolvanen 	return create_die(die, state);
680c1c7627SSami Tolvanen }
690c1c7627SSami Tolvanen 
700c1c7627SSami Tolvanen static void reset_die(struct die *cd)
710c1c7627SSami Tolvanen {
720c1c7627SSami Tolvanen 	struct die_fragment *tmp;
730c1c7627SSami Tolvanen 	struct die_fragment *df;
740c1c7627SSami Tolvanen 
750c1c7627SSami Tolvanen 	list_for_each_entry_safe(df, tmp, &cd->fragments, list) {
760c1c7627SSami Tolvanen 		if (df->type == FRAGMENT_STRING)
770c1c7627SSami Tolvanen 			free(df->data.str);
780c1c7627SSami Tolvanen 		free(df);
790c1c7627SSami Tolvanen 	}
800c1c7627SSami Tolvanen 
810c1c7627SSami Tolvanen 	if (cd->fqn && *cd->fqn)
820c1c7627SSami Tolvanen 		free(cd->fqn);
830c1c7627SSami Tolvanen 	init_die(cd);
840c1c7627SSami Tolvanen }
850c1c7627SSami Tolvanen 
860c1c7627SSami Tolvanen void die_map_free(void)
870c1c7627SSami Tolvanen {
880c1c7627SSami Tolvanen 	struct hlist_node *tmp;
890c1c7627SSami Tolvanen 	unsigned int stats[DIE_LAST + 1];
900c1c7627SSami Tolvanen 	struct die *cd;
910c1c7627SSami Tolvanen 	int i;
920c1c7627SSami Tolvanen 
930c1c7627SSami Tolvanen 	memset(stats, 0, sizeof(stats));
940c1c7627SSami Tolvanen 
950c1c7627SSami Tolvanen 	hash_for_each_safe(die_map, cd, tmp, hash) {
960c1c7627SSami Tolvanen 		stats[cd->state]++;
970c1c7627SSami Tolvanen 		reset_die(cd);
980c1c7627SSami Tolvanen 		free(cd);
990c1c7627SSami Tolvanen 	}
1000c1c7627SSami Tolvanen 	hash_init(die_map);
1010c1c7627SSami Tolvanen 
1020c1c7627SSami Tolvanen 	if (map_hits + map_misses > 0)
1030c1c7627SSami Tolvanen 		debug("hits %u, misses %u (hit rate %.02f%%)", map_hits,
1040c1c7627SSami Tolvanen 		      map_misses,
1050c1c7627SSami Tolvanen 		      (100.0f * map_hits) / (map_hits + map_misses));
1060c1c7627SSami Tolvanen 
1070c1c7627SSami Tolvanen 	for (i = 0; i <= DIE_LAST; i++)
1080c1c7627SSami Tolvanen 		debug("%s: %u entries", die_state_name(i), stats[i]);
1090c1c7627SSami Tolvanen }
1100c1c7627SSami Tolvanen 
1110c1c7627SSami Tolvanen static struct die_fragment *append_item(struct die *cd)
1120c1c7627SSami Tolvanen {
1130c1c7627SSami Tolvanen 	struct die_fragment *df;
1140c1c7627SSami Tolvanen 
1150c1c7627SSami Tolvanen 	df = xmalloc(sizeof(struct die_fragment));
1160c1c7627SSami Tolvanen 	df->type = FRAGMENT_EMPTY;
1170c1c7627SSami Tolvanen 	list_add_tail(&df->list, &cd->fragments);
1180c1c7627SSami Tolvanen 	return df;
1190c1c7627SSami Tolvanen }
1200c1c7627SSami Tolvanen 
1210c1c7627SSami Tolvanen void die_map_add_string(struct die *cd, const char *str)
1220c1c7627SSami Tolvanen {
1230c1c7627SSami Tolvanen 	struct die_fragment *df;
1240c1c7627SSami Tolvanen 
1250c1c7627SSami Tolvanen 	if (!cd)
1260c1c7627SSami Tolvanen 		return;
1270c1c7627SSami Tolvanen 
1280c1c7627SSami Tolvanen 	df = append_item(cd);
1290c1c7627SSami Tolvanen 	df->data.str = xstrdup(str);
1300c1c7627SSami Tolvanen 	df->type = FRAGMENT_STRING;
1310c1c7627SSami Tolvanen }
1320c1c7627SSami Tolvanen 
133*06b8b036SSami Tolvanen void die_map_add_linebreak(struct die *cd, int linebreak)
134*06b8b036SSami Tolvanen {
135*06b8b036SSami Tolvanen 	struct die_fragment *df;
136*06b8b036SSami Tolvanen 
137*06b8b036SSami Tolvanen 	if (!cd)
138*06b8b036SSami Tolvanen 		return;
139*06b8b036SSami Tolvanen 
140*06b8b036SSami Tolvanen 	df = append_item(cd);
141*06b8b036SSami Tolvanen 	df->data.linebreak = linebreak;
142*06b8b036SSami Tolvanen 	df->type = FRAGMENT_LINEBREAK;
143*06b8b036SSami Tolvanen }
144*06b8b036SSami Tolvanen 
1450c1c7627SSami Tolvanen void die_map_add_die(struct die *cd, struct die *child)
1460c1c7627SSami Tolvanen {
1470c1c7627SSami Tolvanen 	struct die_fragment *df;
1480c1c7627SSami Tolvanen 
1490c1c7627SSami Tolvanen 	if (!cd)
1500c1c7627SSami Tolvanen 		return;
1510c1c7627SSami Tolvanen 
1520c1c7627SSami Tolvanen 	df = append_item(cd);
1530c1c7627SSami Tolvanen 	df->data.addr = child->addr;
1540c1c7627SSami Tolvanen 	df->type = FRAGMENT_DIE;
1550c1c7627SSami Tolvanen }
156