xref: /openbmc/linux/scripts/sorttable.h (revision c8a7ff13f5fc6e6b313de2a8e02304c2a90a3906)
110916706SShile Zhang /* SPDX-License-Identifier: GPL-2.0-only */
210916706SShile Zhang /*
310916706SShile Zhang  * sorttable.h
410916706SShile Zhang  *
557fa1899SShile Zhang  * Added ORC unwind tables sort support and other updates:
657fa1899SShile Zhang  * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by:
757fa1899SShile Zhang  * Shile Zhang <shile.zhang@linux.alibaba.com>
857fa1899SShile Zhang  *
910916706SShile Zhang  * Copyright 2011 - 2012 Cavium, Inc.
1010916706SShile Zhang  *
1157fa1899SShile Zhang  * Some of code was taken out of arch/x86/kernel/unwind_orc.c, written by:
1257fa1899SShile Zhang  * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
1357fa1899SShile Zhang  *
1410916706SShile Zhang  * Some of this code was taken out of recordmcount.h written by:
1510916706SShile Zhang  *
1610916706SShile Zhang  * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
1710916706SShile Zhang  * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
1810916706SShile Zhang  */
1910916706SShile Zhang 
2010916706SShile Zhang #undef extable_ent_size
2110916706SShile Zhang #undef compare_extable
2210916706SShile Zhang #undef do_sort
2310916706SShile Zhang #undef Elf_Addr
2410916706SShile Zhang #undef Elf_Ehdr
2510916706SShile Zhang #undef Elf_Shdr
2610916706SShile Zhang #undef Elf_Rel
2710916706SShile Zhang #undef Elf_Rela
2810916706SShile Zhang #undef Elf_Sym
2910916706SShile Zhang #undef ELF_R_SYM
3010916706SShile Zhang #undef Elf_r_sym
3110916706SShile Zhang #undef ELF_R_INFO
3210916706SShile Zhang #undef Elf_r_info
3310916706SShile Zhang #undef ELF_ST_BIND
3410916706SShile Zhang #undef ELF_ST_TYPE
3510916706SShile Zhang #undef fn_ELF_R_SYM
3610916706SShile Zhang #undef fn_ELF_R_INFO
3710916706SShile Zhang #undef uint_t
3810916706SShile Zhang #undef _r
3910916706SShile Zhang #undef _w
4010916706SShile Zhang 
4110916706SShile Zhang #ifdef SORTTABLE_64
4210916706SShile Zhang # define extable_ent_size	16
4310916706SShile Zhang # define compare_extable	compare_extable_64
4410916706SShile Zhang # define do_sort		do_sort_64
4510916706SShile Zhang # define Elf_Addr		Elf64_Addr
4610916706SShile Zhang # define Elf_Ehdr		Elf64_Ehdr
4710916706SShile Zhang # define Elf_Shdr		Elf64_Shdr
4810916706SShile Zhang # define Elf_Rel		Elf64_Rel
4910916706SShile Zhang # define Elf_Rela		Elf64_Rela
5010916706SShile Zhang # define Elf_Sym		Elf64_Sym
5110916706SShile Zhang # define ELF_R_SYM		ELF64_R_SYM
5210916706SShile Zhang # define Elf_r_sym		Elf64_r_sym
5310916706SShile Zhang # define ELF_R_INFO		ELF64_R_INFO
5410916706SShile Zhang # define Elf_r_info		Elf64_r_info
5510916706SShile Zhang # define ELF_ST_BIND		ELF64_ST_BIND
5610916706SShile Zhang # define ELF_ST_TYPE		ELF64_ST_TYPE
5710916706SShile Zhang # define fn_ELF_R_SYM		fn_ELF64_R_SYM
5810916706SShile Zhang # define fn_ELF_R_INFO		fn_ELF64_R_INFO
5910916706SShile Zhang # define uint_t			uint64_t
6010916706SShile Zhang # define _r			r8
6110916706SShile Zhang # define _w			w8
6210916706SShile Zhang #else
6310916706SShile Zhang # define extable_ent_size	8
6410916706SShile Zhang # define compare_extable	compare_extable_32
6510916706SShile Zhang # define do_sort		do_sort_32
6610916706SShile Zhang # define Elf_Addr		Elf32_Addr
6710916706SShile Zhang # define Elf_Ehdr		Elf32_Ehdr
6810916706SShile Zhang # define Elf_Shdr		Elf32_Shdr
6910916706SShile Zhang # define Elf_Rel		Elf32_Rel
7010916706SShile Zhang # define Elf_Rela		Elf32_Rela
7110916706SShile Zhang # define Elf_Sym		Elf32_Sym
7210916706SShile Zhang # define ELF_R_SYM		ELF32_R_SYM
7310916706SShile Zhang # define Elf_r_sym		Elf32_r_sym
7410916706SShile Zhang # define ELF_R_INFO		ELF32_R_INFO
7510916706SShile Zhang # define Elf_r_info		Elf32_r_info
7610916706SShile Zhang # define ELF_ST_BIND		ELF32_ST_BIND
7710916706SShile Zhang # define ELF_ST_TYPE		ELF32_ST_TYPE
7810916706SShile Zhang # define fn_ELF_R_SYM		fn_ELF32_R_SYM
7910916706SShile Zhang # define fn_ELF_R_INFO		fn_ELF32_R_INFO
8010916706SShile Zhang # define uint_t			uint32_t
8110916706SShile Zhang # define _r			r
8210916706SShile Zhang # define _w			w
8310916706SShile Zhang #endif
8410916706SShile Zhang 
8557fa1899SShile Zhang #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
8657fa1899SShile Zhang /* ORC unwinder only support X86_64 */
8757fa1899SShile Zhang #include <errno.h>
8857fa1899SShile Zhang #include <pthread.h>
8957fa1899SShile Zhang #include <asm/orc_types.h>
9057fa1899SShile Zhang 
9157fa1899SShile Zhang #define ERRSTR_MAXSZ	256
9257fa1899SShile Zhang 
9357fa1899SShile Zhang char g_err[ERRSTR_MAXSZ];
9457fa1899SShile Zhang int *g_orc_ip_table;
9557fa1899SShile Zhang struct orc_entry *g_orc_table;
9657fa1899SShile Zhang 
9757fa1899SShile Zhang pthread_t orc_sort_thread;
9857fa1899SShile Zhang 
9957fa1899SShile Zhang static inline unsigned long orc_ip(const int *ip)
10057fa1899SShile Zhang {
10157fa1899SShile Zhang 	return (unsigned long)ip + *ip;
10257fa1899SShile Zhang }
10357fa1899SShile Zhang 
10457fa1899SShile Zhang static int orc_sort_cmp(const void *_a, const void *_b)
10557fa1899SShile Zhang {
10657fa1899SShile Zhang 	struct orc_entry *orc_a;
10757fa1899SShile Zhang 	const int *a = g_orc_ip_table + *(int *)_a;
10857fa1899SShile Zhang 	const int *b = g_orc_ip_table + *(int *)_b;
10957fa1899SShile Zhang 	unsigned long a_val = orc_ip(a);
11057fa1899SShile Zhang 	unsigned long b_val = orc_ip(b);
11157fa1899SShile Zhang 
11257fa1899SShile Zhang 	if (a_val > b_val)
11357fa1899SShile Zhang 		return 1;
11457fa1899SShile Zhang 	if (a_val < b_val)
11557fa1899SShile Zhang 		return -1;
11657fa1899SShile Zhang 
11757fa1899SShile Zhang 	/*
11857fa1899SShile Zhang 	 * The "weak" section terminator entries need to always be on the left
11957fa1899SShile Zhang 	 * to ensure the lookup code skips them in favor of real entries.
12057fa1899SShile Zhang 	 * These terminator entries exist to handle any gaps created by
12157fa1899SShile Zhang 	 * whitelisted .o files which didn't get objtool generation.
12257fa1899SShile Zhang 	 */
12357fa1899SShile Zhang 	orc_a = g_orc_table + (a - g_orc_ip_table);
12457fa1899SShile Zhang 	return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1;
12557fa1899SShile Zhang }
12657fa1899SShile Zhang 
12757fa1899SShile Zhang static void *sort_orctable(void *arg)
12857fa1899SShile Zhang {
12957fa1899SShile Zhang 	int i;
13057fa1899SShile Zhang 	int *idxs = NULL;
13157fa1899SShile Zhang 	int *tmp_orc_ip_table = NULL;
13257fa1899SShile Zhang 	struct orc_entry *tmp_orc_table = NULL;
13357fa1899SShile Zhang 	unsigned int *orc_ip_size = (unsigned int *)arg;
13457fa1899SShile Zhang 	unsigned int num_entries = *orc_ip_size / sizeof(int);
13557fa1899SShile Zhang 	unsigned int orc_size = num_entries * sizeof(struct orc_entry);
13657fa1899SShile Zhang 
13757fa1899SShile Zhang 	idxs = (int *)malloc(*orc_ip_size);
13857fa1899SShile Zhang 	if (!idxs) {
13957fa1899SShile Zhang 		snprintf(g_err, ERRSTR_MAXSZ, "malloc idxs: %s",
14057fa1899SShile Zhang 			 strerror(errno));
14157fa1899SShile Zhang 		pthread_exit(g_err);
14257fa1899SShile Zhang 	}
14357fa1899SShile Zhang 
14457fa1899SShile Zhang 	tmp_orc_ip_table = (int *)malloc(*orc_ip_size);
14557fa1899SShile Zhang 	if (!tmp_orc_ip_table) {
14657fa1899SShile Zhang 		snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_ip_table: %s",
14757fa1899SShile Zhang 			 strerror(errno));
14857fa1899SShile Zhang 		pthread_exit(g_err);
14957fa1899SShile Zhang 	}
15057fa1899SShile Zhang 
15157fa1899SShile Zhang 	tmp_orc_table = (struct orc_entry *)malloc(orc_size);
15257fa1899SShile Zhang 	if (!tmp_orc_table) {
15357fa1899SShile Zhang 		snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_table: %s",
15457fa1899SShile Zhang 			 strerror(errno));
15557fa1899SShile Zhang 		pthread_exit(g_err);
15657fa1899SShile Zhang 	}
15757fa1899SShile Zhang 
15857fa1899SShile Zhang 	/* initialize indices array, convert ip_table to absolute address */
15957fa1899SShile Zhang 	for (i = 0; i < num_entries; i++) {
16057fa1899SShile Zhang 		idxs[i] = i;
16157fa1899SShile Zhang 		tmp_orc_ip_table[i] = g_orc_ip_table[i] + i * sizeof(int);
16257fa1899SShile Zhang 	}
16357fa1899SShile Zhang 	memcpy(tmp_orc_table, g_orc_table, orc_size);
16457fa1899SShile Zhang 
16557fa1899SShile Zhang 	qsort(idxs, num_entries, sizeof(int), orc_sort_cmp);
16657fa1899SShile Zhang 
16757fa1899SShile Zhang 	for (i = 0; i < num_entries; i++) {
16857fa1899SShile Zhang 		if (idxs[i] == i)
16957fa1899SShile Zhang 			continue;
17057fa1899SShile Zhang 
17157fa1899SShile Zhang 		/* convert back to relative address */
17257fa1899SShile Zhang 		g_orc_ip_table[i] = tmp_orc_ip_table[idxs[i]] - i * sizeof(int);
17357fa1899SShile Zhang 		g_orc_table[i] = tmp_orc_table[idxs[i]];
17457fa1899SShile Zhang 	}
17557fa1899SShile Zhang 
17657fa1899SShile Zhang 	free(idxs);
17757fa1899SShile Zhang 	free(tmp_orc_ip_table);
17857fa1899SShile Zhang 	free(tmp_orc_table);
17957fa1899SShile Zhang 	pthread_exit(NULL);
18057fa1899SShile Zhang }
18157fa1899SShile Zhang #endif
18257fa1899SShile Zhang 
18310916706SShile Zhang static int compare_extable(const void *a, const void *b)
18410916706SShile Zhang {
18510916706SShile Zhang 	Elf_Addr av = _r(a);
18610916706SShile Zhang 	Elf_Addr bv = _r(b);
18710916706SShile Zhang 
18810916706SShile Zhang 	if (av < bv)
18910916706SShile Zhang 		return -1;
19010916706SShile Zhang 	if (av > bv)
19110916706SShile Zhang 		return 1;
19210916706SShile Zhang 	return 0;
19310916706SShile Zhang }
19410916706SShile Zhang 
19510916706SShile Zhang static int do_sort(Elf_Ehdr *ehdr,
19610916706SShile Zhang 		   char const *const fname,
19710916706SShile Zhang 		   table_sort_t custom_sort)
19810916706SShile Zhang {
19957fa1899SShile Zhang 	int rc = -1;
20010916706SShile Zhang 	Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
20110916706SShile Zhang 	Elf_Shdr *strtab_sec = NULL;
20210916706SShile Zhang 	Elf_Shdr *symtab_sec = NULL;
20310916706SShile Zhang 	Elf_Shdr *extab_sec = NULL;
20410916706SShile Zhang 	Elf_Sym *sym;
20510916706SShile Zhang 	const Elf_Sym *symtab;
20610916706SShile Zhang 	Elf32_Word *symtab_shndx = NULL;
20710916706SShile Zhang 	Elf_Sym *sort_needed_sym = NULL;
20810916706SShile Zhang 	Elf_Shdr *sort_needed_sec;
20910916706SShile Zhang 	Elf_Rel *relocs = NULL;
21010916706SShile Zhang 	int relocs_size = 0;
21110916706SShile Zhang 	uint32_t *sort_needed_loc;
21210916706SShile Zhang 	const char *secstrings;
21310916706SShile Zhang 	const char *strtab;
21410916706SShile Zhang 	char *extab_image;
21510916706SShile Zhang 	int extab_index = 0;
21610916706SShile Zhang 	int i;
21710916706SShile Zhang 	int idx;
21810916706SShile Zhang 	unsigned int shnum;
21910916706SShile Zhang 	unsigned int shstrndx;
22057fa1899SShile Zhang #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
22157fa1899SShile Zhang 	unsigned int orc_ip_size = 0;
22257fa1899SShile Zhang 	unsigned int orc_size = 0;
22357fa1899SShile Zhang 	unsigned int orc_num_entries = 0;
22457fa1899SShile Zhang #endif
22510916706SShile Zhang 
22610916706SShile Zhang 	shstrndx = r2(&ehdr->e_shstrndx);
22710916706SShile Zhang 	if (shstrndx == SHN_XINDEX)
22810916706SShile Zhang 		shstrndx = r(&shdr[0].sh_link);
22910916706SShile Zhang 	secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset);
23010916706SShile Zhang 
23110916706SShile Zhang 	shnum = r2(&ehdr->e_shnum);
23210916706SShile Zhang 	if (shnum == SHN_UNDEF)
23310916706SShile Zhang 		shnum = _r(&shdr[0].sh_size);
23410916706SShile Zhang 
23510916706SShile Zhang 	for (i = 0, s = shdr; s < shdr + shnum; i++, s++) {
23610916706SShile Zhang 		idx = r(&s->sh_name);
23710916706SShile Zhang 		if (!strcmp(secstrings + idx, "__ex_table")) {
23810916706SShile Zhang 			extab_sec = s;
23910916706SShile Zhang 			extab_index = i;
24010916706SShile Zhang 		}
24110916706SShile Zhang 		if (!strcmp(secstrings + idx, ".symtab"))
24210916706SShile Zhang 			symtab_sec = s;
24310916706SShile Zhang 		if (!strcmp(secstrings + idx, ".strtab"))
24410916706SShile Zhang 			strtab_sec = s;
24510916706SShile Zhang 
24610916706SShile Zhang 		if ((r(&s->sh_type) == SHT_REL ||
24710916706SShile Zhang 		     r(&s->sh_type) == SHT_RELA) &&
24810916706SShile Zhang 		    r(&s->sh_info) == extab_index) {
24910916706SShile Zhang 			relocs = (void *)ehdr + _r(&s->sh_offset);
25010916706SShile Zhang 			relocs_size = _r(&s->sh_size);
25110916706SShile Zhang 		}
25210916706SShile Zhang 		if (r(&s->sh_type) == SHT_SYMTAB_SHNDX)
25310916706SShile Zhang 			symtab_shndx = (Elf32_Word *)((const char *)ehdr +
25410916706SShile Zhang 						      _r(&s->sh_offset));
25557fa1899SShile Zhang 
25657fa1899SShile Zhang #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
25757fa1899SShile Zhang 		/* locate the ORC unwind tables */
25857fa1899SShile Zhang 		if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
25957fa1899SShile Zhang 			orc_ip_size = s->sh_size;
26057fa1899SShile Zhang 			g_orc_ip_table = (int *)((void *)ehdr +
26157fa1899SShile Zhang 						   s->sh_offset);
26257fa1899SShile Zhang 		}
26357fa1899SShile Zhang 		if (!strcmp(secstrings + idx, ".orc_unwind")) {
26457fa1899SShile Zhang 			orc_size = s->sh_size;
26557fa1899SShile Zhang 			g_orc_table = (struct orc_entry *)((void *)ehdr +
26657fa1899SShile Zhang 							     s->sh_offset);
26757fa1899SShile Zhang 		}
26857fa1899SShile Zhang #endif
26957fa1899SShile Zhang 	} /* for loop */
27057fa1899SShile Zhang 
27157fa1899SShile Zhang #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
27257fa1899SShile Zhang 	if (!g_orc_ip_table || !g_orc_table) {
27357fa1899SShile Zhang 		fprintf(stderr,
27457fa1899SShile Zhang 			"incomplete ORC unwind tables in file: %s\n", fname);
27557fa1899SShile Zhang 		goto out;
27610916706SShile Zhang 	}
27710916706SShile Zhang 
27857fa1899SShile Zhang 	orc_num_entries = orc_ip_size / sizeof(int);
27957fa1899SShile Zhang 	if (orc_ip_size % sizeof(int) != 0 ||
28057fa1899SShile Zhang 	    orc_size % sizeof(struct orc_entry) != 0 ||
28157fa1899SShile Zhang 	    orc_num_entries != orc_size / sizeof(struct orc_entry)) {
28257fa1899SShile Zhang 		fprintf(stderr,
28357fa1899SShile Zhang 			"inconsistent ORC unwind table entries in file: %s\n",
28457fa1899SShile Zhang 			fname);
28557fa1899SShile Zhang 		goto out;
28657fa1899SShile Zhang 	}
28757fa1899SShile Zhang 
28857fa1899SShile Zhang 	/* create thread to sort ORC unwind tables concurrently */
28957fa1899SShile Zhang 	if (pthread_create(&orc_sort_thread, NULL,
29057fa1899SShile Zhang 			   sort_orctable, &orc_ip_size)) {
29157fa1899SShile Zhang 		fprintf(stderr,
29257fa1899SShile Zhang 			"pthread_create orc_sort_thread failed '%s': %s\n",
29357fa1899SShile Zhang 			strerror(errno), fname);
29457fa1899SShile Zhang 		goto out;
29557fa1899SShile Zhang 	}
29657fa1899SShile Zhang #endif
29710916706SShile Zhang 	if (!extab_sec) {
29810916706SShile Zhang 		fprintf(stderr,	"no __ex_table in file: %s\n", fname);
29957fa1899SShile Zhang 		goto out;
30010916706SShile Zhang 	}
30110916706SShile Zhang 
30210916706SShile Zhang 	if (!symtab_sec) {
30310916706SShile Zhang 		fprintf(stderr,	"no .symtab in file: %s\n", fname);
30457fa1899SShile Zhang 		goto out;
30510916706SShile Zhang 	}
30610916706SShile Zhang 
30710916706SShile Zhang 	if (!strtab_sec) {
30810916706SShile Zhang 		fprintf(stderr,	"no .strtab in file: %s\n", fname);
30957fa1899SShile Zhang 		goto out;
31010916706SShile Zhang 	}
31110916706SShile Zhang 
31210916706SShile Zhang 	extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
31310916706SShile Zhang 	strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
31410916706SShile Zhang 	symtab = (const Elf_Sym *)((const char *)ehdr +
31510916706SShile Zhang 						  _r(&symtab_sec->sh_offset));
31610916706SShile Zhang 
31710916706SShile Zhang 	if (custom_sort) {
31810916706SShile Zhang 		custom_sort(extab_image, _r(&extab_sec->sh_size));
31910916706SShile Zhang 	} else {
32010916706SShile Zhang 		int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
32110916706SShile Zhang 		qsort(extab_image, num_entries,
32210916706SShile Zhang 		      extable_ent_size, compare_extable);
32310916706SShile Zhang 	}
32410916706SShile Zhang 
32510916706SShile Zhang 	/* If there were relocations, we no longer need them. */
32610916706SShile Zhang 	if (relocs)
32710916706SShile Zhang 		memset(relocs, 0, relocs_size);
32810916706SShile Zhang 
32910916706SShile Zhang 	/* find the flag main_extable_sort_needed */
33010916706SShile Zhang 	for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
33110916706SShile Zhang 	     sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym);
33210916706SShile Zhang 	     sym++) {
33310916706SShile Zhang 		if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
33410916706SShile Zhang 			continue;
33510916706SShile Zhang 		if (!strcmp(strtab + r(&sym->st_name),
33610916706SShile Zhang 			    "main_extable_sort_needed")) {
33710916706SShile Zhang 			sort_needed_sym = sym;
33810916706SShile Zhang 			break;
33910916706SShile Zhang 		}
34010916706SShile Zhang 	}
34110916706SShile Zhang 
34210916706SShile Zhang 	if (!sort_needed_sym) {
34310916706SShile Zhang 		fprintf(stderr,
34410916706SShile Zhang 			"no main_extable_sort_needed symbol in file: %s\n",
34510916706SShile Zhang 			fname);
34657fa1899SShile Zhang 		goto out;
34710916706SShile Zhang 	}
34810916706SShile Zhang 
34910916706SShile Zhang 	sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx),
35010916706SShile Zhang 					     sort_needed_sym - symtab,
35110916706SShile Zhang 					     symtab_shndx)];
35210916706SShile Zhang 	sort_needed_loc = (void *)ehdr +
35310916706SShile Zhang 		_r(&sort_needed_sec->sh_offset) +
35410916706SShile Zhang 		_r(&sort_needed_sym->st_value) -
35510916706SShile Zhang 		_r(&sort_needed_sec->sh_addr);
35610916706SShile Zhang 
35710916706SShile Zhang 	/* extable has been sorted, clear the flag */
35810916706SShile Zhang 	w(0, sort_needed_loc);
35957fa1899SShile Zhang 	rc = 0;
36010916706SShile Zhang 
36157fa1899SShile Zhang out:
36257fa1899SShile Zhang #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
36357fa1899SShile Zhang 	if (orc_sort_thread) {
36457fa1899SShile Zhang 		void *retval = NULL;
36557fa1899SShile Zhang 		/* wait for ORC tables sort done */
36657fa1899SShile Zhang 		rc = pthread_join(orc_sort_thread, &retval);
367*c8a7ff13SYinan Liu 		if (rc) {
36857fa1899SShile Zhang 			fprintf(stderr,
36957fa1899SShile Zhang 				"pthread_join failed '%s': %s\n",
37057fa1899SShile Zhang 				strerror(errno), fname);
371*c8a7ff13SYinan Liu 		} else if (retval) {
37257fa1899SShile Zhang 			rc = -1;
37357fa1899SShile Zhang 			fprintf(stderr,
37457fa1899SShile Zhang 				"failed to sort ORC tables '%s': %s\n",
37557fa1899SShile Zhang 				(char *)retval, fname);
37657fa1899SShile Zhang 		}
37757fa1899SShile Zhang 	}
37857fa1899SShile Zhang #endif
37957fa1899SShile Zhang 	return rc;
38010916706SShile Zhang }
381