vdso.c 1.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/kernel.h>

#include "vdso.h"
#include "util.h"
#include "symbol.h"
#include "linux/string.h"
15
#include "debug.h"
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94

static bool vdso_found;
static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX";

static int find_vdso_map(void **start, void **end)
{
	FILE *maps;
	char line[128];
	int found = 0;

	maps = fopen("/proc/self/maps", "r");
	if (!maps) {
		pr_err("vdso: cannot open maps\n");
		return -1;
	}

	while (!found && fgets(line, sizeof(line), maps)) {
		int m = -1;

		/* We care only about private r-x mappings. */
		if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
				start, end, &m))
			continue;
		if (m < 0)
			continue;

		if (!strncmp(&line[m], VDSO__MAP_NAME,
			     sizeof(VDSO__MAP_NAME) - 1))
			found = 1;
	}

	fclose(maps);
	return !found;
}

static char *get_file(void)
{
	char *vdso = NULL;
	char *buf = NULL;
	void *start, *end;
	size_t size;
	int fd;

	if (vdso_found)
		return vdso_file;

	if (find_vdso_map(&start, &end))
		return NULL;

	size = end - start;

	buf = memdup(start, size);
	if (!buf)
		return NULL;

	fd = mkstemp(vdso_file);
	if (fd < 0)
		goto out;

	if (size == (size_t) write(fd, buf, size))
		vdso = vdso_file;

	close(fd);

 out:
	free(buf);

	vdso_found = (vdso != NULL);
	return vdso;
}

void vdso__exit(void)
{
	if (vdso_found)
		unlink(vdso_file);
}

struct dso *vdso__dso_findnew(struct list_head *head)
{
95
	struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true);
96 97 98 99 100 101 102 103 104 105 106

	if (!dso) {
		char *file;

		file = get_file();
		if (!file)
			return NULL;

		dso = dso__new(VDSO__MAP_NAME);
		if (dso != NULL) {
			dsos__add(head, dso);
107
			dso__set_long_name(dso, file, false);
108 109 110 111 112
		}
	}

	return dso;
}