// 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/stat.h>
#include <getopt.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 "elf-parse.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 void (*table_sort_t)(char *, int);
/*
* 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 elf_parser.r(&symtab_shndx_start[sym_offs]);
}
static int compare_extable_32(const void *a, const void *b)
{
Elf32_Addr av = elf_parser.r(a);
Elf32_Addr bv = elf_parser.r(b);
if (av < bv)
return -1;
return av > bv;
}
static int compare_extable_64(const void *a, const void *b)
{
Elf64_Addr av = elf_parser.r8(a);
Elf64_Addr bv = elf_parser.r8(b);
if (av < bv)
return -1;
return av > bv;
}
static int (*compare_extable)(const void *a, const void *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;
int *tmp_orc_ip_table = NULL;
struct orc_entry *tmp_orc_table = NULL;
unsigned int *orc_ip_size = (unsi