1414 lines · 31.7 KB · C
RawDownload
// 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.