18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * sorttable.h
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Added ORC unwind tables sort support and other updates:
68c2ecf20Sopenharmony_ci * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by:
78c2ecf20Sopenharmony_ci * Shile Zhang <shile.zhang@linux.alibaba.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright 2011 - 2012 Cavium, Inc.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Some of code was taken out of arch/x86/kernel/unwind_orc.c, written by:
128c2ecf20Sopenharmony_ci * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Some of this code was taken out of recordmcount.h written by:
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
178c2ecf20Sopenharmony_ci * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#undef extable_ent_size
218c2ecf20Sopenharmony_ci#undef compare_extable
228c2ecf20Sopenharmony_ci#undef do_sort
238c2ecf20Sopenharmony_ci#undef Elf_Addr
248c2ecf20Sopenharmony_ci#undef Elf_Ehdr
258c2ecf20Sopenharmony_ci#undef Elf_Shdr
268c2ecf20Sopenharmony_ci#undef Elf_Rel
278c2ecf20Sopenharmony_ci#undef Elf_Rela
288c2ecf20Sopenharmony_ci#undef Elf_Sym
298c2ecf20Sopenharmony_ci#undef ELF_R_SYM
308c2ecf20Sopenharmony_ci#undef Elf_r_sym
318c2ecf20Sopenharmony_ci#undef ELF_R_INFO
328c2ecf20Sopenharmony_ci#undef Elf_r_info
338c2ecf20Sopenharmony_ci#undef ELF_ST_BIND
348c2ecf20Sopenharmony_ci#undef ELF_ST_TYPE
358c2ecf20Sopenharmony_ci#undef fn_ELF_R_SYM
368c2ecf20Sopenharmony_ci#undef fn_ELF_R_INFO
378c2ecf20Sopenharmony_ci#undef uint_t
388c2ecf20Sopenharmony_ci#undef _r
398c2ecf20Sopenharmony_ci#undef _w
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#ifdef SORTTABLE_64
428c2ecf20Sopenharmony_ci# define extable_ent_size	16
438c2ecf20Sopenharmony_ci# define compare_extable	compare_extable_64
448c2ecf20Sopenharmony_ci# define do_sort		do_sort_64
458c2ecf20Sopenharmony_ci# define Elf_Addr		Elf64_Addr
468c2ecf20Sopenharmony_ci# define Elf_Ehdr		Elf64_Ehdr
478c2ecf20Sopenharmony_ci# define Elf_Shdr		Elf64_Shdr
488c2ecf20Sopenharmony_ci# define Elf_Rel		Elf64_Rel
498c2ecf20Sopenharmony_ci# define Elf_Rela		Elf64_Rela
508c2ecf20Sopenharmony_ci# define Elf_Sym		Elf64_Sym
518c2ecf20Sopenharmony_ci# define ELF_R_SYM		ELF64_R_SYM
528c2ecf20Sopenharmony_ci# define Elf_r_sym		Elf64_r_sym
538c2ecf20Sopenharmony_ci# define ELF_R_INFO		ELF64_R_INFO
548c2ecf20Sopenharmony_ci# define Elf_r_info		Elf64_r_info
558c2ecf20Sopenharmony_ci# define ELF_ST_BIND		ELF64_ST_BIND
568c2ecf20Sopenharmony_ci# define ELF_ST_TYPE		ELF64_ST_TYPE
578c2ecf20Sopenharmony_ci# define fn_ELF_R_SYM		fn_ELF64_R_SYM
588c2ecf20Sopenharmony_ci# define fn_ELF_R_INFO		fn_ELF64_R_INFO
598c2ecf20Sopenharmony_ci# define uint_t			uint64_t
608c2ecf20Sopenharmony_ci# define _r			r8
618c2ecf20Sopenharmony_ci# define _w			w8
628c2ecf20Sopenharmony_ci#else
638c2ecf20Sopenharmony_ci# define extable_ent_size	8
648c2ecf20Sopenharmony_ci# define compare_extable	compare_extable_32
658c2ecf20Sopenharmony_ci# define do_sort		do_sort_32
668c2ecf20Sopenharmony_ci# define Elf_Addr		Elf32_Addr
678c2ecf20Sopenharmony_ci# define Elf_Ehdr		Elf32_Ehdr
688c2ecf20Sopenharmony_ci# define Elf_Shdr		Elf32_Shdr
698c2ecf20Sopenharmony_ci# define Elf_Rel		Elf32_Rel
708c2ecf20Sopenharmony_ci# define Elf_Rela		Elf32_Rela
718c2ecf20Sopenharmony_ci# define Elf_Sym		Elf32_Sym
728c2ecf20Sopenharmony_ci# define ELF_R_SYM		ELF32_R_SYM
738c2ecf20Sopenharmony_ci# define Elf_r_sym		Elf32_r_sym
748c2ecf20Sopenharmony_ci# define ELF_R_INFO		ELF32_R_INFO
758c2ecf20Sopenharmony_ci# define Elf_r_info		Elf32_r_info
768c2ecf20Sopenharmony_ci# define ELF_ST_BIND		ELF32_ST_BIND
778c2ecf20Sopenharmony_ci# define ELF_ST_TYPE		ELF32_ST_TYPE
788c2ecf20Sopenharmony_ci# define fn_ELF_R_SYM		fn_ELF32_R_SYM
798c2ecf20Sopenharmony_ci# define fn_ELF_R_INFO		fn_ELF32_R_INFO
808c2ecf20Sopenharmony_ci# define uint_t			uint32_t
818c2ecf20Sopenharmony_ci# define _r			r
828c2ecf20Sopenharmony_ci# define _w			w
838c2ecf20Sopenharmony_ci#endif
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
868c2ecf20Sopenharmony_ci/* ORC unwinder only support X86_64 */
878c2ecf20Sopenharmony_ci#include <errno.h>
888c2ecf20Sopenharmony_ci#include <pthread.h>
898c2ecf20Sopenharmony_ci#include <asm/orc_types.h>
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci#define ERRSTR_MAXSZ	256
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cichar g_err[ERRSTR_MAXSZ];
948c2ecf20Sopenharmony_ciint *g_orc_ip_table;
958c2ecf20Sopenharmony_cistruct orc_entry *g_orc_table;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cipthread_t orc_sort_thread;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic inline unsigned long orc_ip(const int *ip)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	return (unsigned long)ip + *ip;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic int orc_sort_cmp(const void *_a, const void *_b)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	struct orc_entry *orc_a;
1078c2ecf20Sopenharmony_ci	const int *a = g_orc_ip_table + *(int *)_a;
1088c2ecf20Sopenharmony_ci	const int *b = g_orc_ip_table + *(int *)_b;
1098c2ecf20Sopenharmony_ci	unsigned long a_val = orc_ip(a);
1108c2ecf20Sopenharmony_ci	unsigned long b_val = orc_ip(b);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	if (a_val > b_val)
1138c2ecf20Sopenharmony_ci		return 1;
1148c2ecf20Sopenharmony_ci	if (a_val < b_val)
1158c2ecf20Sopenharmony_ci		return -1;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/*
1188c2ecf20Sopenharmony_ci	 * The "weak" section terminator entries need to always be on the left
1198c2ecf20Sopenharmony_ci	 * to ensure the lookup code skips them in favor of real entries.
1208c2ecf20Sopenharmony_ci	 * These terminator entries exist to handle any gaps created by
1218c2ecf20Sopenharmony_ci	 * whitelisted .o files which didn't get objtool generation.
1228c2ecf20Sopenharmony_ci	 */
1238c2ecf20Sopenharmony_ci	orc_a = g_orc_table + (a - g_orc_ip_table);
1248c2ecf20Sopenharmony_ci	return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic void *sort_orctable(void *arg)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	int i;
1308c2ecf20Sopenharmony_ci	int *idxs = NULL;
1318c2ecf20Sopenharmony_ci	int *tmp_orc_ip_table = NULL;
1328c2ecf20Sopenharmony_ci	struct orc_entry *tmp_orc_table = NULL;
1338c2ecf20Sopenharmony_ci	unsigned int *orc_ip_size = (unsigned int *)arg;
1348c2ecf20Sopenharmony_ci	unsigned int num_entries = *orc_ip_size / sizeof(int);
1358c2ecf20Sopenharmony_ci	unsigned int orc_size = num_entries * sizeof(struct orc_entry);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	idxs = (int *)malloc(*orc_ip_size);
1388c2ecf20Sopenharmony_ci	if (!idxs) {
1398c2ecf20Sopenharmony_ci		snprintf(g_err, ERRSTR_MAXSZ, "malloc idxs: %s",
1408c2ecf20Sopenharmony_ci			 strerror(errno));
1418c2ecf20Sopenharmony_ci		pthread_exit(g_err);
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	tmp_orc_ip_table = (int *)malloc(*orc_ip_size);
1458c2ecf20Sopenharmony_ci	if (!tmp_orc_ip_table) {
1468c2ecf20Sopenharmony_ci		snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_ip_table: %s",
1478c2ecf20Sopenharmony_ci			 strerror(errno));
1488c2ecf20Sopenharmony_ci		pthread_exit(g_err);
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	tmp_orc_table = (struct orc_entry *)malloc(orc_size);
1528c2ecf20Sopenharmony_ci	if (!tmp_orc_table) {
1538c2ecf20Sopenharmony_ci		snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_table: %s",
1548c2ecf20Sopenharmony_ci			 strerror(errno));
1558c2ecf20Sopenharmony_ci		pthread_exit(g_err);
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* initialize indices array, convert ip_table to absolute address */
1598c2ecf20Sopenharmony_ci	for (i = 0; i < num_entries; i++) {
1608c2ecf20Sopenharmony_ci		idxs[i] = i;
1618c2ecf20Sopenharmony_ci		tmp_orc_ip_table[i] = g_orc_ip_table[i] + i * sizeof(int);
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci	memcpy(tmp_orc_table, g_orc_table, orc_size);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	qsort(idxs, num_entries, sizeof(int), orc_sort_cmp);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	for (i = 0; i < num_entries; i++) {
1688c2ecf20Sopenharmony_ci		if (idxs[i] == i)
1698c2ecf20Sopenharmony_ci			continue;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		/* convert back to relative address */
1728c2ecf20Sopenharmony_ci		g_orc_ip_table[i] = tmp_orc_ip_table[idxs[i]] - i * sizeof(int);
1738c2ecf20Sopenharmony_ci		g_orc_table[i] = tmp_orc_table[idxs[i]];
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	free(idxs);
1778c2ecf20Sopenharmony_ci	free(tmp_orc_ip_table);
1788c2ecf20Sopenharmony_ci	free(tmp_orc_table);
1798c2ecf20Sopenharmony_ci	pthread_exit(NULL);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci#endif
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic int compare_extable(const void *a, const void *b)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	Elf_Addr av = _r(a);
1868c2ecf20Sopenharmony_ci	Elf_Addr bv = _r(b);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (av < bv)
1898c2ecf20Sopenharmony_ci		return -1;
1908c2ecf20Sopenharmony_ci	if (av > bv)
1918c2ecf20Sopenharmony_ci		return 1;
1928c2ecf20Sopenharmony_ci	return 0;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int do_sort(Elf_Ehdr *ehdr,
1968c2ecf20Sopenharmony_ci		   char const *const fname,
1978c2ecf20Sopenharmony_ci		   table_sort_t custom_sort)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	int rc = -1;
2008c2ecf20Sopenharmony_ci	Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
2018c2ecf20Sopenharmony_ci	Elf_Shdr *strtab_sec = NULL;
2028c2ecf20Sopenharmony_ci	Elf_Shdr *symtab_sec = NULL;
2038c2ecf20Sopenharmony_ci	Elf_Shdr *extab_sec = NULL;
2048c2ecf20Sopenharmony_ci	Elf_Sym *sym;
2058c2ecf20Sopenharmony_ci	const Elf_Sym *symtab;
2068c2ecf20Sopenharmony_ci	Elf32_Word *symtab_shndx = NULL;
2078c2ecf20Sopenharmony_ci	Elf_Sym *sort_needed_sym = NULL;
2088c2ecf20Sopenharmony_ci	Elf_Shdr *sort_needed_sec;
2098c2ecf20Sopenharmony_ci	Elf_Rel *relocs = NULL;
2108c2ecf20Sopenharmony_ci	int relocs_size = 0;
2118c2ecf20Sopenharmony_ci	uint32_t *sort_needed_loc;
2128c2ecf20Sopenharmony_ci	const char *secstrings;
2138c2ecf20Sopenharmony_ci	const char *strtab;
2148c2ecf20Sopenharmony_ci	char *extab_image;
2158c2ecf20Sopenharmony_ci	int extab_index = 0;
2168c2ecf20Sopenharmony_ci	int i;
2178c2ecf20Sopenharmony_ci	int idx;
2188c2ecf20Sopenharmony_ci	unsigned int shnum;
2198c2ecf20Sopenharmony_ci	unsigned int shstrndx;
2208c2ecf20Sopenharmony_ci#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
2218c2ecf20Sopenharmony_ci	unsigned int orc_ip_size = 0;
2228c2ecf20Sopenharmony_ci	unsigned int orc_size = 0;
2238c2ecf20Sopenharmony_ci	unsigned int orc_num_entries = 0;
2248c2ecf20Sopenharmony_ci#endif
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	shstrndx = r2(&ehdr->e_shstrndx);
2278c2ecf20Sopenharmony_ci	if (shstrndx == SHN_XINDEX)
2288c2ecf20Sopenharmony_ci		shstrndx = r(&shdr[0].sh_link);
2298c2ecf20Sopenharmony_ci	secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	shnum = r2(&ehdr->e_shnum);
2328c2ecf20Sopenharmony_ci	if (shnum == SHN_UNDEF)
2338c2ecf20Sopenharmony_ci		shnum = _r(&shdr[0].sh_size);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	for (i = 0, s = shdr; s < shdr + shnum; i++, s++) {
2368c2ecf20Sopenharmony_ci		idx = r(&s->sh_name);
2378c2ecf20Sopenharmony_ci		if (!strcmp(secstrings + idx, "__ex_table")) {
2388c2ecf20Sopenharmony_ci			extab_sec = s;
2398c2ecf20Sopenharmony_ci			extab_index = i;
2408c2ecf20Sopenharmony_ci		}
2418c2ecf20Sopenharmony_ci		if (!strcmp(secstrings + idx, ".symtab"))
2428c2ecf20Sopenharmony_ci			symtab_sec = s;
2438c2ecf20Sopenharmony_ci		if (!strcmp(secstrings + idx, ".strtab"))
2448c2ecf20Sopenharmony_ci			strtab_sec = s;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci		if ((r(&s->sh_type) == SHT_REL ||
2478c2ecf20Sopenharmony_ci		     r(&s->sh_type) == SHT_RELA) &&
2488c2ecf20Sopenharmony_ci		    r(&s->sh_info) == extab_index) {
2498c2ecf20Sopenharmony_ci			relocs = (void *)ehdr + _r(&s->sh_offset);
2508c2ecf20Sopenharmony_ci			relocs_size = _r(&s->sh_size);
2518c2ecf20Sopenharmony_ci		}
2528c2ecf20Sopenharmony_ci		if (r(&s->sh_type) == SHT_SYMTAB_SHNDX)
2538c2ecf20Sopenharmony_ci			symtab_shndx = (Elf32_Word *)((const char *)ehdr +
2548c2ecf20Sopenharmony_ci						      _r(&s->sh_offset));
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
2578c2ecf20Sopenharmony_ci		/* locate the ORC unwind tables */
2588c2ecf20Sopenharmony_ci		if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
2598c2ecf20Sopenharmony_ci			orc_ip_size = s->sh_size;
2608c2ecf20Sopenharmony_ci			g_orc_ip_table = (int *)((void *)ehdr +
2618c2ecf20Sopenharmony_ci						   s->sh_offset);
2628c2ecf20Sopenharmony_ci		}
2638c2ecf20Sopenharmony_ci		if (!strcmp(secstrings + idx, ".orc_unwind")) {
2648c2ecf20Sopenharmony_ci			orc_size = s->sh_size;
2658c2ecf20Sopenharmony_ci			g_orc_table = (struct orc_entry *)((void *)ehdr +
2668c2ecf20Sopenharmony_ci							     s->sh_offset);
2678c2ecf20Sopenharmony_ci		}
2688c2ecf20Sopenharmony_ci#endif
2698c2ecf20Sopenharmony_ci	} /* for loop */
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
2728c2ecf20Sopenharmony_ci	if (!g_orc_ip_table || !g_orc_table) {
2738c2ecf20Sopenharmony_ci		fprintf(stderr,
2748c2ecf20Sopenharmony_ci			"incomplete ORC unwind tables in file: %s\n", fname);
2758c2ecf20Sopenharmony_ci		goto out;
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	orc_num_entries = orc_ip_size / sizeof(int);
2798c2ecf20Sopenharmony_ci	if (orc_ip_size % sizeof(int) != 0 ||
2808c2ecf20Sopenharmony_ci	    orc_size % sizeof(struct orc_entry) != 0 ||
2818c2ecf20Sopenharmony_ci	    orc_num_entries != orc_size / sizeof(struct orc_entry)) {
2828c2ecf20Sopenharmony_ci		fprintf(stderr,
2838c2ecf20Sopenharmony_ci			"inconsistent ORC unwind table entries in file: %s\n",
2848c2ecf20Sopenharmony_ci			fname);
2858c2ecf20Sopenharmony_ci		goto out;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	/* create thread to sort ORC unwind tables concurrently */
2898c2ecf20Sopenharmony_ci	if (pthread_create(&orc_sort_thread, NULL,
2908c2ecf20Sopenharmony_ci			   sort_orctable, &orc_ip_size)) {
2918c2ecf20Sopenharmony_ci		fprintf(stderr,
2928c2ecf20Sopenharmony_ci			"pthread_create orc_sort_thread failed '%s': %s\n",
2938c2ecf20Sopenharmony_ci			strerror(errno), fname);
2948c2ecf20Sopenharmony_ci		goto out;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci#endif
2978c2ecf20Sopenharmony_ci	if (!extab_sec) {
2988c2ecf20Sopenharmony_ci		fprintf(stderr,	"no __ex_table in file: %s\n", fname);
2998c2ecf20Sopenharmony_ci		goto out;
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (!symtab_sec) {
3038c2ecf20Sopenharmony_ci		fprintf(stderr,	"no .symtab in file: %s\n", fname);
3048c2ecf20Sopenharmony_ci		goto out;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (!strtab_sec) {
3088c2ecf20Sopenharmony_ci		fprintf(stderr,	"no .strtab in file: %s\n", fname);
3098c2ecf20Sopenharmony_ci		goto out;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
3138c2ecf20Sopenharmony_ci	strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
3148c2ecf20Sopenharmony_ci	symtab = (const Elf_Sym *)((const char *)ehdr +
3158c2ecf20Sopenharmony_ci						  _r(&symtab_sec->sh_offset));
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (custom_sort) {
3188c2ecf20Sopenharmony_ci		custom_sort(extab_image, _r(&extab_sec->sh_size));
3198c2ecf20Sopenharmony_ci	} else {
3208c2ecf20Sopenharmony_ci		int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
3218c2ecf20Sopenharmony_ci		qsort(extab_image, num_entries,
3228c2ecf20Sopenharmony_ci		      extable_ent_size, compare_extable);
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	/* If there were relocations, we no longer need them. */
3268c2ecf20Sopenharmony_ci	if (relocs)
3278c2ecf20Sopenharmony_ci		memset(relocs, 0, relocs_size);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/* find the flag main_extable_sort_needed */
3308c2ecf20Sopenharmony_ci	for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
3318c2ecf20Sopenharmony_ci	     sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym);
3328c2ecf20Sopenharmony_ci	     sym++) {
3338c2ecf20Sopenharmony_ci		if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
3348c2ecf20Sopenharmony_ci			continue;
3358c2ecf20Sopenharmony_ci		if (!strcmp(strtab + r(&sym->st_name),
3368c2ecf20Sopenharmony_ci			    "main_extable_sort_needed")) {
3378c2ecf20Sopenharmony_ci			sort_needed_sym = sym;
3388c2ecf20Sopenharmony_ci			break;
3398c2ecf20Sopenharmony_ci		}
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (!sort_needed_sym) {
3438c2ecf20Sopenharmony_ci		fprintf(stderr,
3448c2ecf20Sopenharmony_ci			"no main_extable_sort_needed symbol in file: %s\n",
3458c2ecf20Sopenharmony_ci			fname);
3468c2ecf20Sopenharmony_ci		goto out;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx),
3508c2ecf20Sopenharmony_ci					     sort_needed_sym - symtab,
3518c2ecf20Sopenharmony_ci					     symtab_shndx)];
3528c2ecf20Sopenharmony_ci	sort_needed_loc = (void *)ehdr +
3538c2ecf20Sopenharmony_ci		_r(&sort_needed_sec->sh_offset) +
3548c2ecf20Sopenharmony_ci		_r(&sort_needed_sym->st_value) -
3558c2ecf20Sopenharmony_ci		_r(&sort_needed_sec->sh_addr);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/* extable has been sorted, clear the flag */
3588c2ecf20Sopenharmony_ci	w(0, sort_needed_loc);
3598c2ecf20Sopenharmony_ci	rc = 0;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ciout:
3628c2ecf20Sopenharmony_ci#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
3638c2ecf20Sopenharmony_ci	if (orc_sort_thread) {
3648c2ecf20Sopenharmony_ci		void *retval = NULL;
3658c2ecf20Sopenharmony_ci		/* wait for ORC tables sort done */
3668c2ecf20Sopenharmony_ci		rc = pthread_join(orc_sort_thread, &retval);
3678c2ecf20Sopenharmony_ci		if (rc)
3688c2ecf20Sopenharmony_ci			fprintf(stderr,
3698c2ecf20Sopenharmony_ci				"pthread_join failed '%s': %s\n",
3708c2ecf20Sopenharmony_ci				strerror(errno), fname);
3718c2ecf20Sopenharmony_ci		else if (retval) {
3728c2ecf20Sopenharmony_ci			rc = -1;
3738c2ecf20Sopenharmony_ci			fprintf(stderr,
3748c2ecf20Sopenharmony_ci				"failed to sort ORC tables '%s': %s\n",
3758c2ecf20Sopenharmony_ci				(char *)retval, fname);
3768c2ecf20Sopenharmony_ci		}
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci#endif
3798c2ecf20Sopenharmony_ci	return rc;
3808c2ecf20Sopenharmony_ci}
381