0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 #include <inttypes.h>
0042 #include <stdint.h>
0043 #include <unistd.h>
0044 #include <stdarg.h>
0045 #include <stdlib.h>
0046 #include <stdio.h>
0047 #include <string.h>
0048 #include <fcntl.h>
0049 #include <err.h>
0050
0051 #include <sys/mman.h>
0052 #include <sys/types.h>
0053 #include <tools/be_byteshift.h>
0054
0055 #include <linux/elf.h>
0056 #include <linux/types.h>
0057 #include <linux/kernel.h>
0058
0059 const char *outfilename;
0060
0061
0062 enum {
0063 sym_vvar_start,
0064 sym_VDSO_FAKE_SECTION_TABLE_START,
0065 sym_VDSO_FAKE_SECTION_TABLE_END,
0066 };
0067
0068 struct vdso_sym {
0069 const char *name;
0070 int export;
0071 };
0072
0073 struct vdso_sym required_syms[] = {
0074 [sym_vvar_start] = {"vvar_start", 1},
0075 [sym_VDSO_FAKE_SECTION_TABLE_START] = {
0076 "VDSO_FAKE_SECTION_TABLE_START", 0
0077 },
0078 [sym_VDSO_FAKE_SECTION_TABLE_END] = {
0079 "VDSO_FAKE_SECTION_TABLE_END", 0
0080 },
0081 };
0082
0083 __attribute__((format(printf, 1, 2))) __attribute__((noreturn))
0084 static void fail(const char *format, ...)
0085 {
0086 va_list ap;
0087
0088 va_start(ap, format);
0089 fprintf(stderr, "Error: ");
0090 vfprintf(stderr, format, ap);
0091 if (outfilename)
0092 unlink(outfilename);
0093 exit(1);
0094 va_end(ap);
0095 }
0096
0097
0098
0099
0100 #define GBE(x, bits, ifnot) \
0101 __builtin_choose_expr( \
0102 (sizeof(*(x)) == bits/8), \
0103 (__typeof__(*(x)))get_unaligned_be##bits(x), ifnot)
0104
0105 #define LAST_GBE(x) \
0106 __builtin_choose_expr(sizeof(*(x)) == 1, *(x), (void)(0))
0107
0108 #define GET_BE(x) \
0109 GBE(x, 64, GBE(x, 32, GBE(x, 16, LAST_GBE(x))))
0110
0111 #define PBE(x, val, bits, ifnot) \
0112 __builtin_choose_expr( \
0113 (sizeof(*(x)) == bits/8), \
0114 put_unaligned_be##bits((val), (x)), ifnot)
0115
0116 #define LAST_PBE(x, val) \
0117 __builtin_choose_expr(sizeof(*(x)) == 1, *(x) = (val), (void)(0))
0118
0119 #define PUT_BE(x, val) \
0120 PBE(x, val, 64, PBE(x, val, 32, PBE(x, val, 16, LAST_PBE(x, val))))
0121
0122 #define NSYMS ARRAY_SIZE(required_syms)
0123
0124 #define BITSFUNC3(name, bits, suffix) name##bits##suffix
0125 #define BITSFUNC2(name, bits, suffix) BITSFUNC3(name, bits, suffix)
0126 #define BITSFUNC(name) BITSFUNC2(name, ELF_BITS, )
0127
0128 #define INT_BITS BITSFUNC2(int, ELF_BITS, _t)
0129
0130 #define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x
0131 #define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x)
0132 #define ELF(x) ELF_BITS_XFORM(ELF_BITS, x)
0133
0134 #define ELF_BITS 64
0135 #include "vdso2c.h"
0136 #undef ELF_BITS
0137
0138 #define ELF_BITS 32
0139 #include "vdso2c.h"
0140 #undef ELF_BITS
0141
0142 static void go(void *raw_addr, size_t raw_len,
0143 void *stripped_addr, size_t stripped_len,
0144 FILE *outfile, const char *name)
0145 {
0146 Elf64_Ehdr *hdr = (Elf64_Ehdr *)raw_addr;
0147
0148 if (hdr->e_ident[EI_CLASS] == ELFCLASS64) {
0149 go64(raw_addr, raw_len, stripped_addr, stripped_len,
0150 outfile, name);
0151 } else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) {
0152 go32(raw_addr, raw_len, stripped_addr, stripped_len,
0153 outfile, name);
0154 } else {
0155 fail("unknown ELF class\n");
0156 }
0157 }
0158
0159 static void map_input(const char *name, void **addr, size_t *len, int prot)
0160 {
0161 off_t tmp_len;
0162
0163 int fd = open(name, O_RDONLY);
0164
0165 if (fd == -1)
0166 err(1, "%s", name);
0167
0168 tmp_len = lseek(fd, 0, SEEK_END);
0169 if (tmp_len == (off_t)-1)
0170 err(1, "lseek");
0171 *len = (size_t)tmp_len;
0172
0173 *addr = mmap(NULL, tmp_len, prot, MAP_PRIVATE, fd, 0);
0174 if (*addr == MAP_FAILED)
0175 err(1, "mmap");
0176
0177 close(fd);
0178 }
0179
0180 int main(int argc, char **argv)
0181 {
0182 size_t raw_len, stripped_len;
0183 void *raw_addr, *stripped_addr;
0184 FILE *outfile;
0185 char *name, *tmp;
0186 int namelen;
0187
0188 if (argc != 4) {
0189 printf("Usage: vdso2c RAW_INPUT STRIPPED_INPUT OUTPUT\n");
0190 return 1;
0191 }
0192
0193
0194
0195
0196
0197 name = strdup(argv[3]);
0198 namelen = strlen(name);
0199 if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) {
0200 name = NULL;
0201 } else {
0202 tmp = strrchr(name, '/');
0203 if (tmp)
0204 name = tmp + 1;
0205 tmp = strchr(name, '.');
0206 if (tmp)
0207 *tmp = '\0';
0208 for (tmp = name; *tmp; tmp++)
0209 if (*tmp == '-')
0210 *tmp = '_';
0211 }
0212
0213 map_input(argv[1], &raw_addr, &raw_len, PROT_READ);
0214 map_input(argv[2], &stripped_addr, &stripped_len, PROT_READ);
0215
0216 outfilename = argv[3];
0217 outfile = fopen(outfilename, "w");
0218 if (!outfile)
0219 err(1, "%s", argv[2]);
0220
0221 go(raw_addr, raw_len, stripped_addr, stripped_len, outfile, name);
0222
0223 munmap(raw_addr, raw_len);
0224 munmap(stripped_addr, stripped_len);
0225 fclose(outfile);
0226
0227 return 0;
0228 }