// SPDX-License-Identifier: GPL-2.0-only/* * sorttable.c: Sort the kernel's table * * Added ORC unwind tables sort support and other updates: * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by: * Shile Zhang <shile.zhang@linux.alibaba.com> * * Copyright 2011 - 2012 Cavium, Inc. * * Based on code taken from recortmcount.c which is: * * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. * * Restructured to fit Linux format, as well as other updates: * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. */ /* * Strategy: alter the vmlinux file in-place. */ #include <sys/types.h>#include <sys/mman.h>#include <sys/stat.h>#include <getopt.h>#include <elf.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <pthread.h> #include <tools/be_byteshift.h>#include <tools/le_byteshift.h> #ifndef EM_ARCOMPACT#define EM_ARCOMPACT 93#endif #ifndef EM_XTENSA#define EM_XTENSA 94#endif #ifndef EM_AARCH64#define EM_AARCH64 183#endif #ifndef EM_MICROBLAZE#define EM_MICROBLAZE 189#endif #ifndef EM_ARCV2#define EM_ARCV2 195#endif #ifndef EM_RISCV#define EM_RISCV 243#endif #ifndef EM_LOONGARCH#define EM_LOONGARCH 258#endif typedef union { Elf32_Ehdr e32; Elf64_Ehdr e64;} Elf_Ehdr; typedef union { Elf32_Shdr e32; Elf64_Shdr e64;} Elf_Shdr; typedef union { Elf32_Sym e32; Elf64_Sym e64;} Elf_Sym; typedef union { Elf32_Rela e32; Elf64_Rela e64;} Elf_Rela; static uint32_t (*r)(const uint32_t *);static uint16_t (*r2)(const uint16_t *);static uint64_t (*r8)(const uint64_t *);static void (*w)(uint32_t, uint32_t *);static void (*w8)(uint64_t, uint64_t *);typedef void (*table_sort_t)(char *, int); static struct elf_funcs { int (*compare_extable)(const void *a, const void *b); uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr); uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr); uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr); uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr); uint64_t (*shdr_addr)(Elf_Shdr *shdr); uint64_t (*shdr_offset)(Elf_Shdr *shdr); uint64_t (*shdr_size)(Elf_Shdr *shdr); uint64_t (*shdr_entsize)(Elf_Shdr *shdr); uint32_t (*shdr_link)(Elf_Shdr *shdr); uint32_t (*shdr_name)(Elf_Shdr *shdr); uint32_t (*shdr_type)(Elf_Shdr *shdr); uint8_t (*sym_type)(Elf_Sym *sym); uint32_t (*sym_name)(Elf_Sym *sym); uint64_t (*sym_value)(Elf_Sym *sym); uint16_t (*sym_shndx)(Elf_Sym *sym); uint64_t (*rela_offset)(Elf_Rela *rela); uint64_t (*rela_info)(Elf_Rela *rela); uint64_t (*rela_addend)(Elf_Rela *rela); void (*rela_write_addend)(Elf_Rela *rela, uint64_t val);} e; static uint64_t ehdr64_shoff(Elf_Ehdr *ehdr){ return r8(&ehdr->e64.e_shoff);} static uint64_t ehdr32_shoff(Elf_Ehdr *ehdr){ return r(&ehdr->e32.e_shoff);} static uint64_t ehdr_shoff(Elf_Ehdr *ehdr){ return e.ehdr_shoff(ehdr);} #define EHDR_HALF(fn_name) \static uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr) \{ \ return r2(&ehdr->e64.e_##fn_name); \} \ \static uint16_t ehdr32_##fn_name(Elf_Ehdr *ehdr) \{ \ return r2(&ehdr->e32.e_##fn_name); \} \ \static uint16_t ehdr_##fn_name(Elf_Ehdr *ehdr) \{ \ return e.ehdr_##fn_name(ehdr); \} EHDR_HALF(shentsize)EHDR_HALF(shstrndx)EHDR_HALF(shnum) #define SHDR_WORD(fn_name) \static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \{ \ return r(&shdr->e64.sh_##fn_name); \} \ \static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \{ \ return r(&shdr->e32.sh_##fn_name); \} \ \static uint32_t shdr_##fn_name(Elf_Shdr *shdr) \{ \ return e.shdr_##fn_name(shdr); \} #define SHDR_ADDR(fn_name) \static uint64_t shdr64_##fn_name(Elf_Shdr *shdr) \{ \ return r8(&shdr->e64.sh_##fn_name); \} \ \static uint64_t shdr32_##fn_name(Elf_Shdr *shdr) \{ \ return r(&shdr->e32.sh_##fn_name); \} \ \static uint64_t shdr_##fn_name(Elf_Shdr *shdr) \{ \ return e.shdr_##fn_name(shdr); \} #define SHDR_WORD(fn_name) \static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \{ \ return r(&shdr->e64.sh_##fn_name); \} \ \static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \{ \ return r(&shdr->e32.sh_##fn_name); \} \static uint32_t shdr_##fn_name(Elf_Shdr *shdr) \{ \ return e.shdr_##fn_name(shdr); \} SHDR_ADDR(addr)SHDR_ADDR(offset)SHDR_ADDR(size)SHDR_ADDR(entsize) SHDR_WORD(link)SHDR_WORD(name)SHDR_WORD(type) #define SYM_ADDR(fn_name) \static uint64_t sym64_##fn_name(Elf_Sym *sym) \{ \ return r8(&sym->e64.st_##fn_name); \} \ \static uint64_t sym32_##fn_name(Elf_Sym *sym) \{ \ return r(&sym->e32.st_##fn_name); \} \ \static uint64_t sym_##fn_name(Elf_Sym *sym) \{ \ return e.sym_##fn_name(sym); \} #define SYM_WORD(fn_name) \static uint32_t sym64_##fn_name(Elf_Sym *sym) \{ \ return r(&sym->e64.st_##fn_name); \} \ \static uint32_t sym32_##fn_name(Elf_Sym *sym) \{ \ return r(&sym->e32.st_##fn_name); \} \ \static uint32_t sym_##fn_name(Elf_Sym *sym) \{ \ return e.sym_##fn_name(sym); \} #define SYM_HALF(fn_name) \static uint16_t sym64_##fn_name(Elf_Sym *sym) \{ \ return r2(&sym->e64.st_##fn_name); \} \ \static uint16_t sym32_##fn_name(Elf_Sym *sym) \{ \ return r2(&sym->e32.st_##fn_name); \} \ \static uint16_t sym_##fn_name(Elf_Sym *sym) \{ \ return e.sym_##fn_name(sym); \} static uint8_t sym64_type(Elf_Sym *sym){ return ELF64_ST_TYPE(sym->e64.st_info);} static uint8_t sym32_type(Elf_Sym *sym){ return ELF32_ST_TYPE(sym->e32.st_info);} static uint8_t sym_type(Elf_Sym *sym){ return e.sym_type(sym);} SYM_ADDR(value)SYM_WORD(name)SYM_HALF(shndx) #define __maybe_unused __attribute__((__unused__)) #define RELA_ADDR(fn_name) \static uint64_t rela64_##fn_name(Elf_Rela *rela) \{ \ return r8((uint64_t *)&rela->e64.r_##fn_name); \} \ \static uint64_t rela32_##fn_name(Elf_Rela *rela) \{ \ return r((uint32_t *)&rela->e32.r_##fn_name); \} \ \static uint64_t __maybe_unused rela_##fn_name(Elf_Rela *rela) \{ \ return e.rela_##fn_name(rela); \} RELA_ADDR(offset)RELA_ADDR(info)RELA_ADDR(addend) static void rela64_write_addend(Elf_Rela *rela, uint64_t val){ w8(val, (uint64_t *)&rela->e64.r_addend);} static void rela32_write_addend(Elf_Rela *rela, uint64_t val){ w(val, (uint32_t *)&rela->e32.r_addend);} /* * Get the whole file as a programming convenience in order to avoid * malloc+lseek+read+free of many pieces. If successful, then mmap * avoids copying unused pieces; else just read the whole file. * Open for both read and write. */static void *mmap_file(char const *fname, size_t *size){ int fd; struct stat sb; void *addr = NULL; fd = open(fname, O_RDWR); if (fd < 0) { perror(fname); return NULL; } if (fstat(fd, &sb) < 0) { perror(fname); goto out; } if (!S_ISREG(sb.st_mode)) { fprintf(stderr, "not a regular file: %s\n", fname); goto out; } addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { fprintf(stderr, "Could not mmap file: %s\n", fname); goto out; } *size = sb.st_size; out: close(fd); return addr;} static uint32_t rbe(const uint32_t *x){ return get_unaligned_be32(x);} static uint16_t r2be(const uint16_t *x){ return get_unaligned_be16(x);} static uint64_t r8be(const uint64_t *x){ return get_unaligned_be64(x);} static uint32_t rle(const uint32_t *x){ return get_unaligned_le32(x);} static uint16_t r2le(const uint16_t *x){ return get_unaligned_le16(x);} static uint64_t r8le(const uint64_t *x){ return get_unaligned_le64(x);} static void wbe(uint32_t val, uint32_t *x){ put_unaligned_be32(val, x);} static void wle(uint32_t val, uint32_t *x){ put_unaligned_le32(val, x);} static void w8be(uint64_t val, uint64_t *x){ put_unaligned_be64(val, x);} static void w8le(uint64_t val, uint64_t *x){ put_unaligned_le64(val, x);} /* * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of * the way to -256..-1, to avoid conflicting with real section * indices. */#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) static inline int is_shndx_special(unsigned int i){ return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;} /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */static inline unsigned int get_secindex(unsigned int shndx, unsigned int sym_offs, const Elf32_Word *symtab_shndx_start){ if (is_shndx_special(shndx)) return SPECIAL(shndx); if (shndx != SHN_XINDEX) return shndx; return r(&symtab_shndx_start[sym_offs]);} static int compare_extable_32(const void *a, const void *b){ Elf32_Addr av = r(a); Elf32_Addr bv = r(b); if (av < bv) return -1; return av > bv;} static int compare_extable_64(const void *a, const void *b){ Elf64_Addr av = r8(a); Elf64_Addr bv = r8(b); if (av < bv) return -1; return av > bv;} static int compare_extable(const void *a, const void *b){ return e.compare_extable(a, b);} static inline void *get_index(void *start, int entsize, int index){ return start + (entsize * index);} static int extable_ent_size;static int long_size; #define ERRSTR_MAXSZ 256 #ifdef UNWINDER_ORC_ENABLED/* ORC unwinder only support X86_64 */#include <asm/orc_types.h> static char g_err[ERRSTR_MAXSZ];static int *g_orc_ip_table;static struct orc_entry *g_orc_table; static pthread_t orc_sort_thread; static inline unsigned long orc_ip(const int *ip){ return (unsigned long)ip + *ip;} static int orc_sort_cmp(const void *_a, const void *_b){ struct orc_entry *orc_a, *orc_b; const int *a = g_orc_ip_table + *(int *)_a; const int *b = g_orc_ip_table + *(int *)_b; unsigned long a_val = orc_ip(a); unsigned long b_val = orc_ip(b); if (a_val > b_val) return 1; if (a_val < b_val) return -1; /* * The "weak" section terminator entries need to always be on the left * to ensure the lookup code skips them in favor of real entries. * These terminator entries exist to handle any gaps created by * whitelisted .o files which didn't get objtool generation. */ orc_a = g_orc_table + (a - g_orc_ip_table); orc_b = g_orc_table + (b - g_orc_ip_table); if (orc_a->type == ORC_TYPE_UNDEFINED && orc_b->type == ORC_TYPE_UNDEFINED) return 0; return orc_a->type == ORC_TYPE_UNDEFINED ? -1 : 1;} static void *sort_orctable(void *arg){ int i; int *idxs = NULL;Lines 1–500 of 1414. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * sorttable.c: Sort the kernel's table * * Added ORC unwind tables sort support and other updates: * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by: * Shile Zhang <shile.zhang@linux.alibaba.com> * * Copyright 2011 - 2012 Cavium, Inc. * * Based on code taken from recortmcount.c which is: * * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. * * Restructured to fit Linux format, as well as other updates: * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. */ /* * Strategy: alter the vmlinux file in-place. */ #include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <getopt.h> #include <elf.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <pthread.h> #include <tools/be_byteshift.h> #include <tools/le_byteshift.h> #ifndef EM_ARCOMPACT #define EM_ARCOMPACT 93 #endif #ifndef EM_XTENSA #define EM_XTENSA 94 #endif #ifndef EM_AARCH64 #define EM_AARCH64 183 #endif #ifndef EM_MICROBLAZE #define EM_MICROBLAZE 189 #endif #ifndef EM_ARCV2 #define EM_ARCV2 195 #endif #ifndef EM_RISCV #define EM_RISCV 243 #endif #ifndef EM_LOONGARCH #define EM_LOONGARCH 258 #endif typedef union { Elf32_Ehdr e32; Elf64_Ehdr e64; } Elf_Ehdr; typedef union { Elf32_Shdr e32; Elf64_Shdr e64; } Elf_Shdr; typedef union { Elf32_Sym e32; Elf64_Sym e64; } Elf_Sym; typedef union { Elf32_Rela e32; Elf64_Rela e64; } Elf_Rela; static uint32_t (*r)(const uint32_t *); static uint16_t (*r2)(const uint16_t *); static uint64_t (*r8)(const uint64_t *); static void (*w)(uint32_t, uint32_t *); static void (*w8)(uint64_t, uint64_t *); typedef void (*table_sort_t)(char *, int); static struct elf_funcs { int (*compare_extable)(const void *a, const void *b); uint64_t (*ehdr_shoff)(Elf_Ehdr *ehdr); uint16_t (*ehdr_shstrndx)(Elf_Ehdr *ehdr); uint16_t (*ehdr_shentsize)(Elf_Ehdr *ehdr); uint16_t (*ehdr_shnum)(Elf_Ehdr *ehdr); uint64_t (*shdr_addr)(Elf_Shdr *shdr); uint64_t (*shdr_offset)(Elf_Shdr *shdr); uint64_t (*shdr_size)(Elf_Shdr *shdr); uint64_t (*shdr_entsize)(Elf_Shdr *shdr); uint32_t (*shdr_link)(Elf_Shdr *shdr); uint32_t (*shdr_name)(Elf_Shdr *shdr); uint32_t (*shdr_type)(Elf_Shdr *shdr); uint8_t (*sym_type)(Elf_Sym *sym); uint32_t (*sym_name)(Elf_Sym *sym); uint64_t (*sym_value)(Elf_Sym *sym); uint16_t (*sym_shndx)(Elf_Sym *sym); uint64_t (*rela_offset)(Elf_Rela *rela); uint64_t (*rela_info)(Elf_Rela *rela); uint64_t (*rela_addend)(Elf_Rela *rela); void (*rela_write_addend)(Elf_Rela *rela, uint64_t val); } e; static uint64_t ehdr64_shoff(Elf_Ehdr *ehdr) { return r8(&ehdr->e64.e_shoff); } static uint64_t ehdr32_shoff(Elf_Ehdr *ehdr) { return r(&ehdr->e32.e_shoff); } static uint64_t ehdr_shoff(Elf_Ehdr *ehdr) { return e.ehdr_shoff(ehdr); } #define EHDR_HALF(fn_name) \ static uint16_t ehdr64_##fn_name(Elf_Ehdr *ehdr) \ { \ return r2(&ehdr->e64.e_##fn_name); \ } \ \ static uint16_t ehdr32_##fn_name(Elf_Ehdr *ehdr) \ { \ return r2(&ehdr->e32.e_##fn_name); \ } \ \ static uint16_t ehdr_##fn_name(Elf_Ehdr *ehdr) \ { \ return e.ehdr_##fn_name(ehdr); \ } EHDR_HALF(shentsize) EHDR_HALF(shstrndx) EHDR_HALF(shnum) #define SHDR_WORD(fn_name) \ static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \ { \ return r(&shdr->e64.sh_##fn_name); \ } \ \ static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \ { \ return r(&shdr->e32.sh_##fn_name); \ } \ \ static uint32_t shdr_##fn_name(Elf_Shdr *shdr) \ { \ return e.shdr_##fn_name(shdr); \ } #define SHDR_ADDR(fn_name) \ static uint64_t shdr64_##fn_name(Elf_Shdr *shdr) \ { \ return r8(&shdr->e64.sh_##fn_name); \ } \ \ static uint64_t shdr32_##fn_name(Elf_Shdr *shdr) \ { \ return r(&shdr->e32.sh_##fn_name); \ } \ \ static uint64_t shdr_##fn_name(Elf_Shdr *shdr) \ { \ return e.shdr_##fn_name(shdr); \ } #define SHDR_WORD(fn_name) \ static uint32_t shdr64_##fn_name(Elf_Shdr *shdr) \ { \ return r(&shdr->e64.sh_##fn_name); \ } \ \ static uint32_t shdr32_##fn_name(Elf_Shdr *shdr) \ { \ return r(&shdr->e32.sh_##fn_name); \ } \ static uint32_t shdr_##fn_name(Elf_Shdr *shdr) \ { \ return e.shdr_##fn_name(shdr); \ } SHDR_ADDR(addr) SHDR_ADDR(offset) SHDR_ADDR(size) SHDR_ADDR(entsize) SHDR_WORD(link) SHDR_WORD(name) SHDR_WORD(type) #define SYM_ADDR(fn_name) \ static uint64_t sym64_##fn_name(Elf_Sym *sym) \ { \ return r8(&sym->e64.st_##fn_name); \ } \ \ static uint64_t sym32_##fn_name(Elf_Sym *sym) \ { \ return r(&sym->e32.st_##fn_name); \ } \ \ static uint64_t sym_##fn_name(Elf_Sym *sym) \ { \ return e.sym_##fn_name(sym); \ } #define SYM_WORD(fn_name) \ static uint32_t sym64_##fn_name(Elf_Sym *sym) \ { \ return r(&sym->e64.st_##fn_name); \ } \ \ static uint32_t sym32_##fn_name(Elf_Sym *sym) \ { \ return r(&sym->e32.st_##fn_name); \ } \ \ static uint32_t sym_##fn_name(Elf_Sym *sym) \ { \ return e.sym_##fn_name(sym); \ } #define SYM_HALF(fn_name) \ static uint16_t sym64_##fn_name(Elf_Sym *sym) \ { \ return r2(&sym->e64.st_##fn_name); \ } \ \ static uint16_t sym32_##fn_name(Elf_Sym *sym) \ { \ return r2(&sym->e32.st_##fn_name); \ } \ \ static uint16_t sym_##fn_name(Elf_Sym *sym) \ { \ return e.sym_##fn_name(sym); \ } static uint8_t sym64_type(Elf_Sym *sym) { return ELF64_ST_TYPE(sym->e64.st_info); } static uint8_t sym32_type(Elf_Sym *sym) { return ELF32_ST_TYPE(sym->e32.st_info); } static uint8_t sym_type(Elf_Sym *sym) { return e.sym_type(sym); } SYM_ADDR(value) SYM_WORD(name) SYM_HALF(shndx) #define __maybe_unused __attribute__((__unused__)) #define RELA_ADDR(fn_name) \ static uint64_t rela64_##fn_name(Elf_Rela *rela) \ { \ return r8((uint64_t *)&rela->e64.r_##fn_name); \ } \ \ static uint64_t rela32_##fn_name(Elf_Rela *rela) \ { \ return r((uint32_t *)&rela->e32.r_##fn_name); \ } \ \ static uint64_t __maybe_unused rela_##fn_name(Elf_Rela *rela) \ { \ return e.rela_##fn_name(rela); \ } RELA_ADDR(offset) RELA_ADDR(info) RELA_ADDR(addend) static void rela64_write_addend(Elf_Rela *rela, uint64_t val) { w8(val, (uint64_t *)&rela->e64.r_addend); } static void rela32_write_addend(Elf_Rela *rela, uint64_t val) { w(val, (uint32_t *)&rela->e32.r_addend); } /* * Get the whole file as a programming convenience in order to avoid * malloc+lseek+read+free of many pieces. If successful, then mmap * avoids copying unused pieces; else just read the whole file. * Open for both read and write. */ static void *mmap_file(char const *fname, size_t *size) { int fd; struct stat sb; void *addr = NULL; fd = open(fname, O_RDWR); if (fd < 0) { perror(fname); return NULL; } if (fstat(fd, &sb) < 0) { perror(fname); goto out; } if (!S_ISREG(sb.st_mode)) { fprintf(stderr, "not a regular file: %s\n", fname); goto out; } addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { fprintf(stderr, "Could not mmap file: %s\n", fname); goto out; } *size = sb.st_size; out: close(fd); return addr; } static uint32_t rbe(const uint32_t *x) { return get_unaligned_be32(x); } static uint16_t r2be(const uint16_t *x) { return get_unaligned_be16(x); } static uint64_t r8be(const uint64_t *x) { return get_unaligned_be64(x); } static uint32_t rle(const uint32_t *x) { return get_unaligned_le32(x); } static uint16_t r2le(const uint16_t *x) { return get_unaligned_le16(x); } static uint64_t r8le(const uint64_t *x) { return get_unaligned_le64(x); } static void wbe(uint32_t val, uint32_t *x) { put_unaligned_be32(val, x); } static void wle(uint32_t val, uint32_t *x) { put_unaligned_le32(val, x); } static void w8be(uint64_t val, uint64_t *x) { put_unaligned_be64(val, x); } static void w8le(uint64_t val, uint64_t *x) { put_unaligned_le64(val, x); } /* * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of * the way to -256..-1, to avoid conflicting with real section * indices. */ #define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) static inline int is_shndx_special(unsigned int i) { return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; } /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ static inline unsigned int get_secindex(unsigned int shndx, unsigned int sym_offs, const Elf32_Word *symtab_shndx_start) { if (is_shndx_special(shndx)) return SPECIAL(shndx); if (shndx != SHN_XINDEX) return shndx; return r(&symtab_shndx_start[sym_offs]); } static int compare_extable_32(const void *a, const void *b) { Elf32_Addr av = r(a); Elf32_Addr bv = r(b); if (av < bv) return -1; return av > bv; } static int compare_extable_64(const void *a, const void *b) { Elf64_Addr av = r8(a); Elf64_Addr bv = r8(b); if (av < bv) return -1; return av > bv; } static int compare_extable(const void *a, const void *b) { return e.compare_extable(a, b); } static inline void *get_index(void *start, int entsize, int index) { return start + (entsize * index); } static int extable_ent_size; static int long_size; #define ERRSTR_MAXSZ 256 #ifdef UNWINDER_ORC_ENABLED /* ORC unwinder only support X86_64 */ #include <asm/orc_types.h> static char g_err[ERRSTR_MAXSZ]; static int *g_orc_ip_table; static struct orc_entry *g_orc_table; static pthread_t orc_sort_thread; static inline unsigned long orc_ip(const int *ip) { return (unsigned long)ip + *ip; } static int orc_sort_cmp(const void *_a, const void *_b) { struct orc_entry *orc_a, *orc_b; const int *a = g_orc_ip_table + *(int *)_a; const int *b = g_orc_ip_table + *(int *)_b; unsigned long a_val = orc_ip(a); unsigned long b_val = orc_ip(b); if (a_val > b_val) return 1; if (a_val < b_val) return -1; /* * The "weak" section terminator entries need to always be on the left * to ensure the lookup code skips them in favor of real entries. * These terminator entries exist to handle any gaps created by * whitelisted .o files which didn't get objtool generation. */ orc_a = g_orc_table + (a - g_orc_ip_table); orc_b = g_orc_table + (b - g_orc_ip_table); if (orc_a->type == ORC_TYPE_UNDEFINED && orc_b->type == ORC_TYPE_UNDEFINED) return 0; return orc_a->type == ORC_TYPE_UNDEFINED ? -1 : 1; } static void *sort_orctable(void *arg) { int i; int *idxs = NULL;