sortextable.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * sortextable.h
  3. *
  4. * Copyright 2011 - 2012 Cavium, Inc.
  5. *
  6. * Some of this code was taken out of recordmcount.h written by:
  7. *
  8. * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
  9. * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
  10. *
  11. *
  12. * Licensed under the GNU General Public License, version 2 (GPLv2).
  13. */
  14. #undef extable_ent_size
  15. #undef compare_extable
  16. #undef do_func
  17. #undef Elf_Addr
  18. #undef Elf_Ehdr
  19. #undef Elf_Shdr
  20. #undef Elf_Rel
  21. #undef Elf_Rela
  22. #undef Elf_Sym
  23. #undef ELF_R_SYM
  24. #undef Elf_r_sym
  25. #undef ELF_R_INFO
  26. #undef Elf_r_info
  27. #undef ELF_ST_BIND
  28. #undef ELF_ST_TYPE
  29. #undef fn_ELF_R_SYM
  30. #undef fn_ELF_R_INFO
  31. #undef uint_t
  32. #undef _r
  33. #undef _w
  34. #ifdef SORTEXTABLE_64
  35. # define extable_ent_size 16
  36. # define compare_extable compare_extable_64
  37. # define do_func do64
  38. # define Elf_Addr Elf64_Addr
  39. # define Elf_Ehdr Elf64_Ehdr
  40. # define Elf_Shdr Elf64_Shdr
  41. # define Elf_Rel Elf64_Rel
  42. # define Elf_Rela Elf64_Rela
  43. # define Elf_Sym Elf64_Sym
  44. # define ELF_R_SYM ELF64_R_SYM
  45. # define Elf_r_sym Elf64_r_sym
  46. # define ELF_R_INFO ELF64_R_INFO
  47. # define Elf_r_info Elf64_r_info
  48. # define ELF_ST_BIND ELF64_ST_BIND
  49. # define ELF_ST_TYPE ELF64_ST_TYPE
  50. # define fn_ELF_R_SYM fn_ELF64_R_SYM
  51. # define fn_ELF_R_INFO fn_ELF64_R_INFO
  52. # define uint_t uint64_t
  53. # define _r r8
  54. # define _w w8
  55. #else
  56. # define extable_ent_size 8
  57. # define compare_extable compare_extable_32
  58. # define do_func do32
  59. # define Elf_Addr Elf32_Addr
  60. # define Elf_Ehdr Elf32_Ehdr
  61. # define Elf_Shdr Elf32_Shdr
  62. # define Elf_Rel Elf32_Rel
  63. # define Elf_Rela Elf32_Rela
  64. # define Elf_Sym Elf32_Sym
  65. # define ELF_R_SYM ELF32_R_SYM
  66. # define Elf_r_sym Elf32_r_sym
  67. # define ELF_R_INFO ELF32_R_INFO
  68. # define Elf_r_info Elf32_r_info
  69. # define ELF_ST_BIND ELF32_ST_BIND
  70. # define ELF_ST_TYPE ELF32_ST_TYPE
  71. # define fn_ELF_R_SYM fn_ELF32_R_SYM
  72. # define fn_ELF_R_INFO fn_ELF32_R_INFO
  73. # define uint_t uint32_t
  74. # define _r r
  75. # define _w w
  76. #endif
  77. static int compare_extable(const void *a, const void *b)
  78. {
  79. Elf_Addr av = _r(a);
  80. Elf_Addr bv = _r(b);
  81. if (av < bv)
  82. return -1;
  83. if (av > bv)
  84. return 1;
  85. return 0;
  86. }
  87. static void
  88. do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
  89. {
  90. Elf_Shdr *shdr;
  91. Elf_Shdr *shstrtab_sec;
  92. Elf_Shdr *strtab_sec = NULL;
  93. Elf_Shdr *symtab_sec = NULL;
  94. Elf_Shdr *extab_sec = NULL;
  95. Elf_Sym *sym;
  96. Elf_Sym *sort_needed_sym;
  97. Elf_Shdr *sort_needed_sec;
  98. Elf_Rel *relocs = NULL;
  99. int relocs_size;
  100. uint32_t *sort_done_location;
  101. const char *secstrtab;
  102. const char *strtab;
  103. char *extab_image;
  104. int extab_index = 0;
  105. int i;
  106. int idx;
  107. shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
  108. shstrtab_sec = shdr + r2(&ehdr->e_shstrndx);
  109. secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset);
  110. for (i = 0; i < r2(&ehdr->e_shnum); i++) {
  111. idx = r(&shdr[i].sh_name);
  112. if (strcmp(secstrtab + idx, "__ex_table") == 0) {
  113. extab_sec = shdr + i;
  114. extab_index = i;
  115. }
  116. if ((r(&shdr[i].sh_type) == SHT_REL ||
  117. r(&shdr[i].sh_type) == SHT_RELA) &&
  118. r(&shdr[i].sh_info) == extab_index) {
  119. relocs = (void *)ehdr + _r(&shdr[i].sh_offset);
  120. relocs_size = _r(&shdr[i].sh_size);
  121. }
  122. if (strcmp(secstrtab + idx, ".symtab") == 0)
  123. symtab_sec = shdr + i;
  124. if (strcmp(secstrtab + idx, ".strtab") == 0)
  125. strtab_sec = shdr + i;
  126. }
  127. if (strtab_sec == NULL) {
  128. fprintf(stderr, "no .strtab in file: %s\n", fname);
  129. fail_file();
  130. }
  131. if (symtab_sec == NULL) {
  132. fprintf(stderr, "no .symtab in file: %s\n", fname);
  133. fail_file();
  134. }
  135. if (extab_sec == NULL) {
  136. fprintf(stderr, "no __ex_table in file: %s\n", fname);
  137. fail_file();
  138. }
  139. strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
  140. extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
  141. if (custom_sort) {
  142. custom_sort(extab_image, _r(&extab_sec->sh_size));
  143. } else {
  144. int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
  145. qsort(extab_image, num_entries,
  146. extable_ent_size, compare_extable);
  147. }
  148. /* If there were relocations, we no longer need them. */
  149. if (relocs)
  150. memset(relocs, 0, relocs_size);
  151. /* find main_extable_sort_needed */
  152. sort_needed_sym = NULL;
  153. for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) {
  154. sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
  155. sym += i;
  156. if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
  157. continue;
  158. idx = r(&sym->st_name);
  159. if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) {
  160. sort_needed_sym = sym;
  161. break;
  162. }
  163. }
  164. if (sort_needed_sym == NULL) {
  165. fprintf(stderr,
  166. "no main_extable_sort_needed symbol in file: %s\n",
  167. fname);
  168. fail_file();
  169. }
  170. sort_needed_sec = &shdr[r2(&sort_needed_sym->st_shndx)];
  171. sort_done_location = (void *)ehdr +
  172. _r(&sort_needed_sec->sh_offset) +
  173. _r(&sort_needed_sym->st_value) -
  174. _r(&sort_needed_sec->sh_addr);
  175. #if 1
  176. printf("sort done marker at %lx\n",
  177. (unsigned long)((char *)sort_done_location - (char *)ehdr));
  178. #endif
  179. /* We sorted it, clear the flag. */
  180. w(0, sort_done_location);
  181. }