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