xref: /linux-6.15/scripts/sorttable.c (revision 4acda8ed)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * sorttable.c: Sort the kernel's table
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  * Based on code taken from recortmcount.c which is:
12  *
13  * Copyright 2009 John F. Reiser <[email protected]>.  All rights reserved.
14  *
15  * Restructured to fit Linux format, as well as other updates:
16  * Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc.
17  */
18 
19 /*
20  * Strategy: alter the vmlinux file in-place.
21  */
22 
23 #include <sys/types.h>
24 #include <sys/mman.h>
25 #include <sys/stat.h>
26 #include <getopt.h>
27 #include <elf.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <pthread.h>
35 
36 #include <tools/be_byteshift.h>
37 #include <tools/le_byteshift.h>
38 
39 #ifndef EM_ARCOMPACT
40 #define EM_ARCOMPACT	93
41 #endif
42 
43 #ifndef EM_XTENSA
44 #define EM_XTENSA	94
45 #endif
46 
47 #ifndef EM_AARCH64
48 #define EM_AARCH64	183
49 #endif
50 
51 #ifndef EM_MICROBLAZE
52 #define EM_MICROBLAZE	189
53 #endif
54 
55 #ifndef EM_ARCV2
56 #define EM_ARCV2	195
57 #endif
58 
59 #ifndef EM_RISCV
60 #define EM_RISCV	243
61 #endif
62 
63 #ifndef EM_LOONGARCH
64 #define EM_LOONGARCH	258
65 #endif
66 
67 typedef union {
68 	Elf32_Ehdr	e32;
69 	Elf64_Ehdr	e64;
70 } Elf_Ehdr;
71 
72 typedef union {
73 	Elf32_Shdr	e32;
74 	Elf64_Shdr	e64;
75 } Elf_Shdr;
76 
77 typedef union {
78 	Elf32_Sym	e32;
79 	Elf64_Sym	e64;
80 } Elf_Sym;
81 
82 static uint32_t (*r)(const uint32_t *);
83 static uint16_t (*r2)(const uint16_t *);
84 static uint64_t (*r8)(const uint64_t *);
85 static void (*w)(uint32_t, uint32_t *);
86 typedef void (*table_sort_t)(char *, int);
87 
88 static uint64_t ehdr64_shoff(Elf_Ehdr *ehdr)
89 {
90 	return r8(&ehdr->e64.e_shoff);
91 }
92 
93 static uint64_t ehdr32_shoff(Elf_Ehdr *ehdr)
94 {
95 	return r(&ehdr->e32.e_shoff);
96 }
97 
98 #define EHDR_HALF(fn_name)				\
99 static uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr)	\
100 {							\
101 	return r2(&ehdr->e64.e_##fn_name);		\
102 }							\
103 							\
104 static uint16_t ehdr32_##fn_name(Elf_Ehdr *ehdr)	\
105 {							\
106 	return r2(&ehdr->e32.e_##fn_name);		\
107 }
108 
109 EHDR_HALF(shentsize)
110 EHDR_HALF(shstrndx)
111 EHDR_HALF(shnum)
112 
113 #define SHDR_WORD(fn_name)				\
114 static uint32_t shdr64_##fn_name(Elf_Shdr *shdr)	\
115 {							\
116 	return r(&shdr->e64.sh_##fn_name);		\
117 }							\
118 							\
119 static uint32_t shdr32_##fn_name(Elf_Shdr *shdr)	\
120 {							\
121 	return r(&shdr->e32.sh_##fn_name);		\
122 }
123 
124 #define SHDR_ADDR(fn_name)				\
125 static uint64_t shdr64_##fn_name(Elf_Shdr *shdr)	\
126 {							\
127 	return r8(&shdr->e64.sh_##fn_name);		\
128 }							\
129 							\
130 static uint64_t shdr32_##fn_name(Elf_Shdr *shdr)	\
131 {							\
132 	return r(&shdr->e32.sh_##fn_name);		\
133 }
134 
135 #define SHDR_WORD(fn_name)				\
136 static uint32_t shdr64_##fn_name(Elf_Shdr *shdr)	\
137 {							\
138 	return r(&shdr->e64.sh_##fn_name);		\
139 }							\
140 							\
141 static uint32_t shdr32_##fn_name(Elf_Shdr *shdr)	\
142 {							\
143 	return r(&shdr->e32.sh_##fn_name);		\
144 }
145 
146 SHDR_ADDR(addr)
147 SHDR_ADDR(offset)
148 SHDR_ADDR(size)
149 SHDR_ADDR(entsize)
150 
151 SHDR_WORD(link)
152 SHDR_WORD(name)
153 SHDR_WORD(type)
154 
155 #define SYM_ADDR(fn_name)			\
156 static uint64_t sym64_##fn_name(Elf_Sym *sym)	\
157 {						\
158 	return r8(&sym->e64.st_##fn_name);	\
159 }						\
160 						\
161 static uint64_t sym32_##fn_name(Elf_Sym *sym)	\
162 {						\
163 	return r(&sym->e32.st_##fn_name);	\
164 }
165 
166 #define SYM_WORD(fn_name)			\
167 static uint32_t sym64_##fn_name(Elf_Sym *sym)	\
168 {						\
169 	return r(&sym->e64.st_##fn_name);	\
170 }						\
171 						\
172 static uint32_t sym32_##fn_name(Elf_Sym *sym)	\
173 {						\
174 	return r(&sym->e32.st_##fn_name);	\
175 }
176 
177 #define SYM_HALF(fn_name)			\
178 static uint16_t sym64_##fn_name(Elf_Sym *sym)	\
179 {						\
180 	return r2(&sym->e64.st_##fn_name);	\
181 }						\
182 						\
183 static uint16_t sym32_##fn_name(Elf_Sym *sym)	\
184 {						\
185 	return r2(&sym->e32.st_##fn_name);	\
186 }
187 
188 static uint8_t sym64_type(Elf_Sym *sym)
189 {
190 	return ELF64_ST_TYPE(sym->e64.st_info);
191 }
192 
193 static uint8_t sym32_type(Elf_Sym *sym)
194 {
195 	return ELF32_ST_TYPE(sym->e32.st_info);
196 }
197 
198 SYM_ADDR(value)
199 SYM_WORD(name)
200 SYM_HALF(shndx)
201 
202 /*
203  * Get the whole file as a programming convenience in order to avoid
204  * malloc+lseek+read+free of many pieces.  If successful, then mmap
205  * avoids copying unused pieces; else just read the whole file.
206  * Open for both read and write.
207  */
208 static void *mmap_file(char const *fname, size_t *size)
209 {
210 	int fd;
211 	struct stat sb;
212 	void *addr = NULL;
213 
214 	fd = open(fname, O_RDWR);
215 	if (fd < 0) {
216 		perror(fname);
217 		return NULL;
218 	}
219 	if (fstat(fd, &sb) < 0) {
220 		perror(fname);
221 		goto out;
222 	}
223 	if (!S_ISREG(sb.st_mode)) {
224 		fprintf(stderr, "not a regular file: %s\n", fname);
225 		goto out;
226 	}
227 
228 	addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
229 	if (addr == MAP_FAILED) {
230 		fprintf(stderr, "Could not mmap file: %s\n", fname);
231 		goto out;
232 	}
233 
234 	*size = sb.st_size;
235 
236 out:
237 	close(fd);
238 	return addr;
239 }
240 
241 static uint32_t rbe(const uint32_t *x)
242 {
243 	return get_unaligned_be32(x);
244 }
245 
246 static uint16_t r2be(const uint16_t *x)
247 {
248 	return get_unaligned_be16(x);
249 }
250 
251 static uint64_t r8be(const uint64_t *x)
252 {
253 	return get_unaligned_be64(x);
254 }
255 
256 static uint32_t rle(const uint32_t *x)
257 {
258 	return get_unaligned_le32(x);
259 }
260 
261 static uint16_t r2le(const uint16_t *x)
262 {
263 	return get_unaligned_le16(x);
264 }
265 
266 static uint64_t r8le(const uint64_t *x)
267 {
268 	return get_unaligned_le64(x);
269 }
270 
271 static void wbe(uint32_t val, uint32_t *x)
272 {
273 	put_unaligned_be32(val, x);
274 }
275 
276 static void wle(uint32_t val, uint32_t *x)
277 {
278 	put_unaligned_le32(val, x);
279 }
280 
281 /*
282  * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
283  * the way to -256..-1, to avoid conflicting with real section
284  * indices.
285  */
286 #define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))
287 
288 static inline int is_shndx_special(unsigned int i)
289 {
290 	return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
291 }
292 
293 /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
294 static inline unsigned int get_secindex(unsigned int shndx,
295 					unsigned int sym_offs,
296 					const Elf32_Word *symtab_shndx_start)
297 {
298 	if (is_shndx_special(shndx))
299 		return SPECIAL(shndx);
300 	if (shndx != SHN_XINDEX)
301 		return shndx;
302 	return r(&symtab_shndx_start[sym_offs]);
303 }
304 
305 static int compare_extable_32(const void *a, const void *b)
306 {
307 	Elf32_Addr av = r(a);
308 	Elf32_Addr bv = r(b);
309 
310 	if (av < bv)
311 		return -1;
312 	return av > bv;
313 }
314 
315 static int compare_extable_64(const void *a, const void *b)
316 {
317 	Elf64_Addr av = r8(a);
318 	Elf64_Addr bv = r8(b);
319 
320 	if (av < bv)
321 		return -1;
322 	return av > bv;
323 }
324 
325 static inline void *get_index(void *start, int entsize, int index)
326 {
327 	return start + (entsize * index);
328 }
329 
330 
331 static int (*compare_extable)(const void *a, const void *b);
332 static uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr);
333 static uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr);
334 static uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr);
335 static uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr);
336 static uint64_t (*shdr_addr)(Elf_Shdr *shdr);
337 static uint64_t (*shdr_offset)(Elf_Shdr *shdr);
338 static uint64_t (*shdr_size)(Elf_Shdr *shdr);
339 static uint64_t (*shdr_entsize)(Elf_Shdr *shdr);
340 static uint32_t (*shdr_link)(Elf_Shdr *shdr);
341 static uint32_t (*shdr_name)(Elf_Shdr *shdr);
342 static uint32_t (*shdr_type)(Elf_Shdr *shdr);
343 static uint8_t (*sym_type)(Elf_Sym *sym);
344 static uint32_t (*sym_name)(Elf_Sym *sym);
345 static uint64_t (*sym_value)(Elf_Sym *sym);
346 static uint16_t (*sym_shndx)(Elf_Sym *sym);
347 
348 static int extable_ent_size;
349 static int long_size;
350 
351 
352 #ifdef UNWINDER_ORC_ENABLED
353 /* ORC unwinder only support X86_64 */
354 #include <asm/orc_types.h>
355 
356 #define ERRSTR_MAXSZ	256
357 
358 static char g_err[ERRSTR_MAXSZ];
359 static int *g_orc_ip_table;
360 static struct orc_entry *g_orc_table;
361 
362 static pthread_t orc_sort_thread;
363 
364 static inline unsigned long orc_ip(const int *ip)
365 {
366 	return (unsigned long)ip + *ip;
367 }
368 
369 static int orc_sort_cmp(const void *_a, const void *_b)
370 {
371 	struct orc_entry *orc_a, *orc_b;
372 	const int *a = g_orc_ip_table + *(int *)_a;
373 	const int *b = g_orc_ip_table + *(int *)_b;
374 	unsigned long a_val = orc_ip(a);
375 	unsigned long b_val = orc_ip(b);
376 
377 	if (a_val > b_val)
378 		return 1;
379 	if (a_val < b_val)
380 		return -1;
381 
382 	/*
383 	 * The "weak" section terminator entries need to always be on the left
384 	 * to ensure the lookup code skips them in favor of real entries.
385 	 * These terminator entries exist to handle any gaps created by
386 	 * whitelisted .o files which didn't get objtool generation.
387 	 */
388 	orc_a = g_orc_table + (a - g_orc_ip_table);
389 	orc_b = g_orc_table + (b - g_orc_ip_table);
390 	if (orc_a->type == ORC_TYPE_UNDEFINED && orc_b->type == ORC_TYPE_UNDEFINED)
391 		return 0;
392 	return orc_a->type == ORC_TYPE_UNDEFINED ? -1 : 1;
393 }
394 
395 static void *sort_orctable(void *arg)
396 {
397 	int i;
398 	int *idxs = NULL;
399 	int *tmp_orc_ip_table = NULL;
400 	struct orc_entry *tmp_orc_table = NULL;
401 	unsigned int *orc_ip_size = (unsigned int *)arg;
402 	unsigned int num_entries = *orc_ip_size / sizeof(int);
403 	unsigned int orc_size = num_entries * sizeof(struct orc_entry);
404 
405 	idxs = (int *)malloc(*orc_ip_size);
406 	if (!idxs) {
407 		snprintf(g_err, ERRSTR_MAXSZ, "malloc idxs: %s",
408 			 strerror(errno));
409 		pthread_exit(g_err);
410 	}
411 
412 	tmp_orc_ip_table = (int *)malloc(*orc_ip_size);
413 	if (!tmp_orc_ip_table) {
414 		snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_ip_table: %s",
415 			 strerror(errno));
416 		pthread_exit(g_err);
417 	}
418 
419 	tmp_orc_table = (struct orc_entry *)malloc(orc_size);
420 	if (!tmp_orc_table) {
421 		snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_table: %s",
422 			 strerror(errno));
423 		pthread_exit(g_err);
424 	}
425 
426 	/* initialize indices array, convert ip_table to absolute address */
427 	for (i = 0; i < num_entries; i++) {
428 		idxs[i] = i;
429 		tmp_orc_ip_table[i] = g_orc_ip_table[i] + i * sizeof(int);
430 	}
431 	memcpy(tmp_orc_table, g_orc_table, orc_size);
432 
433 	qsort(idxs, num_entries, sizeof(int), orc_sort_cmp);
434 
435 	for (i = 0; i < num_entries; i++) {
436 		if (idxs[i] == i)
437 			continue;
438 
439 		/* convert back to relative address */
440 		g_orc_ip_table[i] = tmp_orc_ip_table[idxs[i]] - i * sizeof(int);
441 		g_orc_table[i] = tmp_orc_table[idxs[i]];
442 	}
443 
444 	free(idxs);
445 	free(tmp_orc_ip_table);
446 	free(tmp_orc_table);
447 	pthread_exit(NULL);
448 }
449 #endif
450 
451 #ifdef MCOUNT_SORT_ENABLED
452 static pthread_t mcount_sort_thread;
453 
454 struct elf_mcount_loc {
455 	Elf_Ehdr *ehdr;
456 	Elf_Shdr *init_data_sec;
457 	uint64_t start_mcount_loc;
458 	uint64_t stop_mcount_loc;
459 };
460 
461 /* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
462 static void *sort_mcount_loc(void *arg)
463 {
464 	struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;
465 	uint64_t offset = emloc->start_mcount_loc - shdr_addr(emloc->init_data_sec)
466 					+ shdr_offset(emloc->init_data_sec);
467 	uint64_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
468 	unsigned char *start_loc = (void *)emloc->ehdr + offset;
469 
470 	qsort(start_loc, count/long_size, long_size, compare_extable);
471 	return NULL;
472 }
473 
474 /* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
475 static void get_mcount_loc(struct elf_mcount_loc *emloc, Elf_Shdr *symtab_sec,
476 			   const char *strtab)
477 {
478 	Elf_Sym *sym, *end_sym;
479 	int symentsize = shdr_entsize(symtab_sec);
480 	int found = 0;
481 
482 	sym = (void *)emloc->ehdr + shdr_offset(symtab_sec);
483 	end_sym = (void *)sym + shdr_size(symtab_sec);
484 
485 	while (sym < end_sym) {
486 		if (!strcmp(strtab + sym_name(sym), "__start_mcount_loc")) {
487 			emloc->start_mcount_loc = sym_value(sym);
488 			if (++found == 2)
489 				break;
490 		} else if (!strcmp(strtab + sym_name(sym), "__stop_mcount_loc")) {
491 			emloc->stop_mcount_loc = sym_value(sym);
492 			if (++found == 2)
493 				break;
494 		}
495 		sym = (void *)sym + symentsize;
496 	}
497 
498 	if (!emloc->start_mcount_loc) {
499 		fprintf(stderr, "get start_mcount_loc error!");
500 		return;
501 	}
502 
503 	if (!emloc->stop_mcount_loc) {
504 		fprintf(stderr, "get stop_mcount_loc error!");
505 		return;
506 	}
507 }
508 #endif
509 
510 static int do_sort(Elf_Ehdr *ehdr,
511 		   char const *const fname,
512 		   table_sort_t custom_sort)
513 {
514 	int rc = -1;
515 	Elf_Shdr *shdr_start;
516 	Elf_Shdr *strtab_sec = NULL;
517 	Elf_Shdr *symtab_sec = NULL;
518 	Elf_Shdr *extab_sec = NULL;
519 	Elf_Shdr *string_sec;
520 	Elf_Sym *sym;
521 	const Elf_Sym *symtab;
522 	Elf32_Word *symtab_shndx = NULL;
523 	Elf_Sym *sort_needed_sym = NULL;
524 	Elf_Shdr *sort_needed_sec;
525 	uint32_t *sort_needed_loc;
526 	void *sym_start;
527 	void *sym_end;
528 	const char *secstrings;
529 	const char *strtab;
530 	char *extab_image;
531 	int sort_need_index;
532 	int symentsize;
533 	int shentsize;
534 	int idx;
535 	int i;
536 	unsigned int shnum;
537 	unsigned int shstrndx;
538 #ifdef MCOUNT_SORT_ENABLED
539 	struct elf_mcount_loc mstruct = {0};
540 #endif
541 #ifdef UNWINDER_ORC_ENABLED
542 	unsigned int orc_ip_size = 0;
543 	unsigned int orc_size = 0;
544 	unsigned int orc_num_entries = 0;
545 #endif
546 
547 	shdr_start = (Elf_Shdr *)((char *)ehdr + ehdr_shoff(ehdr));
548 	shentsize = ehdr_shentsize(ehdr);
549 
550 	shstrndx = ehdr_shstrndx(ehdr);
551 	if (shstrndx == SHN_XINDEX)
552 		shstrndx = shdr_link(shdr_start);
553 	string_sec = get_index(shdr_start, shentsize, shstrndx);
554 	secstrings = (const char *)ehdr + shdr_offset(string_sec);
555 
556 	shnum = ehdr_shnum(ehdr);
557 	if (shnum == SHN_UNDEF)
558 		shnum = shdr_size(shdr_start);
559 
560 	for (i = 0; i < shnum; i++) {
561 		Elf_Shdr *shdr = get_index(shdr_start, shentsize, i);
562 
563 		idx = shdr_name(shdr);
564 		if (!strcmp(secstrings + idx, "__ex_table"))
565 			extab_sec = shdr;
566 		if (!strcmp(secstrings + idx, ".symtab"))
567 			symtab_sec = shdr;
568 		if (!strcmp(secstrings + idx, ".strtab"))
569 			strtab_sec = shdr;
570 
571 		if (shdr_type(shdr) == SHT_SYMTAB_SHNDX)
572 			symtab_shndx = (Elf32_Word *)((const char *)ehdr +
573 						      shdr_offset(shdr));
574 
575 #ifdef MCOUNT_SORT_ENABLED
576 		/* locate the .init.data section in vmlinux */
577 		if (!strcmp(secstrings + idx, ".init.data"))
578 			mstruct.init_data_sec = shdr;
579 #endif
580 
581 #ifdef UNWINDER_ORC_ENABLED
582 		/* locate the ORC unwind tables */
583 		if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
584 			orc_ip_size = shdr_size(shdr);
585 			g_orc_ip_table = (int *)((void *)ehdr +
586 						   shdr_offset(shdr));
587 		}
588 		if (!strcmp(secstrings + idx, ".orc_unwind")) {
589 			orc_size = shdr_size(shdr);
590 			g_orc_table = (struct orc_entry *)((void *)ehdr +
591 							     shdr_offset(shdr));
592 		}
593 #endif
594 	} /* for loop */
595 
596 #ifdef UNWINDER_ORC_ENABLED
597 	if (!g_orc_ip_table || !g_orc_table) {
598 		fprintf(stderr,
599 			"incomplete ORC unwind tables in file: %s\n", fname);
600 		goto out;
601 	}
602 
603 	orc_num_entries = orc_ip_size / sizeof(int);
604 	if (orc_ip_size % sizeof(int) != 0 ||
605 	    orc_size % sizeof(struct orc_entry) != 0 ||
606 	    orc_num_entries != orc_size / sizeof(struct orc_entry)) {
607 		fprintf(stderr,
608 			"inconsistent ORC unwind table entries in file: %s\n",
609 			fname);
610 		goto out;
611 	}
612 
613 	/* create thread to sort ORC unwind tables concurrently */
614 	if (pthread_create(&orc_sort_thread, NULL,
615 			   sort_orctable, &orc_ip_size)) {
616 		fprintf(stderr,
617 			"pthread_create orc_sort_thread failed '%s': %s\n",
618 			strerror(errno), fname);
619 		goto out;
620 	}
621 #endif
622 	if (!extab_sec) {
623 		fprintf(stderr,	"no __ex_table in file: %s\n", fname);
624 		goto out;
625 	}
626 
627 	if (!symtab_sec) {
628 		fprintf(stderr,	"no .symtab in file: %s\n", fname);
629 		goto out;
630 	}
631 
632 	if (!strtab_sec) {
633 		fprintf(stderr,	"no .strtab in file: %s\n", fname);
634 		goto out;
635 	}
636 
637 	extab_image = (void *)ehdr + shdr_offset(extab_sec);
638 	strtab = (const char *)ehdr + shdr_offset(strtab_sec);
639 	symtab = (const Elf_Sym *)((const char *)ehdr + shdr_offset(symtab_sec));
640 
641 #ifdef MCOUNT_SORT_ENABLED
642 	mstruct.ehdr = ehdr;
643 	get_mcount_loc(&mstruct, symtab_sec, strtab);
644 
645 	if (!mstruct.init_data_sec || !mstruct.start_mcount_loc || !mstruct.stop_mcount_loc) {
646 		fprintf(stderr,
647 			"incomplete mcount's sort in file: %s\n",
648 			fname);
649 		goto out;
650 	}
651 
652 	/* create thread to sort mcount_loc concurrently */
653 	if (pthread_create(&mcount_sort_thread, NULL, &sort_mcount_loc, &mstruct)) {
654 		fprintf(stderr,
655 			"pthread_create mcount_sort_thread failed '%s': %s\n",
656 			strerror(errno), fname);
657 		goto out;
658 	}
659 #endif
660 
661 	if (custom_sort) {
662 		custom_sort(extab_image, shdr_size(extab_sec));
663 	} else {
664 		int num_entries = shdr_size(extab_sec) / extable_ent_size;
665 		qsort(extab_image, num_entries,
666 		      extable_ent_size, compare_extable);
667 	}
668 
669 	/* find the flag main_extable_sort_needed */
670 	sym_start = (void *)ehdr + shdr_offset(symtab_sec);
671 	sym_end = sym_start + shdr_size(symtab_sec);
672 	symentsize = shdr_entsize(symtab_sec);
673 
674 	for (sym = sym_start; (void *)sym + symentsize < sym_end;
675 	     sym = (void *)sym + symentsize) {
676 		if (sym_type(sym) != STT_OBJECT)
677 			continue;
678 		if (!strcmp(strtab + sym_name(sym),
679 			    "main_extable_sort_needed")) {
680 			sort_needed_sym = sym;
681 			break;
682 		}
683 	}
684 
685 	if (!sort_needed_sym) {
686 		fprintf(stderr,
687 			"no main_extable_sort_needed symbol in file: %s\n",
688 			fname);
689 		goto out;
690 	}
691 
692 	sort_need_index = get_secindex(sym_shndx(sym),
693 				       ((void *)sort_needed_sym - (void *)symtab) / symentsize,
694 				       symtab_shndx);
695 	sort_needed_sec = get_index(shdr_start, shentsize, sort_need_index);
696 	sort_needed_loc = (void *)ehdr +
697 		shdr_offset(sort_needed_sec) +
698 		sym_value(sort_needed_sym) - shdr_addr(sort_needed_sec);
699 
700 	/* extable has been sorted, clear the flag */
701 	w(0, sort_needed_loc);
702 	rc = 0;
703 
704 out:
705 #ifdef UNWINDER_ORC_ENABLED
706 	if (orc_sort_thread) {
707 		void *retval = NULL;
708 		/* wait for ORC tables sort done */
709 		rc = pthread_join(orc_sort_thread, &retval);
710 		if (rc) {
711 			fprintf(stderr,
712 				"pthread_join failed '%s': %s\n",
713 				strerror(errno), fname);
714 		} else if (retval) {
715 			rc = -1;
716 			fprintf(stderr,
717 				"failed to sort ORC tables '%s': %s\n",
718 				(char *)retval, fname);
719 		}
720 	}
721 #endif
722 
723 #ifdef MCOUNT_SORT_ENABLED
724 	if (mcount_sort_thread) {
725 		void *retval = NULL;
726 		/* wait for mcount sort done */
727 		rc = pthread_join(mcount_sort_thread, &retval);
728 		if (rc) {
729 			fprintf(stderr,
730 				"pthread_join failed '%s': %s\n",
731 				strerror(errno), fname);
732 		} else if (retval) {
733 			rc = -1;
734 			fprintf(stderr,
735 				"failed to sort mcount '%s': %s\n",
736 				(char *)retval, fname);
737 		}
738 	}
739 #endif
740 	return rc;
741 }
742 
743 static int compare_relative_table(const void *a, const void *b)
744 {
745 	int32_t av = (int32_t)r(a);
746 	int32_t bv = (int32_t)r(b);
747 
748 	if (av < bv)
749 		return -1;
750 	if (av > bv)
751 		return 1;
752 	return 0;
753 }
754 
755 static void sort_relative_table(char *extab_image, int image_size)
756 {
757 	int i = 0;
758 
759 	/*
760 	 * Do the same thing the runtime sort does, first normalize to
761 	 * being relative to the start of the section.
762 	 */
763 	while (i < image_size) {
764 		uint32_t *loc = (uint32_t *)(extab_image + i);
765 		w(r(loc) + i, loc);
766 		i += 4;
767 	}
768 
769 	qsort(extab_image, image_size / 8, 8, compare_relative_table);
770 
771 	/* Now denormalize. */
772 	i = 0;
773 	while (i < image_size) {
774 		uint32_t *loc = (uint32_t *)(extab_image + i);
775 		w(r(loc) - i, loc);
776 		i += 4;
777 	}
778 }
779 
780 static void sort_relative_table_with_data(char *extab_image, int image_size)
781 {
782 	int i = 0;
783 
784 	while (i < image_size) {
785 		uint32_t *loc = (uint32_t *)(extab_image + i);
786 
787 		w(r(loc) + i, loc);
788 		w(r(loc + 1) + i + 4, loc + 1);
789 		/* Don't touch the fixup type or data */
790 
791 		i += sizeof(uint32_t) * 3;
792 	}
793 
794 	qsort(extab_image, image_size / 12, 12, compare_relative_table);
795 
796 	i = 0;
797 	while (i < image_size) {
798 		uint32_t *loc = (uint32_t *)(extab_image + i);
799 
800 		w(r(loc) - i, loc);
801 		w(r(loc + 1) - (i + 4), loc + 1);
802 		/* Don't touch the fixup type or data */
803 
804 		i += sizeof(uint32_t) * 3;
805 	}
806 }
807 
808 static int do_file(char const *const fname, void *addr)
809 {
810 	Elf_Ehdr *ehdr = addr;
811 	table_sort_t custom_sort = NULL;
812 
813 	switch (ehdr->e32.e_ident[EI_DATA]) {
814 	case ELFDATA2LSB:
815 		r	= rle;
816 		r2	= r2le;
817 		r8	= r8le;
818 		w	= wle;
819 		break;
820 	case ELFDATA2MSB:
821 		r	= rbe;
822 		r2	= r2be;
823 		r8	= r8be;
824 		w	= wbe;
825 		break;
826 	default:
827 		fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
828 			ehdr->e32.e_ident[EI_DATA], fname);
829 		return -1;
830 	}
831 
832 	if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
833 	    (r2(&ehdr->e32.e_type) != ET_EXEC && r2(&ehdr->e32.e_type) != ET_DYN) ||
834 	    ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
835 		fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname);
836 		return -1;
837 	}
838 
839 	switch (r2(&ehdr->e32.e_machine)) {
840 	case EM_386:
841 	case EM_AARCH64:
842 	case EM_LOONGARCH:
843 	case EM_RISCV:
844 	case EM_S390:
845 	case EM_X86_64:
846 		custom_sort = sort_relative_table_with_data;
847 		break;
848 	case EM_PARISC:
849 	case EM_PPC:
850 	case EM_PPC64:
851 		custom_sort = sort_relative_table;
852 		break;
853 	case EM_ARCOMPACT:
854 	case EM_ARCV2:
855 	case EM_ARM:
856 	case EM_MICROBLAZE:
857 	case EM_MIPS:
858 	case EM_XTENSA:
859 		break;
860 	default:
861 		fprintf(stderr, "unrecognized e_machine %d %s\n",
862 			r2(&ehdr->e32.e_machine), fname);
863 		return -1;
864 	}
865 
866 	switch (ehdr->e32.e_ident[EI_CLASS]) {
867 	case ELFCLASS32:
868 		if (r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) ||
869 		    r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) {
870 			fprintf(stderr,
871 				"unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
872 			return -1;
873 		}
874 
875 		compare_extable		= compare_extable_32;
876 		ehdr_shoff		= ehdr32_shoff;
877 		ehdr_shentsize		= ehdr32_shentsize;
878 		ehdr_shstrndx		= ehdr32_shstrndx;
879 		ehdr_shnum		= ehdr32_shnum;
880 		shdr_addr		= shdr32_addr;
881 		shdr_offset		= shdr32_offset;
882 		shdr_link		= shdr32_link;
883 		shdr_size		= shdr32_size;
884 		shdr_name		= shdr32_name;
885 		shdr_type		= shdr32_type;
886 		shdr_entsize		= shdr32_entsize;
887 		sym_type		= sym32_type;
888 		sym_name		= sym32_name;
889 		sym_value		= sym32_value;
890 		sym_shndx		= sym32_shndx;
891 		long_size		= 4;
892 		extable_ent_size	= 8;
893 		break;
894 	case ELFCLASS64:
895 		if (r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) ||
896 		    r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) {
897 			fprintf(stderr,
898 				"unrecognized ET_EXEC/ET_DYN file: %s\n",
899 				fname);
900 			return -1;
901 		}
902 
903 		compare_extable		= compare_extable_64;
904 		ehdr_shoff		= ehdr64_shoff;
905 		ehdr_shentsize		= ehdr64_shentsize;
906 		ehdr_shstrndx		= ehdr64_shstrndx;
907 		ehdr_shnum		= ehdr64_shnum;
908 		shdr_addr		= shdr64_addr;
909 		shdr_offset		= shdr64_offset;
910 		shdr_link		= shdr64_link;
911 		shdr_size		= shdr64_size;
912 		shdr_name		= shdr64_name;
913 		shdr_type		= shdr64_type;
914 		shdr_entsize		= shdr64_entsize;
915 		sym_type		= sym64_type;
916 		sym_name		= sym64_name;
917 		sym_value		= sym64_value;
918 		sym_shndx		= sym64_shndx;
919 		long_size		= 8;
920 		extable_ent_size	= 16;
921 
922 		break;
923 	default:
924 		fprintf(stderr, "unrecognized ELF class %d %s\n",
925 			ehdr->e32.e_ident[EI_CLASS], fname);
926 		return -1;
927 	}
928 
929 	return do_sort(ehdr, fname, custom_sort);
930 }
931 
932 int main(int argc, char *argv[])
933 {
934 	int i, n_error = 0;  /* gcc-4.3.0 false positive complaint */
935 	size_t size = 0;
936 	void *addr = NULL;
937 
938 	if (argc < 2) {
939 		fprintf(stderr, "usage: sorttable vmlinux...\n");
940 		return 0;
941 	}
942 
943 	/* Process each file in turn, allowing deep failure. */
944 	for (i = 1; i < argc; i++) {
945 		addr = mmap_file(argv[i], &size);
946 		if (!addr) {
947 			++n_error;
948 			continue;
949 		}
950 
951 		if (do_file(argv[i], addr))
952 			++n_error;
953 
954 		munmap(addr, size);
955 	}
956 
957 	return !!n_error;
958 }
959