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