1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2015 Imagination Technologies 4 * Author: Alex Smith <alex.smith@imgtec.com> 5 */ 6 7 /* 8 * This tool is used to generate the real VDSO images from the raw image. It 9 * first patches up the MIPS ABI flags and GNU attributes sections defined in 10 * elf.S to have the correct name and type. It then generates a C source file 11 * to be compiled into the kernel containing the VDSO image data and a 12 * mips_vdso_image struct for it, including symbol offsets extracted from the 13 * image. 14 * 15 * We need to be passed both a stripped and unstripped VDSO image. The stripped 16 * image is compiled into the kernel, but we must also patch up the unstripped 17 * image's ABI flags sections so that it can be installed and used for 18 * debugging. 19 */ 20 21 #include <sys/mman.h> 22 #include <sys/stat.h> 23 #include <sys/types.h> 24 25 #include <byteswap.h> 26 #include <elf.h> 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <inttypes.h> 30 #include <stdarg.h> 31 #include <stdbool.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <unistd.h> 36 37 /* Define these in case the system elf.h is not new enough to have them. */ 38 #ifndef SHT_GNU_ATTRIBUTES 39 # define SHT_GNU_ATTRIBUTES 0x6ffffff5 40 #endif 41 #ifndef SHT_MIPS_ABIFLAGS 42 # define SHT_MIPS_ABIFLAGS 0x7000002a 43 #endif 44 45 enum { 46 ABI_O32 = (1 << 0), 47 ABI_N32 = (1 << 1), 48 ABI_N64 = (1 << 2), 49 50 ABI_ALL = ABI_O32 | ABI_N32 | ABI_N64, 51 }; 52 53 /* Symbols the kernel requires offsets for. */ 54 static struct { 55 const char *name; 56 const char *offset_name; 57 unsigned int abis; 58 } vdso_symbols[] = { 59 { "__vdso_sigreturn", "off_sigreturn", ABI_O32 }, 60 { "__vdso_rt_sigreturn", "off_rt_sigreturn", ABI_ALL }, 61 {} 62 }; 63 64 static const char *program_name; 65 static const char *vdso_name; 66 static unsigned char elf_class; 67 static unsigned int elf_abi; 68 static bool need_swap; 69 static FILE *out_file; 70 71 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 72 # define HOST_ORDER ELFDATA2LSB 73 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 74 # define HOST_ORDER ELFDATA2MSB 75 #endif 76 77 #define BUILD_SWAP(bits) \ 78 static uint##bits##_t swap_uint##bits(uint##bits##_t val) \ 79 { \ 80 return need_swap ? bswap_##bits(val) : val; \ 81 } 82 83 BUILD_SWAP(16) 84 BUILD_SWAP(32) 85 BUILD_SWAP(64) 86 87 #define __FUNC(name, bits) name##bits 88 #define _FUNC(name, bits) __FUNC(name, bits) 89 #define FUNC(name) _FUNC(name, ELF_BITS) 90 91 #define __ELF(x, bits) Elf##bits##_##x 92 #define _ELF(x, bits) __ELF(x, bits) 93 #define ELF(x) _ELF(x, ELF_BITS) 94 95 /* 96 * Include genvdso.h twice with ELF_BITS defined differently to get functions 97 * for both ELF32 and ELF64. 98 */ 99 100 #define ELF_BITS 64 101 #include "genvdso.h" 102 #undef ELF_BITS 103 104 #define ELF_BITS 32 105 #include "genvdso.h" 106 #undef ELF_BITS 107 108 static void *map_vdso(const char *path, size_t *_size) 109 { 110 int fd; 111 struct stat stat; 112 void *addr; 113 const Elf32_Ehdr *ehdr; 114 115 fd = open(path, O_RDWR); 116 if (fd < 0) { 117 fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name, 118 path, strerror(errno)); 119 return NULL; 120 } 121 122 if (fstat(fd, &stat) != 0) { 123 fprintf(stderr, "%s: Failed to stat '%s': %s\n", program_name, 124 path, strerror(errno)); 125 return NULL; 126 } 127 128 addr = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 129 0); 130 if (addr == MAP_FAILED) { 131 fprintf(stderr, "%s: Failed to map '%s': %s\n", program_name, 132 path, strerror(errno)); 133 return NULL; 134 } 135 136 /* ELF32/64 header formats are the same for the bits we're checking. */ 137 ehdr = addr; 138 139 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) { 140 fprintf(stderr, "%s: '%s' is not an ELF file\n", program_name, 141 path); 142 return NULL; 143 } 144 145 elf_class = ehdr->e_ident[EI_CLASS]; 146 switch (elf_class) { 147 case ELFCLASS32: 148 case ELFCLASS64: 149 break; 150 default: 151 fprintf(stderr, "%s: '%s' has invalid ELF class\n", 152 program_name, path); 153 return NULL; 154 } 155 156 switch (ehdr->e_ident[EI_DATA]) { 157 case ELFDATA2LSB: 158 case ELFDATA2MSB: 159 need_swap = ehdr->e_ident[EI_DATA] != HOST_ORDER; 160 break; 161 default: 162 fprintf(stderr, "%s: '%s' has invalid ELF data order\n", 163 program_name, path); 164 return NULL; 165 } 166 167 if (swap_uint16(ehdr->e_machine) != EM_MIPS) { 168 fprintf(stderr, 169 "%s: '%s' has invalid ELF machine (expected EM_MIPS)\n", 170 program_name, path); 171 return NULL; 172 } else if (swap_uint16(ehdr->e_type) != ET_DYN) { 173 fprintf(stderr, 174 "%s: '%s' has invalid ELF type (expected ET_DYN)\n", 175 program_name, path); 176 return NULL; 177 } 178 179 *_size = stat.st_size; 180 return addr; 181 } 182 183 static bool patch_vdso(const char *path, void *vdso) 184 { 185 if (elf_class == ELFCLASS64) 186 return patch_vdso64(path, vdso); 187 else 188 return patch_vdso32(path, vdso); 189 } 190 191 static bool get_symbols(const char *path, void *vdso) 192 { 193 if (elf_class == ELFCLASS64) 194 return get_symbols64(path, vdso); 195 else 196 return get_symbols32(path, vdso); 197 } 198 199 int main(int argc, char **argv) 200 { 201 const char *dbg_vdso_path, *vdso_path, *out_path; 202 void *dbg_vdso, *vdso; 203 size_t dbg_vdso_size, vdso_size, i; 204 205 program_name = argv[0]; 206 207 if (argc < 4 || argc > 5) { 208 fprintf(stderr, 209 "Usage: %s <debug VDSO> <stripped VDSO> <output file> [<name>]\n", 210 program_name); 211 return EXIT_FAILURE; 212 } 213 214 dbg_vdso_path = argv[1]; 215 vdso_path = argv[2]; 216 out_path = argv[3]; 217 vdso_name = (argc > 4) ? argv[4] : ""; 218 219 dbg_vdso = map_vdso(dbg_vdso_path, &dbg_vdso_size); 220 if (!dbg_vdso) 221 return EXIT_FAILURE; 222 223 vdso = map_vdso(vdso_path, &vdso_size); 224 if (!vdso) 225 return EXIT_FAILURE; 226 227 /* Patch both the VDSOs' ABI flags sections. */ 228 if (!patch_vdso(dbg_vdso_path, dbg_vdso)) 229 return EXIT_FAILURE; 230 if (!patch_vdso(vdso_path, vdso)) 231 return EXIT_FAILURE; 232 233 if (msync(dbg_vdso, dbg_vdso_size, MS_SYNC) != 0) { 234 fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name, 235 dbg_vdso_path, strerror(errno)); 236 return EXIT_FAILURE; 237 } else if (msync(vdso, vdso_size, MS_SYNC) != 0) { 238 fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name, 239 vdso_path, strerror(errno)); 240 return EXIT_FAILURE; 241 } 242 243 out_file = fopen(out_path, "w"); 244 if (!out_file) { 245 fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name, 246 out_path, strerror(errno)); 247 return EXIT_FAILURE; 248 } 249 250 fprintf(out_file, "/* Automatically generated - do not edit */\n"); 251 fprintf(out_file, "#include <linux/linkage.h>\n"); 252 fprintf(out_file, "#include <linux/mm.h>\n"); 253 fprintf(out_file, "#include <asm/vdso.h>\n"); 254 255 /* Write out the stripped VDSO data. */ 256 fprintf(out_file, 257 "static unsigned char vdso_data[PAGE_ALIGN(%zu)] __page_aligned_data = {\n\t", 258 vdso_size); 259 for (i = 0; i < vdso_size; i++) { 260 if (!(i % 10)) 261 fprintf(out_file, "\n\t"); 262 fprintf(out_file, "0x%02x, ", ((unsigned char *)vdso)[i]); 263 } 264 fprintf(out_file, "\n};\n"); 265 266 /* Preallocate a page array. */ 267 fprintf(out_file, 268 "static struct page *vdso_pages[PAGE_ALIGN(%zu) / PAGE_SIZE];\n", 269 vdso_size); 270 271 fprintf(out_file, "struct mips_vdso_image vdso_image%s%s = {\n", 272 (vdso_name[0]) ? "_" : "", vdso_name); 273 fprintf(out_file, "\t.data = vdso_data,\n"); 274 fprintf(out_file, "\t.size = PAGE_ALIGN(%zu),\n", vdso_size); 275 fprintf(out_file, "\t.mapping = {\n"); 276 fprintf(out_file, "\t\t.name = \"[vdso]\",\n"); 277 fprintf(out_file, "\t\t.pages = vdso_pages,\n"); 278 fprintf(out_file, "\t},\n"); 279 280 /* Calculate and write symbol offsets to <output file> */ 281 if (!get_symbols(dbg_vdso_path, dbg_vdso)) { 282 unlink(out_path); 283 return EXIT_FAILURE; 284 } 285 286 fprintf(out_file, "};\n"); 287 288 return EXIT_SUCCESS; 289 } 290