sorttable.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * sorttable.h
  4. *
  5. * Added ORC unwind tables sort support and other updates:
  6. * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by:
  7. * Shile Zhang <[email protected]>
  8. *
  9. * Copyright 2011 - 2012 Cavium, Inc.
  10. *
  11. * Some of code was taken out of arch/x86/kernel/unwind_orc.c, written by:
  12. * Copyright (C) 2017 Josh Poimboeuf <[email protected]>
  13. *
  14. * Some of this code was taken out of recordmcount.h written by:
  15. *
  16. * Copyright 2009 John F. Reiser <[email protected]>. All rights reserved.
  17. * Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc.
  18. */
  19. #undef extable_ent_size
  20. #undef compare_extable
  21. #undef get_mcount_loc
  22. #undef sort_mcount_loc
  23. #undef elf_mcount_loc
  24. #undef do_sort
  25. #undef Elf_Addr
  26. #undef Elf_Ehdr
  27. #undef Elf_Shdr
  28. #undef Elf_Rel
  29. #undef Elf_Rela
  30. #undef Elf_Sym
  31. #undef ELF_R_SYM
  32. #undef Elf_r_sym
  33. #undef ELF_R_INFO
  34. #undef Elf_r_info
  35. #undef ELF_ST_BIND
  36. #undef ELF_ST_TYPE
  37. #undef fn_ELF_R_SYM
  38. #undef fn_ELF_R_INFO
  39. #undef uint_t
  40. #undef _r
  41. #undef _w
  42. #ifdef SORTTABLE_64
  43. # define extable_ent_size 16
  44. # define compare_extable compare_extable_64
  45. # define get_mcount_loc get_mcount_loc_64
  46. # define sort_mcount_loc sort_mcount_loc_64
  47. # define elf_mcount_loc elf_mcount_loc_64
  48. # define do_sort do_sort_64
  49. # define Elf_Addr Elf64_Addr
  50. # define Elf_Ehdr Elf64_Ehdr
  51. # define Elf_Shdr Elf64_Shdr
  52. # define Elf_Rel Elf64_Rel
  53. # define Elf_Rela Elf64_Rela
  54. # define Elf_Sym Elf64_Sym
  55. # define ELF_R_SYM ELF64_R_SYM
  56. # define Elf_r_sym Elf64_r_sym
  57. # define ELF_R_INFO ELF64_R_INFO
  58. # define Elf_r_info Elf64_r_info
  59. # define ELF_ST_BIND ELF64_ST_BIND
  60. # define ELF_ST_TYPE ELF64_ST_TYPE
  61. # define fn_ELF_R_SYM fn_ELF64_R_SYM
  62. # define fn_ELF_R_INFO fn_ELF64_R_INFO
  63. # define uint_t uint64_t
  64. # define _r r8
  65. # define _w w8
  66. #else
  67. # define extable_ent_size 8
  68. # define compare_extable compare_extable_32
  69. # define get_mcount_loc get_mcount_loc_32
  70. # define sort_mcount_loc sort_mcount_loc_32
  71. # define elf_mcount_loc elf_mcount_loc_32
  72. # define do_sort do_sort_32
  73. # define Elf_Addr Elf32_Addr
  74. # define Elf_Ehdr Elf32_Ehdr
  75. # define Elf_Shdr Elf32_Shdr
  76. # define Elf_Rel Elf32_Rel
  77. # define Elf_Rela Elf32_Rela
  78. # define Elf_Sym Elf32_Sym
  79. # define ELF_R_SYM ELF32_R_SYM
  80. # define Elf_r_sym Elf32_r_sym
  81. # define ELF_R_INFO ELF32_R_INFO
  82. # define Elf_r_info Elf32_r_info
  83. # define ELF_ST_BIND ELF32_ST_BIND
  84. # define ELF_ST_TYPE ELF32_ST_TYPE
  85. # define fn_ELF_R_SYM fn_ELF32_R_SYM
  86. # define fn_ELF_R_INFO fn_ELF32_R_INFO
  87. # define uint_t uint32_t
  88. # define _r r
  89. # define _w w
  90. #endif
  91. #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
  92. /* ORC unwinder only support X86_64 */
  93. #include <asm/orc_types.h>
  94. #define ERRSTR_MAXSZ 256
  95. char g_err[ERRSTR_MAXSZ];
  96. int *g_orc_ip_table;
  97. struct orc_entry *g_orc_table;
  98. pthread_t orc_sort_thread;
  99. static inline unsigned long orc_ip(const int *ip)
  100. {
  101. return (unsigned long)ip + *ip;
  102. }
  103. static int orc_sort_cmp(const void *_a, const void *_b)
  104. {
  105. struct orc_entry *orc_a;
  106. const int *a = g_orc_ip_table + *(int *)_a;
  107. const int *b = g_orc_ip_table + *(int *)_b;
  108. unsigned long a_val = orc_ip(a);
  109. unsigned long b_val = orc_ip(b);
  110. if (a_val > b_val)
  111. return 1;
  112. if (a_val < b_val)
  113. return -1;
  114. /*
  115. * The "weak" section terminator entries need to always be on the left
  116. * to ensure the lookup code skips them in favor of real entries.
  117. * These terminator entries exist to handle any gaps created by
  118. * whitelisted .o files which didn't get objtool generation.
  119. */
  120. orc_a = g_orc_table + (a - g_orc_ip_table);
  121. return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1;
  122. }
  123. static void *sort_orctable(void *arg)
  124. {
  125. int i;
  126. int *idxs = NULL;
  127. int *tmp_orc_ip_table = NULL;
  128. struct orc_entry *tmp_orc_table = NULL;
  129. unsigned int *orc_ip_size = (unsigned int *)arg;
  130. unsigned int num_entries = *orc_ip_size / sizeof(int);
  131. unsigned int orc_size = num_entries * sizeof(struct orc_entry);
  132. idxs = (int *)malloc(*orc_ip_size);
  133. if (!idxs) {
  134. snprintf(g_err, ERRSTR_MAXSZ, "malloc idxs: %s",
  135. strerror(errno));
  136. pthread_exit(g_err);
  137. }
  138. tmp_orc_ip_table = (int *)malloc(*orc_ip_size);
  139. if (!tmp_orc_ip_table) {
  140. snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_ip_table: %s",
  141. strerror(errno));
  142. pthread_exit(g_err);
  143. }
  144. tmp_orc_table = (struct orc_entry *)malloc(orc_size);
  145. if (!tmp_orc_table) {
  146. snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_table: %s",
  147. strerror(errno));
  148. pthread_exit(g_err);
  149. }
  150. /* initialize indices array, convert ip_table to absolute address */
  151. for (i = 0; i < num_entries; i++) {
  152. idxs[i] = i;
  153. tmp_orc_ip_table[i] = g_orc_ip_table[i] + i * sizeof(int);
  154. }
  155. memcpy(tmp_orc_table, g_orc_table, orc_size);
  156. qsort(idxs, num_entries, sizeof(int), orc_sort_cmp);
  157. for (i = 0; i < num_entries; i++) {
  158. if (idxs[i] == i)
  159. continue;
  160. /* convert back to relative address */
  161. g_orc_ip_table[i] = tmp_orc_ip_table[idxs[i]] - i * sizeof(int);
  162. g_orc_table[i] = tmp_orc_table[idxs[i]];
  163. }
  164. free(idxs);
  165. free(tmp_orc_ip_table);
  166. free(tmp_orc_table);
  167. pthread_exit(NULL);
  168. }
  169. #endif
  170. static int compare_extable(const void *a, const void *b)
  171. {
  172. Elf_Addr av = _r(a);
  173. Elf_Addr bv = _r(b);
  174. if (av < bv)
  175. return -1;
  176. if (av > bv)
  177. return 1;
  178. return 0;
  179. }
  180. #ifdef MCOUNT_SORT_ENABLED
  181. pthread_t mcount_sort_thread;
  182. struct elf_mcount_loc {
  183. Elf_Ehdr *ehdr;
  184. Elf_Shdr *init_data_sec;
  185. uint_t start_mcount_loc;
  186. uint_t stop_mcount_loc;
  187. };
  188. /* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
  189. static void *sort_mcount_loc(void *arg)
  190. {
  191. struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;
  192. uint_t offset = emloc->start_mcount_loc - _r(&(emloc->init_data_sec)->sh_addr)
  193. + _r(&(emloc->init_data_sec)->sh_offset);
  194. uint_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
  195. unsigned char *start_loc = (void *)emloc->ehdr + offset;
  196. qsort(start_loc, count/sizeof(uint_t), sizeof(uint_t), compare_extable);
  197. return NULL;
  198. }
  199. /* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
  200. static void get_mcount_loc(uint_t *_start, uint_t *_stop)
  201. {
  202. FILE *file_start, *file_stop;
  203. char start_buff[20];
  204. char stop_buff[20];
  205. int len = 0;
  206. file_start = popen(" grep start_mcount System.map | awk '{print $1}' ", "r");
  207. if (!file_start) {
  208. fprintf(stderr, "get start_mcount_loc error!");
  209. return;
  210. }
  211. file_stop = popen(" grep stop_mcount System.map | awk '{print $1}' ", "r");
  212. if (!file_stop) {
  213. fprintf(stderr, "get stop_mcount_loc error!");
  214. pclose(file_start);
  215. return;
  216. }
  217. while (fgets(start_buff, sizeof(start_buff), file_start) != NULL) {
  218. len = strlen(start_buff);
  219. start_buff[len - 1] = '\0';
  220. }
  221. *_start = strtoul(start_buff, NULL, 16);
  222. while (fgets(stop_buff, sizeof(stop_buff), file_stop) != NULL) {
  223. len = strlen(stop_buff);
  224. stop_buff[len - 1] = '\0';
  225. }
  226. *_stop = strtoul(stop_buff, NULL, 16);
  227. pclose(file_start);
  228. pclose(file_stop);
  229. }
  230. #endif
  231. static int do_sort(Elf_Ehdr *ehdr,
  232. char const *const fname,
  233. table_sort_t custom_sort)
  234. {
  235. int rc = -1;
  236. Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
  237. Elf_Shdr *strtab_sec = NULL;
  238. Elf_Shdr *symtab_sec = NULL;
  239. Elf_Shdr *extab_sec = NULL;
  240. Elf_Sym *sym;
  241. const Elf_Sym *symtab;
  242. Elf32_Word *symtab_shndx = NULL;
  243. Elf_Sym *sort_needed_sym = NULL;
  244. Elf_Shdr *sort_needed_sec;
  245. Elf_Rel *relocs = NULL;
  246. int relocs_size = 0;
  247. uint32_t *sort_needed_loc;
  248. const char *secstrings;
  249. const char *strtab;
  250. char *extab_image;
  251. int extab_index = 0;
  252. int i;
  253. int idx;
  254. unsigned int shnum;
  255. unsigned int shstrndx;
  256. #ifdef MCOUNT_SORT_ENABLED
  257. struct elf_mcount_loc mstruct = {0};
  258. uint_t _start_mcount_loc = 0;
  259. uint_t _stop_mcount_loc = 0;
  260. #endif
  261. #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
  262. unsigned int orc_ip_size = 0;
  263. unsigned int orc_size = 0;
  264. unsigned int orc_num_entries = 0;
  265. #endif
  266. shstrndx = r2(&ehdr->e_shstrndx);
  267. if (shstrndx == SHN_XINDEX)
  268. shstrndx = r(&shdr[0].sh_link);
  269. secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset);
  270. shnum = r2(&ehdr->e_shnum);
  271. if (shnum == SHN_UNDEF)
  272. shnum = _r(&shdr[0].sh_size);
  273. for (i = 0, s = shdr; s < shdr + shnum; i++, s++) {
  274. idx = r(&s->sh_name);
  275. if (!strcmp(secstrings + idx, "__ex_table")) {
  276. extab_sec = s;
  277. extab_index = i;
  278. }
  279. if (!strcmp(secstrings + idx, ".symtab"))
  280. symtab_sec = s;
  281. if (!strcmp(secstrings + idx, ".strtab"))
  282. strtab_sec = s;
  283. if ((r(&s->sh_type) == SHT_REL ||
  284. r(&s->sh_type) == SHT_RELA) &&
  285. r(&s->sh_info) == extab_index) {
  286. relocs = (void *)ehdr + _r(&s->sh_offset);
  287. relocs_size = _r(&s->sh_size);
  288. }
  289. if (r(&s->sh_type) == SHT_SYMTAB_SHNDX)
  290. symtab_shndx = (Elf32_Word *)((const char *)ehdr +
  291. _r(&s->sh_offset));
  292. #ifdef MCOUNT_SORT_ENABLED
  293. /* locate the .init.data section in vmlinux */
  294. if (!strcmp(secstrings + idx, ".init.data")) {
  295. get_mcount_loc(&_start_mcount_loc, &_stop_mcount_loc);
  296. mstruct.ehdr = ehdr;
  297. mstruct.init_data_sec = s;
  298. mstruct.start_mcount_loc = _start_mcount_loc;
  299. mstruct.stop_mcount_loc = _stop_mcount_loc;
  300. }
  301. #endif
  302. #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
  303. /* locate the ORC unwind tables */
  304. if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
  305. orc_ip_size = s->sh_size;
  306. g_orc_ip_table = (int *)((void *)ehdr +
  307. s->sh_offset);
  308. }
  309. if (!strcmp(secstrings + idx, ".orc_unwind")) {
  310. orc_size = s->sh_size;
  311. g_orc_table = (struct orc_entry *)((void *)ehdr +
  312. s->sh_offset);
  313. }
  314. #endif
  315. } /* for loop */
  316. #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
  317. if (!g_orc_ip_table || !g_orc_table) {
  318. fprintf(stderr,
  319. "incomplete ORC unwind tables in file: %s\n", fname);
  320. goto out;
  321. }
  322. orc_num_entries = orc_ip_size / sizeof(int);
  323. if (orc_ip_size % sizeof(int) != 0 ||
  324. orc_size % sizeof(struct orc_entry) != 0 ||
  325. orc_num_entries != orc_size / sizeof(struct orc_entry)) {
  326. fprintf(stderr,
  327. "inconsistent ORC unwind table entries in file: %s\n",
  328. fname);
  329. goto out;
  330. }
  331. /* create thread to sort ORC unwind tables concurrently */
  332. if (pthread_create(&orc_sort_thread, NULL,
  333. sort_orctable, &orc_ip_size)) {
  334. fprintf(stderr,
  335. "pthread_create orc_sort_thread failed '%s': %s\n",
  336. strerror(errno), fname);
  337. goto out;
  338. }
  339. #endif
  340. #ifdef MCOUNT_SORT_ENABLED
  341. if (!mstruct.init_data_sec || !_start_mcount_loc || !_stop_mcount_loc) {
  342. fprintf(stderr,
  343. "incomplete mcount's sort in file: %s\n",
  344. fname);
  345. goto out;
  346. }
  347. /* create thread to sort mcount_loc concurrently */
  348. if (pthread_create(&mcount_sort_thread, NULL, &sort_mcount_loc, &mstruct)) {
  349. fprintf(stderr,
  350. "pthread_create mcount_sort_thread failed '%s': %s\n",
  351. strerror(errno), fname);
  352. goto out;
  353. }
  354. #endif
  355. if (!extab_sec) {
  356. fprintf(stderr, "no __ex_table in file: %s\n", fname);
  357. goto out;
  358. }
  359. if (!symtab_sec) {
  360. fprintf(stderr, "no .symtab in file: %s\n", fname);
  361. goto out;
  362. }
  363. if (!strtab_sec) {
  364. fprintf(stderr, "no .strtab in file: %s\n", fname);
  365. goto out;
  366. }
  367. extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
  368. strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
  369. symtab = (const Elf_Sym *)((const char *)ehdr +
  370. _r(&symtab_sec->sh_offset));
  371. if (custom_sort) {
  372. custom_sort(extab_image, _r(&extab_sec->sh_size));
  373. } else {
  374. int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
  375. qsort(extab_image, num_entries,
  376. extable_ent_size, compare_extable);
  377. }
  378. /* If there were relocations, we no longer need them. */
  379. if (relocs)
  380. memset(relocs, 0, relocs_size);
  381. /* find the flag main_extable_sort_needed */
  382. for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
  383. sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym);
  384. sym++) {
  385. if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
  386. continue;
  387. if (!strcmp(strtab + r(&sym->st_name),
  388. "main_extable_sort_needed")) {
  389. sort_needed_sym = sym;
  390. break;
  391. }
  392. }
  393. if (!sort_needed_sym) {
  394. fprintf(stderr,
  395. "no main_extable_sort_needed symbol in file: %s\n",
  396. fname);
  397. goto out;
  398. }
  399. sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx),
  400. sort_needed_sym - symtab,
  401. symtab_shndx)];
  402. sort_needed_loc = (void *)ehdr +
  403. _r(&sort_needed_sec->sh_offset) +
  404. _r(&sort_needed_sym->st_value) -
  405. _r(&sort_needed_sec->sh_addr);
  406. /* extable has been sorted, clear the flag */
  407. w(0, sort_needed_loc);
  408. rc = 0;
  409. out:
  410. #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
  411. if (orc_sort_thread) {
  412. void *retval = NULL;
  413. /* wait for ORC tables sort done */
  414. rc = pthread_join(orc_sort_thread, &retval);
  415. if (rc) {
  416. fprintf(stderr,
  417. "pthread_join failed '%s': %s\n",
  418. strerror(errno), fname);
  419. } else if (retval) {
  420. rc = -1;
  421. fprintf(stderr,
  422. "failed to sort ORC tables '%s': %s\n",
  423. (char *)retval, fname);
  424. }
  425. }
  426. #endif
  427. #ifdef MCOUNT_SORT_ENABLED
  428. if (mcount_sort_thread) {
  429. void *retval = NULL;
  430. /* wait for mcount sort done */
  431. rc = pthread_join(mcount_sort_thread, &retval);
  432. if (rc) {
  433. fprintf(stderr,
  434. "pthread_join failed '%s': %s\n",
  435. strerror(errno), fname);
  436. } else if (retval) {
  437. rc = -1;
  438. fprintf(stderr,
  439. "failed to sort mcount '%s': %s\n",
  440. (char *)retval, fname);
  441. }
  442. }
  443. #endif
  444. return rc;
  445. }