| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- // 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;
- }
|