symsearch.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Helper functions for finding the symbol in an ELF which is "nearest"
  4. * to a given address.
  5. */
  6. #include <xalloc.h>
  7. #include "modpost.h"
  8. struct syminfo {
  9. unsigned int symbol_index;
  10. unsigned int section_index;
  11. Elf_Addr addr;
  12. };
  13. /*
  14. * Container used to hold an entire binary search table.
  15. * Entries in table are ascending, sorted first by section_index,
  16. * then by addr, and last by symbol_index. The sorting by
  17. * symbol_index is used to ensure predictable behavior when
  18. * multiple symbols are present with the same address; all
  19. * symbols past the first are effectively ignored, by eliding
  20. * them in symsearch_fixup().
  21. */
  22. struct symsearch {
  23. unsigned int table_size;
  24. struct syminfo table[];
  25. };
  26. static int syminfo_compare(const void *s1, const void *s2)
  27. {
  28. const struct syminfo *sym1 = s1;
  29. const struct syminfo *sym2 = s2;
  30. if (sym1->section_index > sym2->section_index)
  31. return 1;
  32. if (sym1->section_index < sym2->section_index)
  33. return -1;
  34. if (sym1->addr > sym2->addr)
  35. return 1;
  36. if (sym1->addr < sym2->addr)
  37. return -1;
  38. if (sym1->symbol_index > sym2->symbol_index)
  39. return 1;
  40. if (sym1->symbol_index < sym2->symbol_index)
  41. return -1;
  42. return 0;
  43. }
  44. static unsigned int symbol_count(struct elf_info *elf)
  45. {
  46. unsigned int result = 0;
  47. for (Elf_Sym *sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
  48. if (is_valid_name(elf, sym))
  49. result++;
  50. }
  51. return result;
  52. }
  53. /*
  54. * Populate the search array that we just allocated.
  55. * Be slightly paranoid here. The ELF file is mmap'd and could
  56. * conceivably change between symbol_count() and symsearch_populate().
  57. * If we notice any difference, bail out rather than potentially
  58. * propagating errors or crashing.
  59. */
  60. static void symsearch_populate(struct elf_info *elf,
  61. struct syminfo *table,
  62. unsigned int table_size)
  63. {
  64. bool is_arm = (elf->hdr->e_machine == EM_ARM);
  65. for (Elf_Sym *sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
  66. if (is_valid_name(elf, sym)) {
  67. if (table_size-- == 0)
  68. fatal("%s: size mismatch\n", __func__);
  69. table->symbol_index = sym - elf->symtab_start;
  70. table->section_index = get_secindex(elf, sym);
  71. table->addr = sym->st_value;
  72. /*
  73. * For ARM Thumb instruction, the bit 0 of st_value is
  74. * set if the symbol is STT_FUNC type. Mask it to get
  75. * the address.
  76. */
  77. if (is_arm && ELF_ST_TYPE(sym->st_info) == STT_FUNC)
  78. table->addr &= ~1;
  79. table++;
  80. }
  81. }
  82. if (table_size != 0)
  83. fatal("%s: size mismatch\n", __func__);
  84. }
  85. /*
  86. * Do any fixups on the table after sorting.
  87. * For now, this just finds adjacent entries which have
  88. * the same section_index and addr, and it propagates
  89. * the first symbol_index over the subsequent entries,
  90. * so that only one symbol_index is seen for any given
  91. * section_index and addr. This ensures that whether
  92. * we're looking at an address from "above" or "below"
  93. * that we see the same symbol_index.
  94. * This does leave some duplicate entries in the table;
  95. * in practice, these are a small fraction of the
  96. * total number of entries, and they are harmless to
  97. * the binary search algorithm other than a few occasional
  98. * unnecessary comparisons.
  99. */
  100. static void symsearch_fixup(struct syminfo *table, unsigned int table_size)
  101. {
  102. /* Don't look at index 0, it will never change. */
  103. for (unsigned int i = 1; i < table_size; i++) {
  104. if (table[i].addr == table[i - 1].addr &&
  105. table[i].section_index == table[i - 1].section_index) {
  106. table[i].symbol_index = table[i - 1].symbol_index;
  107. }
  108. }
  109. }
  110. void symsearch_init(struct elf_info *elf)
  111. {
  112. unsigned int table_size = symbol_count(elf);
  113. elf->symsearch = xmalloc(sizeof(struct symsearch) +
  114. sizeof(struct syminfo) * table_size);
  115. elf->symsearch->table_size = table_size;
  116. symsearch_populate(elf, elf->symsearch->table, table_size);
  117. qsort(elf->symsearch->table, table_size,
  118. sizeof(struct syminfo), syminfo_compare);
  119. symsearch_fixup(elf->symsearch->table, table_size);
  120. }
  121. void symsearch_finish(struct elf_info *elf)
  122. {
  123. free(elf->symsearch);
  124. elf->symsearch = NULL;
  125. }
  126. /*
  127. * Find the syminfo which is in secndx and "nearest" to addr.
  128. * allow_negative: allow returning a symbol whose address is > addr.
  129. * min_distance: ignore symbols which are further away than this.
  130. *
  131. * Returns a pointer into the symbol table for success.
  132. * Returns NULL if no legal symbol is found within the requested range.
  133. */
  134. Elf_Sym *symsearch_find_nearest(struct elf_info *elf, Elf_Addr addr,
  135. unsigned int secndx, bool allow_negative,
  136. Elf_Addr min_distance)
  137. {
  138. unsigned int hi = elf->symsearch->table_size;
  139. unsigned int lo = 0;
  140. struct syminfo *table = elf->symsearch->table;
  141. struct syminfo target;
  142. target.addr = addr;
  143. target.section_index = secndx;
  144. target.symbol_index = ~0; /* compares greater than any actual index */
  145. while (hi > lo) {
  146. unsigned int mid = lo + (hi - lo) / 2; /* Avoids overflow */
  147. if (syminfo_compare(&table[mid], &target) > 0)
  148. hi = mid;
  149. else
  150. lo = mid + 1;
  151. }
  152. /*
  153. * table[hi], if it exists, is the first entry in the array which
  154. * lies beyond target. table[hi - 1], if it exists, is the last
  155. * entry in the array which comes before target, including the
  156. * case where it perfectly matches the section and the address.
  157. *
  158. * Note -- if the address we're looking up falls perfectly
  159. * in the middle of two symbols, this is written to always
  160. * prefer the symbol with the lower address.
  161. */
  162. Elf_Sym *result = NULL;
  163. if (allow_negative &&
  164. hi < elf->symsearch->table_size &&
  165. table[hi].section_index == secndx &&
  166. table[hi].addr - addr <= min_distance) {
  167. min_distance = table[hi].addr - addr;
  168. result = &elf->symtab_start[table[hi].symbol_index];
  169. }
  170. if (hi > 0 &&
  171. table[hi - 1].section_index == secndx &&
  172. addr - table[hi - 1].addr <= min_distance) {
  173. result = &elf->symtab_start[table[hi - 1].symbol_index];
  174. }
  175. return result;
  176. }