mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-22 07:53:11 -05:00
Updates to scipts/sorttable for 6.14:
The sorttable.c was a copy from recordmcount.c which is very hard to maintain. That's because it uses macro helpers and places the code in a header file sorttable.h to handle both the 64 bit and 32 bit version of the Elf structures. It also uses _r()/r()/r2() wrappers around accessing the data which will read the 64 bit or 32 bit version of the data as well as handle endianess. If the wrong wrapper is used, an invalid value will result, and this has been a cause for bugs in the past. In fact the new ORC code doesn't even use it. That's fine because ORC is only for 64 bit x86 which is the default parsing. Instead of having a bunch of macros defined and then include the code twice from a header, the Elf structures are each wrapped in a union. The union holds the 64 bit and 32 bit version of the needed structure. Then a structure of function pointers is used, along with helper macros to access the ELF types appropriately for their byte size and endianess. How to reference the data fields is moved from the code that implements the sorting to the helper functions where all accesses to a field will use he same helper function. As long as the helper functions access the fields correctly, the code will also access the fields. This is an improvement over having to code implementing the sorting having to make sure it always uses the right accessor function when reading an ELF field. This is a clean up only, the functionality of the scripts/sorttable.c does not change. -----BEGIN PGP SIGNATURE----- iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCZ5AO2RQccm9zdGVkdEBn b29kbWlzLm9yZwAKCRAp5XQQmuv6qj6pAQDAHA3mtawVYgq/Kw8OAc6r2NLP5Q58 8nptwPVoATomLgEA2HO38cu1N8Fxg+zMgQ4L9eYfa0QdE3XKD0WNbG4x7wE= =go8s -----END PGP SIGNATURE----- Merge tag 'trace-sorttable-v6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull scipts/sorttable updates from Steven Rostedt: "The sorttable.c was a copy from recordmcount.c which is very hard to maintain. That's because it uses macro helpers and places the code in a header file sorttable.h to handle both the 64 bit and 32 bit version of the Elf structures. It also uses _r()/r()/r2() wrappers around accessing the data which will read the 64 bit or 32 bit version of the data as well as handle endianess. If the wrong wrapper is used, an invalid value will result, and this has been a cause for bugs in the past. In fact the new ORC code doesn't even use it. That's fine because ORC is only for 64 bit x86 which is the default parsing. Instead of having a bunch of macros defined and then include the code twice from a header, the Elf structures are each wrapped in a union. The union holds the 64 bit and 32 bit version of the needed structure. Then a structure of function pointers is used, along with helper macros to access the ELF types appropriately for their byte size and endianess. How to reference the data fields is moved from the code that implements the sorting to the helper functions where all accesses to a field will use he same helper function. As long as the helper functions access the fields correctly, the code will also access the fields. This is an improvement over having to code implementing the sorting having to make sure it always uses the right accessor function when reading an ELF field. This is a clean up only, the functionality of the scripts/sorttable.c does not change" * tag 'trace-sorttable-v6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: scripts/sorttable: Use a structure of function pointers for elf helpers scripts/sorttable: Get start/stop_mcount_loc from ELF file directly scripts/sorttable: Move code from sorttable.h into sorttable.c scripts/sorttable: Use uint64_t for mcount sorting scripts/sorttable: Add helper functions for Elf_Sym scripts/sorttable: Add helper functions for Elf_Shdr scripts/sorttable: Add helper functions for Elf_Ehdr scripts/sorttable: Convert Elf_Sym MACRO over to a union scripts/sorttable: Replace Elf_Shdr Macro with a union scripts/sorttable: Convert Elf_Ehdr to union scripts/sorttable: Make compare_extable() into two functions scripts/sorttable: Have the ORC code use the _r() functions to read scripts/sorttable: Remove unneeded Elf_Rel scripts/sorttable: Remove unused write functions scripts/sorttable: Remove unused macro defines
This commit is contained in:
commit
c0e75905ca
2 changed files with 685 additions and 555 deletions
|
@ -64,14 +64,204 @@
|
|||
#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;
|
||||
|
||||
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 (*w2)(uint16_t, uint16_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);
|
||||
} 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)
|
||||
|
||||
/*
|
||||
* Get the whole file as a programming convenience in order to avoid
|
||||
* malloc+lseek+read+free of many pieces. If successful, then mmap
|
||||
|
@ -146,31 +336,11 @@ static void wbe(uint32_t val, uint32_t *x)
|
|||
put_unaligned_be32(val, x);
|
||||
}
|
||||
|
||||
static void w2be(uint16_t val, uint16_t *x)
|
||||
{
|
||||
put_unaligned_be16(val, x);
|
||||
}
|
||||
|
||||
static void w8be(uint64_t val, uint64_t *x)
|
||||
{
|
||||
put_unaligned_be64(val, x);
|
||||
}
|
||||
|
||||
static void wle(uint32_t val, uint32_t *x)
|
||||
{
|
||||
put_unaligned_le32(val, x);
|
||||
}
|
||||
|
||||
static void w2le(uint16_t val, uint16_t *x)
|
||||
{
|
||||
put_unaligned_le16(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
|
||||
|
@ -195,10 +365,430 @@ static inline unsigned int get_secindex(unsigned int shndx,
|
|||
return r(&symtab_shndx_start[sym_offs]);
|
||||
}
|
||||
|
||||
/* 32 bit and 64 bit are very similar */
|
||||
#include "sorttable.h"
|
||||
#define SORTTABLE_64
|
||||
#include "sorttable.h"
|
||||
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;
|
||||
|
||||
|
||||
#ifdef UNWINDER_ORC_ENABLED
|
||||
/* ORC unwinder only support X86_64 */
|
||||
#include <asm/orc_types.h>
|
||||
|
||||
#define ERRSTR_MAXSZ 256
|
||||
|
||||
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;
|
||||
int *tmp_orc_ip_table = NULL;
|
||||
struct orc_entry *tmp_orc_table = NULL;
|
||||
unsigned int *orc_ip_size = (unsigned int *)arg;
|
||||
unsigned int num_entries = *orc_ip_size / sizeof(int);
|
||||
unsigned int orc_size = num_entries * sizeof(struct orc_entry);
|
||||
|
||||
idxs = (int *)malloc(*orc_ip_size);
|
||||
if (!idxs) {
|
||||
snprintf(g_err, ERRSTR_MAXSZ, "malloc idxs: %s",
|
||||
strerror(errno));
|
||||
pthread_exit(g_err);
|
||||
}
|
||||
|
||||
tmp_orc_ip_table = (int *)malloc(*orc_ip_size);
|
||||
if (!tmp_orc_ip_table) {
|
||||
snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_ip_table: %s",
|
||||
strerror(errno));
|
||||
pthread_exit(g_err);
|
||||
}
|
||||
|
||||
tmp_orc_table = (struct orc_entry *)malloc(orc_size);
|
||||
if (!tmp_orc_table) {
|
||||
snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_table: %s",
|
||||
strerror(errno));
|
||||
pthread_exit(g_err);
|
||||
}
|
||||
|
||||
/* initialize indices array, convert ip_table to absolute address */
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
idxs[i] = i;
|
||||
tmp_orc_ip_table[i] = g_orc_ip_table[i] + i * sizeof(int);
|
||||
}
|
||||
memcpy(tmp_orc_table, g_orc_table, orc_size);
|
||||
|
||||
qsort(idxs, num_entries, sizeof(int), orc_sort_cmp);
|
||||
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
if (idxs[i] == i)
|
||||
continue;
|
||||
|
||||
/* convert back to relative address */
|
||||
g_orc_ip_table[i] = tmp_orc_ip_table[idxs[i]] - i * sizeof(int);
|
||||
g_orc_table[i] = tmp_orc_table[idxs[i]];
|
||||
}
|
||||
|
||||
free(idxs);
|
||||
free(tmp_orc_ip_table);
|
||||
free(tmp_orc_table);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MCOUNT_SORT_ENABLED
|
||||
static pthread_t mcount_sort_thread;
|
||||
|
||||
struct elf_mcount_loc {
|
||||
Elf_Ehdr *ehdr;
|
||||
Elf_Shdr *init_data_sec;
|
||||
uint64_t start_mcount_loc;
|
||||
uint64_t stop_mcount_loc;
|
||||
};
|
||||
|
||||
/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
|
||||
static void *sort_mcount_loc(void *arg)
|
||||
{
|
||||
struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;
|
||||
uint64_t offset = emloc->start_mcount_loc - shdr_addr(emloc->init_data_sec)
|
||||
+ shdr_offset(emloc->init_data_sec);
|
||||
uint64_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
|
||||
unsigned char *start_loc = (void *)emloc->ehdr + offset;
|
||||
|
||||
qsort(start_loc, count/long_size, long_size, compare_extable);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
|
||||
static void get_mcount_loc(struct elf_mcount_loc *emloc, Elf_Shdr *symtab_sec,
|
||||
const char *strtab)
|
||||
{
|
||||
Elf_Sym *sym, *end_sym;
|
||||
int symentsize = shdr_entsize(symtab_sec);
|
||||
int found = 0;
|
||||
|
||||
sym = (void *)emloc->ehdr + shdr_offset(symtab_sec);
|
||||
end_sym = (void *)sym + shdr_size(symtab_sec);
|
||||
|
||||
while (sym < end_sym) {
|
||||
if (!strcmp(strtab + sym_name(sym), "__start_mcount_loc")) {
|
||||
emloc->start_mcount_loc = sym_value(sym);
|
||||
if (++found == 2)
|
||||
break;
|
||||
} else if (!strcmp(strtab + sym_name(sym), "__stop_mcount_loc")) {
|
||||
emloc->stop_mcount_loc = sym_value(sym);
|
||||
if (++found == 2)
|
||||
break;
|
||||
}
|
||||
sym = (void *)sym + symentsize;
|
||||
}
|
||||
|
||||
if (!emloc->start_mcount_loc) {
|
||||
fprintf(stderr, "get start_mcount_loc error!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!emloc->stop_mcount_loc) {
|
||||
fprintf(stderr, "get stop_mcount_loc error!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int do_sort(Elf_Ehdr *ehdr,
|
||||
char const *const fname,
|
||||
table_sort_t custom_sort)
|
||||
{
|
||||
int rc = -1;
|
||||
Elf_Shdr *shdr_start;
|
||||
Elf_Shdr *strtab_sec = NULL;
|
||||
Elf_Shdr *symtab_sec = NULL;
|
||||
Elf_Shdr *extab_sec = NULL;
|
||||
Elf_Shdr *string_sec;
|
||||
Elf_Sym *sym;
|
||||
const Elf_Sym *symtab;
|
||||
Elf32_Word *symtab_shndx = NULL;
|
||||
Elf_Sym *sort_needed_sym = NULL;
|
||||
Elf_Shdr *sort_needed_sec;
|
||||
uint32_t *sort_needed_loc;
|
||||
void *sym_start;
|
||||
void *sym_end;
|
||||
const char *secstrings;
|
||||
const char *strtab;
|
||||
char *extab_image;
|
||||
int sort_need_index;
|
||||
int symentsize;
|
||||
int shentsize;
|
||||
int idx;
|
||||
int i;
|
||||
unsigned int shnum;
|
||||
unsigned int shstrndx;
|
||||
#ifdef MCOUNT_SORT_ENABLED
|
||||
struct elf_mcount_loc mstruct = {0};
|
||||
#endif
|
||||
#ifdef UNWINDER_ORC_ENABLED
|
||||
unsigned int orc_ip_size = 0;
|
||||
unsigned int orc_size = 0;
|
||||
unsigned int orc_num_entries = 0;
|
||||
#endif
|
||||
|
||||
shdr_start = (Elf_Shdr *)((char *)ehdr + ehdr_shoff(ehdr));
|
||||
shentsize = ehdr_shentsize(ehdr);
|
||||
|
||||
shstrndx = ehdr_shstrndx(ehdr);
|
||||
if (shstrndx == SHN_XINDEX)
|
||||
shstrndx = shdr_link(shdr_start);
|
||||
string_sec = get_index(shdr_start, shentsize, shstrndx);
|
||||
secstrings = (const char *)ehdr + shdr_offset(string_sec);
|
||||
|
||||
shnum = ehdr_shnum(ehdr);
|
||||
if (shnum == SHN_UNDEF)
|
||||
shnum = shdr_size(shdr_start);
|
||||
|
||||
for (i = 0; i < shnum; i++) {
|
||||
Elf_Shdr *shdr = get_index(shdr_start, shentsize, i);
|
||||
|
||||
idx = shdr_name(shdr);
|
||||
if (!strcmp(secstrings + idx, "__ex_table"))
|
||||
extab_sec = shdr;
|
||||
if (!strcmp(secstrings + idx, ".symtab"))
|
||||
symtab_sec = shdr;
|
||||
if (!strcmp(secstrings + idx, ".strtab"))
|
||||
strtab_sec = shdr;
|
||||
|
||||
if (shdr_type(shdr) == SHT_SYMTAB_SHNDX)
|
||||
symtab_shndx = (Elf32_Word *)((const char *)ehdr +
|
||||
shdr_offset(shdr));
|
||||
|
||||
#ifdef MCOUNT_SORT_ENABLED
|
||||
/* locate the .init.data section in vmlinux */
|
||||
if (!strcmp(secstrings + idx, ".init.data"))
|
||||
mstruct.init_data_sec = shdr;
|
||||
#endif
|
||||
|
||||
#ifdef UNWINDER_ORC_ENABLED
|
||||
/* locate the ORC unwind tables */
|
||||
if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
|
||||
orc_ip_size = shdr_size(shdr);
|
||||
g_orc_ip_table = (int *)((void *)ehdr +
|
||||
shdr_offset(shdr));
|
||||
}
|
||||
if (!strcmp(secstrings + idx, ".orc_unwind")) {
|
||||
orc_size = shdr_size(shdr);
|
||||
g_orc_table = (struct orc_entry *)((void *)ehdr +
|
||||
shdr_offset(shdr));
|
||||
}
|
||||
#endif
|
||||
} /* for loop */
|
||||
|
||||
#ifdef UNWINDER_ORC_ENABLED
|
||||
if (!g_orc_ip_table || !g_orc_table) {
|
||||
fprintf(stderr,
|
||||
"incomplete ORC unwind tables in file: %s\n", fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
orc_num_entries = orc_ip_size / sizeof(int);
|
||||
if (orc_ip_size % sizeof(int) != 0 ||
|
||||
orc_size % sizeof(struct orc_entry) != 0 ||
|
||||
orc_num_entries != orc_size / sizeof(struct orc_entry)) {
|
||||
fprintf(stderr,
|
||||
"inconsistent ORC unwind table entries in file: %s\n",
|
||||
fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* create thread to sort ORC unwind tables concurrently */
|
||||
if (pthread_create(&orc_sort_thread, NULL,
|
||||
sort_orctable, &orc_ip_size)) {
|
||||
fprintf(stderr,
|
||||
"pthread_create orc_sort_thread failed '%s': %s\n",
|
||||
strerror(errno), fname);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
if (!extab_sec) {
|
||||
fprintf(stderr, "no __ex_table in file: %s\n", fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!symtab_sec) {
|
||||
fprintf(stderr, "no .symtab in file: %s\n", fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strtab_sec) {
|
||||
fprintf(stderr, "no .strtab in file: %s\n", fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
extab_image = (void *)ehdr + shdr_offset(extab_sec);
|
||||
strtab = (const char *)ehdr + shdr_offset(strtab_sec);
|
||||
symtab = (const Elf_Sym *)((const char *)ehdr + shdr_offset(symtab_sec));
|
||||
|
||||
#ifdef MCOUNT_SORT_ENABLED
|
||||
mstruct.ehdr = ehdr;
|
||||
get_mcount_loc(&mstruct, symtab_sec, strtab);
|
||||
|
||||
if (!mstruct.init_data_sec || !mstruct.start_mcount_loc || !mstruct.stop_mcount_loc) {
|
||||
fprintf(stderr,
|
||||
"incomplete mcount's sort in file: %s\n",
|
||||
fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* create thread to sort mcount_loc concurrently */
|
||||
if (pthread_create(&mcount_sort_thread, NULL, &sort_mcount_loc, &mstruct)) {
|
||||
fprintf(stderr,
|
||||
"pthread_create mcount_sort_thread failed '%s': %s\n",
|
||||
strerror(errno), fname);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (custom_sort) {
|
||||
custom_sort(extab_image, shdr_size(extab_sec));
|
||||
} else {
|
||||
int num_entries = shdr_size(extab_sec) / extable_ent_size;
|
||||
qsort(extab_image, num_entries,
|
||||
extable_ent_size, compare_extable);
|
||||
}
|
||||
|
||||
/* find the flag main_extable_sort_needed */
|
||||
sym_start = (void *)ehdr + shdr_offset(symtab_sec);
|
||||
sym_end = sym_start + shdr_size(symtab_sec);
|
||||
symentsize = shdr_entsize(symtab_sec);
|
||||
|
||||
for (sym = sym_start; (void *)sym + symentsize < sym_end;
|
||||
sym = (void *)sym + symentsize) {
|
||||
if (sym_type(sym) != STT_OBJECT)
|
||||
continue;
|
||||
if (!strcmp(strtab + sym_name(sym),
|
||||
"main_extable_sort_needed")) {
|
||||
sort_needed_sym = sym;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sort_needed_sym) {
|
||||
fprintf(stderr,
|
||||
"no main_extable_sort_needed symbol in file: %s\n",
|
||||
fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sort_need_index = get_secindex(sym_shndx(sym),
|
||||
((void *)sort_needed_sym - (void *)symtab) / symentsize,
|
||||
symtab_shndx);
|
||||
sort_needed_sec = get_index(shdr_start, shentsize, sort_need_index);
|
||||
sort_needed_loc = (void *)ehdr +
|
||||
shdr_offset(sort_needed_sec) +
|
||||
sym_value(sort_needed_sym) - shdr_addr(sort_needed_sec);
|
||||
|
||||
/* extable has been sorted, clear the flag */
|
||||
w(0, sort_needed_loc);
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
#ifdef UNWINDER_ORC_ENABLED
|
||||
if (orc_sort_thread) {
|
||||
void *retval = NULL;
|
||||
/* wait for ORC tables sort done */
|
||||
rc = pthread_join(orc_sort_thread, &retval);
|
||||
if (rc) {
|
||||
fprintf(stderr,
|
||||
"pthread_join failed '%s': %s\n",
|
||||
strerror(errno), fname);
|
||||
} else if (retval) {
|
||||
rc = -1;
|
||||
fprintf(stderr,
|
||||
"failed to sort ORC tables '%s': %s\n",
|
||||
(char *)retval, fname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MCOUNT_SORT_ENABLED
|
||||
if (mcount_sort_thread) {
|
||||
void *retval = NULL;
|
||||
/* wait for mcount sort done */
|
||||
rc = pthread_join(mcount_sort_thread, &retval);
|
||||
if (rc) {
|
||||
fprintf(stderr,
|
||||
"pthread_join failed '%s': %s\n",
|
||||
strerror(errno), fname);
|
||||
} else if (retval) {
|
||||
rc = -1;
|
||||
fprintf(stderr,
|
||||
"failed to sort mcount '%s': %s\n",
|
||||
(char *)retval, fname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int compare_relative_table(const void *a, const void *b)
|
||||
{
|
||||
|
@ -267,41 +857,36 @@ static void sort_relative_table_with_data(char *extab_image, int image_size)
|
|||
|
||||
static int do_file(char const *const fname, void *addr)
|
||||
{
|
||||
int rc = -1;
|
||||
Elf32_Ehdr *ehdr = addr;
|
||||
Elf_Ehdr *ehdr = addr;
|
||||
table_sort_t custom_sort = NULL;
|
||||
|
||||
switch (ehdr->e_ident[EI_DATA]) {
|
||||
switch (ehdr->e32.e_ident[EI_DATA]) {
|
||||
case ELFDATA2LSB:
|
||||
r = rle;
|
||||
r2 = r2le;
|
||||
r8 = r8le;
|
||||
w = wle;
|
||||
w2 = w2le;
|
||||
w8 = w8le;
|
||||
break;
|
||||
case ELFDATA2MSB:
|
||||
r = rbe;
|
||||
r2 = r2be;
|
||||
r8 = r8be;
|
||||
w = wbe;
|
||||
w2 = w2be;
|
||||
w8 = w8be;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
|
||||
ehdr->e_ident[EI_DATA], fname);
|
||||
ehdr->e32.e_ident[EI_DATA], fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 ||
|
||||
(r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN) ||
|
||||
ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
|
||||
if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
|
||||
(r2(&ehdr->e32.e_type) != ET_EXEC && r2(&ehdr->e32.e_type) != ET_DYN) ||
|
||||
ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
|
||||
fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (r2(&ehdr->e_machine)) {
|
||||
switch (r2(&ehdr->e32.e_machine)) {
|
||||
case EM_386:
|
||||
case EM_AARCH64:
|
||||
case EM_LOONGARCH:
|
||||
|
@ -324,40 +909,85 @@ static int do_file(char const *const fname, void *addr)
|
|||
break;
|
||||
default:
|
||||
fprintf(stderr, "unrecognized e_machine %d %s\n",
|
||||
r2(&ehdr->e_machine), fname);
|
||||
r2(&ehdr->e32.e_machine), fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (ehdr->e_ident[EI_CLASS]) {
|
||||
case ELFCLASS32:
|
||||
if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) ||
|
||||
r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
|
||||
switch (ehdr->e32.e_ident[EI_CLASS]) {
|
||||
case ELFCLASS32: {
|
||||
struct elf_funcs efuncs = {
|
||||
.compare_extable = compare_extable_32,
|
||||
.ehdr_shoff = ehdr32_shoff,
|
||||
.ehdr_shentsize = ehdr32_shentsize,
|
||||
.ehdr_shstrndx = ehdr32_shstrndx,
|
||||
.ehdr_shnum = ehdr32_shnum,
|
||||
.shdr_addr = shdr32_addr,
|
||||
.shdr_offset = shdr32_offset,
|
||||
.shdr_link = shdr32_link,
|
||||
.shdr_size = shdr32_size,
|
||||
.shdr_name = shdr32_name,
|
||||
.shdr_type = shdr32_type,
|
||||
.shdr_entsize = shdr32_entsize,
|
||||
.sym_type = sym32_type,
|
||||
.sym_name = sym32_name,
|
||||
.sym_value = sym32_value,
|
||||
.sym_shndx = sym32_shndx,
|
||||
};
|
||||
|
||||
e = efuncs;
|
||||
long_size = 4;
|
||||
extable_ent_size = 8;
|
||||
|
||||
if (r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) ||
|
||||
r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) {
|
||||
fprintf(stderr,
|
||||
"unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
|
||||
break;
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
rc = do_sort_32(ehdr, fname, custom_sort);
|
||||
break;
|
||||
case ELFCLASS64:
|
||||
{
|
||||
Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
|
||||
if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) ||
|
||||
r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
|
||||
case ELFCLASS64: {
|
||||
struct elf_funcs efuncs = {
|
||||
.compare_extable = compare_extable_64,
|
||||
.ehdr_shoff = ehdr64_shoff,
|
||||
.ehdr_shentsize = ehdr64_shentsize,
|
||||
.ehdr_shstrndx = ehdr64_shstrndx,
|
||||
.ehdr_shnum = ehdr64_shnum,
|
||||
.shdr_addr = shdr64_addr,
|
||||
.shdr_offset = shdr64_offset,
|
||||
.shdr_link = shdr64_link,
|
||||
.shdr_size = shdr64_size,
|
||||
.shdr_name = shdr64_name,
|
||||
.shdr_type = shdr64_type,
|
||||
.shdr_entsize = shdr64_entsize,
|
||||
.sym_type = sym64_type,
|
||||
.sym_name = sym64_name,
|
||||
.sym_value = sym64_value,
|
||||
.sym_shndx = sym64_shndx,
|
||||
};
|
||||
|
||||
e = efuncs;
|
||||
long_size = 8;
|
||||
extable_ent_size = 16;
|
||||
|
||||
if (r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) ||
|
||||
r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) {
|
||||
fprintf(stderr,
|
||||
"unrecognized ET_EXEC/ET_DYN file: %s\n",
|
||||
fname);
|
||||
break;
|
||||
return -1;
|
||||
}
|
||||
rc = do_sort_64(ghdr, fname, custom_sort);
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unrecognized ELF class %d %s\n",
|
||||
ehdr->e_ident[EI_CLASS], fname);
|
||||
break;
|
||||
ehdr->e32.e_ident[EI_CLASS], fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return do_sort(ehdr, fname, custom_sort);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
|
|
@ -1,500 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* sorttable.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Some of code was taken out of arch/x86/kernel/unwind_orc.c, written by:
|
||||
* Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
|
||||
*
|
||||
* Some of this code was taken out of recordmcount.h written by:
|
||||
*
|
||||
* Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
|
||||
* Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
|
||||
*/
|
||||
|
||||
#undef extable_ent_size
|
||||
#undef compare_extable
|
||||
#undef get_mcount_loc
|
||||
#undef sort_mcount_loc
|
||||
#undef elf_mcount_loc
|
||||
#undef do_sort
|
||||
#undef Elf_Addr
|
||||
#undef Elf_Ehdr
|
||||
#undef Elf_Shdr
|
||||
#undef Elf_Rel
|
||||
#undef Elf_Rela
|
||||
#undef Elf_Sym
|
||||
#undef ELF_R_SYM
|
||||
#undef Elf_r_sym
|
||||
#undef ELF_R_INFO
|
||||
#undef Elf_r_info
|
||||
#undef ELF_ST_BIND
|
||||
#undef ELF_ST_TYPE
|
||||
#undef fn_ELF_R_SYM
|
||||
#undef fn_ELF_R_INFO
|
||||
#undef uint_t
|
||||
#undef _r
|
||||
#undef _w
|
||||
|
||||
#ifdef SORTTABLE_64
|
||||
# define extable_ent_size 16
|
||||
# define compare_extable compare_extable_64
|
||||
# define get_mcount_loc get_mcount_loc_64
|
||||
# define sort_mcount_loc sort_mcount_loc_64
|
||||
# define elf_mcount_loc elf_mcount_loc_64
|
||||
# define do_sort do_sort_64
|
||||
# define Elf_Addr Elf64_Addr
|
||||
# define Elf_Ehdr Elf64_Ehdr
|
||||
# define Elf_Shdr Elf64_Shdr
|
||||
# define Elf_Rel Elf64_Rel
|
||||
# define Elf_Rela Elf64_Rela
|
||||
# define Elf_Sym Elf64_Sym
|
||||
# define ELF_R_SYM ELF64_R_SYM
|
||||
# define Elf_r_sym Elf64_r_sym
|
||||
# define ELF_R_INFO ELF64_R_INFO
|
||||
# define Elf_r_info Elf64_r_info
|
||||
# define ELF_ST_BIND ELF64_ST_BIND
|
||||
# define ELF_ST_TYPE ELF64_ST_TYPE
|
||||
# define fn_ELF_R_SYM fn_ELF64_R_SYM
|
||||
# define fn_ELF_R_INFO fn_ELF64_R_INFO
|
||||
# define uint_t uint64_t
|
||||
# define _r r8
|
||||
# define _w w8
|
||||
#else
|
||||
# define extable_ent_size 8
|
||||
# define compare_extable compare_extable_32
|
||||
# define get_mcount_loc get_mcount_loc_32
|
||||
# define sort_mcount_loc sort_mcount_loc_32
|
||||
# define elf_mcount_loc elf_mcount_loc_32
|
||||
# define do_sort do_sort_32
|
||||
# define Elf_Addr Elf32_Addr
|
||||
# define Elf_Ehdr Elf32_Ehdr
|
||||
# define Elf_Shdr Elf32_Shdr
|
||||
# define Elf_Rel Elf32_Rel
|
||||
# define Elf_Rela Elf32_Rela
|
||||
# define Elf_Sym Elf32_Sym
|
||||
# define ELF_R_SYM ELF32_R_SYM
|
||||
# define Elf_r_sym Elf32_r_sym
|
||||
# define ELF_R_INFO ELF32_R_INFO
|
||||
# define Elf_r_info Elf32_r_info
|
||||
# define ELF_ST_BIND ELF32_ST_BIND
|
||||
# define ELF_ST_TYPE ELF32_ST_TYPE
|
||||
# define fn_ELF_R_SYM fn_ELF32_R_SYM
|
||||
# define fn_ELF_R_INFO fn_ELF32_R_INFO
|
||||
# define uint_t uint32_t
|
||||
# define _r r
|
||||
# define _w w
|
||||
#endif
|
||||
|
||||
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
|
||||
/* ORC unwinder only support X86_64 */
|
||||
#include <asm/orc_types.h>
|
||||
|
||||
#define ERRSTR_MAXSZ 256
|
||||
|
||||
char g_err[ERRSTR_MAXSZ];
|
||||
int *g_orc_ip_table;
|
||||
struct orc_entry *g_orc_table;
|
||||
|
||||
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;
|
||||
int *tmp_orc_ip_table = NULL;
|
||||
struct orc_entry *tmp_orc_table = NULL;
|
||||
unsigned int *orc_ip_size = (unsigned int *)arg;
|
||||
unsigned int num_entries = *orc_ip_size / sizeof(int);
|
||||
unsigned int orc_size = num_entries * sizeof(struct orc_entry);
|
||||
|
||||
idxs = (int *)malloc(*orc_ip_size);
|
||||
if (!idxs) {
|
||||
snprintf(g_err, ERRSTR_MAXSZ, "malloc idxs: %s",
|
||||
strerror(errno));
|
||||
pthread_exit(g_err);
|
||||
}
|
||||
|
||||
tmp_orc_ip_table = (int *)malloc(*orc_ip_size);
|
||||
if (!tmp_orc_ip_table) {
|
||||
snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_ip_table: %s",
|
||||
strerror(errno));
|
||||
pthread_exit(g_err);
|
||||
}
|
||||
|
||||
tmp_orc_table = (struct orc_entry *)malloc(orc_size);
|
||||
if (!tmp_orc_table) {
|
||||
snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_table: %s",
|
||||
strerror(errno));
|
||||
pthread_exit(g_err);
|
||||
}
|
||||
|
||||
/* initialize indices array, convert ip_table to absolute address */
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
idxs[i] = i;
|
||||
tmp_orc_ip_table[i] = g_orc_ip_table[i] + i * sizeof(int);
|
||||
}
|
||||
memcpy(tmp_orc_table, g_orc_table, orc_size);
|
||||
|
||||
qsort(idxs, num_entries, sizeof(int), orc_sort_cmp);
|
||||
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
if (idxs[i] == i)
|
||||
continue;
|
||||
|
||||
/* convert back to relative address */
|
||||
g_orc_ip_table[i] = tmp_orc_ip_table[idxs[i]] - i * sizeof(int);
|
||||
g_orc_table[i] = tmp_orc_table[idxs[i]];
|
||||
}
|
||||
|
||||
free(idxs);
|
||||
free(tmp_orc_ip_table);
|
||||
free(tmp_orc_table);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int compare_extable(const void *a, const void *b)
|
||||
{
|
||||
Elf_Addr av = _r(a);
|
||||
Elf_Addr bv = _r(b);
|
||||
|
||||
if (av < bv)
|
||||
return -1;
|
||||
if (av > bv)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#ifdef MCOUNT_SORT_ENABLED
|
||||
pthread_t mcount_sort_thread;
|
||||
|
||||
struct elf_mcount_loc {
|
||||
Elf_Ehdr *ehdr;
|
||||
Elf_Shdr *init_data_sec;
|
||||
uint_t start_mcount_loc;
|
||||
uint_t stop_mcount_loc;
|
||||
};
|
||||
|
||||
/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
|
||||
static void *sort_mcount_loc(void *arg)
|
||||
{
|
||||
struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;
|
||||
uint_t offset = emloc->start_mcount_loc - _r(&(emloc->init_data_sec)->sh_addr)
|
||||
+ _r(&(emloc->init_data_sec)->sh_offset);
|
||||
uint_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
|
||||
unsigned char *start_loc = (void *)emloc->ehdr + offset;
|
||||
|
||||
qsort(start_loc, count/sizeof(uint_t), sizeof(uint_t), compare_extable);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
|
||||
static void get_mcount_loc(uint_t *_start, uint_t *_stop)
|
||||
{
|
||||
FILE *file_start, *file_stop;
|
||||
char start_buff[20];
|
||||
char stop_buff[20];
|
||||
int len = 0;
|
||||
|
||||
file_start = popen(" grep start_mcount System.map | awk '{print $1}' ", "r");
|
||||
if (!file_start) {
|
||||
fprintf(stderr, "get start_mcount_loc error!");
|
||||
return;
|
||||
}
|
||||
|
||||
file_stop = popen(" grep stop_mcount System.map | awk '{print $1}' ", "r");
|
||||
if (!file_stop) {
|
||||
fprintf(stderr, "get stop_mcount_loc error!");
|
||||
pclose(file_start);
|
||||
return;
|
||||
}
|
||||
|
||||
while (fgets(start_buff, sizeof(start_buff), file_start) != NULL) {
|
||||
len = strlen(start_buff);
|
||||
start_buff[len - 1] = '\0';
|
||||
}
|
||||
*_start = strtoul(start_buff, NULL, 16);
|
||||
|
||||
while (fgets(stop_buff, sizeof(stop_buff), file_stop) != NULL) {
|
||||
len = strlen(stop_buff);
|
||||
stop_buff[len - 1] = '\0';
|
||||
}
|
||||
*_stop = strtoul(stop_buff, NULL, 16);
|
||||
|
||||
pclose(file_start);
|
||||
pclose(file_stop);
|
||||
}
|
||||
#endif
|
||||
static int do_sort(Elf_Ehdr *ehdr,
|
||||
char const *const fname,
|
||||
table_sort_t custom_sort)
|
||||
{
|
||||
int rc = -1;
|
||||
Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
|
||||
Elf_Shdr *strtab_sec = NULL;
|
||||
Elf_Shdr *symtab_sec = NULL;
|
||||
Elf_Shdr *extab_sec = NULL;
|
||||
Elf_Sym *sym;
|
||||
const Elf_Sym *symtab;
|
||||
Elf32_Word *symtab_shndx = NULL;
|
||||
Elf_Sym *sort_needed_sym = NULL;
|
||||
Elf_Shdr *sort_needed_sec;
|
||||
Elf_Rel *relocs = NULL;
|
||||
int relocs_size = 0;
|
||||
uint32_t *sort_needed_loc;
|
||||
const char *secstrings;
|
||||
const char *strtab;
|
||||
char *extab_image;
|
||||
int extab_index = 0;
|
||||
int i;
|
||||
int idx;
|
||||
unsigned int shnum;
|
||||
unsigned int shstrndx;
|
||||
#ifdef MCOUNT_SORT_ENABLED
|
||||
struct elf_mcount_loc mstruct = {0};
|
||||
uint_t _start_mcount_loc = 0;
|
||||
uint_t _stop_mcount_loc = 0;
|
||||
#endif
|
||||
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
|
||||
unsigned int orc_ip_size = 0;
|
||||
unsigned int orc_size = 0;
|
||||
unsigned int orc_num_entries = 0;
|
||||
#endif
|
||||
|
||||
shstrndx = r2(&ehdr->e_shstrndx);
|
||||
if (shstrndx == SHN_XINDEX)
|
||||
shstrndx = r(&shdr[0].sh_link);
|
||||
secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset);
|
||||
|
||||
shnum = r2(&ehdr->e_shnum);
|
||||
if (shnum == SHN_UNDEF)
|
||||
shnum = _r(&shdr[0].sh_size);
|
||||
|
||||
for (i = 0, s = shdr; s < shdr + shnum; i++, s++) {
|
||||
idx = r(&s->sh_name);
|
||||
if (!strcmp(secstrings + idx, "__ex_table")) {
|
||||
extab_sec = s;
|
||||
extab_index = i;
|
||||
}
|
||||
if (!strcmp(secstrings + idx, ".symtab"))
|
||||
symtab_sec = s;
|
||||
if (!strcmp(secstrings + idx, ".strtab"))
|
||||
strtab_sec = s;
|
||||
|
||||
if ((r(&s->sh_type) == SHT_REL ||
|
||||
r(&s->sh_type) == SHT_RELA) &&
|
||||
r(&s->sh_info) == extab_index) {
|
||||
relocs = (void *)ehdr + _r(&s->sh_offset);
|
||||
relocs_size = _r(&s->sh_size);
|
||||
}
|
||||
if (r(&s->sh_type) == SHT_SYMTAB_SHNDX)
|
||||
symtab_shndx = (Elf32_Word *)((const char *)ehdr +
|
||||
_r(&s->sh_offset));
|
||||
|
||||
#ifdef MCOUNT_SORT_ENABLED
|
||||
/* locate the .init.data section in vmlinux */
|
||||
if (!strcmp(secstrings + idx, ".init.data")) {
|
||||
get_mcount_loc(&_start_mcount_loc, &_stop_mcount_loc);
|
||||
mstruct.ehdr = ehdr;
|
||||
mstruct.init_data_sec = s;
|
||||
mstruct.start_mcount_loc = _start_mcount_loc;
|
||||
mstruct.stop_mcount_loc = _stop_mcount_loc;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
|
||||
/* locate the ORC unwind tables */
|
||||
if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
|
||||
orc_ip_size = s->sh_size;
|
||||
g_orc_ip_table = (int *)((void *)ehdr +
|
||||
s->sh_offset);
|
||||
}
|
||||
if (!strcmp(secstrings + idx, ".orc_unwind")) {
|
||||
orc_size = s->sh_size;
|
||||
g_orc_table = (struct orc_entry *)((void *)ehdr +
|
||||
s->sh_offset);
|
||||
}
|
||||
#endif
|
||||
} /* for loop */
|
||||
|
||||
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
|
||||
if (!g_orc_ip_table || !g_orc_table) {
|
||||
fprintf(stderr,
|
||||
"incomplete ORC unwind tables in file: %s\n", fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
orc_num_entries = orc_ip_size / sizeof(int);
|
||||
if (orc_ip_size % sizeof(int) != 0 ||
|
||||
orc_size % sizeof(struct orc_entry) != 0 ||
|
||||
orc_num_entries != orc_size / sizeof(struct orc_entry)) {
|
||||
fprintf(stderr,
|
||||
"inconsistent ORC unwind table entries in file: %s\n",
|
||||
fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* create thread to sort ORC unwind tables concurrently */
|
||||
if (pthread_create(&orc_sort_thread, NULL,
|
||||
sort_orctable, &orc_ip_size)) {
|
||||
fprintf(stderr,
|
||||
"pthread_create orc_sort_thread failed '%s': %s\n",
|
||||
strerror(errno), fname);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MCOUNT_SORT_ENABLED
|
||||
if (!mstruct.init_data_sec || !_start_mcount_loc || !_stop_mcount_loc) {
|
||||
fprintf(stderr,
|
||||
"incomplete mcount's sort in file: %s\n",
|
||||
fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* create thread to sort mcount_loc concurrently */
|
||||
if (pthread_create(&mcount_sort_thread, NULL, &sort_mcount_loc, &mstruct)) {
|
||||
fprintf(stderr,
|
||||
"pthread_create mcount_sort_thread failed '%s': %s\n",
|
||||
strerror(errno), fname);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
if (!extab_sec) {
|
||||
fprintf(stderr, "no __ex_table in file: %s\n", fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!symtab_sec) {
|
||||
fprintf(stderr, "no .symtab in file: %s\n", fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strtab_sec) {
|
||||
fprintf(stderr, "no .strtab in file: %s\n", fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
|
||||
strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
|
||||
symtab = (const Elf_Sym *)((const char *)ehdr +
|
||||
_r(&symtab_sec->sh_offset));
|
||||
|
||||
if (custom_sort) {
|
||||
custom_sort(extab_image, _r(&extab_sec->sh_size));
|
||||
} else {
|
||||
int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
|
||||
qsort(extab_image, num_entries,
|
||||
extable_ent_size, compare_extable);
|
||||
}
|
||||
|
||||
/* If there were relocations, we no longer need them. */
|
||||
if (relocs)
|
||||
memset(relocs, 0, relocs_size);
|
||||
|
||||
/* find the flag main_extable_sort_needed */
|
||||
for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
|
||||
sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym);
|
||||
sym++) {
|
||||
if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
|
||||
continue;
|
||||
if (!strcmp(strtab + r(&sym->st_name),
|
||||
"main_extable_sort_needed")) {
|
||||
sort_needed_sym = sym;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sort_needed_sym) {
|
||||
fprintf(stderr,
|
||||
"no main_extable_sort_needed symbol in file: %s\n",
|
||||
fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx),
|
||||
sort_needed_sym - symtab,
|
||||
symtab_shndx)];
|
||||
sort_needed_loc = (void *)ehdr +
|
||||
_r(&sort_needed_sec->sh_offset) +
|
||||
_r(&sort_needed_sym->st_value) -
|
||||
_r(&sort_needed_sec->sh_addr);
|
||||
|
||||
/* extable has been sorted, clear the flag */
|
||||
w(0, sort_needed_loc);
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
|
||||
if (orc_sort_thread) {
|
||||
void *retval = NULL;
|
||||
/* wait for ORC tables sort done */
|
||||
rc = pthread_join(orc_sort_thread, &retval);
|
||||
if (rc) {
|
||||
fprintf(stderr,
|
||||
"pthread_join failed '%s': %s\n",
|
||||
strerror(errno), fname);
|
||||
} else if (retval) {
|
||||
rc = -1;
|
||||
fprintf(stderr,
|
||||
"failed to sort ORC tables '%s': %s\n",
|
||||
(char *)retval, fname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MCOUNT_SORT_ENABLED
|
||||
if (mcount_sort_thread) {
|
||||
void *retval = NULL;
|
||||
/* wait for mcount sort done */
|
||||
rc = pthread_join(mcount_sort_thread, &retval);
|
||||
if (rc) {
|
||||
fprintf(stderr,
|
||||
"pthread_join failed '%s': %s\n",
|
||||
strerror(errno), fname);
|
||||
} else if (retval) {
|
||||
rc = -1;
|
||||
fprintf(stderr,
|
||||
"failed to sort mcount '%s': %s\n",
|
||||
(char *)retval, fname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
Loading…
Reference in a new issue