sorttable.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  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 <shile.zhang@linux.alibaba.com>
  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 <jpoimboe@redhat.com>
  13. *
  14. * Some of this code was taken out of recordmcount.h written by:
  15. *
  16. * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
  17. * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, 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, *orc_b;
  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. orc_b = g_orc_table + (b - g_orc_ip_table);
  122. if (orc_a->type == ORC_TYPE_UNDEFINED && orc_b->type == ORC_TYPE_UNDEFINED)
  123. return 0;
  124. return orc_a->type == ORC_TYPE_UNDEFINED ? -1 : 1;
  125. }
  126. static void *sort_orctable(void *arg)
  127. {
  128. int i;
  129. int *idxs = NULL;
  130. int *tmp_orc_ip_table = NULL;
  131. struct orc_entry *tmp_orc_table = NULL;
  132. unsigned int *orc_ip_size = (unsigned int *)arg;
  133. unsigned int num_entries = *orc_ip_size / sizeof(int);
  134. unsigned int orc_size = num_entries * sizeof(struct orc_entry);
  135. idxs = (int *)malloc(*orc_ip_size);
  136. if (!idxs) {
  137. snprintf(g_err, ERRSTR_MAXSZ, "malloc idxs: %s",
  138. strerror(errno));
  139. pthread_exit(g_err);
  140. }
  141. tmp_orc_ip_table = (int *)malloc(*orc_ip_size);
  142. if (!tmp_orc_ip_table) {
  143. snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_ip_table: %s",
  144. strerror(errno));
  145. pthread_exit(g_err);
  146. }
  147. tmp_orc_table = (struct orc_entry *)malloc(orc_size);
  148. if (!tmp_orc_table) {
  149. snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_table: %s",
  150. strerror(errno));
  151. pthread_exit(g_err);
  152. }
  153. /* initialize indices array, convert ip_table to absolute address */
  154. for (i = 0; i < num_entries; i++) {
  155. idxs[i] = i;
  156. tmp_orc_ip_table[i] = g_orc_ip_table[i] + i * sizeof(int);
  157. }
  158. memcpy(tmp_orc_table, g_orc_table, orc_size);
  159. qsort(idxs, num_entries, sizeof(int), orc_sort_cmp);
  160. for (i = 0; i < num_entries; i++) {
  161. if (idxs[i] == i)
  162. continue;
  163. /* convert back to relative address */
  164. g_orc_ip_table[i] = tmp_orc_ip_table[idxs[i]] - i * sizeof(int);
  165. g_orc_table[i] = tmp_orc_table[idxs[i]];
  166. }
  167. free(idxs);
  168. free(tmp_orc_ip_table);
  169. free(tmp_orc_table);
  170. pthread_exit(NULL);
  171. }
  172. #endif
  173. static int compare_extable(const void *a, const void *b)
  174. {
  175. Elf_Addr av = _r(a);
  176. Elf_Addr bv = _r(b);
  177. if (av < bv)
  178. return -1;
  179. if (av > bv)
  180. return 1;
  181. return 0;
  182. }
  183. #ifdef MCOUNT_SORT_ENABLED
  184. pthread_t mcount_sort_thread;
  185. struct elf_mcount_loc {
  186. Elf_Ehdr *ehdr;
  187. Elf_Shdr *init_data_sec;
  188. uint_t start_mcount_loc;
  189. uint_t stop_mcount_loc;
  190. };
  191. /* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
  192. static void *sort_mcount_loc(void *arg)
  193. {
  194. struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;
  195. uint_t offset = emloc->start_mcount_loc - _r(&(emloc->init_data_sec)->sh_addr)
  196. + _r(&(emloc->init_data_sec)->sh_offset);
  197. uint_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
  198. unsigned char *start_loc = (void *)emloc->ehdr + offset;
  199. qsort(start_loc, count/sizeof(uint_t), sizeof(uint_t), compare_extable);
  200. return NULL;
  201. }
  202. /* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
  203. static void get_mcount_loc(uint_t *_start, uint_t *_stop)
  204. {
  205. FILE *file_start, *file_stop;
  206. char start_buff[20];
  207. char stop_buff[20];
  208. int len = 0;
  209. file_start = popen(" grep start_mcount System.map | awk '{print $1}' ", "r");
  210. if (!file_start) {
  211. fprintf(stderr, "get start_mcount_loc error!");
  212. return;
  213. }
  214. file_stop = popen(" grep stop_mcount System.map | awk '{print $1}' ", "r");
  215. if (!file_stop) {
  216. fprintf(stderr, "get stop_mcount_loc error!");
  217. pclose(file_start);
  218. return;
  219. }
  220. while (fgets(start_buff, sizeof(start_buff), file_start) != NULL) {
  221. len = strlen(start_buff);
  222. start_buff[len - 1] = '\0';
  223. }
  224. *_start = strtoul(start_buff, NULL, 16);
  225. while (fgets(stop_buff, sizeof(stop_buff), file_stop) != NULL) {
  226. len = strlen(stop_buff);
  227. stop_buff[len - 1] = '\0';
  228. }
  229. *_stop = strtoul(stop_buff, NULL, 16);
  230. pclose(file_start);
  231. pclose(file_stop);
  232. }
  233. #endif
  234. static int do_sort(Elf_Ehdr *ehdr,
  235. char const *const fname,
  236. table_sort_t custom_sort)
  237. {
  238. int rc = -1;
  239. Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
  240. Elf_Shdr *strtab_sec = NULL;
  241. Elf_Shdr *symtab_sec = NULL;
  242. Elf_Shdr *extab_sec = NULL;
  243. Elf_Sym *sym;
  244. const Elf_Sym *symtab;
  245. Elf32_Word *symtab_shndx = NULL;
  246. Elf_Sym *sort_needed_sym = NULL;
  247. Elf_Shdr *sort_needed_sec;
  248. Elf_Rel *relocs = NULL;
  249. int relocs_size = 0;
  250. uint32_t *sort_needed_loc;
  251. const char *secstrings;
  252. const char *strtab;
  253. char *extab_image;
  254. int extab_index = 0;
  255. int i;
  256. int idx;
  257. unsigned int shnum;
  258. unsigned int shstrndx;
  259. #ifdef MCOUNT_SORT_ENABLED
  260. struct elf_mcount_loc mstruct = {0};
  261. uint_t _start_mcount_loc = 0;
  262. uint_t _stop_mcount_loc = 0;
  263. #endif
  264. #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
  265. unsigned int orc_ip_size = 0;
  266. unsigned int orc_size = 0;
  267. unsigned int orc_num_entries = 0;
  268. #endif
  269. shstrndx = r2(&ehdr->e_shstrndx);
  270. if (shstrndx == SHN_XINDEX)
  271. shstrndx = r(&shdr[0].sh_link);
  272. secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset);
  273. shnum = r2(&ehdr->e_shnum);
  274. if (shnum == SHN_UNDEF)
  275. shnum = _r(&shdr[0].sh_size);
  276. for (i = 0, s = shdr; s < shdr + shnum; i++, s++) {
  277. idx = r(&s->sh_name);
  278. if (!strcmp(secstrings + idx, "__ex_table")) {
  279. extab_sec = s;
  280. extab_index = i;
  281. }
  282. if (!strcmp(secstrings + idx, ".symtab"))
  283. symtab_sec = s;
  284. if (!strcmp(secstrings + idx, ".strtab"))
  285. strtab_sec = s;
  286. if ((r(&s->sh_type) == SHT_REL ||
  287. r(&s->sh_type) == SHT_RELA) &&
  288. r(&s->sh_info) == extab_index) {
  289. relocs = (void *)ehdr + _r(&s->sh_offset);
  290. relocs_size = _r(&s->sh_size);
  291. }
  292. if (r(&s->sh_type) == SHT_SYMTAB_SHNDX)
  293. symtab_shndx = (Elf32_Word *)((const char *)ehdr +
  294. _r(&s->sh_offset));
  295. #ifdef MCOUNT_SORT_ENABLED
  296. /* locate the .init.data section in vmlinux */
  297. if (!strcmp(secstrings + idx, ".init.data")) {
  298. get_mcount_loc(&_start_mcount_loc, &_stop_mcount_loc);
  299. mstruct.ehdr = ehdr;
  300. mstruct.init_data_sec = s;
  301. mstruct.start_mcount_loc = _start_mcount_loc;
  302. mstruct.stop_mcount_loc = _stop_mcount_loc;
  303. }
  304. #endif
  305. #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
  306. /* locate the ORC unwind tables */
  307. if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
  308. orc_ip_size = s->sh_size;
  309. g_orc_ip_table = (int *)((void *)ehdr +
  310. s->sh_offset);
  311. }
  312. if (!strcmp(secstrings + idx, ".orc_unwind")) {
  313. orc_size = s->sh_size;
  314. g_orc_table = (struct orc_entry *)((void *)ehdr +
  315. s->sh_offset);
  316. }
  317. #endif
  318. } /* for loop */
  319. #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
  320. if (!g_orc_ip_table || !g_orc_table) {
  321. fprintf(stderr,
  322. "incomplete ORC unwind tables in file: %s\n", fname);
  323. goto out;
  324. }
  325. orc_num_entries = orc_ip_size / sizeof(int);
  326. if (orc_ip_size % sizeof(int) != 0 ||
  327. orc_size % sizeof(struct orc_entry) != 0 ||
  328. orc_num_entries != orc_size / sizeof(struct orc_entry)) {
  329. fprintf(stderr,
  330. "inconsistent ORC unwind table entries in file: %s\n",
  331. fname);
  332. goto out;
  333. }
  334. /* create thread to sort ORC unwind tables concurrently */
  335. if (pthread_create(&orc_sort_thread, NULL,
  336. sort_orctable, &orc_ip_size)) {
  337. fprintf(stderr,
  338. "pthread_create orc_sort_thread failed '%s': %s\n",
  339. strerror(errno), fname);
  340. goto out;
  341. }
  342. #endif
  343. #ifdef MCOUNT_SORT_ENABLED
  344. if (!mstruct.init_data_sec || !_start_mcount_loc || !_stop_mcount_loc) {
  345. fprintf(stderr,
  346. "incomplete mcount's sort in file: %s\n",
  347. fname);
  348. goto out;
  349. }
  350. /* create thread to sort mcount_loc concurrently */
  351. if (pthread_create(&mcount_sort_thread, NULL, &sort_mcount_loc, &mstruct)) {
  352. fprintf(stderr,
  353. "pthread_create mcount_sort_thread failed '%s': %s\n",
  354. strerror(errno), fname);
  355. goto out;
  356. }
  357. #endif
  358. if (!extab_sec) {
  359. fprintf(stderr, "no __ex_table in file: %s\n", fname);
  360. goto out;
  361. }
  362. if (!symtab_sec) {
  363. fprintf(stderr, "no .symtab in file: %s\n", fname);
  364. goto out;
  365. }
  366. if (!strtab_sec) {
  367. fprintf(stderr, "no .strtab in file: %s\n", fname);
  368. goto out;
  369. }
  370. extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
  371. strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
  372. symtab = (const Elf_Sym *)((const char *)ehdr +
  373. _r(&symtab_sec->sh_offset));
  374. if (custom_sort) {
  375. custom_sort(extab_image, _r(&extab_sec->sh_size));
  376. } else {
  377. int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
  378. qsort(extab_image, num_entries,
  379. extable_ent_size, compare_extable);
  380. }
  381. /* If there were relocations, we no longer need them. */
  382. if (relocs)
  383. memset(relocs, 0, relocs_size);
  384. /* find the flag main_extable_sort_needed */
  385. for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
  386. sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym);
  387. sym++) {
  388. if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
  389. continue;
  390. if (!strcmp(strtab + r(&sym->st_name),
  391. "main_extable_sort_needed")) {
  392. sort_needed_sym = sym;
  393. break;
  394. }
  395. }
  396. if (!sort_needed_sym) {
  397. fprintf(stderr,
  398. "no main_extable_sort_needed symbol in file: %s\n",
  399. fname);
  400. goto out;
  401. }
  402. sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx),
  403. sort_needed_sym - symtab,
  404. symtab_shndx)];
  405. sort_needed_loc = (void *)ehdr +
  406. _r(&sort_needed_sec->sh_offset) +
  407. _r(&sort_needed_sym->st_value) -
  408. _r(&sort_needed_sec->sh_addr);
  409. /* extable has been sorted, clear the flag */
  410. w(0, sort_needed_loc);
  411. rc = 0;
  412. out:
  413. #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
  414. if (orc_sort_thread) {
  415. void *retval = NULL;
  416. /* wait for ORC tables sort done */
  417. rc = pthread_join(orc_sort_thread, &retval);
  418. if (rc) {
  419. fprintf(stderr,
  420. "pthread_join failed '%s': %s\n",
  421. strerror(errno), fname);
  422. } else if (retval) {
  423. rc = -1;
  424. fprintf(stderr,
  425. "failed to sort ORC tables '%s': %s\n",
  426. (char *)retval, fname);
  427. }
  428. }
  429. #endif
  430. #ifdef MCOUNT_SORT_ENABLED
  431. if (mcount_sort_thread) {
  432. void *retval = NULL;
  433. /* wait for mcount sort done */
  434. rc = pthread_join(mcount_sort_thread, &retval);
  435. if (rc) {
  436. fprintf(stderr,
  437. "pthread_join failed '%s': %s\n",
  438. strerror(errno), fname);
  439. } else if (retval) {
  440. rc = -1;
  441. fprintf(stderr,
  442. "failed to sort mcount '%s': %s\n",
  443. (char *)retval, fname);
  444. }
  445. }
  446. #endif
  447. return rc;
  448. }