File Index
Files and directories
Sign in
FILE

die.c

File preview with syntax highlighting.

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