Home | History | Annotate | Download | only in util
      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 }
    112