Commit | Line | Data |
---|---|---|
7dbf4dcf JO |
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 | { | |
f9ceffb6 | 94 | struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true); |
7dbf4dcf JO |
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 | } |