1
2#include <unistd.h>
3#include <stdio.h>
4#include <string.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <stdlib.h>
9#include <linux/kernel.h>
10
11#include "vdso.h"
12#include "util.h"
13#include "symbol.h"
14#include "linux/string.h"
15
16static bool vdso_found;
17static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX";
18
19static int find_vdso_map(void **start, void **end)
20{
21	FILE *maps;
22	char line[128];
23	int found = 0;
24
25	maps = fopen("/proc/self/maps", "r");
26	if (!maps) {
27		pr_err("vdso: cannot open maps\n");
28		return -1;
29	}
30
31	while (!found && fgets(line, sizeof(line), maps)) {
32		int m = -1;
33
34		/* We care only about private r-x mappings. */
35		if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
36				start, end, &m))
37			continue;
38		if (m < 0)
39			continue;
40
41		if (!strncmp(&line[m], VDSO__MAP_NAME,
42			     sizeof(VDSO__MAP_NAME) - 1))
43			found = 1;
44	}
45
46	fclose(maps);
47	return !found;
48}
49
50static char *get_file(void)
51{
52	char *vdso = NULL;
53	char *buf = NULL;
54	void *start, *end;
55	size_t size;
56	int fd;
57
58	if (vdso_found)
59		return vdso_file;
60
61	if (find_vdso_map(&start, &end))
62		return NULL;
63
64	size = end - start;
65
66	buf = memdup(start, size);
67	if (!buf)
68		return NULL;
69
70	fd = mkstemp(vdso_file);
71	if (fd < 0)
72		goto out;
73
74	if (size == (size_t) write(fd, buf, size))
75		vdso = vdso_file;
76
77	close(fd);
78
79 out:
80	free(buf);
81
82	vdso_found = (vdso != NULL);
83	return vdso;
84}
85
86void vdso__exit(void)
87{
88	if (vdso_found)
89		unlink(vdso_file);
90}
91
92struct dso *vdso__dso_findnew(struct list_head *head)
93{
94	struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true);
95
96	if (!dso) {
97		char *file;
98
99		file = get_file();
100		if (!file)
101			return NULL;
102
103		dso = dso__new(VDSO__MAP_NAME);
104		if (dso != NULL) {
105			dsos__add(head, dso);
106			dso__set_long_name(dso, file);
107		}
108	}
109
110	return dso;
111}
112