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