Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool updates from Ingo Molnar:
"The main changes are to move the ORC unwind table sorting from early
init to build-time - this speeds up booting.

No change in functionality intended"

* 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/unwind/orc: Fix !CONFIG_MODULES build warning
x86/unwind/orc: Remove boot-time ORC unwind tables sorting
scripts/sorttable: Implement build-time ORC unwind table sorting
scripts/sorttable: Rename 'sortextable' to 'sorttable'
scripts/sortextable: Refactor the do_func() function
scripts/sortextable: Remove dead code
scripts/sortextable: Clean up the code to meet the kernel coding style better
scripts/sortextable: Rewrite error/success handling

+795 -632
+1 -1
arch/arc/Kconfig
··· 13 13 select ARCH_HAS_SYNC_DMA_FOR_DEVICE 14 14 select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC 15 15 select ARCH_32BIT_OFF_T 16 - select BUILDTIME_EXTABLE_SORT 16 + select BUILDTIME_TABLE_SORT 17 17 select CLONE_BACKWARDS 18 18 select COMMON_CLK 19 19 select DMA_DIRECT_REMAP
+1 -1
arch/arm/Kconfig
··· 36 36 select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU 37 37 select ARCH_WANT_IPC_PARSE_VERSION 38 38 select BINFMT_FLAT_ARGVP_ENVP_ON_STACK 39 - select BUILDTIME_EXTABLE_SORT if MMU 39 + select BUILDTIME_TABLE_SORT if MMU 40 40 select CLONE_BACKWARDS 41 41 select CPU_PM if SUSPEND || CPU_IDLE 42 42 select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS
+1 -1
arch/arm64/Kconfig
··· 81 81 select ARM_GIC_V3 82 82 select ARM_GIC_V3_ITS if PCI 83 83 select ARM_PSCI_FW 84 - select BUILDTIME_EXTABLE_SORT 84 + select BUILDTIME_TABLE_SORT 85 85 select CLONE_BACKWARDS 86 86 select COMMON_CLK 87 87 select CPU_PM if (SUSPEND || CPU_IDLE)
+1 -1
arch/microblaze/Kconfig
··· 11 11 select ARCH_HAS_UNCACHED_SEGMENT if !MMU 12 12 select ARCH_MIGHT_HAVE_PC_PARPORT 13 13 select ARCH_WANT_IPC_PARSE_VERSION 14 - select BUILDTIME_EXTABLE_SORT 14 + select BUILDTIME_TABLE_SORT 15 15 select TIMER_OF 16 16 select CLONE_BACKWARDS3 17 17 select COMMON_CLK
+1 -1
arch/mips/Kconfig
··· 15 15 select ARCH_USE_QUEUED_SPINLOCKS 16 16 select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU 17 17 select ARCH_WANT_IPC_PARSE_VERSION 18 - select BUILDTIME_EXTABLE_SORT 18 + select BUILDTIME_TABLE_SORT 19 19 select CLONE_BACKWARDS 20 20 select CPU_NO_EFFICIENT_FFS if (TARGET_ISA_REV < 1) 21 21 select CPU_PM if CPU_IDLE
+1 -1
arch/parisc/Kconfig
··· 18 18 select RTC_DRV_GENERIC 19 19 select INIT_ALL_POSSIBLE 20 20 select BUG 21 - select BUILDTIME_EXTABLE_SORT 21 + select BUILDTIME_TABLE_SORT 22 22 select HAVE_PCI 23 23 select HAVE_PERF_EVENTS 24 24 select HAVE_KERNEL_BZIP2
+1 -1
arch/powerpc/Kconfig
··· 149 149 select ARCH_WANT_IPC_PARSE_VERSION 150 150 select ARCH_WEAK_RELEASE_ACQUIRE 151 151 select BINFMT_ELF 152 - select BUILDTIME_EXTABLE_SORT 152 + select BUILDTIME_TABLE_SORT 153 153 select CLONE_BACKWARDS 154 154 select DCACHE_WORD_ACCESS if PPC64 && CPU_LITTLE_ENDIAN 155 155 select DYNAMIC_FTRACE if FUNCTION_TRACER
+1 -1
arch/s390/Kconfig
··· 110 110 select ARCH_USE_CMPXCHG_LOCKREF 111 111 select ARCH_WANTS_DYNAMIC_TASK_STRUCT 112 112 select ARCH_WANT_IPC_PARSE_VERSION 113 - select BUILDTIME_EXTABLE_SORT 113 + select BUILDTIME_TABLE_SORT 114 114 select CLONE_BACKWARDS2 115 115 select DYNAMIC_FTRACE if FUNCTION_TRACER 116 116 select GENERIC_CLOCKEVENTS
+1 -1
arch/x86/Kconfig
··· 96 96 select ARCH_WANTS_DYNAMIC_TASK_STRUCT 97 97 select ARCH_WANT_HUGE_PMD_SHARE 98 98 select ARCH_WANTS_THP_SWAP if X86_64 99 - select BUILDTIME_EXTABLE_SORT 99 + select BUILDTIME_TABLE_SORT 100 100 select CLKEVT_I8253 101 101 select CLOCKSOURCE_VALIDATE_LAST_CYCLE 102 102 select CLOCKSOURCE_WATCHDOG
+7 -4
arch/x86/kernel/unwind_orc.c
··· 187 187 return orc_ftrace_find(ip); 188 188 } 189 189 190 + #ifdef CONFIG_MODULES 191 + 190 192 static void orc_sort_swap(void *_a, void *_b, int size) 191 193 { 192 194 struct orc_entry *orc_a, *orc_b; ··· 231 229 return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1; 232 230 } 233 231 234 - #ifdef CONFIG_MODULES 235 232 void unwind_module_init(struct module *mod, void *_orc_ip, size_t orc_ip_size, 236 233 void *_orc, size_t orc_size) 237 234 { ··· 274 273 return; 275 274 } 276 275 277 - /* Sort the .orc_unwind and .orc_unwind_ip tables: */ 278 - sort(__start_orc_unwind_ip, num_entries, sizeof(int), orc_sort_cmp, 279 - orc_sort_swap); 276 + /* 277 + * Note, the orc_unwind and orc_unwind_ip tables were already 278 + * sorted at build time via the 'sorttable' tool. 279 + * It's ready for binary search straight away, no need to sort it. 280 + */ 280 281 281 282 /* Initialize the fast lookup table: */ 282 283 lookup_num_blocks = orc_lookup_end - orc_lookup;
+1 -1
arch/xtensa/Kconfig
··· 11 11 select ARCH_USE_QUEUED_SPINLOCKS 12 12 select ARCH_WANT_FRAME_POINTERS 13 13 select ARCH_WANT_IPC_PARSE_VERSION 14 - select BUILDTIME_EXTABLE_SORT 14 + select BUILDTIME_TABLE_SORT 15 15 select CLONE_BACKWARDS 16 16 select COMMON_CLK 17 17 select DMA_REMAP if MMU
+1 -1
init/Kconfig
··· 58 58 config IRQ_WORK 59 59 bool 60 60 61 - config BUILDTIME_EXTABLE_SORT 61 + config BUILDTIME_TABLE_SORT 62 62 bool 63 63 64 64 config THREAD_INFO_IN_TASK
+1 -1
scripts/.gitignore
··· 6 6 kallsyms 7 7 unifdef 8 8 recordmcount 9 - sortextable 9 + sorttable 10 10 asn1_compiler 11 11 extract-cert 12 12 sign-file
+11 -2
scripts/Makefile
··· 13 13 hostprogs-$(CONFIG_KALLSYMS) += kallsyms 14 14 hostprogs-$(CONFIG_VT) += conmakehash 15 15 hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount 16 - hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable 16 + hostprogs-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable 17 17 hostprogs-$(CONFIG_ASN1) += asn1_compiler 18 18 hostprogs-$(CONFIG_MODULE_SIG_FORMAT) += sign-file 19 19 hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert 20 20 hostprogs-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert 21 21 22 - HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include 22 + HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include 23 23 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include 24 24 HOSTLDLIBS_sign-file = -lcrypto 25 25 HOSTLDLIBS_extract-cert = -lcrypto 26 + 27 + ifdef CONFIG_UNWINDER_ORC 28 + ifeq ($(ARCH),x86_64) 29 + ARCH := x86 30 + endif 31 + HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include 32 + HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED 33 + HOSTLDLIBS_sorttable = -lpthread 34 + endif 26 35 27 36 always := $(hostprogs-y) $(hostprogs-m) 28 37
-400
scripts/sortextable.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-only 2 - /* 3 - * sortextable.c: Sort the kernel's exception table 4 - * 5 - * Copyright 2011 - 2012 Cavium, Inc. 6 - * 7 - * Based on code taken from recortmcount.c which is: 8 - * 9 - * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. 10 - * 11 - * Restructured to fit Linux format, as well as other updates: 12 - * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. 13 - */ 14 - 15 - /* 16 - * Strategy: alter the vmlinux file in-place. 17 - */ 18 - 19 - #include <sys/types.h> 20 - #include <sys/mman.h> 21 - #include <sys/stat.h> 22 - #include <getopt.h> 23 - #include <elf.h> 24 - #include <fcntl.h> 25 - #include <setjmp.h> 26 - #include <stdio.h> 27 - #include <stdlib.h> 28 - #include <string.h> 29 - #include <unistd.h> 30 - 31 - #include <tools/be_byteshift.h> 32 - #include <tools/le_byteshift.h> 33 - 34 - #ifndef EM_ARCOMPACT 35 - #define EM_ARCOMPACT 93 36 - #endif 37 - 38 - #ifndef EM_XTENSA 39 - #define EM_XTENSA 94 40 - #endif 41 - 42 - #ifndef EM_AARCH64 43 - #define EM_AARCH64 183 44 - #endif 45 - 46 - #ifndef EM_MICROBLAZE 47 - #define EM_MICROBLAZE 189 48 - #endif 49 - 50 - #ifndef EM_ARCV2 51 - #define EM_ARCV2 195 52 - #endif 53 - 54 - static int fd_map; /* File descriptor for file being modified. */ 55 - static int mmap_failed; /* Boolean flag. */ 56 - static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ 57 - static struct stat sb; /* Remember .st_size, etc. */ 58 - static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ 59 - 60 - /* setjmp() return values */ 61 - enum { 62 - SJ_SETJMP = 0, /* hardwired first return */ 63 - SJ_FAIL, 64 - SJ_SUCCEED 65 - }; 66 - 67 - /* Per-file resource cleanup when multiple files. */ 68 - static void 69 - cleanup(void) 70 - { 71 - if (!mmap_failed) 72 - munmap(ehdr_curr, sb.st_size); 73 - close(fd_map); 74 - } 75 - 76 - static void __attribute__((noreturn)) 77 - fail_file(void) 78 - { 79 - cleanup(); 80 - longjmp(jmpenv, SJ_FAIL); 81 - } 82 - 83 - /* 84 - * Get the whole file as a programming convenience in order to avoid 85 - * malloc+lseek+read+free of many pieces. If successful, then mmap 86 - * avoids copying unused pieces; else just read the whole file. 87 - * Open for both read and write. 88 - */ 89 - static void *mmap_file(char const *fname) 90 - { 91 - void *addr; 92 - 93 - fd_map = open(fname, O_RDWR); 94 - if (fd_map < 0 || fstat(fd_map, &sb) < 0) { 95 - perror(fname); 96 - fail_file(); 97 - } 98 - if (!S_ISREG(sb.st_mode)) { 99 - fprintf(stderr, "not a regular file: %s\n", fname); 100 - fail_file(); 101 - } 102 - addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, 103 - fd_map, 0); 104 - if (addr == MAP_FAILED) { 105 - mmap_failed = 1; 106 - fprintf(stderr, "Could not mmap file: %s\n", fname); 107 - fail_file(); 108 - } 109 - return addr; 110 - } 111 - 112 - static uint64_t r8be(const uint64_t *x) 113 - { 114 - return get_unaligned_be64(x); 115 - } 116 - static uint32_t rbe(const uint32_t *x) 117 - { 118 - return get_unaligned_be32(x); 119 - } 120 - static uint16_t r2be(const uint16_t *x) 121 - { 122 - return get_unaligned_be16(x); 123 - } 124 - static uint64_t r8le(const uint64_t *x) 125 - { 126 - return get_unaligned_le64(x); 127 - } 128 - static uint32_t rle(const uint32_t *x) 129 - { 130 - return get_unaligned_le32(x); 131 - } 132 - static uint16_t r2le(const uint16_t *x) 133 - { 134 - return get_unaligned_le16(x); 135 - } 136 - 137 - static void w8be(uint64_t val, uint64_t *x) 138 - { 139 - put_unaligned_be64(val, x); 140 - } 141 - static void wbe(uint32_t val, uint32_t *x) 142 - { 143 - put_unaligned_be32(val, x); 144 - } 145 - static void w2be(uint16_t val, uint16_t *x) 146 - { 147 - put_unaligned_be16(val, x); 148 - } 149 - static void w8le(uint64_t val, uint64_t *x) 150 - { 151 - put_unaligned_le64(val, x); 152 - } 153 - static void wle(uint32_t val, uint32_t *x) 154 - { 155 - put_unaligned_le32(val, x); 156 - } 157 - static void w2le(uint16_t val, uint16_t *x) 158 - { 159 - put_unaligned_le16(val, x); 160 - } 161 - 162 - static uint64_t (*r8)(const uint64_t *); 163 - static uint32_t (*r)(const uint32_t *); 164 - static uint16_t (*r2)(const uint16_t *); 165 - static void (*w8)(uint64_t, uint64_t *); 166 - static void (*w)(uint32_t, uint32_t *); 167 - static void (*w2)(uint16_t, uint16_t *); 168 - 169 - typedef void (*table_sort_t)(char *, int); 170 - 171 - /* 172 - * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of 173 - * the way to -256..-1, to avoid conflicting with real section 174 - * indices. 175 - */ 176 - #define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) 177 - 178 - static inline int is_shndx_special(unsigned int i) 179 - { 180 - return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; 181 - } 182 - 183 - /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ 184 - static inline unsigned int get_secindex(unsigned int shndx, 185 - unsigned int sym_offs, 186 - const Elf32_Word *symtab_shndx_start) 187 - { 188 - if (is_shndx_special(shndx)) 189 - return SPECIAL(shndx); 190 - if (shndx != SHN_XINDEX) 191 - return shndx; 192 - return r(&symtab_shndx_start[sym_offs]); 193 - } 194 - 195 - /* 32 bit and 64 bit are very similar */ 196 - #include "sortextable.h" 197 - #define SORTEXTABLE_64 198 - #include "sortextable.h" 199 - 200 - static int compare_relative_table(const void *a, const void *b) 201 - { 202 - int32_t av = (int32_t)r(a); 203 - int32_t bv = (int32_t)r(b); 204 - 205 - if (av < bv) 206 - return -1; 207 - if (av > bv) 208 - return 1; 209 - return 0; 210 - } 211 - 212 - static void x86_sort_relative_table(char *extab_image, int image_size) 213 - { 214 - int i; 215 - 216 - i = 0; 217 - while (i < image_size) { 218 - uint32_t *loc = (uint32_t *)(extab_image + i); 219 - 220 - w(r(loc) + i, loc); 221 - w(r(loc + 1) + i + 4, loc + 1); 222 - w(r(loc + 2) + i + 8, loc + 2); 223 - 224 - i += sizeof(uint32_t) * 3; 225 - } 226 - 227 - qsort(extab_image, image_size / 12, 12, compare_relative_table); 228 - 229 - i = 0; 230 - while (i < image_size) { 231 - uint32_t *loc = (uint32_t *)(extab_image + i); 232 - 233 - w(r(loc) - i, loc); 234 - w(r(loc + 1) - (i + 4), loc + 1); 235 - w(r(loc + 2) - (i + 8), loc + 2); 236 - 237 - i += sizeof(uint32_t) * 3; 238 - } 239 - } 240 - 241 - static void sort_relative_table(char *extab_image, int image_size) 242 - { 243 - int i; 244 - 245 - /* 246 - * Do the same thing the runtime sort does, first normalize to 247 - * being relative to the start of the section. 248 - */ 249 - i = 0; 250 - while (i < image_size) { 251 - uint32_t *loc = (uint32_t *)(extab_image + i); 252 - w(r(loc) + i, loc); 253 - i += 4; 254 - } 255 - 256 - qsort(extab_image, image_size / 8, 8, compare_relative_table); 257 - 258 - /* Now denormalize. */ 259 - i = 0; 260 - while (i < image_size) { 261 - uint32_t *loc = (uint32_t *)(extab_image + i); 262 - w(r(loc) - i, loc); 263 - i += 4; 264 - } 265 - } 266 - 267 - static void 268 - do_file(char const *const fname) 269 - { 270 - table_sort_t custom_sort; 271 - Elf32_Ehdr *ehdr = mmap_file(fname); 272 - 273 - ehdr_curr = ehdr; 274 - switch (ehdr->e_ident[EI_DATA]) { 275 - default: 276 - fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", 277 - ehdr->e_ident[EI_DATA], fname); 278 - fail_file(); 279 - break; 280 - case ELFDATA2LSB: 281 - r = rle; 282 - r2 = r2le; 283 - r8 = r8le; 284 - w = wle; 285 - w2 = w2le; 286 - w8 = w8le; 287 - break; 288 - case ELFDATA2MSB: 289 - r = rbe; 290 - r2 = r2be; 291 - r8 = r8be; 292 - w = wbe; 293 - w2 = w2be; 294 - w8 = w8be; 295 - break; 296 - } /* end switch */ 297 - if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 298 - || (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN) 299 - || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { 300 - fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname); 301 - fail_file(); 302 - } 303 - 304 - custom_sort = NULL; 305 - switch (r2(&ehdr->e_machine)) { 306 - default: 307 - fprintf(stderr, "unrecognized e_machine %d %s\n", 308 - r2(&ehdr->e_machine), fname); 309 - fail_file(); 310 - break; 311 - case EM_386: 312 - case EM_X86_64: 313 - custom_sort = x86_sort_relative_table; 314 - break; 315 - 316 - case EM_S390: 317 - case EM_AARCH64: 318 - case EM_PARISC: 319 - case EM_PPC: 320 - case EM_PPC64: 321 - custom_sort = sort_relative_table; 322 - break; 323 - case EM_ARCOMPACT: 324 - case EM_ARCV2: 325 - case EM_ARM: 326 - case EM_MICROBLAZE: 327 - case EM_MIPS: 328 - case EM_XTENSA: 329 - break; 330 - } /* end switch */ 331 - 332 - switch (ehdr->e_ident[EI_CLASS]) { 333 - default: 334 - fprintf(stderr, "unrecognized ELF class %d %s\n", 335 - ehdr->e_ident[EI_CLASS], fname); 336 - fail_file(); 337 - break; 338 - case ELFCLASS32: 339 - if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) 340 - || r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { 341 - fprintf(stderr, 342 - "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); 343 - fail_file(); 344 - } 345 - do32(ehdr, fname, custom_sort); 346 - break; 347 - case ELFCLASS64: { 348 - Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; 349 - if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) 350 - || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { 351 - fprintf(stderr, 352 - "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); 353 - fail_file(); 354 - } 355 - do64(ghdr, fname, custom_sort); 356 - break; 357 - } 358 - } /* end switch */ 359 - 360 - cleanup(); 361 - } 362 - 363 - int 364 - main(int argc, char *argv[]) 365 - { 366 - int n_error = 0; /* gcc-4.3.0 false positive complaint */ 367 - int i; 368 - 369 - if (argc < 2) { 370 - fprintf(stderr, "usage: sortextable vmlinux...\n"); 371 - return 0; 372 - } 373 - 374 - /* Process each file in turn, allowing deep failure. */ 375 - for (i = 1; i < argc; i++) { 376 - char *file = argv[i]; 377 - int const sjval = setjmp(jmpenv); 378 - 379 - switch (sjval) { 380 - default: 381 - fprintf(stderr, "internal error: %s\n", file); 382 - exit(1); 383 - break; 384 - case SJ_SETJMP: /* normal sequence */ 385 - /* Avoid problems if early cleanup() */ 386 - fd_map = -1; 387 - ehdr_curr = NULL; 388 - mmap_failed = 1; 389 - do_file(file); 390 - break; 391 - case SJ_FAIL: /* error in do_file or below */ 392 - ++n_error; 393 - break; 394 - case SJ_SUCCEED: /* premature success */ 395 - /* do nothing */ 396 - break; 397 - } /* end switch */ 398 - } 399 - return !!n_error; 400 - }
-209
scripts/sortextable.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0-only */ 2 - /* 3 - * sortextable.h 4 - * 5 - * Copyright 2011 - 2012 Cavium, Inc. 6 - * 7 - * Some of this code was taken out of recordmcount.h written by: 8 - * 9 - * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. 10 - * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. 11 - */ 12 - 13 - #undef extable_ent_size 14 - #undef compare_extable 15 - #undef do_func 16 - #undef Elf_Addr 17 - #undef Elf_Ehdr 18 - #undef Elf_Shdr 19 - #undef Elf_Rel 20 - #undef Elf_Rela 21 - #undef Elf_Sym 22 - #undef ELF_R_SYM 23 - #undef Elf_r_sym 24 - #undef ELF_R_INFO 25 - #undef Elf_r_info 26 - #undef ELF_ST_BIND 27 - #undef ELF_ST_TYPE 28 - #undef fn_ELF_R_SYM 29 - #undef fn_ELF_R_INFO 30 - #undef uint_t 31 - #undef _r 32 - #undef _w 33 - 34 - #ifdef SORTEXTABLE_64 35 - # define extable_ent_size 16 36 - # define compare_extable compare_extable_64 37 - # define do_func do64 38 - # define Elf_Addr Elf64_Addr 39 - # define Elf_Ehdr Elf64_Ehdr 40 - # define Elf_Shdr Elf64_Shdr 41 - # define Elf_Rel Elf64_Rel 42 - # define Elf_Rela Elf64_Rela 43 - # define Elf_Sym Elf64_Sym 44 - # define ELF_R_SYM ELF64_R_SYM 45 - # define Elf_r_sym Elf64_r_sym 46 - # define ELF_R_INFO ELF64_R_INFO 47 - # define Elf_r_info Elf64_r_info 48 - # define ELF_ST_BIND ELF64_ST_BIND 49 - # define ELF_ST_TYPE ELF64_ST_TYPE 50 - # define fn_ELF_R_SYM fn_ELF64_R_SYM 51 - # define fn_ELF_R_INFO fn_ELF64_R_INFO 52 - # define uint_t uint64_t 53 - # define _r r8 54 - # define _w w8 55 - #else 56 - # define extable_ent_size 8 57 - # define compare_extable compare_extable_32 58 - # define do_func do32 59 - # define Elf_Addr Elf32_Addr 60 - # define Elf_Ehdr Elf32_Ehdr 61 - # define Elf_Shdr Elf32_Shdr 62 - # define Elf_Rel Elf32_Rel 63 - # define Elf_Rela Elf32_Rela 64 - # define Elf_Sym Elf32_Sym 65 - # define ELF_R_SYM ELF32_R_SYM 66 - # define Elf_r_sym Elf32_r_sym 67 - # define ELF_R_INFO ELF32_R_INFO 68 - # define Elf_r_info Elf32_r_info 69 - # define ELF_ST_BIND ELF32_ST_BIND 70 - # define ELF_ST_TYPE ELF32_ST_TYPE 71 - # define fn_ELF_R_SYM fn_ELF32_R_SYM 72 - # define fn_ELF_R_INFO fn_ELF32_R_INFO 73 - # define uint_t uint32_t 74 - # define _r r 75 - # define _w w 76 - #endif 77 - 78 - static int compare_extable(const void *a, const void *b) 79 - { 80 - Elf_Addr av = _r(a); 81 - Elf_Addr bv = _r(b); 82 - 83 - if (av < bv) 84 - return -1; 85 - if (av > bv) 86 - return 1; 87 - return 0; 88 - } 89 - 90 - static void 91 - do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) 92 - { 93 - Elf_Shdr *shdr; 94 - Elf_Shdr *shstrtab_sec; 95 - Elf_Shdr *strtab_sec = NULL; 96 - Elf_Shdr *symtab_sec = NULL; 97 - Elf_Shdr *extab_sec = NULL; 98 - Elf_Sym *sym; 99 - const Elf_Sym *symtab; 100 - Elf32_Word *symtab_shndx_start = NULL; 101 - Elf_Sym *sort_needed_sym; 102 - Elf_Shdr *sort_needed_sec; 103 - Elf_Rel *relocs = NULL; 104 - int relocs_size = 0; 105 - uint32_t *sort_done_location; 106 - const char *secstrtab; 107 - const char *strtab; 108 - char *extab_image; 109 - int extab_index = 0; 110 - int i; 111 - int idx; 112 - unsigned int num_sections; 113 - unsigned int secindex_strings; 114 - 115 - shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); 116 - 117 - num_sections = r2(&ehdr->e_shnum); 118 - if (num_sections == SHN_UNDEF) 119 - num_sections = _r(&shdr[0].sh_size); 120 - 121 - secindex_strings = r2(&ehdr->e_shstrndx); 122 - if (secindex_strings == SHN_XINDEX) 123 - secindex_strings = r(&shdr[0].sh_link); 124 - 125 - shstrtab_sec = shdr + secindex_strings; 126 - secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset); 127 - for (i = 0; i < num_sections; i++) { 128 - idx = r(&shdr[i].sh_name); 129 - if (strcmp(secstrtab + idx, "__ex_table") == 0) { 130 - extab_sec = shdr + i; 131 - extab_index = i; 132 - } 133 - if ((r(&shdr[i].sh_type) == SHT_REL || 134 - r(&shdr[i].sh_type) == SHT_RELA) && 135 - r(&shdr[i].sh_info) == extab_index) { 136 - relocs = (void *)ehdr + _r(&shdr[i].sh_offset); 137 - relocs_size = _r(&shdr[i].sh_size); 138 - } 139 - if (strcmp(secstrtab + idx, ".symtab") == 0) 140 - symtab_sec = shdr + i; 141 - if (strcmp(secstrtab + idx, ".strtab") == 0) 142 - strtab_sec = shdr + i; 143 - if (r(&shdr[i].sh_type) == SHT_SYMTAB_SHNDX) 144 - symtab_shndx_start = (Elf32_Word *)( 145 - (const char *)ehdr + _r(&shdr[i].sh_offset)); 146 - } 147 - if (strtab_sec == NULL) { 148 - fprintf(stderr, "no .strtab in file: %s\n", fname); 149 - fail_file(); 150 - } 151 - if (symtab_sec == NULL) { 152 - fprintf(stderr, "no .symtab in file: %s\n", fname); 153 - fail_file(); 154 - } 155 - symtab = (const Elf_Sym *)((const char *)ehdr + 156 - _r(&symtab_sec->sh_offset)); 157 - if (extab_sec == NULL) { 158 - fprintf(stderr, "no __ex_table in file: %s\n", fname); 159 - fail_file(); 160 - } 161 - strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); 162 - 163 - extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); 164 - 165 - if (custom_sort) { 166 - custom_sort(extab_image, _r(&extab_sec->sh_size)); 167 - } else { 168 - int num_entries = _r(&extab_sec->sh_size) / extable_ent_size; 169 - qsort(extab_image, num_entries, 170 - extable_ent_size, compare_extable); 171 - } 172 - /* If there were relocations, we no longer need them. */ 173 - if (relocs) 174 - memset(relocs, 0, relocs_size); 175 - 176 - /* find main_extable_sort_needed */ 177 - sort_needed_sym = NULL; 178 - for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { 179 - sym = (void *)ehdr + _r(&symtab_sec->sh_offset); 180 - sym += i; 181 - if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) 182 - continue; 183 - idx = r(&sym->st_name); 184 - if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { 185 - sort_needed_sym = sym; 186 - break; 187 - } 188 - } 189 - if (sort_needed_sym == NULL) { 190 - fprintf(stderr, 191 - "no main_extable_sort_needed symbol in file: %s\n", 192 - fname); 193 - fail_file(); 194 - } 195 - sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), 196 - sort_needed_sym - symtab, 197 - symtab_shndx_start)]; 198 - sort_done_location = (void *)ehdr + 199 - _r(&sort_needed_sec->sh_offset) + 200 - _r(&sort_needed_sym->st_value) - 201 - _r(&sort_needed_sec->sh_addr); 202 - 203 - #if 0 204 - printf("sort done marker at %lx\n", 205 - (unsigned long)((char *)sort_done_location - (char *)ehdr)); 206 - #endif 207 - /* We sorted it, clear the flag. */ 208 - w(0, sort_done_location); 209 - }
+377
scripts/sorttable.c
··· 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 <shile.zhang@linux.alibaba.com> 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 <jreiser@BitWagon.com>. All rights reserved. 14 + * 15 + * Restructured to fit Linux format, as well as other updates: 16 + * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, 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 + 34 + #include <tools/be_byteshift.h> 35 + #include <tools/le_byteshift.h> 36 + 37 + #ifndef EM_ARCOMPACT 38 + #define EM_ARCOMPACT 93 39 + #endif 40 + 41 + #ifndef EM_XTENSA 42 + #define EM_XTENSA 94 43 + #endif 44 + 45 + #ifndef EM_AARCH64 46 + #define EM_AARCH64 183 47 + #endif 48 + 49 + #ifndef EM_MICROBLAZE 50 + #define EM_MICROBLAZE 189 51 + #endif 52 + 53 + #ifndef EM_ARCV2 54 + #define EM_ARCV2 195 55 + #endif 56 + 57 + static uint32_t (*r)(const uint32_t *); 58 + static uint16_t (*r2)(const uint16_t *); 59 + static uint64_t (*r8)(const uint64_t *); 60 + static void (*w)(uint32_t, uint32_t *); 61 + static void (*w2)(uint16_t, uint16_t *); 62 + static void (*w8)(uint64_t, uint64_t *); 63 + typedef void (*table_sort_t)(char *, int); 64 + 65 + /* 66 + * Get the whole file as a programming convenience in order to avoid 67 + * malloc+lseek+read+free of many pieces. If successful, then mmap 68 + * avoids copying unused pieces; else just read the whole file. 69 + * Open for both read and write. 70 + */ 71 + static void *mmap_file(char const *fname, size_t *size) 72 + { 73 + int fd; 74 + struct stat sb; 75 + void *addr = NULL; 76 + 77 + fd = open(fname, O_RDWR); 78 + if (fd < 0) { 79 + perror(fname); 80 + return NULL; 81 + } 82 + if (fstat(fd, &sb) < 0) { 83 + perror(fname); 84 + goto out; 85 + } 86 + if (!S_ISREG(sb.st_mode)) { 87 + fprintf(stderr, "not a regular file: %s\n", fname); 88 + goto out; 89 + } 90 + 91 + addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 92 + if (addr == MAP_FAILED) { 93 + fprintf(stderr, "Could not mmap file: %s\n", fname); 94 + goto out; 95 + } 96 + 97 + *size = sb.st_size; 98 + 99 + out: 100 + close(fd); 101 + return addr; 102 + } 103 + 104 + static uint32_t rbe(const uint32_t *x) 105 + { 106 + return get_unaligned_be32(x); 107 + } 108 + 109 + static uint16_t r2be(const uint16_t *x) 110 + { 111 + return get_unaligned_be16(x); 112 + } 113 + 114 + static uint64_t r8be(const uint64_t *x) 115 + { 116 + return get_unaligned_be64(x); 117 + } 118 + 119 + static uint32_t rle(const uint32_t *x) 120 + { 121 + return get_unaligned_le32(x); 122 + } 123 + 124 + static uint16_t r2le(const uint16_t *x) 125 + { 126 + return get_unaligned_le16(x); 127 + } 128 + 129 + static uint64_t r8le(const uint64_t *x) 130 + { 131 + return get_unaligned_le64(x); 132 + } 133 + 134 + static void wbe(uint32_t val, uint32_t *x) 135 + { 136 + put_unaligned_be32(val, x); 137 + } 138 + 139 + static void w2be(uint16_t val, uint16_t *x) 140 + { 141 + put_unaligned_be16(val, x); 142 + } 143 + 144 + static void w8be(uint64_t val, uint64_t *x) 145 + { 146 + put_unaligned_be64(val, x); 147 + } 148 + 149 + static void wle(uint32_t val, uint32_t *x) 150 + { 151 + put_unaligned_le32(val, x); 152 + } 153 + 154 + static void w2le(uint16_t val, uint16_t *x) 155 + { 156 + put_unaligned_le16(val, x); 157 + } 158 + 159 + static void w8le(uint64_t val, uint64_t *x) 160 + { 161 + put_unaligned_le64(val, x); 162 + } 163 + 164 + /* 165 + * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of 166 + * the way to -256..-1, to avoid conflicting with real section 167 + * indices. 168 + */ 169 + #define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) 170 + 171 + static inline int is_shndx_special(unsigned int i) 172 + { 173 + return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; 174 + } 175 + 176 + /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ 177 + static inline unsigned int get_secindex(unsigned int shndx, 178 + unsigned int sym_offs, 179 + const Elf32_Word *symtab_shndx_start) 180 + { 181 + if (is_shndx_special(shndx)) 182 + return SPECIAL(shndx); 183 + if (shndx != SHN_XINDEX) 184 + return shndx; 185 + return r(&symtab_shndx_start[sym_offs]); 186 + } 187 + 188 + /* 32 bit and 64 bit are very similar */ 189 + #include "sorttable.h" 190 + #define SORTTABLE_64 191 + #include "sorttable.h" 192 + 193 + static int compare_relative_table(const void *a, const void *b) 194 + { 195 + int32_t av = (int32_t)r(a); 196 + int32_t bv = (int32_t)r(b); 197 + 198 + if (av < bv) 199 + return -1; 200 + if (av > bv) 201 + return 1; 202 + return 0; 203 + } 204 + 205 + static void sort_relative_table(char *extab_image, int image_size) 206 + { 207 + int i = 0; 208 + 209 + /* 210 + * Do the same thing the runtime sort does, first normalize to 211 + * being relative to the start of the section. 212 + */ 213 + while (i < image_size) { 214 + uint32_t *loc = (uint32_t *)(extab_image + i); 215 + w(r(loc) + i, loc); 216 + i += 4; 217 + } 218 + 219 + qsort(extab_image, image_size / 8, 8, compare_relative_table); 220 + 221 + /* Now denormalize. */ 222 + i = 0; 223 + while (i < image_size) { 224 + uint32_t *loc = (uint32_t *)(extab_image + i); 225 + w(r(loc) - i, loc); 226 + i += 4; 227 + } 228 + } 229 + 230 + static void x86_sort_relative_table(char *extab_image, int image_size) 231 + { 232 + int i = 0; 233 + 234 + while (i < image_size) { 235 + uint32_t *loc = (uint32_t *)(extab_image + i); 236 + 237 + w(r(loc) + i, loc); 238 + w(r(loc + 1) + i + 4, loc + 1); 239 + w(r(loc + 2) + i + 8, loc + 2); 240 + 241 + i += sizeof(uint32_t) * 3; 242 + } 243 + 244 + qsort(extab_image, image_size / 12, 12, compare_relative_table); 245 + 246 + i = 0; 247 + while (i < image_size) { 248 + uint32_t *loc = (uint32_t *)(extab_image + i); 249 + 250 + w(r(loc) - i, loc); 251 + w(r(loc + 1) - (i + 4), loc + 1); 252 + w(r(loc + 2) - (i + 8), loc + 2); 253 + 254 + i += sizeof(uint32_t) * 3; 255 + } 256 + } 257 + 258 + static int do_file(char const *const fname, void *addr) 259 + { 260 + int rc = -1; 261 + Elf32_Ehdr *ehdr = addr; 262 + table_sort_t custom_sort = NULL; 263 + 264 + switch (ehdr->e_ident[EI_DATA]) { 265 + case ELFDATA2LSB: 266 + r = rle; 267 + r2 = r2le; 268 + r8 = r8le; 269 + w = wle; 270 + w2 = w2le; 271 + w8 = w8le; 272 + break; 273 + case ELFDATA2MSB: 274 + r = rbe; 275 + r2 = r2be; 276 + r8 = r8be; 277 + w = wbe; 278 + w2 = w2be; 279 + w8 = w8be; 280 + break; 281 + default: 282 + fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", 283 + ehdr->e_ident[EI_DATA], fname); 284 + return -1; 285 + } 286 + 287 + if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 || 288 + (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN) || 289 + ehdr->e_ident[EI_VERSION] != EV_CURRENT) { 290 + fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname); 291 + return -1; 292 + } 293 + 294 + switch (r2(&ehdr->e_machine)) { 295 + case EM_386: 296 + case EM_X86_64: 297 + custom_sort = x86_sort_relative_table; 298 + break; 299 + case EM_S390: 300 + case EM_AARCH64: 301 + case EM_PARISC: 302 + case EM_PPC: 303 + case EM_PPC64: 304 + custom_sort = sort_relative_table; 305 + break; 306 + case EM_ARCOMPACT: 307 + case EM_ARCV2: 308 + case EM_ARM: 309 + case EM_MICROBLAZE: 310 + case EM_MIPS: 311 + case EM_XTENSA: 312 + break; 313 + default: 314 + fprintf(stderr, "unrecognized e_machine %d %s\n", 315 + r2(&ehdr->e_machine), fname); 316 + return -1; 317 + } 318 + 319 + switch (ehdr->e_ident[EI_CLASS]) { 320 + case ELFCLASS32: 321 + if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) || 322 + r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { 323 + fprintf(stderr, 324 + "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); 325 + break; 326 + } 327 + rc = do_sort_32(ehdr, fname, custom_sort); 328 + break; 329 + case ELFCLASS64: 330 + { 331 + Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; 332 + if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) || 333 + r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { 334 + fprintf(stderr, 335 + "unrecognized ET_EXEC/ET_DYN file: %s\n", 336 + fname); 337 + break; 338 + } 339 + rc = do_sort_64(ghdr, fname, custom_sort); 340 + } 341 + break; 342 + default: 343 + fprintf(stderr, "unrecognized ELF class %d %s\n", 344 + ehdr->e_ident[EI_CLASS], fname); 345 + break; 346 + } 347 + 348 + return rc; 349 + } 350 + 351 + int main(int argc, char *argv[]) 352 + { 353 + int i, n_error = 0; /* gcc-4.3.0 false positive complaint */ 354 + size_t size = 0; 355 + void *addr = NULL; 356 + 357 + if (argc < 2) { 358 + fprintf(stderr, "usage: sorttable vmlinux...\n"); 359 + return 0; 360 + } 361 + 362 + /* Process each file in turn, allowing deep failure. */ 363 + for (i = 1; i < argc; i++) { 364 + addr = mmap_file(argv[i], &size); 365 + if (!addr) { 366 + ++n_error; 367 + continue; 368 + } 369 + 370 + if (do_file(argv[i], addr)) 371 + ++n_error; 372 + 373 + munmap(addr, size); 374 + } 375 + 376 + return !!n_error; 377 + }
+380
scripts/sorttable.h
··· 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 + 20 + #undef extable_ent_size 21 + #undef compare_extable 22 + #undef do_sort 23 + #undef Elf_Addr 24 + #undef Elf_Ehdr 25 + #undef Elf_Shdr 26 + #undef Elf_Rel 27 + #undef Elf_Rela 28 + #undef Elf_Sym 29 + #undef ELF_R_SYM 30 + #undef Elf_r_sym 31 + #undef ELF_R_INFO 32 + #undef Elf_r_info 33 + #undef ELF_ST_BIND 34 + #undef ELF_ST_TYPE 35 + #undef fn_ELF_R_SYM 36 + #undef fn_ELF_R_INFO 37 + #undef uint_t 38 + #undef _r 39 + #undef _w 40 + 41 + #ifdef SORTTABLE_64 42 + # define extable_ent_size 16 43 + # define compare_extable compare_extable_64 44 + # define do_sort do_sort_64 45 + # define Elf_Addr Elf64_Addr 46 + # define Elf_Ehdr Elf64_Ehdr 47 + # define Elf_Shdr Elf64_Shdr 48 + # define Elf_Rel Elf64_Rel 49 + # define Elf_Rela Elf64_Rela 50 + # define Elf_Sym Elf64_Sym 51 + # define ELF_R_SYM ELF64_R_SYM 52 + # define Elf_r_sym Elf64_r_sym 53 + # define ELF_R_INFO ELF64_R_INFO 54 + # define Elf_r_info Elf64_r_info 55 + # define ELF_ST_BIND ELF64_ST_BIND 56 + # define ELF_ST_TYPE ELF64_ST_TYPE 57 + # define fn_ELF_R_SYM fn_ELF64_R_SYM 58 + # define fn_ELF_R_INFO fn_ELF64_R_INFO 59 + # define uint_t uint64_t 60 + # define _r r8 61 + # define _w w8 62 + #else 63 + # define extable_ent_size 8 64 + # define compare_extable compare_extable_32 65 + # define do_sort do_sort_32 66 + # define Elf_Addr Elf32_Addr 67 + # define Elf_Ehdr Elf32_Ehdr 68 + # define Elf_Shdr Elf32_Shdr 69 + # define Elf_Rel Elf32_Rel 70 + # define Elf_Rela Elf32_Rela 71 + # define Elf_Sym Elf32_Sym 72 + # define ELF_R_SYM ELF32_R_SYM 73 + # define Elf_r_sym Elf32_r_sym 74 + # define ELF_R_INFO ELF32_R_INFO 75 + # define Elf_r_info Elf32_r_info 76 + # define ELF_ST_BIND ELF32_ST_BIND 77 + # define ELF_ST_TYPE ELF32_ST_TYPE 78 + # define fn_ELF_R_SYM fn_ELF32_R_SYM 79 + # define fn_ELF_R_INFO fn_ELF32_R_INFO 80 + # define uint_t uint32_t 81 + # define _r r 82 + # define _w w 83 + #endif 84 + 85 + #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) 86 + /* ORC unwinder only support X86_64 */ 87 + #include <errno.h> 88 + #include <pthread.h> 89 + #include <asm/orc_types.h> 90 + 91 + #define ERRSTR_MAXSZ 256 92 + 93 + char g_err[ERRSTR_MAXSZ]; 94 + int *g_orc_ip_table; 95 + struct orc_entry *g_orc_table; 96 + 97 + pthread_t orc_sort_thread; 98 + 99 + static inline unsigned long orc_ip(const int *ip) 100 + { 101 + return (unsigned long)ip + *ip; 102 + } 103 + 104 + static int orc_sort_cmp(const void *_a, const void *_b) 105 + { 106 + struct orc_entry *orc_a; 107 + const int *a = g_orc_ip_table + *(int *)_a; 108 + const int *b = g_orc_ip_table + *(int *)_b; 109 + unsigned long a_val = orc_ip(a); 110 + unsigned long b_val = orc_ip(b); 111 + 112 + if (a_val > b_val) 113 + return 1; 114 + if (a_val < b_val) 115 + return -1; 116 + 117 + /* 118 + * The "weak" section terminator entries need to always be on the left 119 + * to ensure the lookup code skips them in favor of real entries. 120 + * These terminator entries exist to handle any gaps created by 121 + * whitelisted .o files which didn't get objtool generation. 122 + */ 123 + orc_a = g_orc_table + (a - g_orc_ip_table); 124 + return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1; 125 + } 126 + 127 + static void *sort_orctable(void *arg) 128 + { 129 + int i; 130 + int *idxs = NULL; 131 + int *tmp_orc_ip_table = NULL; 132 + struct orc_entry *tmp_orc_table = NULL; 133 + unsigned int *orc_ip_size = (unsigned int *)arg; 134 + unsigned int num_entries = *orc_ip_size / sizeof(int); 135 + unsigned int orc_size = num_entries * sizeof(struct orc_entry); 136 + 137 + idxs = (int *)malloc(*orc_ip_size); 138 + if (!idxs) { 139 + snprintf(g_err, ERRSTR_MAXSZ, "malloc idxs: %s", 140 + strerror(errno)); 141 + pthread_exit(g_err); 142 + } 143 + 144 + tmp_orc_ip_table = (int *)malloc(*orc_ip_size); 145 + if (!tmp_orc_ip_table) { 146 + snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_ip_table: %s", 147 + strerror(errno)); 148 + pthread_exit(g_err); 149 + } 150 + 151 + tmp_orc_table = (struct orc_entry *)malloc(orc_size); 152 + if (!tmp_orc_table) { 153 + snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_table: %s", 154 + strerror(errno)); 155 + pthread_exit(g_err); 156 + } 157 + 158 + /* initialize indices array, convert ip_table to absolute address */ 159 + for (i = 0; i < num_entries; i++) { 160 + idxs[i] = i; 161 + tmp_orc_ip_table[i] = g_orc_ip_table[i] + i * sizeof(int); 162 + } 163 + memcpy(tmp_orc_table, g_orc_table, orc_size); 164 + 165 + qsort(idxs, num_entries, sizeof(int), orc_sort_cmp); 166 + 167 + for (i = 0; i < num_entries; i++) { 168 + if (idxs[i] == i) 169 + continue; 170 + 171 + /* convert back to relative address */ 172 + g_orc_ip_table[i] = tmp_orc_ip_table[idxs[i]] - i * sizeof(int); 173 + g_orc_table[i] = tmp_orc_table[idxs[i]]; 174 + } 175 + 176 + free(idxs); 177 + free(tmp_orc_ip_table); 178 + free(tmp_orc_table); 179 + pthread_exit(NULL); 180 + } 181 + #endif 182 + 183 + static int compare_extable(const void *a, const void *b) 184 + { 185 + Elf_Addr av = _r(a); 186 + Elf_Addr bv = _r(b); 187 + 188 + if (av < bv) 189 + return -1; 190 + if (av > bv) 191 + return 1; 192 + return 0; 193 + } 194 + 195 + static int do_sort(Elf_Ehdr *ehdr, 196 + char const *const fname, 197 + table_sort_t custom_sort) 198 + { 199 + int rc = -1; 200 + Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); 201 + Elf_Shdr *strtab_sec = NULL; 202 + Elf_Shdr *symtab_sec = NULL; 203 + Elf_Shdr *extab_sec = NULL; 204 + Elf_Sym *sym; 205 + const Elf_Sym *symtab; 206 + Elf32_Word *symtab_shndx = NULL; 207 + Elf_Sym *sort_needed_sym = NULL; 208 + Elf_Shdr *sort_needed_sec; 209 + Elf_Rel *relocs = NULL; 210 + int relocs_size = 0; 211 + uint32_t *sort_needed_loc; 212 + const char *secstrings; 213 + const char *strtab; 214 + char *extab_image; 215 + int extab_index = 0; 216 + int i; 217 + int idx; 218 + unsigned int shnum; 219 + unsigned int shstrndx; 220 + #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) 221 + unsigned int orc_ip_size = 0; 222 + unsigned int orc_size = 0; 223 + unsigned int orc_num_entries = 0; 224 + #endif 225 + 226 + shstrndx = r2(&ehdr->e_shstrndx); 227 + if (shstrndx == SHN_XINDEX) 228 + shstrndx = r(&shdr[0].sh_link); 229 + secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset); 230 + 231 + shnum = r2(&ehdr->e_shnum); 232 + if (shnum == SHN_UNDEF) 233 + shnum = _r(&shdr[0].sh_size); 234 + 235 + for (i = 0, s = shdr; s < shdr + shnum; i++, s++) { 236 + idx = r(&s->sh_name); 237 + if (!strcmp(secstrings + idx, "__ex_table")) { 238 + extab_sec = s; 239 + extab_index = i; 240 + } 241 + if (!strcmp(secstrings + idx, ".symtab")) 242 + symtab_sec = s; 243 + if (!strcmp(secstrings + idx, ".strtab")) 244 + strtab_sec = s; 245 + 246 + if ((r(&s->sh_type) == SHT_REL || 247 + r(&s->sh_type) == SHT_RELA) && 248 + r(&s->sh_info) == extab_index) { 249 + relocs = (void *)ehdr + _r(&s->sh_offset); 250 + relocs_size = _r(&s->sh_size); 251 + } 252 + if (r(&s->sh_type) == SHT_SYMTAB_SHNDX) 253 + symtab_shndx = (Elf32_Word *)((const char *)ehdr + 254 + _r(&s->sh_offset)); 255 + 256 + #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) 257 + /* locate the ORC unwind tables */ 258 + if (!strcmp(secstrings + idx, ".orc_unwind_ip")) { 259 + orc_ip_size = s->sh_size; 260 + g_orc_ip_table = (int *)((void *)ehdr + 261 + s->sh_offset); 262 + } 263 + if (!strcmp(secstrings + idx, ".orc_unwind")) { 264 + orc_size = s->sh_size; 265 + g_orc_table = (struct orc_entry *)((void *)ehdr + 266 + s->sh_offset); 267 + } 268 + #endif 269 + } /* for loop */ 270 + 271 + #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) 272 + if (!g_orc_ip_table || !g_orc_table) { 273 + fprintf(stderr, 274 + "incomplete ORC unwind tables in file: %s\n", fname); 275 + goto out; 276 + } 277 + 278 + orc_num_entries = orc_ip_size / sizeof(int); 279 + if (orc_ip_size % sizeof(int) != 0 || 280 + orc_size % sizeof(struct orc_entry) != 0 || 281 + orc_num_entries != orc_size / sizeof(struct orc_entry)) { 282 + fprintf(stderr, 283 + "inconsistent ORC unwind table entries in file: %s\n", 284 + fname); 285 + goto out; 286 + } 287 + 288 + /* create thread to sort ORC unwind tables concurrently */ 289 + if (pthread_create(&orc_sort_thread, NULL, 290 + sort_orctable, &orc_ip_size)) { 291 + fprintf(stderr, 292 + "pthread_create orc_sort_thread failed '%s': %s\n", 293 + strerror(errno), fname); 294 + goto out; 295 + } 296 + #endif 297 + if (!extab_sec) { 298 + fprintf(stderr, "no __ex_table in file: %s\n", fname); 299 + goto out; 300 + } 301 + 302 + if (!symtab_sec) { 303 + fprintf(stderr, "no .symtab in file: %s\n", fname); 304 + goto out; 305 + } 306 + 307 + if (!strtab_sec) { 308 + fprintf(stderr, "no .strtab in file: %s\n", fname); 309 + goto out; 310 + } 311 + 312 + extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); 313 + strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); 314 + symtab = (const Elf_Sym *)((const char *)ehdr + 315 + _r(&symtab_sec->sh_offset)); 316 + 317 + if (custom_sort) { 318 + custom_sort(extab_image, _r(&extab_sec->sh_size)); 319 + } else { 320 + int num_entries = _r(&extab_sec->sh_size) / extable_ent_size; 321 + qsort(extab_image, num_entries, 322 + extable_ent_size, compare_extable); 323 + } 324 + 325 + /* If there were relocations, we no longer need them. */ 326 + if (relocs) 327 + memset(relocs, 0, relocs_size); 328 + 329 + /* find the flag main_extable_sort_needed */ 330 + for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset); 331 + sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); 332 + sym++) { 333 + if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) 334 + continue; 335 + if (!strcmp(strtab + r(&sym->st_name), 336 + "main_extable_sort_needed")) { 337 + sort_needed_sym = sym; 338 + break; 339 + } 340 + } 341 + 342 + if (!sort_needed_sym) { 343 + fprintf(stderr, 344 + "no main_extable_sort_needed symbol in file: %s\n", 345 + fname); 346 + goto out; 347 + } 348 + 349 + sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), 350 + sort_needed_sym - symtab, 351 + symtab_shndx)]; 352 + sort_needed_loc = (void *)ehdr + 353 + _r(&sort_needed_sec->sh_offset) + 354 + _r(&sort_needed_sym->st_value) - 355 + _r(&sort_needed_sec->sh_addr); 356 + 357 + /* extable has been sorted, clear the flag */ 358 + w(0, sort_needed_loc); 359 + rc = 0; 360 + 361 + out: 362 + #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) 363 + if (orc_sort_thread) { 364 + void *retval = NULL; 365 + /* wait for ORC tables sort done */ 366 + rc = pthread_join(orc_sort_thread, &retval); 367 + if (rc) 368 + fprintf(stderr, 369 + "pthread_join failed '%s': %s\n", 370 + strerror(errno), fname); 371 + else if (retval) { 372 + rc = -1; 373 + fprintf(stderr, 374 + "failed to sort ORC tables '%s': %s\n", 375 + (char *)retval, fname); 376 + } 377 + } 378 + #endif 379 + return rc; 380 + }