1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * vdso2c - A vdso image preparation tool 4 * Copyright (c) 2014 Andy Lutomirski and others 5 * 6 * vdso2c requires stripped and unstripped input. It would be trivial 7 * to fully strip the input in here, but, for reasons described below, 8 * we need to write a section table. Doing this is more or less 9 * equivalent to dropping all non-allocatable sections, but it's 10 * easier to let objcopy handle that instead of doing it ourselves. 11 * If we ever need to do something fancier than what objcopy provides, 12 * it would be straightforward to add here. 13 * 14 * We keep a section table for a few reasons: 15 * 16 * Binutils has issues debugging the vDSO: it reads the section table to 17 * find SHT_NOTE; it won't look at PT_NOTE for the in-memory vDSO, which 18 * would break build-id if we removed the section table. Binutils 19 * also requires that shstrndx != 0. See: 20 * https://sourceware.org/bugzilla/show_bug.cgi?id=17064 21 * 22 * elfutils might not look for PT_NOTE if there is a section table at 23 * all. I don't know whether this matters for any practical purpose. 24 * 25 * For simplicity, rather than hacking up a partial section table, we 26 * just write a mostly complete one. We omit non-dynamic symbols, 27 * though, since they're rather large. 28 * 29 * Once binutils gets fixed, we might be able to drop this for all but 30 * the 64-bit vdso, since build-id only works in kernel RPMs, and 31 * systems that update to new enough kernel RPMs will likely update 32 * binutils in sync. build-id has never worked for home-built kernel 33 * RPMs without manual symlinking, and I suspect that no one ever does 34 * that. 35 */ 36 37 /* 38 * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. 39 */ 40 41 #include <inttypes.h> 42 #include <stdint.h> 43 #include <unistd.h> 44 #include <stdarg.h> 45 #include <stdlib.h> 46 #include <stdio.h> 47 #include <string.h> 48 #include <fcntl.h> 49 #include <err.h> 50 51 #include <sys/mman.h> 52 #include <sys/types.h> 53 #include <tools/be_byteshift.h> 54 55 #include <linux/elf.h> 56 #include <linux/types.h> 57 #include <linux/kernel.h> 58 59 const char *outfilename; 60 61 __attribute__((format(printf, 1, 2))) __attribute__((noreturn)) 62 static void fail(const char *format, ...) 63 { 64 va_list ap; 65 66 va_start(ap, format); 67 fprintf(stderr, "Error: "); 68 vfprintf(stderr, format, ap); 69 if (outfilename) 70 unlink(outfilename); 71 exit(1); 72 va_end(ap); 73 } 74 75 /* 76 * Evil macros for big-endian reads and writes 77 */ 78 #define GBE(x, bits, ifnot) \ 79 __builtin_choose_expr( \ 80 (sizeof(*(x)) == bits/8), \ 81 (__typeof__(*(x)))get_unaligned_be##bits(x), ifnot) 82 83 #define LAST_GBE(x) \ 84 __builtin_choose_expr(sizeof(*(x)) == 1, *(x), (void)(0)) 85 86 #define GET_BE(x) \ 87 GBE(x, 64, GBE(x, 32, GBE(x, 16, LAST_GBE(x)))) 88 89 #define PBE(x, val, bits, ifnot) \ 90 __builtin_choose_expr( \ 91 (sizeof(*(x)) == bits/8), \ 92 put_unaligned_be##bits((val), (x)), ifnot) 93 94 #define LAST_PBE(x, val) \ 95 __builtin_choose_expr(sizeof(*(x)) == 1, *(x) = (val), (void)(0)) 96 97 #define PUT_BE(x, val) \ 98 PBE(x, val, 64, PBE(x, val, 32, PBE(x, val, 16, LAST_PBE(x, val)))) 99 100 #define BITSFUNC3(name, bits, suffix) name##bits##suffix 101 #define BITSFUNC2(name, bits, suffix) BITSFUNC3(name, bits, suffix) 102 #define BITSFUNC(name) BITSFUNC2(name, ELF_BITS, ) 103 104 #define INT_BITS BITSFUNC2(int, ELF_BITS, _t) 105 106 #define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x 107 #define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x) 108 #define ELF(x) ELF_BITS_XFORM(ELF_BITS, x) 109 110 #define ELF_BITS 64 111 #include "vdso2c.h" 112 #undef ELF_BITS 113 114 #define ELF_BITS 32 115 #include "vdso2c.h" 116 #undef ELF_BITS 117 118 static void go(void *raw_addr, size_t raw_len, 119 void *stripped_addr, size_t stripped_len, 120 FILE *outfile, const char *name) 121 { 122 Elf64_Ehdr *hdr = (Elf64_Ehdr *)raw_addr; 123 124 if (hdr->e_ident[EI_CLASS] == ELFCLASS64) { 125 go64(raw_addr, raw_len, stripped_addr, stripped_len, 126 outfile, name); 127 } else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) { 128 go32(raw_addr, raw_len, stripped_addr, stripped_len, 129 outfile, name); 130 } else { 131 fail("unknown ELF class\n"); 132 } 133 } 134 135 static void map_input(const char *name, void **addr, size_t *len, int prot) 136 { 137 off_t tmp_len; 138 139 int fd = open(name, O_RDONLY); 140 141 if (fd == -1) 142 err(1, "%s", name); 143 144 tmp_len = lseek(fd, 0, SEEK_END); 145 if (tmp_len == (off_t)-1) 146 err(1, "lseek"); 147 *len = (size_t)tmp_len; 148 149 *addr = mmap(NULL, tmp_len, prot, MAP_PRIVATE, fd, 0); 150 if (*addr == MAP_FAILED) 151 err(1, "mmap"); 152 153 close(fd); 154 } 155 156 int main(int argc, char **argv) 157 { 158 size_t raw_len, stripped_len; 159 void *raw_addr, *stripped_addr; 160 FILE *outfile; 161 char *name, *tmp; 162 int namelen; 163 164 if (argc != 4) { 165 printf("Usage: vdso2c RAW_INPUT STRIPPED_INPUT OUTPUT\n"); 166 return 1; 167 } 168 169 /* 170 * Figure out the struct name. If we're writing to a .so file, 171 * generate raw output insted. 172 */ 173 name = strdup(argv[3]); 174 namelen = strlen(name); 175 if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) { 176 name = NULL; 177 } else { 178 tmp = strrchr(name, '/'); 179 if (tmp) 180 name = tmp + 1; 181 tmp = strchr(name, '.'); 182 if (tmp) 183 *tmp = '\0'; 184 for (tmp = name; *tmp; tmp++) 185 if (*tmp == '-') 186 *tmp = '_'; 187 } 188 189 map_input(argv[1], &raw_addr, &raw_len, PROT_READ); 190 map_input(argv[2], &stripped_addr, &stripped_len, PROT_READ); 191 192 outfilename = argv[3]; 193 outfile = fopen(outfilename, "w"); 194 if (!outfile) 195 err(1, "%s", argv[2]); 196 197 go(raw_addr, raw_len, stripped_addr, stripped_len, outfile, name); 198 199 munmap(raw_addr, raw_len); 200 munmap(stripped_addr, stripped_len); 201 fclose(outfile); 202 203 return 0; 204 } 205