mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 00:28:52 +02:00 
			
		
		
		
	 e06aa69de2
			
		
	
	
		e06aa69de2
		
	
	
	
	
		
			
			The preferred form is to use the variable being allocated to, rather than explicitly supplying a type name which might become stale. Also do this for memset. Suggested-by: Masahiro Yamada <masahiroy@kernel.org> Signed-off-by: Giuliano Procida <gprocida@google.com> Reviewed-by: Sami Tolvanen <samitolvanen@google.com> Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
		
			
				
	
	
		
			166 lines
		
	
	
	
		
			3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			166 lines
		
	
	
	
		
			3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| /*
 | |
|  * Copyright (C) 2024 Google LLC
 | |
|  */
 | |
| 
 | |
| #include <string.h>
 | |
| #include "gendwarfksyms.h"
 | |
| 
 | |
| #define DIE_HASH_BITS 16
 | |
| 
 | |
| /* {die->addr, state} -> struct die * */
 | |
| static HASHTABLE_DEFINE(die_map, 1 << DIE_HASH_BITS);
 | |
| 
 | |
| static unsigned int map_hits;
 | |
| static unsigned int map_misses;
 | |
| 
 | |
| static inline unsigned int die_hash(uintptr_t addr, enum die_state state)
 | |
| {
 | |
| 	return hash_32(addr_hash(addr) ^ (unsigned int)state);
 | |
| }
 | |
| 
 | |
| static void init_die(struct die *cd)
 | |
| {
 | |
| 	cd->state = DIE_INCOMPLETE;
 | |
| 	cd->mapped = false;
 | |
| 	cd->fqn = NULL;
 | |
| 	cd->tag = -1;
 | |
| 	cd->addr = 0;
 | |
| 	INIT_LIST_HEAD(&cd->fragments);
 | |
| }
 | |
| 
 | |
| static struct die *create_die(Dwarf_Die *die, enum die_state state)
 | |
| {
 | |
| 	struct die *cd;
 | |
| 
 | |
| 	cd = xmalloc(sizeof(*cd));
 | |
| 	init_die(cd);
 | |
| 	cd->addr = (uintptr_t)die->addr;
 | |
| 
 | |
| 	hash_add(die_map, &cd->hash, die_hash(cd->addr, state));
 | |
| 	return cd;
 | |
| }
 | |
| 
 | |
| int __die_map_get(uintptr_t addr, enum die_state state, struct die **res)
 | |
| {
 | |
| 	struct die *cd;
 | |
| 
 | |
| 	hash_for_each_possible(die_map, cd, hash, die_hash(addr, state)) {
 | |
| 		if (cd->addr == addr && cd->state == state) {
 | |
| 			*res = cd;
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| struct die *die_map_get(Dwarf_Die *die, enum die_state state)
 | |
| {
 | |
| 	struct die *cd;
 | |
| 
 | |
| 	if (__die_map_get((uintptr_t)die->addr, state, &cd) == 0) {
 | |
| 		map_hits++;
 | |
| 		return cd;
 | |
| 	}
 | |
| 
 | |
| 	map_misses++;
 | |
| 	return create_die(die, state);
 | |
| }
 | |
| 
 | |
| static void reset_die(struct die *cd)
 | |
| {
 | |
| 	struct die_fragment *tmp;
 | |
| 	struct die_fragment *df;
 | |
| 
 | |
| 	list_for_each_entry_safe(df, tmp, &cd->fragments, list) {
 | |
| 		if (df->type == FRAGMENT_STRING)
 | |
| 			free(df->data.str);
 | |
| 		free(df);
 | |
| 	}
 | |
| 
 | |
| 	if (cd->fqn && *cd->fqn)
 | |
| 		free(cd->fqn);
 | |
| 	init_die(cd);
 | |
| }
 | |
| 
 | |
| void die_map_for_each(die_map_callback_t func, void *arg)
 | |
| {
 | |
| 	struct hlist_node *tmp;
 | |
| 	struct die *cd;
 | |
| 
 | |
| 	hash_for_each_safe(die_map, cd, tmp, hash) {
 | |
| 		func(cd, arg);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void die_map_free(void)
 | |
| {
 | |
| 	struct hlist_node *tmp;
 | |
| 	unsigned int stats[DIE_LAST + 1];
 | |
| 	struct die *cd;
 | |
| 	int i;
 | |
| 
 | |
| 	memset(stats, 0, sizeof(stats));
 | |
| 
 | |
| 	hash_for_each_safe(die_map, cd, tmp, hash) {
 | |
| 		stats[cd->state]++;
 | |
| 		reset_die(cd);
 | |
| 		free(cd);
 | |
| 	}
 | |
| 	hash_init(die_map);
 | |
| 
 | |
| 	if (map_hits + map_misses > 0)
 | |
| 		debug("hits %u, misses %u (hit rate %.02f%%)", map_hits,
 | |
| 		      map_misses,
 | |
| 		      (100.0f * map_hits) / (map_hits + map_misses));
 | |
| 
 | |
| 	for (i = 0; i <= DIE_LAST; i++)
 | |
| 		debug("%s: %u entries", die_state_name(i), stats[i]);
 | |
| }
 | |
| 
 | |
| static struct die_fragment *append_item(struct die *cd)
 | |
| {
 | |
| 	struct die_fragment *df;
 | |
| 
 | |
| 	df = xmalloc(sizeof(*df));
 | |
| 	df->type = FRAGMENT_EMPTY;
 | |
| 	list_add_tail(&df->list, &cd->fragments);
 | |
| 	return df;
 | |
| }
 | |
| 
 | |
| void die_map_add_string(struct die *cd, const char *str)
 | |
| {
 | |
| 	struct die_fragment *df;
 | |
| 
 | |
| 	if (!cd)
 | |
| 		return;
 | |
| 
 | |
| 	df = append_item(cd);
 | |
| 	df->data.str = xstrdup(str);
 | |
| 	df->type = FRAGMENT_STRING;
 | |
| }
 | |
| 
 | |
| void die_map_add_linebreak(struct die *cd, int linebreak)
 | |
| {
 | |
| 	struct die_fragment *df;
 | |
| 
 | |
| 	if (!cd)
 | |
| 		return;
 | |
| 
 | |
| 	df = append_item(cd);
 | |
| 	df->data.linebreak = linebreak;
 | |
| 	df->type = FRAGMENT_LINEBREAK;
 | |
| }
 | |
| 
 | |
| void die_map_add_die(struct die *cd, struct die *child)
 | |
| {
 | |
| 	struct die_fragment *df;
 | |
| 
 | |
| 	if (!cd)
 | |
| 		return;
 | |
| 
 | |
| 	df = append_item(cd);
 | |
| 	df->data.addr = child->addr;
 | |
| 	df->type = FRAGMENT_DIE;
 | |
| }
 |