[PATCH 10/17] perf, tool: Back [vdso] DSO with real data

From: Jiri Olsa
Date: Wed May 02 2012 - 07:38:27 EST


Storing data for VDSO shared object, because we need it for
the unwind process.

The idea is that VDSO shared object is same for all process
on a running system, so it makes no difference if we store
it inside the tracer - perf.

The record command:
When [vdso] map memory is hit, we retrieve [vdso] DSO image
and store it into temporary file. During the build-id
processing the [vdso] DSO image is stored in build-id db,
and build-id refference is made inside perf.data. The temporary
file is removed when record is finished.

The report command:
We read build-id from perf.data and store [vdso] DSO object.
This object is refferenced and attached to map when the MMAP
events are processed. Thus during the SAMPLE event processing
we have correct mmap/dso attached.

Adding following API for vdso object:
vdso__file
- vdso temp file path

vdso__get_file
- finds and store VDSO image into temp file,
the temp file path is returned

vdso__exit
- removes temporary VDSO image if there's any

Signed-off-by: Jiri Olsa <jolsa@xxxxxxxxxx>
---
tools/perf/Makefile | 2 +
tools/perf/util/map.c | 23 ++++++++++-
tools/perf/util/session.c | 2 +
tools/perf/util/vdso.c | 90 +++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/vdso.h | 8 ++++
5 files changed, 123 insertions(+), 2 deletions(-)
create mode 100644 tools/perf/util/vdso.c
create mode 100644 tools/perf/util/vdso.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7055a00..04e15d2 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -300,6 +300,7 @@ LIB_H += util/cpumap.h
LIB_H += util/top.h
LIB_H += $(ARCH_INCLUDE)
LIB_H += util/cgroup.h
+LIB_H += util/vdso.h

LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/alias.o
@@ -361,6 +362,7 @@ LIB_OBJS += $(OUTPUT)util/util.o
LIB_OBJS += $(OUTPUT)util/xyarray.o
LIB_OBJS += $(OUTPUT)util/cpumap.o
LIB_OBJS += $(OUTPUT)util/cgroup.o
+LIB_OBJS += $(OUTPUT)util/vdso.o

BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o

diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 35ae568..1649ea0 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -7,6 +7,7 @@
#include <stdio.h>
#include <unistd.h>
#include "map.h"
+#include "vdso.h"

const char *map_type__name[MAP__NR_TYPES] = {
[MAP__FUNCTION] = "Functions",
@@ -18,10 +19,14 @@ static inline int is_anon_memory(const char *filename)
return strcmp(filename, "//anon") == 0;
}

+static inline int is_vdso_memory(const char *filename)
+{
+ return !strcmp(filename, "[vdso]");
+}
+
static inline int is_no_dso_memory(const char *filename)
{
return !strcmp(filename, "[stack]") ||
- !strcmp(filename, "[vdso]") ||
!strcmp(filename, "[heap]");
}

@@ -50,9 +55,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
if (self != NULL) {
char newfilename[PATH_MAX];
struct dso *dso;
- int anon, no_dso;
+ int anon, no_dso, vdso;

anon = is_anon_memory(filename);
+ vdso = is_vdso_memory(filename);
no_dso = is_no_dso_memory(filename);

if (anon) {
@@ -60,10 +66,23 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
filename = newfilename;
}

+ if (vdso) {
+ filename = (char *) vdso__file;
+ pgoff = 0;
+ }
+
dso = __dsos__findnew(dsos__list, filename);
if (dso == NULL)
goto out_delete;

+ if (vdso && !dso->has_build_id) {
+ char *file_vdso = vdso__get_file();
+ if (file_vdso)
+ dso__set_long_name(dso, file_vdso);
+ else
+ no_dso = 1;
+ }
+
map__init(self, type, start, start + len, pgoff, dso);

if (anon || no_dso) {
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1efd3be..ae30ca5 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -14,6 +14,7 @@
#include "sort.h"
#include "util.h"
#include "cpumap.h"
+#include "vdso.h"

static int perf_session__open(struct perf_session *self, bool force)
{
@@ -209,6 +210,7 @@ void perf_session__delete(struct perf_session *self)
machine__exit(&self->host_machine);
close(self->fd);
free(self);
+ vdso__exit();
}

void machine__remove_thread(struct machine *self, struct thread *th)
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
new file mode 100644
index 0000000..e964482
--- /dev/null
+++ b/tools/perf/util/vdso.c
@@ -0,0 +1,90 @@
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/kernel.h>
+#include "vdso.h"
+#include "util.h"
+
+const char vdso__file[] = "/tmp/vdso.so";
+static bool vdso_found;
+
+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]", 6))
+ found = 1;
+ }
+
+ fclose(maps);
+ return !found;
+}
+
+char *vdso__get_file(void)
+{
+ char *vdso = NULL;
+ char *buf = NULL;
+ void *start, *end;
+
+ do {
+ int fd, size;
+
+ if (vdso_found) {
+ vdso = (char *) vdso__file;
+ break;
+ }
+
+ if (find_vdso_map(&start, &end))
+ break;
+
+ size = end - start;
+ buf = malloc(size);
+ if (!buf)
+ break;
+
+ memcpy(buf, start, size);
+
+ fd = open(vdso__file, O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
+ if (fd < 0)
+ break;
+
+ if (size == write(fd, buf, size))
+ vdso = (char *) vdso__file;
+
+ close(fd);
+ } while (0);
+
+ if (buf)
+ free(buf);
+
+ vdso_found = (vdso != NULL);
+ return vdso;
+}
+
+void vdso__exit(void)
+{
+ if (vdso_found)
+ unlink(vdso__file);
+}
diff --git a/tools/perf/util/vdso.h b/tools/perf/util/vdso.h
new file mode 100644
index 0000000..908b041
--- /dev/null
+++ b/tools/perf/util/vdso.h
@@ -0,0 +1,8 @@
+#ifndef __VDSO__
+#define __VDSO__
+
+extern const char vdso__file[];
+char *vdso__get_file(void);
+void vdso__exit(void);
+
+#endif /* __VDSO__ */
--
1.7.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/