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