aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@redhat.com>2012-09-10 12:50:19 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-09-11 11:08:30 -0400
commit7dbf4dcfe2987c35c2c4675cd7ae1b6006979176 (patch)
treece04e8dd07222ed105d32a5ecb7b45f5469c68c4 /tools
parent1c4be9ff5933e5c0f033ea98169cd89e22c90900 (diff)
perf tools: Back [vdso] DSO with real data
Storing data for VDSO shared object, because we need it for the post unwind processing. The VDSO shared object is same for all process on a running system, so it makes no difference when we store it inside the tracer - perf. When [vdso] map memory is hit, we retrieve [vdso] DSO image and store it into temporary file. During the build-id processing phase, the [vdso] DSO image is stored in build-id db, and build-id reference is made inside perf.data. The build-id vdso file object is called '[vdso]'. We don't use temporary file name which gets removed when record is finished. During report phase the vdso build-id object is treated as any other build-id DSO object. Adding following API for vdso object: bool is_vdso_map(const char *filename) - returns true if the filename matches vdso map name struct dso *vdso__dso_findnew(struct list_head *head) - find/create proper vdso DSO object vdso__exit(void) - removes temporary VDSO image if there's any This change makes backtrace dwarf post unwind possible from [vdso] maps. Following output is current report of [vdso] sample dwarf backtrace: # Overhead Command Shared Object Symbol # ........ ....... ................. ............................. # 99.52% ex [vdso] [.] 0x00007fff3ace89af | --- 0x7fff3ace89af Following output is new report of [vdso] sample dwarf backtrace: # Overhead Command Shared Object Symbol # ........ ....... ................. ............................. # 99.52% ex [vdso] [.] 0x00000000000009af | --- 0x7fff3ace89af main __libc_start_main _start Signed-off-by: Jiri Olsa <jolsa@redhat.com> Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1347295819-23177-5-git-send-email-jolsa@redhat.com [ committer note: s/ALIGN/PERF_ALIGN/g to cope with the android build changes ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Makefile2
-rw-r--r--tools/perf/builtin-buildid-cache.c3
-rw-r--r--tools/perf/util/header.c70
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/map.c12
-rw-r--r--tools/perf/util/session.c2
-rw-r--r--tools/perf/util/vdso.c111
-rw-r--r--tools/perf/util/vdso.h18
8 files changed, 194 insertions, 26 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 1d2723c01b8..209774bcee2 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -337,6 +337,7 @@ LIB_H += util/intlist.h
337LIB_H += util/perf_regs.h 337LIB_H += util/perf_regs.h
338LIB_H += util/unwind.h 338LIB_H += util/unwind.h
339LIB_H += ui/helpline.h 339LIB_H += ui/helpline.h
340LIB_H += util/vdso.h
340 341
341LIB_OBJS += $(OUTPUT)util/abspath.o 342LIB_OBJS += $(OUTPUT)util/abspath.o
342LIB_OBJS += $(OUTPUT)util/alias.o 343LIB_OBJS += $(OUTPUT)util/alias.o
@@ -404,6 +405,7 @@ LIB_OBJS += $(OUTPUT)util/cgroup.o
404LIB_OBJS += $(OUTPUT)util/target.o 405LIB_OBJS += $(OUTPUT)util/target.o
405LIB_OBJS += $(OUTPUT)util/rblist.o 406LIB_OBJS += $(OUTPUT)util/rblist.o
406LIB_OBJS += $(OUTPUT)util/intlist.o 407LIB_OBJS += $(OUTPUT)util/intlist.o
408LIB_OBJS += $(OUTPUT)util/vdso.o
407 409
408LIB_OBJS += $(OUTPUT)ui/helpline.o 410LIB_OBJS += $(OUTPUT)ui/helpline.o
409LIB_OBJS += $(OUTPUT)ui/hist.o 411LIB_OBJS += $(OUTPUT)ui/hist.o
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 29ad20e6791..995368e84e4 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -43,7 +43,8 @@ static int build_id_cache__add_file(const char *filename, const char *debugdir)
43 } 43 }
44 44
45 build_id__sprintf(build_id, sizeof(build_id), sbuild_id); 45 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
46 err = build_id_cache__add_s(sbuild_id, debugdir, filename, false); 46 err = build_id_cache__add_s(sbuild_id, debugdir, filename,
47 false, false);
47 if (verbose) 48 if (verbose)
48 pr_info("Adding %s %s: %s\n", sbuild_id, filename, 49 pr_info("Adding %s %s: %s\n", sbuild_id, filename,
49 err ? "FAIL" : "Ok"); 50 err ? "FAIL" : "Ok");
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 974e7589a6b..87996cab21d 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -21,6 +21,7 @@
21#include "debug.h" 21#include "debug.h"
22#include "cpumap.h" 22#include "cpumap.h"
23#include "pmu.h" 23#include "pmu.h"
24#include "vdso.h"
24 25
25static bool no_buildid_cache = false; 26static bool no_buildid_cache = false;
26 27
@@ -207,6 +208,29 @@ perf_header__set_cmdline(int argc, const char **argv)
207 continue; \ 208 continue; \
208 else 209 else
209 210
211static int write_buildid(char *name, size_t name_len, u8 *build_id,
212 pid_t pid, u16 misc, int fd)
213{
214 int err;
215 struct build_id_event b;
216 size_t len;
217
218 len = name_len + 1;
219 len = PERF_ALIGN(len, NAME_ALIGN);
220
221 memset(&b, 0, sizeof(b));
222 memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
223 b.pid = pid;
224 b.header.misc = misc;
225 b.header.size = sizeof(b) + len;
226
227 err = do_write(fd, &b, sizeof(b));
228 if (err < 0)
229 return err;
230
231 return write_padded(fd, name, name_len + 1, len);
232}
233
210static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, 234static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
211 u16 misc, int fd) 235 u16 misc, int fd)
212{ 236{
@@ -214,24 +238,23 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
214 238
215 dsos__for_each_with_build_id(pos, head) { 239 dsos__for_each_with_build_id(pos, head) {
216 int err; 240 int err;
217 struct build_id_event b; 241 char *name;
218 size_t len; 242 size_t name_len;
219 243
220 if (!pos->hit) 244 if (!pos->hit)
221 continue; 245 continue;
222 len = pos->long_name_len + 1; 246
223 len = PERF_ALIGN(len, NAME_ALIGN); 247 if (is_vdso_map(pos->short_name)) {
224 memset(&b, 0, sizeof(b)); 248 name = (char *) VDSO__MAP_NAME;
225 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 249 name_len = sizeof(VDSO__MAP_NAME) + 1;
226 b.pid = pid; 250 } else {
227 b.header.misc = misc; 251 name = pos->long_name;
228 b.header.size = sizeof(b) + len; 252 name_len = pos->long_name_len + 1;
229 err = do_write(fd, &b, sizeof(b)); 253 }
230 if (err < 0) 254
231 return err; 255 err = write_buildid(name, name_len, pos->build_id,
232 err = write_padded(fd, pos->long_name, 256 pid, misc, fd);
233 pos->long_name_len + 1, len); 257 if (err)
234 if (err < 0)
235 return err; 258 return err;
236 } 259 }
237 260
@@ -277,19 +300,20 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd)
277} 300}
278 301
279int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, 302int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
280 const char *name, bool is_kallsyms) 303 const char *name, bool is_kallsyms, bool is_vdso)
281{ 304{
282 const size_t size = PATH_MAX; 305 const size_t size = PATH_MAX;
283 char *realname, *filename = zalloc(size), 306 char *realname, *filename = zalloc(size),
284 *linkname = zalloc(size), *targetname; 307 *linkname = zalloc(size), *targetname;
285 int len, err = -1; 308 int len, err = -1;
309 bool slash = is_kallsyms || is_vdso;
286 310
287 if (is_kallsyms) { 311 if (is_kallsyms) {
288 if (symbol_conf.kptr_restrict) { 312 if (symbol_conf.kptr_restrict) {
289 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); 313 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
290 return 0; 314 return 0;
291 } 315 }
292 realname = (char *)name; 316 realname = (char *) name;
293 } else 317 } else
294 realname = realpath(name, NULL); 318 realname = realpath(name, NULL);
295 319
@@ -297,7 +321,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
297 goto out_free; 321 goto out_free;
298 322
299 len = scnprintf(filename, size, "%s%s%s", 323 len = scnprintf(filename, size, "%s%s%s",
300 debugdir, is_kallsyms ? "/" : "", realname); 324 debugdir, slash ? "/" : "",
325 is_vdso ? VDSO__MAP_NAME : realname);
301 if (mkdir_p(filename, 0755)) 326 if (mkdir_p(filename, 0755))
302 goto out_free; 327 goto out_free;
303 328
@@ -333,13 +358,14 @@ out_free:
333 358
334static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, 359static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
335 const char *name, const char *debugdir, 360 const char *name, const char *debugdir,
336 bool is_kallsyms) 361 bool is_kallsyms, bool is_vdso)
337{ 362{
338 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 363 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
339 364
340 build_id__sprintf(build_id, build_id_size, sbuild_id); 365 build_id__sprintf(build_id, build_id_size, sbuild_id);
341 366
342 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms); 367 return build_id_cache__add_s(sbuild_id, debugdir, name,
368 is_kallsyms, is_vdso);
343} 369}
344 370
345int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) 371int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
@@ -383,9 +409,11 @@ out_free:
383static int dso__cache_build_id(struct dso *dso, const char *debugdir) 409static int dso__cache_build_id(struct dso *dso, const char *debugdir)
384{ 410{
385 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 411 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
412 bool is_vdso = is_vdso_map(dso->short_name);
386 413
387 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), 414 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id),
388 dso->long_name, debugdir, is_kallsyms); 415 dso->long_name, debugdir,
416 is_kallsyms, is_vdso);
389} 417}
390 418
391static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) 419static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 9d5eedceda7..209dad4fee2 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -96,7 +96,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
96int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full); 96int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
97 97
98int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, 98int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
99 const char *name, bool is_kallsyms); 99 const char *name, bool is_kallsyms, bool is_vdso);
100int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); 100int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
101 101
102int perf_event__synthesize_attr(struct perf_tool *tool, 102int perf_event__synthesize_attr(struct perf_tool *tool,
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 7d37159c1e9..b442ee49452 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -9,6 +9,7 @@
9#include "map.h" 9#include "map.h"
10#include "thread.h" 10#include "thread.h"
11#include "strlist.h" 11#include "strlist.h"
12#include "vdso.h"
12 13
13const char *map_type__name[MAP__NR_TYPES] = { 14const char *map_type__name[MAP__NR_TYPES] = {
14 [MAP__FUNCTION] = "Functions", 15 [MAP__FUNCTION] = "Functions",
@@ -23,7 +24,6 @@ static inline int is_anon_memory(const char *filename)
23static inline int is_no_dso_memory(const char *filename) 24static inline int is_no_dso_memory(const char *filename)
24{ 25{
25 return !strcmp(filename, "[stack]") || 26 return !strcmp(filename, "[stack]") ||
26 !strcmp(filename, "[vdso]") ||
27 !strcmp(filename, "[heap]"); 27 !strcmp(filename, "[heap]");
28} 28}
29 29
@@ -52,9 +52,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
52 if (self != NULL) { 52 if (self != NULL) {
53 char newfilename[PATH_MAX]; 53 char newfilename[PATH_MAX];
54 struct dso *dso; 54 struct dso *dso;
55 int anon, no_dso; 55 int anon, no_dso, vdso;
56 56
57 anon = is_anon_memory(filename); 57 anon = is_anon_memory(filename);
58 vdso = is_vdso_map(filename);
58 no_dso = is_no_dso_memory(filename); 59 no_dso = is_no_dso_memory(filename);
59 60
60 if (anon) { 61 if (anon) {
@@ -62,7 +63,12 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
62 filename = newfilename; 63 filename = newfilename;
63 } 64 }
64 65
65 dso = __dsos__findnew(dsos__list, filename); 66 if (vdso) {
67 pgoff = 0;
68 dso = vdso__dso_findnew(dsos__list);
69 } else
70 dso = __dsos__findnew(dsos__list, filename);
71
66 if (dso == NULL) 72 if (dso == NULL)
67 goto out_delete; 73 goto out_delete;
68 74
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 0ecd62be209..e0fd6c71cc5 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -17,6 +17,7 @@
17#include "event-parse.h" 17#include "event-parse.h"
18#include "perf_regs.h" 18#include "perf_regs.h"
19#include "unwind.h" 19#include "unwind.h"
20#include "vdso.h"
20 21
21static int perf_session__open(struct perf_session *self, bool force) 22static int perf_session__open(struct perf_session *self, bool force)
22{ 23{
@@ -211,6 +212,7 @@ void perf_session__delete(struct perf_session *self)
211 machine__exit(&self->host_machine); 212 machine__exit(&self->host_machine);
212 close(self->fd); 213 close(self->fd);
213 free(self); 214 free(self);
215 vdso__exit();
214} 216}
215 217
216void machine__remove_thread(struct machine *self, struct thread *th) 218void 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 00000000000..e60951fcdb1
--- /dev/null
+++ b/tools/perf/util/vdso.c
@@ -0,0 +1,111 @@
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
16static bool vdso_found;
17static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX";
18
19static 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
50static 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
86void vdso__exit(void)
87{
88 if (vdso_found)
89 unlink(vdso_file);
90}
91
92struct dso *vdso__dso_findnew(struct list_head *head)
93{
94 struct dso *dso = dsos__find(head, VDSO__MAP_NAME);
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}
diff --git a/tools/perf/util/vdso.h b/tools/perf/util/vdso.h
new file mode 100644
index 00000000000..0f76e7caf6f
--- /dev/null
+++ b/tools/perf/util/vdso.h
@@ -0,0 +1,18 @@
1#ifndef __PERF_VDSO__
2#define __PERF_VDSO__
3
4#include <linux/types.h>
5#include <string.h>
6#include <stdbool.h>
7
8#define VDSO__MAP_NAME "[vdso]"
9
10static inline bool is_vdso_map(const char *filename)
11{
12 return !strcmp(filename, VDSO__MAP_NAME);
13}
14
15struct dso *vdso__dso_findnew(struct list_head *head);
16void vdso__exit(void);
17
18#endif /* __PERF_VDSO__ */