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