vdso2c.c 3.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
#include <inttypes.h>
#include <stdint.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <err.h>

#include <sys/mman.h>
#include <sys/types.h>

14 15
#include <tools/le_byteshift.h>

16 17 18
#include <linux/elf.h>
#include <linux/types.h>

19 20
const char *outfilename;

21
/* Symbols that we need in vdso2c. */
22 23 24 25 26 27 28 29 30 31 32
enum {
	sym_vvar_page,
	sym_hpet_page,
	sym_end_mapping,
};

const int special_pages[] = {
	sym_vvar_page,
	sym_hpet_page,
};

33
char const * const required_syms[] = {
34 35 36
	[sym_vvar_page] = "vvar_page",
	[sym_hpet_page] = "hpet_page",
	[sym_end_mapping] = "end_mapping",
37 38 39 40 41 42 43 44 45 46 47 48 49 50
	"VDSO32_NOTE_MASK",
	"VDSO32_SYSENTER_RETURN",
	"__kernel_vsyscall",
	"__kernel_sigreturn",
	"__kernel_rt_sigreturn",
};

__attribute__((format(printf, 1, 2))) __attribute__((noreturn))
static void fail(const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	fprintf(stderr, "Error: ");
	vfprintf(stderr, format, ap);
51
	unlink(outfilename);
52 53 54 55
	exit(1);
	va_end(ap);
}

56
/*
57
 * Evil macros for little-endian reads and writes
58
 */
59
#define GLE(x, bits, ifnot)						\
60
	__builtin_choose_expr(						\
61 62
		(sizeof(*(x)) == bits/8),				\
		(__typeof__(*(x)))get_unaligned_le##bits(x), ifnot)
63

64
extern void bad_get_le(void);
65
#define LAST_GLE(x)							\
66
	__builtin_choose_expr(sizeof(*(x)) == 1, *(x), bad_get_le())
67

68
#define GET_LE(x)							\
69 70 71 72 73 74 75 76 77 78 79 80 81 82
	GLE(x, 64, GLE(x, 32, GLE(x, 16, LAST_GLE(x))))

#define PLE(x, val, bits, ifnot)					\
	__builtin_choose_expr(						\
		(sizeof(*(x)) == bits/8),				\
		put_unaligned_le##bits((val), (x)), ifnot)

extern void bad_put_le(void);
#define LAST_PLE(x, val)						\
	__builtin_choose_expr(sizeof(*(x)) == 1, *(x) = (val), bad_put_le())

#define PUT_LE(x, val)					\
	PLE(x, val, 64, PLE(x, val, 32, PLE(x, val, 16, LAST_PLE(x, val))))

83

84 85
#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0]))

86 87 88 89 90 91 92 93 94
#define BITSFUNC3(name, bits) name##bits
#define BITSFUNC2(name, bits) BITSFUNC3(name, bits)
#define BITSFUNC(name) BITSFUNC2(name, ELF_BITS)

#define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x
#define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x)
#define ELF(x) ELF_BITS_XFORM(ELF_BITS, x)

#define ELF_BITS 64
95
#include "vdso2c.h"
96 97 98
#undef ELF_BITS

#define ELF_BITS 32
99
#include "vdso2c.h"
100
#undef ELF_BITS
101

102
static void go(void *addr, size_t len, FILE *outfile, const char *name)
103 104 105 106
{
	Elf64_Ehdr *hdr = (Elf64_Ehdr *)addr;

	if (hdr->e_ident[EI_CLASS] == ELFCLASS64) {
107
		go64(addr, len, outfile, name);
108
	} else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) {
109
		go32(addr, len, outfile, name);
110
	} else {
111
		fail("unknown ELF class\n");
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
	}
}

int main(int argc, char **argv)
{
	int fd;
	off_t len;
	void *addr;
	FILE *outfile;
	char *name, *tmp;
	int namelen;

	if (argc != 3) {
		printf("Usage: vdso2c INPUT OUTPUT\n");
		return 1;
	}

	/*
	 * Figure out the struct name.  If we're writing to a .so file,
	 * generate raw output insted.
	 */
	name = strdup(argv[2]);
	namelen = strlen(name);
	if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) {
		name = NULL;
	} else {
		tmp = strrchr(name, '/');
		if (tmp)
			name = tmp + 1;
		tmp = strchr(name, '.');
		if (tmp)
			*tmp = '\0';
		for (tmp = name; *tmp; tmp++)
			if (*tmp == '-')
				*tmp = '_';
	}

	fd = open(argv[1], O_RDONLY);
	if (fd == -1)
		err(1, "%s", argv[1]);

	len = lseek(fd, 0, SEEK_END);
	if (len == (off_t)-1)
		err(1, "lseek");

	addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
	if (addr == MAP_FAILED)
		err(1, "mmap");

161 162
	outfilename = argv[2];
	outfile = fopen(outfilename, "w");
163 164 165
	if (!outfile)
		err(1, "%s", argv[2]);

166
	go(addr, (size_t)len, outfile, name);
167 168 169 170

	munmap(addr, len);
	fclose(outfile);

171
	return 0;
172
}