xref: /linux/tools/perf/util/vdso.c (revision 4413e16d9d21673bb5048a2e542f1aaa00015c2e)
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 
16 static bool vdso_found;
17 static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX";
18 
19 static 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 
50 static 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 
86 void vdso__exit(void)
87 {
88 	if (vdso_found)
89 		unlink(vdso_file);
90 }
91 
92 struct dso *vdso__dso_findnew(struct list_head *head)
93 {
94 	struct dso *dso = dsos__find(head, VDSO__MAP_NAME);
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