1*fa82cce7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 29a08862aSNagarathnam Muthusamy /* 39a08862aSNagarathnam Muthusamy * vdso2c - A vdso image preparation tool 49a08862aSNagarathnam Muthusamy * Copyright (c) 2014 Andy Lutomirski and others 59a08862aSNagarathnam Muthusamy * 69a08862aSNagarathnam Muthusamy * vdso2c requires stripped and unstripped input. It would be trivial 79a08862aSNagarathnam Muthusamy * to fully strip the input in here, but, for reasons described below, 89a08862aSNagarathnam Muthusamy * we need to write a section table. Doing this is more or less 99a08862aSNagarathnam Muthusamy * equivalent to dropping all non-allocatable sections, but it's 109a08862aSNagarathnam Muthusamy * easier to let objcopy handle that instead of doing it ourselves. 119a08862aSNagarathnam Muthusamy * If we ever need to do something fancier than what objcopy provides, 129a08862aSNagarathnam Muthusamy * it would be straightforward to add here. 139a08862aSNagarathnam Muthusamy * 149a08862aSNagarathnam Muthusamy * We keep a section table for a few reasons: 159a08862aSNagarathnam Muthusamy * 169a08862aSNagarathnam Muthusamy * Binutils has issues debugging the vDSO: it reads the section table to 179a08862aSNagarathnam Muthusamy * find SHT_NOTE; it won't look at PT_NOTE for the in-memory vDSO, which 189a08862aSNagarathnam Muthusamy * would break build-id if we removed the section table. Binutils 199a08862aSNagarathnam Muthusamy * also requires that shstrndx != 0. See: 209a08862aSNagarathnam Muthusamy * https://sourceware.org/bugzilla/show_bug.cgi?id=17064 219a08862aSNagarathnam Muthusamy * 229a08862aSNagarathnam Muthusamy * elfutils might not look for PT_NOTE if there is a section table at 239a08862aSNagarathnam Muthusamy * all. I don't know whether this matters for any practical purpose. 249a08862aSNagarathnam Muthusamy * 259a08862aSNagarathnam Muthusamy * For simplicity, rather than hacking up a partial section table, we 269a08862aSNagarathnam Muthusamy * just write a mostly complete one. We omit non-dynamic symbols, 279a08862aSNagarathnam Muthusamy * though, since they're rather large. 289a08862aSNagarathnam Muthusamy * 299a08862aSNagarathnam Muthusamy * Once binutils gets fixed, we might be able to drop this for all but 309a08862aSNagarathnam Muthusamy * the 64-bit vdso, since build-id only works in kernel RPMs, and 319a08862aSNagarathnam Muthusamy * systems that update to new enough kernel RPMs will likely update 329a08862aSNagarathnam Muthusamy * binutils in sync. build-id has never worked for home-built kernel 339a08862aSNagarathnam Muthusamy * RPMs without manual symlinking, and I suspect that no one ever does 349a08862aSNagarathnam Muthusamy * that. 359a08862aSNagarathnam Muthusamy */ 369a08862aSNagarathnam Muthusamy 379a08862aSNagarathnam Muthusamy /* 389a08862aSNagarathnam Muthusamy * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. 399a08862aSNagarathnam Muthusamy */ 409a08862aSNagarathnam Muthusamy 419a08862aSNagarathnam Muthusamy #include <inttypes.h> 429a08862aSNagarathnam Muthusamy #include <stdint.h> 439a08862aSNagarathnam Muthusamy #include <unistd.h> 449a08862aSNagarathnam Muthusamy #include <stdarg.h> 459a08862aSNagarathnam Muthusamy #include <stdlib.h> 469a08862aSNagarathnam Muthusamy #include <stdio.h> 479a08862aSNagarathnam Muthusamy #include <string.h> 489a08862aSNagarathnam Muthusamy #include <fcntl.h> 499a08862aSNagarathnam Muthusamy #include <err.h> 509a08862aSNagarathnam Muthusamy 519a08862aSNagarathnam Muthusamy #include <sys/mman.h> 529a08862aSNagarathnam Muthusamy #include <sys/types.h> 539a08862aSNagarathnam Muthusamy #include <tools/be_byteshift.h> 549a08862aSNagarathnam Muthusamy 559a08862aSNagarathnam Muthusamy #include <linux/elf.h> 569a08862aSNagarathnam Muthusamy #include <linux/types.h> 579a08862aSNagarathnam Muthusamy #include <linux/kernel.h> 589a08862aSNagarathnam Muthusamy 599a08862aSNagarathnam Muthusamy const char *outfilename; 609a08862aSNagarathnam Muthusamy 619a08862aSNagarathnam Muthusamy /* Symbols that we need in vdso2c. */ 629a08862aSNagarathnam Muthusamy enum { 639a08862aSNagarathnam Muthusamy sym_vvar_start, 649a08862aSNagarathnam Muthusamy sym_VDSO_FAKE_SECTION_TABLE_START, 659a08862aSNagarathnam Muthusamy sym_VDSO_FAKE_SECTION_TABLE_END, 669a08862aSNagarathnam Muthusamy }; 679a08862aSNagarathnam Muthusamy 689a08862aSNagarathnam Muthusamy struct vdso_sym { 699a08862aSNagarathnam Muthusamy const char *name; 709a08862aSNagarathnam Muthusamy int export; 719a08862aSNagarathnam Muthusamy }; 729a08862aSNagarathnam Muthusamy 739a08862aSNagarathnam Muthusamy struct vdso_sym required_syms[] = { 749a08862aSNagarathnam Muthusamy [sym_vvar_start] = {"vvar_start", 1}, 759a08862aSNagarathnam Muthusamy [sym_VDSO_FAKE_SECTION_TABLE_START] = { 769a08862aSNagarathnam Muthusamy "VDSO_FAKE_SECTION_TABLE_START", 0 779a08862aSNagarathnam Muthusamy }, 789a08862aSNagarathnam Muthusamy [sym_VDSO_FAKE_SECTION_TABLE_END] = { 799a08862aSNagarathnam Muthusamy "VDSO_FAKE_SECTION_TABLE_END", 0 809a08862aSNagarathnam Muthusamy }, 819a08862aSNagarathnam Muthusamy }; 829a08862aSNagarathnam Muthusamy 839a08862aSNagarathnam Muthusamy __attribute__((format(printf, 1, 2))) __attribute__((noreturn)) 849a08862aSNagarathnam Muthusamy static void fail(const char *format, ...) 859a08862aSNagarathnam Muthusamy { 869a08862aSNagarathnam Muthusamy va_list ap; 879a08862aSNagarathnam Muthusamy 889a08862aSNagarathnam Muthusamy va_start(ap, format); 899a08862aSNagarathnam Muthusamy fprintf(stderr, "Error: "); 909a08862aSNagarathnam Muthusamy vfprintf(stderr, format, ap); 919a08862aSNagarathnam Muthusamy if (outfilename) 929a08862aSNagarathnam Muthusamy unlink(outfilename); 939a08862aSNagarathnam Muthusamy exit(1); 949a08862aSNagarathnam Muthusamy va_end(ap); 959a08862aSNagarathnam Muthusamy } 969a08862aSNagarathnam Muthusamy 979a08862aSNagarathnam Muthusamy /* 989a08862aSNagarathnam Muthusamy * Evil macros for big-endian reads and writes 999a08862aSNagarathnam Muthusamy */ 1009a08862aSNagarathnam Muthusamy #define GBE(x, bits, ifnot) \ 1019a08862aSNagarathnam Muthusamy __builtin_choose_expr( \ 1029a08862aSNagarathnam Muthusamy (sizeof(*(x)) == bits/8), \ 1039a08862aSNagarathnam Muthusamy (__typeof__(*(x)))get_unaligned_be##bits(x), ifnot) 1049a08862aSNagarathnam Muthusamy 1059a08862aSNagarathnam Muthusamy #define LAST_GBE(x) \ 1069a08862aSNagarathnam Muthusamy __builtin_choose_expr(sizeof(*(x)) == 1, *(x), (void)(0)) 1079a08862aSNagarathnam Muthusamy 1089a08862aSNagarathnam Muthusamy #define GET_BE(x) \ 1099a08862aSNagarathnam Muthusamy GBE(x, 64, GBE(x, 32, GBE(x, 16, LAST_GBE(x)))) 1109a08862aSNagarathnam Muthusamy 1119a08862aSNagarathnam Muthusamy #define PBE(x, val, bits, ifnot) \ 1129a08862aSNagarathnam Muthusamy __builtin_choose_expr( \ 1139a08862aSNagarathnam Muthusamy (sizeof(*(x)) == bits/8), \ 1149a08862aSNagarathnam Muthusamy put_unaligned_be##bits((val), (x)), ifnot) 1159a08862aSNagarathnam Muthusamy 1169a08862aSNagarathnam Muthusamy #define LAST_PBE(x, val) \ 1179a08862aSNagarathnam Muthusamy __builtin_choose_expr(sizeof(*(x)) == 1, *(x) = (val), (void)(0)) 1189a08862aSNagarathnam Muthusamy 1199a08862aSNagarathnam Muthusamy #define PUT_BE(x, val) \ 1209a08862aSNagarathnam Muthusamy PBE(x, val, 64, PBE(x, val, 32, PBE(x, val, 16, LAST_PBE(x, val)))) 1219a08862aSNagarathnam Muthusamy 1229a08862aSNagarathnam Muthusamy #define NSYMS ARRAY_SIZE(required_syms) 1239a08862aSNagarathnam Muthusamy 1249a08862aSNagarathnam Muthusamy #define BITSFUNC3(name, bits, suffix) name##bits##suffix 1259a08862aSNagarathnam Muthusamy #define BITSFUNC2(name, bits, suffix) BITSFUNC3(name, bits, suffix) 1269a08862aSNagarathnam Muthusamy #define BITSFUNC(name) BITSFUNC2(name, ELF_BITS, ) 1279a08862aSNagarathnam Muthusamy 1289a08862aSNagarathnam Muthusamy #define INT_BITS BITSFUNC2(int, ELF_BITS, _t) 1299a08862aSNagarathnam Muthusamy 1309a08862aSNagarathnam Muthusamy #define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x 1319a08862aSNagarathnam Muthusamy #define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x) 1329a08862aSNagarathnam Muthusamy #define ELF(x) ELF_BITS_XFORM(ELF_BITS, x) 1339a08862aSNagarathnam Muthusamy 1349a08862aSNagarathnam Muthusamy #define ELF_BITS 64 1359a08862aSNagarathnam Muthusamy #include "vdso2c.h" 1369a08862aSNagarathnam Muthusamy #undef ELF_BITS 1379a08862aSNagarathnam Muthusamy 1389a08862aSNagarathnam Muthusamy #define ELF_BITS 32 1399a08862aSNagarathnam Muthusamy #include "vdso2c.h" 1409a08862aSNagarathnam Muthusamy #undef ELF_BITS 1419a08862aSNagarathnam Muthusamy 1429a08862aSNagarathnam Muthusamy static void go(void *raw_addr, size_t raw_len, 1439a08862aSNagarathnam Muthusamy void *stripped_addr, size_t stripped_len, 1449a08862aSNagarathnam Muthusamy FILE *outfile, const char *name) 1459a08862aSNagarathnam Muthusamy { 1469a08862aSNagarathnam Muthusamy Elf64_Ehdr *hdr = (Elf64_Ehdr *)raw_addr; 1479a08862aSNagarathnam Muthusamy 1489a08862aSNagarathnam Muthusamy if (hdr->e_ident[EI_CLASS] == ELFCLASS64) { 1499a08862aSNagarathnam Muthusamy go64(raw_addr, raw_len, stripped_addr, stripped_len, 1509a08862aSNagarathnam Muthusamy outfile, name); 1519a08862aSNagarathnam Muthusamy } else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) { 1529a08862aSNagarathnam Muthusamy go32(raw_addr, raw_len, stripped_addr, stripped_len, 1539a08862aSNagarathnam Muthusamy outfile, name); 1549a08862aSNagarathnam Muthusamy } else { 1559a08862aSNagarathnam Muthusamy fail("unknown ELF class\n"); 1569a08862aSNagarathnam Muthusamy } 1579a08862aSNagarathnam Muthusamy } 1589a08862aSNagarathnam Muthusamy 1599a08862aSNagarathnam Muthusamy static void map_input(const char *name, void **addr, size_t *len, int prot) 1609a08862aSNagarathnam Muthusamy { 1619a08862aSNagarathnam Muthusamy off_t tmp_len; 1629a08862aSNagarathnam Muthusamy 1639a08862aSNagarathnam Muthusamy int fd = open(name, O_RDONLY); 1649a08862aSNagarathnam Muthusamy 1659a08862aSNagarathnam Muthusamy if (fd == -1) 1669a08862aSNagarathnam Muthusamy err(1, "%s", name); 1679a08862aSNagarathnam Muthusamy 1689a08862aSNagarathnam Muthusamy tmp_len = lseek(fd, 0, SEEK_END); 1699a08862aSNagarathnam Muthusamy if (tmp_len == (off_t)-1) 1709a08862aSNagarathnam Muthusamy err(1, "lseek"); 1719a08862aSNagarathnam Muthusamy *len = (size_t)tmp_len; 1729a08862aSNagarathnam Muthusamy 1739a08862aSNagarathnam Muthusamy *addr = mmap(NULL, tmp_len, prot, MAP_PRIVATE, fd, 0); 1749a08862aSNagarathnam Muthusamy if (*addr == MAP_FAILED) 1759a08862aSNagarathnam Muthusamy err(1, "mmap"); 1769a08862aSNagarathnam Muthusamy 1779a08862aSNagarathnam Muthusamy close(fd); 1789a08862aSNagarathnam Muthusamy } 1799a08862aSNagarathnam Muthusamy 1809a08862aSNagarathnam Muthusamy int main(int argc, char **argv) 1819a08862aSNagarathnam Muthusamy { 1829a08862aSNagarathnam Muthusamy size_t raw_len, stripped_len; 1839a08862aSNagarathnam Muthusamy void *raw_addr, *stripped_addr; 1849a08862aSNagarathnam Muthusamy FILE *outfile; 1859a08862aSNagarathnam Muthusamy char *name, *tmp; 1869a08862aSNagarathnam Muthusamy int namelen; 1879a08862aSNagarathnam Muthusamy 1889a08862aSNagarathnam Muthusamy if (argc != 4) { 1899a08862aSNagarathnam Muthusamy printf("Usage: vdso2c RAW_INPUT STRIPPED_INPUT OUTPUT\n"); 1909a08862aSNagarathnam Muthusamy return 1; 1919a08862aSNagarathnam Muthusamy } 1929a08862aSNagarathnam Muthusamy 1939a08862aSNagarathnam Muthusamy /* 1949a08862aSNagarathnam Muthusamy * Figure out the struct name. If we're writing to a .so file, 1959a08862aSNagarathnam Muthusamy * generate raw output insted. 1969a08862aSNagarathnam Muthusamy */ 1979a08862aSNagarathnam Muthusamy name = strdup(argv[3]); 1989a08862aSNagarathnam Muthusamy namelen = strlen(name); 1999a08862aSNagarathnam Muthusamy if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) { 2009a08862aSNagarathnam Muthusamy name = NULL; 2019a08862aSNagarathnam Muthusamy } else { 2029a08862aSNagarathnam Muthusamy tmp = strrchr(name, '/'); 2039a08862aSNagarathnam Muthusamy if (tmp) 2049a08862aSNagarathnam Muthusamy name = tmp + 1; 2059a08862aSNagarathnam Muthusamy tmp = strchr(name, '.'); 2069a08862aSNagarathnam Muthusamy if (tmp) 2079a08862aSNagarathnam Muthusamy *tmp = '\0'; 2089a08862aSNagarathnam Muthusamy for (tmp = name; *tmp; tmp++) 2099a08862aSNagarathnam Muthusamy if (*tmp == '-') 2109a08862aSNagarathnam Muthusamy *tmp = '_'; 2119a08862aSNagarathnam Muthusamy } 2129a08862aSNagarathnam Muthusamy 2139a08862aSNagarathnam Muthusamy map_input(argv[1], &raw_addr, &raw_len, PROT_READ); 2149a08862aSNagarathnam Muthusamy map_input(argv[2], &stripped_addr, &stripped_len, PROT_READ); 2159a08862aSNagarathnam Muthusamy 2169a08862aSNagarathnam Muthusamy outfilename = argv[3]; 2179a08862aSNagarathnam Muthusamy outfile = fopen(outfilename, "w"); 2189a08862aSNagarathnam Muthusamy if (!outfile) 2199a08862aSNagarathnam Muthusamy err(1, "%s", argv[2]); 2209a08862aSNagarathnam Muthusamy 2219a08862aSNagarathnam Muthusamy go(raw_addr, raw_len, stripped_addr, stripped_len, outfile, name); 2229a08862aSNagarathnam Muthusamy 2239a08862aSNagarathnam Muthusamy munmap(raw_addr, raw_len); 2249a08862aSNagarathnam Muthusamy munmap(stripped_addr, stripped_len); 2259a08862aSNagarathnam Muthusamy fclose(outfile); 2269a08862aSNagarathnam Muthusamy 2279a08862aSNagarathnam Muthusamy return 0; 2289a08862aSNagarathnam Muthusamy } 229