Merge tag 'char-misc-3.16-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregk...
[cascardo/linux.git] / arch / x86 / vdso / vdso2c.c
1 #include <inttypes.h>
2 #include <stdint.h>
3 #include <unistd.h>
4 #include <stdarg.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <fcntl.h>
9 #include <err.h>
10
11 #include <sys/mman.h>
12 #include <sys/types.h>
13
14 #include <tools/le_byteshift.h>
15
16 #include <linux/elf.h>
17 #include <linux/types.h>
18
19 const char *outfilename;
20
21 /* Symbols that we need in vdso2c. */
22 enum {
23         sym_vvar_page,
24         sym_hpet_page,
25         sym_end_mapping,
26         sym_VDSO_FAKE_SECTION_TABLE_START,
27         sym_VDSO_FAKE_SECTION_TABLE_END,
28 };
29
30 const int special_pages[] = {
31         sym_vvar_page,
32         sym_hpet_page,
33 };
34
35 struct vdso_sym {
36         const char *name;
37         bool export;
38 };
39
40 struct vdso_sym required_syms[] = {
41         [sym_vvar_page] = {"vvar_page", true},
42         [sym_hpet_page] = {"hpet_page", true},
43         [sym_end_mapping] = {"end_mapping", true},
44         [sym_VDSO_FAKE_SECTION_TABLE_START] = {
45                 "VDSO_FAKE_SECTION_TABLE_START", false
46         },
47         [sym_VDSO_FAKE_SECTION_TABLE_END] = {
48                 "VDSO_FAKE_SECTION_TABLE_END", false
49         },
50         {"VDSO32_NOTE_MASK", true},
51         {"VDSO32_SYSENTER_RETURN", true},
52         {"__kernel_vsyscall", true},
53         {"__kernel_sigreturn", true},
54         {"__kernel_rt_sigreturn", true},
55 };
56
57 __attribute__((format(printf, 1, 2))) __attribute__((noreturn))
58 static void fail(const char *format, ...)
59 {
60         va_list ap;
61         va_start(ap, format);
62         fprintf(stderr, "Error: ");
63         vfprintf(stderr, format, ap);
64         unlink(outfilename);
65         exit(1);
66         va_end(ap);
67 }
68
69 /*
70  * Evil macros for little-endian reads and writes
71  */
72 #define GLE(x, bits, ifnot)                                             \
73         __builtin_choose_expr(                                          \
74                 (sizeof(*(x)) == bits/8),                               \
75                 (__typeof__(*(x)))get_unaligned_le##bits(x), ifnot)
76
77 extern void bad_get_le(void);
78 #define LAST_GLE(x)                                                     \
79         __builtin_choose_expr(sizeof(*(x)) == 1, *(x), bad_get_le())
80
81 #define GET_LE(x)                                                       \
82         GLE(x, 64, GLE(x, 32, GLE(x, 16, LAST_GLE(x))))
83
84 #define PLE(x, val, bits, ifnot)                                        \
85         __builtin_choose_expr(                                          \
86                 (sizeof(*(x)) == bits/8),                               \
87                 put_unaligned_le##bits((val), (x)), ifnot)
88
89 extern void bad_put_le(void);
90 #define LAST_PLE(x, val)                                                \
91         __builtin_choose_expr(sizeof(*(x)) == 1, *(x) = (val), bad_put_le())
92
93 #define PUT_LE(x, val)                                  \
94         PLE(x, val, 64, PLE(x, val, 32, PLE(x, val, 16, LAST_PLE(x, val))))
95
96
97 #define NSYMS (sizeof(required_syms) / sizeof(required_syms[0]))
98
99 #define BITSFUNC3(name, bits) name##bits
100 #define BITSFUNC2(name, bits) BITSFUNC3(name, bits)
101 #define BITSFUNC(name) BITSFUNC2(name, ELF_BITS)
102
103 #define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x
104 #define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x)
105 #define ELF(x) ELF_BITS_XFORM(ELF_BITS, x)
106
107 #define ELF_BITS 64
108 #include "vdso2c.h"
109 #undef ELF_BITS
110
111 #define ELF_BITS 32
112 #include "vdso2c.h"
113 #undef ELF_BITS
114
115 static void go(void *addr, size_t len, FILE *outfile, const char *name)
116 {
117         Elf64_Ehdr *hdr = (Elf64_Ehdr *)addr;
118
119         if (hdr->e_ident[EI_CLASS] == ELFCLASS64) {
120                 go64(addr, len, outfile, name);
121         } else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) {
122                 go32(addr, len, outfile, name);
123         } else {
124                 fail("unknown ELF class\n");
125         }
126 }
127
128 int main(int argc, char **argv)
129 {
130         int fd;
131         off_t len;
132         void *addr;
133         FILE *outfile;
134         char *name, *tmp;
135         int namelen;
136
137         if (argc != 3) {
138                 printf("Usage: vdso2c INPUT OUTPUT\n");
139                 return 1;
140         }
141
142         /*
143          * Figure out the struct name.  If we're writing to a .so file,
144          * generate raw output insted.
145          */
146         name = strdup(argv[2]);
147         namelen = strlen(name);
148         if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) {
149                 name = NULL;
150         } else {
151                 tmp = strrchr(name, '/');
152                 if (tmp)
153                         name = tmp + 1;
154                 tmp = strchr(name, '.');
155                 if (tmp)
156                         *tmp = '\0';
157                 for (tmp = name; *tmp; tmp++)
158                         if (*tmp == '-')
159                                 *tmp = '_';
160         }
161
162         fd = open(argv[1], O_RDONLY);
163         if (fd == -1)
164                 err(1, "%s", argv[1]);
165
166         len = lseek(fd, 0, SEEK_END);
167         if (len == (off_t)-1)
168                 err(1, "lseek");
169
170         addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
171         if (addr == MAP_FAILED)
172                 err(1, "mmap");
173
174         outfilename = argv[2];
175         outfile = fopen(outfilename, "w");
176         if (!outfile)
177                 err(1, "%s", argv[2]);
178
179         go(addr, (size_t)len, outfile, name);
180
181         munmap(addr, len);
182         fclose(outfile);
183
184         return 0;
185 }