Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2015 Imagination Technologies
0004  * Author: Alex Smith <alex.smith@imgtec.com>
0005  */
0006 
0007 /*
0008  * This tool is used to generate the real VDSO images from the raw image. It
0009  * first patches up the MIPS ABI flags and GNU attributes sections defined in
0010  * elf.S to have the correct name and type. It then generates a C source file
0011  * to be compiled into the kernel containing the VDSO image data and a
0012  * mips_vdso_image struct for it, including symbol offsets extracted from the
0013  * image.
0014  *
0015  * We need to be passed both a stripped and unstripped VDSO image. The stripped
0016  * image is compiled into the kernel, but we must also patch up the unstripped
0017  * image's ABI flags sections so that it can be installed and used for
0018  * debugging.
0019  */
0020 
0021 #include <sys/mman.h>
0022 #include <sys/stat.h>
0023 #include <sys/types.h>
0024 
0025 #include <byteswap.h>
0026 #include <elf.h>
0027 #include <errno.h>
0028 #include <fcntl.h>
0029 #include <inttypes.h>
0030 #include <stdarg.h>
0031 #include <stdbool.h>
0032 #include <stdio.h>
0033 #include <stdlib.h>
0034 #include <string.h>
0035 #include <unistd.h>
0036 
0037 /* Define these in case the system elf.h is not new enough to have them. */
0038 #ifndef SHT_GNU_ATTRIBUTES
0039 # define SHT_GNU_ATTRIBUTES 0x6ffffff5
0040 #endif
0041 #ifndef SHT_MIPS_ABIFLAGS
0042 # define SHT_MIPS_ABIFLAGS  0x7000002a
0043 #endif
0044 
0045 enum {
0046     ABI_O32 = (1 << 0),
0047     ABI_N32 = (1 << 1),
0048     ABI_N64 = (1 << 2),
0049 
0050     ABI_ALL = ABI_O32 | ABI_N32 | ABI_N64,
0051 };
0052 
0053 /* Symbols the kernel requires offsets for. */
0054 static struct {
0055     const char *name;
0056     const char *offset_name;
0057     unsigned int abis;
0058 } vdso_symbols[] = {
0059     { "__vdso_sigreturn", "off_sigreturn", ABI_O32 },
0060     { "__vdso_rt_sigreturn", "off_rt_sigreturn", ABI_ALL },
0061     {}
0062 };
0063 
0064 static const char *program_name;
0065 static const char *vdso_name;
0066 static unsigned char elf_class;
0067 static unsigned int elf_abi;
0068 static bool need_swap;
0069 static FILE *out_file;
0070 
0071 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
0072 # define HOST_ORDER     ELFDATA2LSB
0073 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
0074 # define HOST_ORDER     ELFDATA2MSB
0075 #endif
0076 
0077 #define BUILD_SWAP(bits)                        \
0078     static uint##bits##_t swap_uint##bits(uint##bits##_t val)   \
0079     {                               \
0080         return need_swap ? bswap_##bits(val) : val;     \
0081     }
0082 
0083 BUILD_SWAP(16)
0084 BUILD_SWAP(32)
0085 BUILD_SWAP(64)
0086 
0087 #define __FUNC(name, bits) name##bits
0088 #define _FUNC(name, bits) __FUNC(name, bits)
0089 #define FUNC(name) _FUNC(name, ELF_BITS)
0090 
0091 #define __ELF(x, bits) Elf##bits##_##x
0092 #define _ELF(x, bits) __ELF(x, bits)
0093 #define ELF(x) _ELF(x, ELF_BITS)
0094 
0095 /*
0096  * Include genvdso.h twice with ELF_BITS defined differently to get functions
0097  * for both ELF32 and ELF64.
0098  */
0099 
0100 #define ELF_BITS 64
0101 #include "genvdso.h"
0102 #undef ELF_BITS
0103 
0104 #define ELF_BITS 32
0105 #include "genvdso.h"
0106 #undef ELF_BITS
0107 
0108 static void *map_vdso(const char *path, size_t *_size)
0109 {
0110     int fd;
0111     struct stat stat;
0112     void *addr;
0113     const Elf32_Ehdr *ehdr;
0114 
0115     fd = open(path, O_RDWR);
0116     if (fd < 0) {
0117         fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
0118             path, strerror(errno));
0119         return NULL;
0120     }
0121 
0122     if (fstat(fd, &stat) != 0) {
0123         fprintf(stderr, "%s: Failed to stat '%s': %s\n", program_name,
0124             path, strerror(errno));
0125         close(fd);
0126         return NULL;
0127     }
0128 
0129     addr = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
0130             0);
0131     if (addr == MAP_FAILED) {
0132         fprintf(stderr, "%s: Failed to map '%s': %s\n", program_name,
0133             path, strerror(errno));
0134         close(fd);
0135         return NULL;
0136     }
0137 
0138     /* ELF32/64 header formats are the same for the bits we're checking. */
0139     ehdr = addr;
0140 
0141     if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
0142         fprintf(stderr, "%s: '%s' is not an ELF file\n", program_name,
0143             path);
0144         close(fd);
0145         return NULL;
0146     }
0147 
0148     elf_class = ehdr->e_ident[EI_CLASS];
0149     switch (elf_class) {
0150     case ELFCLASS32:
0151     case ELFCLASS64:
0152         break;
0153     default:
0154         fprintf(stderr, "%s: '%s' has invalid ELF class\n",
0155             program_name, path);
0156         close(fd);
0157         return NULL;
0158     }
0159 
0160     switch (ehdr->e_ident[EI_DATA]) {
0161     case ELFDATA2LSB:
0162     case ELFDATA2MSB:
0163         need_swap = ehdr->e_ident[EI_DATA] != HOST_ORDER;
0164         break;
0165     default:
0166         fprintf(stderr, "%s: '%s' has invalid ELF data order\n",
0167             program_name, path);
0168         close(fd);
0169         return NULL;
0170     }
0171 
0172     if (swap_uint16(ehdr->e_machine) != EM_MIPS) {
0173         fprintf(stderr,
0174             "%s: '%s' has invalid ELF machine (expected EM_MIPS)\n",
0175             program_name, path);
0176         close(fd);
0177         return NULL;
0178     } else if (swap_uint16(ehdr->e_type) != ET_DYN) {
0179         fprintf(stderr,
0180             "%s: '%s' has invalid ELF type (expected ET_DYN)\n",
0181             program_name, path);
0182         close(fd);
0183         return NULL;
0184     }
0185 
0186     *_size = stat.st_size;
0187     close(fd);
0188     return addr;
0189 }
0190 
0191 static bool patch_vdso(const char *path, void *vdso)
0192 {
0193     if (elf_class == ELFCLASS64)
0194         return patch_vdso64(path, vdso);
0195     else
0196         return patch_vdso32(path, vdso);
0197 }
0198 
0199 static bool get_symbols(const char *path, void *vdso)
0200 {
0201     if (elf_class == ELFCLASS64)
0202         return get_symbols64(path, vdso);
0203     else
0204         return get_symbols32(path, vdso);
0205 }
0206 
0207 int main(int argc, char **argv)
0208 {
0209     const char *dbg_vdso_path, *vdso_path, *out_path;
0210     void *dbg_vdso, *vdso;
0211     size_t dbg_vdso_size, vdso_size, i;
0212 
0213     program_name = argv[0];
0214 
0215     if (argc < 4 || argc > 5) {
0216         fprintf(stderr,
0217             "Usage: %s <debug VDSO> <stripped VDSO> <output file> [<name>]\n",
0218             program_name);
0219         return EXIT_FAILURE;
0220     }
0221 
0222     dbg_vdso_path = argv[1];
0223     vdso_path = argv[2];
0224     out_path = argv[3];
0225     vdso_name = (argc > 4) ? argv[4] : "";
0226 
0227     dbg_vdso = map_vdso(dbg_vdso_path, &dbg_vdso_size);
0228     if (!dbg_vdso)
0229         return EXIT_FAILURE;
0230 
0231     vdso = map_vdso(vdso_path, &vdso_size);
0232     if (!vdso)
0233         return EXIT_FAILURE;
0234 
0235     /* Patch both the VDSOs' ABI flags sections. */
0236     if (!patch_vdso(dbg_vdso_path, dbg_vdso))
0237         return EXIT_FAILURE;
0238     if (!patch_vdso(vdso_path, vdso))
0239         return EXIT_FAILURE;
0240 
0241     if (msync(dbg_vdso, dbg_vdso_size, MS_SYNC) != 0) {
0242         fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
0243             dbg_vdso_path, strerror(errno));
0244         return EXIT_FAILURE;
0245     } else if (msync(vdso, vdso_size, MS_SYNC) != 0) {
0246         fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
0247             vdso_path, strerror(errno));
0248         return EXIT_FAILURE;
0249     }
0250 
0251     out_file = fopen(out_path, "w");
0252     if (!out_file) {
0253         fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
0254             out_path, strerror(errno));
0255         return EXIT_FAILURE;
0256     }
0257 
0258     fprintf(out_file, "/* Automatically generated - do not edit */\n");
0259     fprintf(out_file, "#include <linux/linkage.h>\n");
0260     fprintf(out_file, "#include <linux/mm.h>\n");
0261     fprintf(out_file, "#include <asm/vdso.h>\n");
0262     fprintf(out_file, "static int vdso_mremap(\n");
0263     fprintf(out_file, " const struct vm_special_mapping *sm,\n");
0264     fprintf(out_file, " struct vm_area_struct *new_vma)\n");
0265     fprintf(out_file, "{\n");
0266     fprintf(out_file, " current->mm->context.vdso =\n");
0267     fprintf(out_file, " (void *)(new_vma->vm_start);\n");
0268     fprintf(out_file, " return 0;\n");
0269     fprintf(out_file, "}\n");
0270 
0271     /* Write out the stripped VDSO data. */
0272     fprintf(out_file,
0273         "static unsigned char vdso_data[PAGE_ALIGN(%zu)] __page_aligned_data = {\n\t",
0274         vdso_size);
0275     for (i = 0; i < vdso_size; i++) {
0276         if (!(i % 10))
0277             fprintf(out_file, "\n\t");
0278         fprintf(out_file, "0x%02x, ", ((unsigned char *)vdso)[i]);
0279     }
0280     fprintf(out_file, "\n};\n");
0281 
0282     /* Preallocate a page array. */
0283     fprintf(out_file,
0284         "static struct page *vdso_pages[PAGE_ALIGN(%zu) / PAGE_SIZE];\n",
0285         vdso_size);
0286 
0287     fprintf(out_file, "struct mips_vdso_image vdso_image%s%s = {\n",
0288         (vdso_name[0]) ? "_" : "", vdso_name);
0289     fprintf(out_file, "\t.data = vdso_data,\n");
0290     fprintf(out_file, "\t.size = PAGE_ALIGN(%zu),\n", vdso_size);
0291     fprintf(out_file, "\t.mapping = {\n");
0292     fprintf(out_file, "\t\t.name = \"[vdso]\",\n");
0293     fprintf(out_file, "\t\t.pages = vdso_pages,\n");
0294     fprintf(out_file, "\t\t.mremap = vdso_mremap,\n");
0295     fprintf(out_file, "\t},\n");
0296 
0297     /* Calculate and write symbol offsets to <output file> */
0298     if (!get_symbols(dbg_vdso_path, dbg_vdso)) {
0299         unlink(out_path);
0300         fclose(out_file);
0301         return EXIT_FAILURE;
0302     }
0303 
0304     fprintf(out_file, "};\n");
0305     fclose(out_file);
0306 
0307     return EXIT_SUCCESS;
0308 }