xref: /linux/scripts/gendwarfksyms/die.c (revision 0c1c76274e88c420779c3aea077f9812bd16edaa)
1*0c1c7627SSami Tolvanen // SPDX-License-Identifier: GPL-2.0
2*0c1c7627SSami Tolvanen /*
3*0c1c7627SSami Tolvanen  * Copyright (C) 2024 Google LLC
4*0c1c7627SSami Tolvanen  */
5*0c1c7627SSami Tolvanen 
6*0c1c7627SSami Tolvanen #include <string.h>
7*0c1c7627SSami Tolvanen #include "gendwarfksyms.h"
8*0c1c7627SSami Tolvanen 
9*0c1c7627SSami Tolvanen #define DIE_HASH_BITS 15
10*0c1c7627SSami Tolvanen 
11*0c1c7627SSami Tolvanen /* {die->addr, state} -> struct die * */
12*0c1c7627SSami Tolvanen static HASHTABLE_DEFINE(die_map, 1 << DIE_HASH_BITS);
13*0c1c7627SSami Tolvanen 
14*0c1c7627SSami Tolvanen static unsigned int map_hits;
15*0c1c7627SSami Tolvanen static unsigned int map_misses;
16*0c1c7627SSami Tolvanen 
17*0c1c7627SSami Tolvanen static inline unsigned int die_hash(uintptr_t addr, enum die_state state)
18*0c1c7627SSami Tolvanen {
19*0c1c7627SSami Tolvanen 	return hash_32(addr_hash(addr) ^ (unsigned int)state);
20*0c1c7627SSami Tolvanen }
21*0c1c7627SSami Tolvanen 
22*0c1c7627SSami Tolvanen static void init_die(struct die *cd)
23*0c1c7627SSami Tolvanen {
24*0c1c7627SSami Tolvanen 	cd->state = DIE_INCOMPLETE;
25*0c1c7627SSami Tolvanen 	cd->fqn = NULL;
26*0c1c7627SSami Tolvanen 	cd->tag = -1;
27*0c1c7627SSami Tolvanen 	cd->addr = 0;
28*0c1c7627SSami Tolvanen 	INIT_LIST_HEAD(&cd->fragments);
29*0c1c7627SSami Tolvanen }
30*0c1c7627SSami Tolvanen 
31*0c1c7627SSami Tolvanen static struct die *create_die(Dwarf_Die *die, enum die_state state)
32*0c1c7627SSami Tolvanen {
33*0c1c7627SSami Tolvanen 	struct die *cd;
34*0c1c7627SSami Tolvanen 
35*0c1c7627SSami Tolvanen 	cd = xmalloc(sizeof(struct die));
36*0c1c7627SSami Tolvanen 	init_die(cd);
37*0c1c7627SSami Tolvanen 	cd->addr = (uintptr_t)die->addr;
38*0c1c7627SSami Tolvanen 
39*0c1c7627SSami Tolvanen 	hash_add(die_map, &cd->hash, die_hash(cd->addr, state));
40*0c1c7627SSami Tolvanen 	return cd;
41*0c1c7627SSami Tolvanen }
42*0c1c7627SSami Tolvanen 
43*0c1c7627SSami Tolvanen int __die_map_get(uintptr_t addr, enum die_state state, struct die **res)
44*0c1c7627SSami Tolvanen {
45*0c1c7627SSami Tolvanen 	struct die *cd;
46*0c1c7627SSami Tolvanen 
47*0c1c7627SSami Tolvanen 	hash_for_each_possible(die_map, cd, hash, die_hash(addr, state)) {
48*0c1c7627SSami Tolvanen 		if (cd->addr == addr && cd->state == state) {
49*0c1c7627SSami Tolvanen 			*res = cd;
50*0c1c7627SSami Tolvanen 			return 0;
51*0c1c7627SSami Tolvanen 		}
52*0c1c7627SSami Tolvanen 	}
53*0c1c7627SSami Tolvanen 
54*0c1c7627SSami Tolvanen 	return -1;
55*0c1c7627SSami Tolvanen }
56*0c1c7627SSami Tolvanen 
57*0c1c7627SSami Tolvanen struct die *die_map_get(Dwarf_Die *die, enum die_state state)
58*0c1c7627SSami Tolvanen {
59*0c1c7627SSami Tolvanen 	struct die *cd;
60*0c1c7627SSami Tolvanen 
61*0c1c7627SSami Tolvanen 	if (__die_map_get((uintptr_t)die->addr, state, &cd) == 0) {
62*0c1c7627SSami Tolvanen 		map_hits++;
63*0c1c7627SSami Tolvanen 		return cd;
64*0c1c7627SSami Tolvanen 	}
65*0c1c7627SSami Tolvanen 
66*0c1c7627SSami Tolvanen 	map_misses++;
67*0c1c7627SSami Tolvanen 	return create_die(die, state);
68*0c1c7627SSami Tolvanen }
69*0c1c7627SSami Tolvanen 
70*0c1c7627SSami Tolvanen static void reset_die(struct die *cd)
71*0c1c7627SSami Tolvanen {
72*0c1c7627SSami Tolvanen 	struct die_fragment *tmp;
73*0c1c7627SSami Tolvanen 	struct die_fragment *df;
74*0c1c7627SSami Tolvanen 
75*0c1c7627SSami Tolvanen 	list_for_each_entry_safe(df, tmp, &cd->fragments, list) {
76*0c1c7627SSami Tolvanen 		if (df->type == FRAGMENT_STRING)
77*0c1c7627SSami Tolvanen 			free(df->data.str);
78*0c1c7627SSami Tolvanen 		free(df);
79*0c1c7627SSami Tolvanen 	}
80*0c1c7627SSami Tolvanen 
81*0c1c7627SSami Tolvanen 	if (cd->fqn && *cd->fqn)
82*0c1c7627SSami Tolvanen 		free(cd->fqn);
83*0c1c7627SSami Tolvanen 	init_die(cd);
84*0c1c7627SSami Tolvanen }
85*0c1c7627SSami Tolvanen 
86*0c1c7627SSami Tolvanen void die_map_free(void)
87*0c1c7627SSami Tolvanen {
88*0c1c7627SSami Tolvanen 	struct hlist_node *tmp;
89*0c1c7627SSami Tolvanen 	unsigned int stats[DIE_LAST + 1];
90*0c1c7627SSami Tolvanen 	struct die *cd;
91*0c1c7627SSami Tolvanen 	int i;
92*0c1c7627SSami Tolvanen 
93*0c1c7627SSami Tolvanen 	memset(stats, 0, sizeof(stats));
94*0c1c7627SSami Tolvanen 
95*0c1c7627SSami Tolvanen 	hash_for_each_safe(die_map, cd, tmp, hash) {
96*0c1c7627SSami Tolvanen 		stats[cd->state]++;
97*0c1c7627SSami Tolvanen 		reset_die(cd);
98*0c1c7627SSami Tolvanen 		free(cd);
99*0c1c7627SSami Tolvanen 	}
100*0c1c7627SSami Tolvanen 	hash_init(die_map);
101*0c1c7627SSami Tolvanen 
102*0c1c7627SSami Tolvanen 	if (map_hits + map_misses > 0)
103*0c1c7627SSami Tolvanen 		debug("hits %u, misses %u (hit rate %.02f%%)", map_hits,
104*0c1c7627SSami Tolvanen 		      map_misses,
105*0c1c7627SSami Tolvanen 		      (100.0f * map_hits) / (map_hits + map_misses));
106*0c1c7627SSami Tolvanen 
107*0c1c7627SSami Tolvanen 	for (i = 0; i <= DIE_LAST; i++)
108*0c1c7627SSami Tolvanen 		debug("%s: %u entries", die_state_name(i), stats[i]);
109*0c1c7627SSami Tolvanen }
110*0c1c7627SSami Tolvanen 
111*0c1c7627SSami Tolvanen static struct die_fragment *append_item(struct die *cd)
112*0c1c7627SSami Tolvanen {
113*0c1c7627SSami Tolvanen 	struct die_fragment *df;
114*0c1c7627SSami Tolvanen 
115*0c1c7627SSami Tolvanen 	df = xmalloc(sizeof(struct die_fragment));
116*0c1c7627SSami Tolvanen 	df->type = FRAGMENT_EMPTY;
117*0c1c7627SSami Tolvanen 	list_add_tail(&df->list, &cd->fragments);
118*0c1c7627SSami Tolvanen 	return df;
119*0c1c7627SSami Tolvanen }
120*0c1c7627SSami Tolvanen 
121*0c1c7627SSami Tolvanen void die_map_add_string(struct die *cd, const char *str)
122*0c1c7627SSami Tolvanen {
123*0c1c7627SSami Tolvanen 	struct die_fragment *df;
124*0c1c7627SSami Tolvanen 
125*0c1c7627SSami Tolvanen 	if (!cd)
126*0c1c7627SSami Tolvanen 		return;
127*0c1c7627SSami Tolvanen 
128*0c1c7627SSami Tolvanen 	df = append_item(cd);
129*0c1c7627SSami Tolvanen 	df->data.str = xstrdup(str);
130*0c1c7627SSami Tolvanen 	df->type = FRAGMENT_STRING;
131*0c1c7627SSami Tolvanen }
132*0c1c7627SSami Tolvanen 
133*0c1c7627SSami Tolvanen void die_map_add_die(struct die *cd, struct die *child)
134*0c1c7627SSami Tolvanen {
135*0c1c7627SSami Tolvanen 	struct die_fragment *df;
136*0c1c7627SSami Tolvanen 
137*0c1c7627SSami Tolvanen 	if (!cd)
138*0c1c7627SSami Tolvanen 		return;
139*0c1c7627SSami Tolvanen 
140*0c1c7627SSami Tolvanen 	df = append_item(cd);
141*0c1c7627SSami Tolvanen 	df->data.addr = child->addr;
142*0c1c7627SSami Tolvanen 	df->type = FRAGMENT_DIE;
143*0c1c7627SSami Tolvanen }
144