Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * sorttable.c: Sort the kernel's table
0004  *
0005  * Added ORC unwind tables sort support and other updates:
0006  * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by:
0007  * Shile Zhang <shile.zhang@linux.alibaba.com>
0008  *
0009  * Copyright 2011 - 2012 Cavium, Inc.
0010  *
0011  * Based on code taken from recortmcount.c which is:
0012  *
0013  * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
0014  *
0015  * Restructured to fit Linux format, as well as other updates:
0016  * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
0017  */
0018 
0019 /*
0020  * Strategy: alter the vmlinux file in-place.
0021  */
0022 
0023 #include <sys/types.h>
0024 #include <sys/mman.h>
0025 #include <sys/stat.h>
0026 #include <getopt.h>
0027 #include <elf.h>
0028 #include <fcntl.h>
0029 #include <stdio.h>
0030 #include <stdlib.h>
0031 #include <string.h>
0032 #include <unistd.h>
0033 #include <errno.h>
0034 #include <pthread.h>
0035 
0036 #include <tools/be_byteshift.h>
0037 #include <tools/le_byteshift.h>
0038 
0039 #ifndef EM_ARCOMPACT
0040 #define EM_ARCOMPACT    93
0041 #endif
0042 
0043 #ifndef EM_XTENSA
0044 #define EM_XTENSA   94
0045 #endif
0046 
0047 #ifndef EM_AARCH64
0048 #define EM_AARCH64  183
0049 #endif
0050 
0051 #ifndef EM_MICROBLAZE
0052 #define EM_MICROBLAZE   189
0053 #endif
0054 
0055 #ifndef EM_ARCV2
0056 #define EM_ARCV2    195
0057 #endif
0058 
0059 #ifndef EM_RISCV
0060 #define EM_RISCV    243
0061 #endif
0062 
0063 #ifndef EM_LOONGARCH
0064 #define EM_LOONGARCH    258
0065 #endif
0066 
0067 static uint32_t (*r)(const uint32_t *);
0068 static uint16_t (*r2)(const uint16_t *);
0069 static uint64_t (*r8)(const uint64_t *);
0070 static void (*w)(uint32_t, uint32_t *);
0071 static void (*w2)(uint16_t, uint16_t *);
0072 static void (*w8)(uint64_t, uint64_t *);
0073 typedef void (*table_sort_t)(char *, int);
0074 
0075 /*
0076  * Get the whole file as a programming convenience in order to avoid
0077  * malloc+lseek+read+free of many pieces.  If successful, then mmap
0078  * avoids copying unused pieces; else just read the whole file.
0079  * Open for both read and write.
0080  */
0081 static void *mmap_file(char const *fname, size_t *size)
0082 {
0083     int fd;
0084     struct stat sb;
0085     void *addr = NULL;
0086 
0087     fd = open(fname, O_RDWR);
0088     if (fd < 0) {
0089         perror(fname);
0090         return NULL;
0091     }
0092     if (fstat(fd, &sb) < 0) {
0093         perror(fname);
0094         goto out;
0095     }
0096     if (!S_ISREG(sb.st_mode)) {
0097         fprintf(stderr, "not a regular file: %s\n", fname);
0098         goto out;
0099     }
0100 
0101     addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
0102     if (addr == MAP_FAILED) {
0103         fprintf(stderr, "Could not mmap file: %s\n", fname);
0104         goto out;
0105     }
0106 
0107     *size = sb.st_size;
0108 
0109 out:
0110     close(fd);
0111     return addr;
0112 }
0113 
0114 static uint32_t rbe(const uint32_t *x)
0115 {
0116     return get_unaligned_be32(x);
0117 }
0118 
0119 static uint16_t r2be(const uint16_t *x)
0120 {
0121     return get_unaligned_be16(x);
0122 }
0123 
0124 static uint64_t r8be(const uint64_t *x)
0125 {
0126     return get_unaligned_be64(x);
0127 }
0128 
0129 static uint32_t rle(const uint32_t *x)
0130 {
0131     return get_unaligned_le32(x);
0132 }
0133 
0134 static uint16_t r2le(const uint16_t *x)
0135 {
0136     return get_unaligned_le16(x);
0137 }
0138 
0139 static uint64_t r8le(const uint64_t *x)
0140 {
0141     return get_unaligned_le64(x);
0142 }
0143 
0144 static void wbe(uint32_t val, uint32_t *x)
0145 {
0146     put_unaligned_be32(val, x);
0147 }
0148 
0149 static void w2be(uint16_t val, uint16_t *x)
0150 {
0151     put_unaligned_be16(val, x);
0152 }
0153 
0154 static void w8be(uint64_t val, uint64_t *x)
0155 {
0156     put_unaligned_be64(val, x);
0157 }
0158 
0159 static void wle(uint32_t val, uint32_t *x)
0160 {
0161     put_unaligned_le32(val, x);
0162 }
0163 
0164 static void w2le(uint16_t val, uint16_t *x)
0165 {
0166     put_unaligned_le16(val, x);
0167 }
0168 
0169 static void w8le(uint64_t val, uint64_t *x)
0170 {
0171     put_unaligned_le64(val, x);
0172 }
0173 
0174 /*
0175  * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
0176  * the way to -256..-1, to avoid conflicting with real section
0177  * indices.
0178  */
0179 #define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))
0180 
0181 static inline int is_shndx_special(unsigned int i)
0182 {
0183     return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
0184 }
0185 
0186 /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
0187 static inline unsigned int get_secindex(unsigned int shndx,
0188                     unsigned int sym_offs,
0189                     const Elf32_Word *symtab_shndx_start)
0190 {
0191     if (is_shndx_special(shndx))
0192         return SPECIAL(shndx);
0193     if (shndx != SHN_XINDEX)
0194         return shndx;
0195     return r(&symtab_shndx_start[sym_offs]);
0196 }
0197 
0198 /* 32 bit and 64 bit are very similar */
0199 #include "sorttable.h"
0200 #define SORTTABLE_64
0201 #include "sorttable.h"
0202 
0203 static int compare_relative_table(const void *a, const void *b)
0204 {
0205     int32_t av = (int32_t)r(a);
0206     int32_t bv = (int32_t)r(b);
0207 
0208     if (av < bv)
0209         return -1;
0210     if (av > bv)
0211         return 1;
0212     return 0;
0213 }
0214 
0215 static void sort_relative_table(char *extab_image, int image_size)
0216 {
0217     int i = 0;
0218 
0219     /*
0220      * Do the same thing the runtime sort does, first normalize to
0221      * being relative to the start of the section.
0222      */
0223     while (i < image_size) {
0224         uint32_t *loc = (uint32_t *)(extab_image + i);
0225         w(r(loc) + i, loc);
0226         i += 4;
0227     }
0228 
0229     qsort(extab_image, image_size / 8, 8, compare_relative_table);
0230 
0231     /* Now denormalize. */
0232     i = 0;
0233     while (i < image_size) {
0234         uint32_t *loc = (uint32_t *)(extab_image + i);
0235         w(r(loc) - i, loc);
0236         i += 4;
0237     }
0238 }
0239 
0240 static void sort_relative_table_with_data(char *extab_image, int image_size)
0241 {
0242     int i = 0;
0243 
0244     while (i < image_size) {
0245         uint32_t *loc = (uint32_t *)(extab_image + i);
0246 
0247         w(r(loc) + i, loc);
0248         w(r(loc + 1) + i + 4, loc + 1);
0249         /* Don't touch the fixup type or data */
0250 
0251         i += sizeof(uint32_t) * 3;
0252     }
0253 
0254     qsort(extab_image, image_size / 12, 12, compare_relative_table);
0255 
0256     i = 0;
0257     while (i < image_size) {
0258         uint32_t *loc = (uint32_t *)(extab_image + i);
0259 
0260         w(r(loc) - i, loc);
0261         w(r(loc + 1) - (i + 4), loc + 1);
0262         /* Don't touch the fixup type or data */
0263 
0264         i += sizeof(uint32_t) * 3;
0265     }
0266 }
0267 
0268 static int do_file(char const *const fname, void *addr)
0269 {
0270     int rc = -1;
0271     Elf32_Ehdr *ehdr = addr;
0272     table_sort_t custom_sort = NULL;
0273 
0274     switch (ehdr->e_ident[EI_DATA]) {
0275     case ELFDATA2LSB:
0276         r   = rle;
0277         r2  = r2le;
0278         r8  = r8le;
0279         w   = wle;
0280         w2  = w2le;
0281         w8  = w8le;
0282         break;
0283     case ELFDATA2MSB:
0284         r   = rbe;
0285         r2  = r2be;
0286         r8  = r8be;
0287         w   = wbe;
0288         w2  = w2be;
0289         w8  = w8be;
0290         break;
0291     default:
0292         fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
0293             ehdr->e_ident[EI_DATA], fname);
0294         return -1;
0295     }
0296 
0297     if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 ||
0298         (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN) ||
0299         ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
0300         fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname);
0301         return -1;
0302     }
0303 
0304     switch (r2(&ehdr->e_machine)) {
0305     case EM_386:
0306     case EM_AARCH64:
0307     case EM_RISCV:
0308     case EM_S390:
0309     case EM_X86_64:
0310         custom_sort = sort_relative_table_with_data;
0311         break;
0312     case EM_PARISC:
0313     case EM_PPC:
0314     case EM_PPC64:
0315         custom_sort = sort_relative_table;
0316         break;
0317     case EM_ARCOMPACT:
0318     case EM_ARCV2:
0319     case EM_ARM:
0320     case EM_LOONGARCH:
0321     case EM_MICROBLAZE:
0322     case EM_MIPS:
0323     case EM_XTENSA:
0324         break;
0325     default:
0326         fprintf(stderr, "unrecognized e_machine %d %s\n",
0327             r2(&ehdr->e_machine), fname);
0328         return -1;
0329     }
0330 
0331     switch (ehdr->e_ident[EI_CLASS]) {
0332     case ELFCLASS32:
0333         if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) ||
0334             r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
0335             fprintf(stderr,
0336                 "unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
0337             break;
0338         }
0339         rc = do_sort_32(ehdr, fname, custom_sort);
0340         break;
0341     case ELFCLASS64:
0342         {
0343         Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
0344         if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) ||
0345             r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
0346             fprintf(stderr,
0347                 "unrecognized ET_EXEC/ET_DYN file: %s\n",
0348                 fname);
0349             break;
0350         }
0351         rc = do_sort_64(ghdr, fname, custom_sort);
0352         }
0353         break;
0354     default:
0355         fprintf(stderr, "unrecognized ELF class %d %s\n",
0356             ehdr->e_ident[EI_CLASS], fname);
0357         break;
0358     }
0359 
0360     return rc;
0361 }
0362 
0363 int main(int argc, char *argv[])
0364 {
0365     int i, n_error = 0;  /* gcc-4.3.0 false positive complaint */
0366     size_t size = 0;
0367     void *addr = NULL;
0368 
0369     if (argc < 2) {
0370         fprintf(stderr, "usage: sorttable vmlinux...\n");
0371         return 0;
0372     }
0373 
0374     /* Process each file in turn, allowing deep failure. */
0375     for (i = 1; i < argc; i++) {
0376         addr = mmap_file(argv[i], &size);
0377         if (!addr) {
0378             ++n_error;
0379             continue;
0380         }
0381 
0382         if (do_file(argv[i], addr))
0383             ++n_error;
0384 
0385         munmap(addr, size);
0386     }
0387 
0388     return !!n_error;
0389 }