1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2015 Imagination Technologies
4*4882a593Smuzhiyun * Author: Alex Smith <alex.smith@imgtec.com>
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun /*
8*4882a593Smuzhiyun * This tool is used to generate the real VDSO images from the raw image. It
9*4882a593Smuzhiyun * first patches up the MIPS ABI flags and GNU attributes sections defined in
10*4882a593Smuzhiyun * elf.S to have the correct name and type. It then generates a C source file
11*4882a593Smuzhiyun * to be compiled into the kernel containing the VDSO image data and a
12*4882a593Smuzhiyun * mips_vdso_image struct for it, including symbol offsets extracted from the
13*4882a593Smuzhiyun * image.
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * We need to be passed both a stripped and unstripped VDSO image. The stripped
16*4882a593Smuzhiyun * image is compiled into the kernel, but we must also patch up the unstripped
17*4882a593Smuzhiyun * image's ABI flags sections so that it can be installed and used for
18*4882a593Smuzhiyun * debugging.
19*4882a593Smuzhiyun */
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <sys/mman.h>
22*4882a593Smuzhiyun #include <sys/stat.h>
23*4882a593Smuzhiyun #include <sys/types.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include <byteswap.h>
26*4882a593Smuzhiyun #include <elf.h>
27*4882a593Smuzhiyun #include <errno.h>
28*4882a593Smuzhiyun #include <fcntl.h>
29*4882a593Smuzhiyun #include <inttypes.h>
30*4882a593Smuzhiyun #include <stdarg.h>
31*4882a593Smuzhiyun #include <stdbool.h>
32*4882a593Smuzhiyun #include <stdio.h>
33*4882a593Smuzhiyun #include <stdlib.h>
34*4882a593Smuzhiyun #include <string.h>
35*4882a593Smuzhiyun #include <unistd.h>
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /* Define these in case the system elf.h is not new enough to have them. */
38*4882a593Smuzhiyun #ifndef SHT_GNU_ATTRIBUTES
39*4882a593Smuzhiyun # define SHT_GNU_ATTRIBUTES 0x6ffffff5
40*4882a593Smuzhiyun #endif
41*4882a593Smuzhiyun #ifndef SHT_MIPS_ABIFLAGS
42*4882a593Smuzhiyun # define SHT_MIPS_ABIFLAGS 0x7000002a
43*4882a593Smuzhiyun #endif
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun enum {
46*4882a593Smuzhiyun ABI_O32 = (1 << 0),
47*4882a593Smuzhiyun ABI_N32 = (1 << 1),
48*4882a593Smuzhiyun ABI_N64 = (1 << 2),
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun ABI_ALL = ABI_O32 | ABI_N32 | ABI_N64,
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* Symbols the kernel requires offsets for. */
54*4882a593Smuzhiyun static struct {
55*4882a593Smuzhiyun const char *name;
56*4882a593Smuzhiyun const char *offset_name;
57*4882a593Smuzhiyun unsigned int abis;
58*4882a593Smuzhiyun } vdso_symbols[] = {
59*4882a593Smuzhiyun { "__vdso_sigreturn", "off_sigreturn", ABI_O32 },
60*4882a593Smuzhiyun { "__vdso_rt_sigreturn", "off_rt_sigreturn", ABI_ALL },
61*4882a593Smuzhiyun {}
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun static const char *program_name;
65*4882a593Smuzhiyun static const char *vdso_name;
66*4882a593Smuzhiyun static unsigned char elf_class;
67*4882a593Smuzhiyun static unsigned int elf_abi;
68*4882a593Smuzhiyun static bool need_swap;
69*4882a593Smuzhiyun static FILE *out_file;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
72*4882a593Smuzhiyun # define HOST_ORDER ELFDATA2LSB
73*4882a593Smuzhiyun #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
74*4882a593Smuzhiyun # define HOST_ORDER ELFDATA2MSB
75*4882a593Smuzhiyun #endif
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun #define BUILD_SWAP(bits) \
78*4882a593Smuzhiyun static uint##bits##_t swap_uint##bits(uint##bits##_t val) \
79*4882a593Smuzhiyun { \
80*4882a593Smuzhiyun return need_swap ? bswap_##bits(val) : val; \
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun BUILD_SWAP(16)
84*4882a593Smuzhiyun BUILD_SWAP(32)
85*4882a593Smuzhiyun BUILD_SWAP(64)
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun #define __FUNC(name, bits) name##bits
88*4882a593Smuzhiyun #define _FUNC(name, bits) __FUNC(name, bits)
89*4882a593Smuzhiyun #define FUNC(name) _FUNC(name, ELF_BITS)
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun #define __ELF(x, bits) Elf##bits##_##x
92*4882a593Smuzhiyun #define _ELF(x, bits) __ELF(x, bits)
93*4882a593Smuzhiyun #define ELF(x) _ELF(x, ELF_BITS)
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /*
96*4882a593Smuzhiyun * Include genvdso.h twice with ELF_BITS defined differently to get functions
97*4882a593Smuzhiyun * for both ELF32 and ELF64.
98*4882a593Smuzhiyun */
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun #define ELF_BITS 64
101*4882a593Smuzhiyun #include "genvdso.h"
102*4882a593Smuzhiyun #undef ELF_BITS
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun #define ELF_BITS 32
105*4882a593Smuzhiyun #include "genvdso.h"
106*4882a593Smuzhiyun #undef ELF_BITS
107*4882a593Smuzhiyun
map_vdso(const char * path,size_t * _size)108*4882a593Smuzhiyun static void *map_vdso(const char *path, size_t *_size)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun int fd;
111*4882a593Smuzhiyun struct stat stat;
112*4882a593Smuzhiyun void *addr;
113*4882a593Smuzhiyun const Elf32_Ehdr *ehdr;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun fd = open(path, O_RDWR);
116*4882a593Smuzhiyun if (fd < 0) {
117*4882a593Smuzhiyun fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
118*4882a593Smuzhiyun path, strerror(errno));
119*4882a593Smuzhiyun return NULL;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if (fstat(fd, &stat) != 0) {
123*4882a593Smuzhiyun fprintf(stderr, "%s: Failed to stat '%s': %s\n", program_name,
124*4882a593Smuzhiyun path, strerror(errno));
125*4882a593Smuzhiyun close(fd);
126*4882a593Smuzhiyun return NULL;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun addr = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
130*4882a593Smuzhiyun 0);
131*4882a593Smuzhiyun if (addr == MAP_FAILED) {
132*4882a593Smuzhiyun fprintf(stderr, "%s: Failed to map '%s': %s\n", program_name,
133*4882a593Smuzhiyun path, strerror(errno));
134*4882a593Smuzhiyun close(fd);
135*4882a593Smuzhiyun return NULL;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /* ELF32/64 header formats are the same for the bits we're checking. */
139*4882a593Smuzhiyun ehdr = addr;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
142*4882a593Smuzhiyun fprintf(stderr, "%s: '%s' is not an ELF file\n", program_name,
143*4882a593Smuzhiyun path);
144*4882a593Smuzhiyun close(fd);
145*4882a593Smuzhiyun return NULL;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun elf_class = ehdr->e_ident[EI_CLASS];
149*4882a593Smuzhiyun switch (elf_class) {
150*4882a593Smuzhiyun case ELFCLASS32:
151*4882a593Smuzhiyun case ELFCLASS64:
152*4882a593Smuzhiyun break;
153*4882a593Smuzhiyun default:
154*4882a593Smuzhiyun fprintf(stderr, "%s: '%s' has invalid ELF class\n",
155*4882a593Smuzhiyun program_name, path);
156*4882a593Smuzhiyun close(fd);
157*4882a593Smuzhiyun return NULL;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun switch (ehdr->e_ident[EI_DATA]) {
161*4882a593Smuzhiyun case ELFDATA2LSB:
162*4882a593Smuzhiyun case ELFDATA2MSB:
163*4882a593Smuzhiyun need_swap = ehdr->e_ident[EI_DATA] != HOST_ORDER;
164*4882a593Smuzhiyun break;
165*4882a593Smuzhiyun default:
166*4882a593Smuzhiyun fprintf(stderr, "%s: '%s' has invalid ELF data order\n",
167*4882a593Smuzhiyun program_name, path);
168*4882a593Smuzhiyun close(fd);
169*4882a593Smuzhiyun return NULL;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun if (swap_uint16(ehdr->e_machine) != EM_MIPS) {
173*4882a593Smuzhiyun fprintf(stderr,
174*4882a593Smuzhiyun "%s: '%s' has invalid ELF machine (expected EM_MIPS)\n",
175*4882a593Smuzhiyun program_name, path);
176*4882a593Smuzhiyun close(fd);
177*4882a593Smuzhiyun return NULL;
178*4882a593Smuzhiyun } else if (swap_uint16(ehdr->e_type) != ET_DYN) {
179*4882a593Smuzhiyun fprintf(stderr,
180*4882a593Smuzhiyun "%s: '%s' has invalid ELF type (expected ET_DYN)\n",
181*4882a593Smuzhiyun program_name, path);
182*4882a593Smuzhiyun close(fd);
183*4882a593Smuzhiyun return NULL;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun *_size = stat.st_size;
187*4882a593Smuzhiyun close(fd);
188*4882a593Smuzhiyun return addr;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
patch_vdso(const char * path,void * vdso)191*4882a593Smuzhiyun static bool patch_vdso(const char *path, void *vdso)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun if (elf_class == ELFCLASS64)
194*4882a593Smuzhiyun return patch_vdso64(path, vdso);
195*4882a593Smuzhiyun else
196*4882a593Smuzhiyun return patch_vdso32(path, vdso);
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
get_symbols(const char * path,void * vdso)199*4882a593Smuzhiyun static bool get_symbols(const char *path, void *vdso)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun if (elf_class == ELFCLASS64)
202*4882a593Smuzhiyun return get_symbols64(path, vdso);
203*4882a593Smuzhiyun else
204*4882a593Smuzhiyun return get_symbols32(path, vdso);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
main(int argc,char ** argv)207*4882a593Smuzhiyun int main(int argc, char **argv)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun const char *dbg_vdso_path, *vdso_path, *out_path;
210*4882a593Smuzhiyun void *dbg_vdso, *vdso;
211*4882a593Smuzhiyun size_t dbg_vdso_size, vdso_size, i;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun program_name = argv[0];
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun if (argc < 4 || argc > 5) {
216*4882a593Smuzhiyun fprintf(stderr,
217*4882a593Smuzhiyun "Usage: %s <debug VDSO> <stripped VDSO> <output file> [<name>]\n",
218*4882a593Smuzhiyun program_name);
219*4882a593Smuzhiyun return EXIT_FAILURE;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun dbg_vdso_path = argv[1];
223*4882a593Smuzhiyun vdso_path = argv[2];
224*4882a593Smuzhiyun out_path = argv[3];
225*4882a593Smuzhiyun vdso_name = (argc > 4) ? argv[4] : "";
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun dbg_vdso = map_vdso(dbg_vdso_path, &dbg_vdso_size);
228*4882a593Smuzhiyun if (!dbg_vdso)
229*4882a593Smuzhiyun return EXIT_FAILURE;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun vdso = map_vdso(vdso_path, &vdso_size);
232*4882a593Smuzhiyun if (!vdso)
233*4882a593Smuzhiyun return EXIT_FAILURE;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun /* Patch both the VDSOs' ABI flags sections. */
236*4882a593Smuzhiyun if (!patch_vdso(dbg_vdso_path, dbg_vdso))
237*4882a593Smuzhiyun return EXIT_FAILURE;
238*4882a593Smuzhiyun if (!patch_vdso(vdso_path, vdso))
239*4882a593Smuzhiyun return EXIT_FAILURE;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun if (msync(dbg_vdso, dbg_vdso_size, MS_SYNC) != 0) {
242*4882a593Smuzhiyun fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
243*4882a593Smuzhiyun dbg_vdso_path, strerror(errno));
244*4882a593Smuzhiyun return EXIT_FAILURE;
245*4882a593Smuzhiyun } else if (msync(vdso, vdso_size, MS_SYNC) != 0) {
246*4882a593Smuzhiyun fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
247*4882a593Smuzhiyun vdso_path, strerror(errno));
248*4882a593Smuzhiyun return EXIT_FAILURE;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun out_file = fopen(out_path, "w");
252*4882a593Smuzhiyun if (!out_file) {
253*4882a593Smuzhiyun fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
254*4882a593Smuzhiyun out_path, strerror(errno));
255*4882a593Smuzhiyun return EXIT_FAILURE;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun fprintf(out_file, "/* Automatically generated - do not edit */\n");
259*4882a593Smuzhiyun fprintf(out_file, "#include <linux/linkage.h>\n");
260*4882a593Smuzhiyun fprintf(out_file, "#include <linux/mm.h>\n");
261*4882a593Smuzhiyun fprintf(out_file, "#include <asm/vdso.h>\n");
262*4882a593Smuzhiyun fprintf(out_file, "static int vdso_mremap(\n");
263*4882a593Smuzhiyun fprintf(out_file, " const struct vm_special_mapping *sm,\n");
264*4882a593Smuzhiyun fprintf(out_file, " struct vm_area_struct *new_vma)\n");
265*4882a593Smuzhiyun fprintf(out_file, "{\n");
266*4882a593Smuzhiyun fprintf(out_file, " unsigned long new_size =\n");
267*4882a593Smuzhiyun fprintf(out_file, " new_vma->vm_end - new_vma->vm_start;\n");
268*4882a593Smuzhiyun fprintf(out_file, " if (vdso_image.size != new_size)\n");
269*4882a593Smuzhiyun fprintf(out_file, " return -EINVAL;\n");
270*4882a593Smuzhiyun fprintf(out_file, " current->mm->context.vdso =\n");
271*4882a593Smuzhiyun fprintf(out_file, " (void *)(new_vma->vm_start);\n");
272*4882a593Smuzhiyun fprintf(out_file, " return 0;\n");
273*4882a593Smuzhiyun fprintf(out_file, "}\n");
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun /* Write out the stripped VDSO data. */
276*4882a593Smuzhiyun fprintf(out_file,
277*4882a593Smuzhiyun "static unsigned char vdso_data[PAGE_ALIGN(%zu)] __page_aligned_data = {\n\t",
278*4882a593Smuzhiyun vdso_size);
279*4882a593Smuzhiyun for (i = 0; i < vdso_size; i++) {
280*4882a593Smuzhiyun if (!(i % 10))
281*4882a593Smuzhiyun fprintf(out_file, "\n\t");
282*4882a593Smuzhiyun fprintf(out_file, "0x%02x, ", ((unsigned char *)vdso)[i]);
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun fprintf(out_file, "\n};\n");
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /* Preallocate a page array. */
287*4882a593Smuzhiyun fprintf(out_file,
288*4882a593Smuzhiyun "static struct page *vdso_pages[PAGE_ALIGN(%zu) / PAGE_SIZE];\n",
289*4882a593Smuzhiyun vdso_size);
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun fprintf(out_file, "struct mips_vdso_image vdso_image%s%s = {\n",
292*4882a593Smuzhiyun (vdso_name[0]) ? "_" : "", vdso_name);
293*4882a593Smuzhiyun fprintf(out_file, "\t.data = vdso_data,\n");
294*4882a593Smuzhiyun fprintf(out_file, "\t.size = PAGE_ALIGN(%zu),\n", vdso_size);
295*4882a593Smuzhiyun fprintf(out_file, "\t.mapping = {\n");
296*4882a593Smuzhiyun fprintf(out_file, "\t\t.name = \"[vdso]\",\n");
297*4882a593Smuzhiyun fprintf(out_file, "\t\t.pages = vdso_pages,\n");
298*4882a593Smuzhiyun fprintf(out_file, "\t\t.mremap = vdso_mremap,\n");
299*4882a593Smuzhiyun fprintf(out_file, "\t},\n");
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /* Calculate and write symbol offsets to <output file> */
302*4882a593Smuzhiyun if (!get_symbols(dbg_vdso_path, dbg_vdso)) {
303*4882a593Smuzhiyun unlink(out_path);
304*4882a593Smuzhiyun fclose(out_file);
305*4882a593Smuzhiyun return EXIT_FAILURE;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun fprintf(out_file, "};\n");
309*4882a593Smuzhiyun fclose(out_file);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun return EXIT_SUCCESS;
312*4882a593Smuzhiyun }
313