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 9*10e9510aSSami Tolvanen #define DIE_HASH_BITS 16 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; 25ab443998SSami Tolvanen cd->mapped = false; 260c1c7627SSami Tolvanen cd->fqn = NULL; 270c1c7627SSami Tolvanen cd->tag = -1; 280c1c7627SSami Tolvanen cd->addr = 0; 290c1c7627SSami Tolvanen INIT_LIST_HEAD(&cd->fragments); 300c1c7627SSami Tolvanen } 310c1c7627SSami Tolvanen 320c1c7627SSami Tolvanen static struct die *create_die(Dwarf_Die *die, enum die_state state) 330c1c7627SSami Tolvanen { 340c1c7627SSami Tolvanen struct die *cd; 350c1c7627SSami Tolvanen 360c1c7627SSami Tolvanen cd = xmalloc(sizeof(struct die)); 370c1c7627SSami Tolvanen init_die(cd); 380c1c7627SSami Tolvanen cd->addr = (uintptr_t)die->addr; 390c1c7627SSami Tolvanen 400c1c7627SSami Tolvanen hash_add(die_map, &cd->hash, die_hash(cd->addr, state)); 410c1c7627SSami Tolvanen return cd; 420c1c7627SSami Tolvanen } 430c1c7627SSami Tolvanen 440c1c7627SSami Tolvanen int __die_map_get(uintptr_t addr, enum die_state state, struct die **res) 450c1c7627SSami Tolvanen { 460c1c7627SSami Tolvanen struct die *cd; 470c1c7627SSami Tolvanen 480c1c7627SSami Tolvanen hash_for_each_possible(die_map, cd, hash, die_hash(addr, state)) { 490c1c7627SSami Tolvanen if (cd->addr == addr && cd->state == state) { 500c1c7627SSami Tolvanen *res = cd; 510c1c7627SSami Tolvanen return 0; 520c1c7627SSami Tolvanen } 530c1c7627SSami Tolvanen } 540c1c7627SSami Tolvanen 550c1c7627SSami Tolvanen return -1; 560c1c7627SSami Tolvanen } 570c1c7627SSami Tolvanen 580c1c7627SSami Tolvanen struct die *die_map_get(Dwarf_Die *die, enum die_state state) 590c1c7627SSami Tolvanen { 600c1c7627SSami Tolvanen struct die *cd; 610c1c7627SSami Tolvanen 620c1c7627SSami Tolvanen if (__die_map_get((uintptr_t)die->addr, state, &cd) == 0) { 630c1c7627SSami Tolvanen map_hits++; 640c1c7627SSami Tolvanen return cd; 650c1c7627SSami Tolvanen } 660c1c7627SSami Tolvanen 670c1c7627SSami Tolvanen map_misses++; 680c1c7627SSami Tolvanen return create_die(die, state); 690c1c7627SSami Tolvanen } 700c1c7627SSami Tolvanen 710c1c7627SSami Tolvanen static void reset_die(struct die *cd) 720c1c7627SSami Tolvanen { 730c1c7627SSami Tolvanen struct die_fragment *tmp; 740c1c7627SSami Tolvanen struct die_fragment *df; 750c1c7627SSami Tolvanen 760c1c7627SSami Tolvanen list_for_each_entry_safe(df, tmp, &cd->fragments, list) { 770c1c7627SSami Tolvanen if (df->type == FRAGMENT_STRING) 780c1c7627SSami Tolvanen free(df->data.str); 790c1c7627SSami Tolvanen free(df); 800c1c7627SSami Tolvanen } 810c1c7627SSami Tolvanen 820c1c7627SSami Tolvanen if (cd->fqn && *cd->fqn) 830c1c7627SSami Tolvanen free(cd->fqn); 840c1c7627SSami Tolvanen init_die(cd); 850c1c7627SSami Tolvanen } 860c1c7627SSami Tolvanen 87ab443998SSami Tolvanen void die_map_for_each(die_map_callback_t func, void *arg) 88ab443998SSami Tolvanen { 89ab443998SSami Tolvanen struct hlist_node *tmp; 90ab443998SSami Tolvanen struct die *cd; 91ab443998SSami Tolvanen 92ab443998SSami Tolvanen hash_for_each_safe(die_map, cd, tmp, hash) { 93ab443998SSami Tolvanen func(cd, arg); 94ab443998SSami Tolvanen } 95ab443998SSami Tolvanen } 96ab443998SSami Tolvanen 970c1c7627SSami Tolvanen void die_map_free(void) 980c1c7627SSami Tolvanen { 990c1c7627SSami Tolvanen struct hlist_node *tmp; 1000c1c7627SSami Tolvanen unsigned int stats[DIE_LAST + 1]; 1010c1c7627SSami Tolvanen struct die *cd; 1020c1c7627SSami Tolvanen int i; 1030c1c7627SSami Tolvanen 1040c1c7627SSami Tolvanen memset(stats, 0, sizeof(stats)); 1050c1c7627SSami Tolvanen 1060c1c7627SSami Tolvanen hash_for_each_safe(die_map, cd, tmp, hash) { 1070c1c7627SSami Tolvanen stats[cd->state]++; 1080c1c7627SSami Tolvanen reset_die(cd); 1090c1c7627SSami Tolvanen free(cd); 1100c1c7627SSami Tolvanen } 1110c1c7627SSami Tolvanen hash_init(die_map); 1120c1c7627SSami Tolvanen 1130c1c7627SSami Tolvanen if (map_hits + map_misses > 0) 1140c1c7627SSami Tolvanen debug("hits %u, misses %u (hit rate %.02f%%)", map_hits, 1150c1c7627SSami Tolvanen map_misses, 1160c1c7627SSami Tolvanen (100.0f * map_hits) / (map_hits + map_misses)); 1170c1c7627SSami Tolvanen 1180c1c7627SSami Tolvanen for (i = 0; i <= DIE_LAST; i++) 1190c1c7627SSami Tolvanen debug("%s: %u entries", die_state_name(i), stats[i]); 1200c1c7627SSami Tolvanen } 1210c1c7627SSami Tolvanen 1220c1c7627SSami Tolvanen static struct die_fragment *append_item(struct die *cd) 1230c1c7627SSami Tolvanen { 1240c1c7627SSami Tolvanen struct die_fragment *df; 1250c1c7627SSami Tolvanen 1260c1c7627SSami Tolvanen df = xmalloc(sizeof(struct die_fragment)); 1270c1c7627SSami Tolvanen df->type = FRAGMENT_EMPTY; 1280c1c7627SSami Tolvanen list_add_tail(&df->list, &cd->fragments); 1290c1c7627SSami Tolvanen return df; 1300c1c7627SSami Tolvanen } 1310c1c7627SSami Tolvanen 1320c1c7627SSami Tolvanen void die_map_add_string(struct die *cd, const char *str) 1330c1c7627SSami Tolvanen { 1340c1c7627SSami Tolvanen struct die_fragment *df; 1350c1c7627SSami Tolvanen 1360c1c7627SSami Tolvanen if (!cd) 1370c1c7627SSami Tolvanen return; 1380c1c7627SSami Tolvanen 1390c1c7627SSami Tolvanen df = append_item(cd); 1400c1c7627SSami Tolvanen df->data.str = xstrdup(str); 1410c1c7627SSami Tolvanen df->type = FRAGMENT_STRING; 1420c1c7627SSami Tolvanen } 1430c1c7627SSami Tolvanen 14406b8b036SSami Tolvanen void die_map_add_linebreak(struct die *cd, int linebreak) 14506b8b036SSami Tolvanen { 14606b8b036SSami Tolvanen struct die_fragment *df; 14706b8b036SSami Tolvanen 14806b8b036SSami Tolvanen if (!cd) 14906b8b036SSami Tolvanen return; 15006b8b036SSami Tolvanen 15106b8b036SSami Tolvanen df = append_item(cd); 15206b8b036SSami Tolvanen df->data.linebreak = linebreak; 15306b8b036SSami Tolvanen df->type = FRAGMENT_LINEBREAK; 15406b8b036SSami Tolvanen } 15506b8b036SSami Tolvanen 1560c1c7627SSami Tolvanen void die_map_add_die(struct die *cd, struct die *child) 1570c1c7627SSami Tolvanen { 1580c1c7627SSami Tolvanen struct die_fragment *df; 1590c1c7627SSami Tolvanen 1600c1c7627SSami Tolvanen if (!cd) 1610c1c7627SSami Tolvanen return; 1620c1c7627SSami Tolvanen 1630c1c7627SSami Tolvanen df = append_item(cd); 1640c1c7627SSami Tolvanen df->data.addr = child->addr; 1650c1c7627SSami Tolvanen df->type = FRAGMENT_DIE; 1660c1c7627SSami Tolvanen } 167