Linux-libre 3.12.19-gnu
[librecmc/linux-libre.git] / tools / perf / util / vdso.c
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, 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 }