xref: /OK3568_Linux_fs/kernel/arch/mips/vdso/genvdso.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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