die.c 3.0 KB

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