fix a kmap leak in virtio_console
[linux/fpc-iii.git] / tools / perf / util / vdso.c
blob0ddb3b8a89ecff40fc2626ec5937d2c1bb62a2ca
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>
11 #include "vdso.h"
12 #include "util.h"
13 #include "symbol.h"
14 #include "linux/string.h"
16 static bool vdso_found;
17 static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX";
19 static int find_vdso_map(void **start, void **end)
21 FILE *maps;
22 char line[128];
23 int found = 0;
25 maps = fopen("/proc/self/maps", "r");
26 if (!maps) {
27 pr_err("vdso: cannot open maps\n");
28 return -1;
31 while (!found && fgets(line, sizeof(line), maps)) {
32 int m = -1;
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;
41 if (!strncmp(&line[m], VDSO__MAP_NAME,
42 sizeof(VDSO__MAP_NAME) - 1))
43 found = 1;
46 fclose(maps);
47 return !found;
50 static char *get_file(void)
52 char *vdso = NULL;
53 char *buf = NULL;
54 void *start, *end;
55 size_t size;
56 int fd;
58 if (vdso_found)
59 return vdso_file;
61 if (find_vdso_map(&start, &end))
62 return NULL;
64 size = end - start;
66 buf = memdup(start, size);
67 if (!buf)
68 return NULL;
70 fd = mkstemp(vdso_file);
71 if (fd < 0)
72 goto out;
74 if (size == (size_t) write(fd, buf, size))
75 vdso = vdso_file;
77 close(fd);
79 out:
80 free(buf);
82 vdso_found = (vdso != NULL);
83 return vdso;
86 void vdso__exit(void)
88 if (vdso_found)
89 unlink(vdso_file);
92 struct dso *vdso__dso_findnew(struct list_head *head)
94 struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true);
96 if (!dso) {
97 char *file;
99 file = get_file();
100 if (!file)
101 return NULL;
103 dso = dso__new(VDSO__MAP_NAME);
104 if (dso != NULL) {
105 dsos__add(head, dso);
106 dso__set_long_name(dso, file, false);
110 return dso;