aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-archive.txt22
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt33
-rw-r--r--tools/perf/Documentation/perf-probe.txt20
-rw-r--r--tools/perf/Documentation/perf.txt2
-rw-r--r--tools/perf/Makefile14
-rw-r--r--tools/perf/builtin-annotate.c12
-rw-r--r--tools/perf/builtin-buildid-cache.c133
-rw-r--r--tools/perf/builtin-buildid-list.c40
-rw-r--r--tools/perf/builtin-diff.c74
-rw-r--r--tools/perf/builtin-help.c5
-rw-r--r--tools/perf/builtin-kmem.c46
-rw-r--r--tools/perf/builtin-probe.c79
-rw-r--r--tools/perf/builtin-record.c37
-rw-r--r--tools/perf/builtin-report.c58
-rw-r--r--tools/perf/builtin-sched.c32
-rw-r--r--tools/perf/builtin-stat.c106
-rw-r--r--tools/perf/builtin-timechart.c25
-rw-r--r--tools/perf/builtin-top.c36
-rw-r--r--tools/perf/builtin-trace.c29
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt2
-rw-r--r--tools/perf/design.txt8
-rw-r--r--tools/perf/perf-archive.sh32
-rw-r--r--tools/perf/perf.c3
-rw-r--r--tools/perf/util/data_map.c252
-rw-r--r--tools/perf/util/debug.c1
-rw-r--r--tools/perf/util/debugfs.c17
-rw-r--r--tools/perf/util/debugfs.h2
-rw-r--r--tools/perf/util/event.c214
-rw-r--r--tools/perf/util/event.h79
-rw-r--r--tools/perf/util/header.c278
-rw-r--r--tools/perf/util/header.h9
-rw-r--r--tools/perf/util/map.h73
-rw-r--r--tools/perf/util/parse-events.c48
-rw-r--r--tools/perf/util/probe-event.c105
-rw-r--r--tools/perf/util/probe-event.h2
-rw-r--r--tools/perf/util/probe-finder.c203
-rw-r--r--tools/perf/util/probe-finder.h33
-rw-r--r--tools/perf/util/session.c404
-rw-r--r--tools/perf/util/session.h42
-rw-r--r--tools/perf/util/string.c65
-rw-r--r--tools/perf/util/symbol.c398
-rw-r--r--tools/perf/util/symbol.h33
-rw-r--r--tools/perf/util/thread.h9
-rw-r--r--tools/perf/util/trace-event-info.c64
-rw-r--r--tools/perf/util/util.c94
-rw-r--r--tools/perf/util/util.h3
-rw-r--r--tools/perf/util/values.c1
48 files changed, 2386 insertions, 892 deletions
diff --git a/tools/perf/Documentation/perf-archive.txt b/tools/perf/Documentation/perf-archive.txt
new file mode 100644
index 000000000000..fae174dc7d01
--- /dev/null
+++ b/tools/perf/Documentation/perf-archive.txt
@@ -0,0 +1,22 @@
1perf-archive(1)
2===============
3
4NAME
5----
6perf-archive - Create archive with object files with build-ids found in perf.data file
7
8SYNOPSIS
9--------
10[verse]
11'perf archive' [file]
12
13DESCRIPTION
14-----------
15This command runs runs perf-buildid-list --with-hits, and collects the files
16with the buildids found so that analisys of perf.data contents can be possible
17on another machine.
18
19
20SEE ALSO
21--------
22linkperf:perf-record[1], linkperf:perf-buildid-list[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
new file mode 100644
index 000000000000..88bc3b519746
--- /dev/null
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -0,0 +1,33 @@
1perf-buildid-cache(1)
2=====================
3
4NAME
5----
6perf-buildid-cache - Manage build-id cache.
7
8SYNOPSIS
9--------
10[verse]
11'perf buildid-list <options>'
12
13DESCRIPTION
14-----------
15This command manages the build-id cache. It can add and remove files to the
16cache. In the future it should as well purge older entries, set upper limits
17for the space used by the cache, etc.
18
19OPTIONS
20-------
21-a::
22--add=::
23 Add specified file to the cache.
24-r::
25--remove=::
26 Remove specified file to the cache.
27-v::
28--verbose::
29 Be more verbose.
30
31SEE ALSO
32--------
33linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 250e391b4bc8..2de34075f6a4 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -15,6 +15,8 @@ or
15'perf probe' [options] --del='[GROUP:]EVENT' [...] 15'perf probe' [options] --del='[GROUP:]EVENT' [...]
16or 16or
17'perf probe' --list 17'perf probe' --list
18or
19'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
18 20
19DESCRIPTION 21DESCRIPTION
20----------- 22-----------
@@ -45,6 +47,11 @@ OPTIONS
45--list:: 47--list::
46 List up current probe events. 48 List up current probe events.
47 49
50-L::
51--line=::
52 Show source code lines which can be probed. This needs an argument
53 which specifies a range of the source code.
54
48PROBE SYNTAX 55PROBE SYNTAX
49------------ 56------------
50Probe points are defined by following syntax. 57Probe points are defined by following syntax.
@@ -56,6 +63,19 @@ Probe points are defined by following syntax.
56It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number. 63It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number.
57'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). 64'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
58 65
66LINE SYNTAX
67-----------
68Line range is descripted by following syntax.
69
70 "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]"
71
72FUNC specifies the function name of showing lines. 'RLN' is the start line
73number from function entry line, and 'RLN2' is the end line number. As same as
74probe syntax, 'SRC' means the source file path, 'ALN' is start line number,
75and 'ALN2' is end line number in the file. It is also possible to specify how
76many lines to show by using 'NUM'.
77So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function.
78
59SEE ALSO 79SEE ALSO
60-------- 80--------
61linkperf:perf-trace[1], linkperf:perf-record[1] 81linkperf:perf-trace[1], linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt
index 69c832557199..0eeb247dc7d2 100644
--- a/tools/perf/Documentation/perf.txt
+++ b/tools/perf/Documentation/perf.txt
@@ -12,7 +12,7 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15Performance counters for Linux are are a new kernel-based subsystem 15Performance counters for Linux are a new kernel-based subsystem
16that provide a framework for all things performance analysis. It 16that provide a framework for all things performance analysis. It
17covers hardware level (CPU/PMU, Performance Monitoring Unit) features 17covers hardware level (CPU/PMU, Performance Monitoring Unit) features
18and software features (software counters, tracepoints) as well. 18and software features (software counters, tracepoints) as well.
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 2e7fa3a06806..9b173e66fb41 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -286,11 +286,7 @@ SCRIPT_PERL =
286SCRIPT_SH = 286SCRIPT_SH =
287TEST_PROGRAMS = 287TEST_PROGRAMS =
288 288
289# 289SCRIPT_SH += perf-archive.sh
290# No scripts right now:
291#
292
293# SCRIPT_SH += perf-am.sh
294 290
295# 291#
296# No Perl scripts right now: 292# No Perl scripts right now:
@@ -315,9 +311,6 @@ PROGRAMS += perf
315# List built-in command $C whose implementation cmd_$C() is not in 311# List built-in command $C whose implementation cmd_$C() is not in
316# builtin-$C.o but is linked in as part of some other command. 312# builtin-$C.o but is linked in as part of some other command.
317# 313#
318# None right now:
319#
320# BUILT_INS += perf-init $X
321 314
322# what 'all' will build and 'install' will install, in perfexecdir 315# what 'all' will build and 'install' will install, in perfexecdir
323ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 316ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
@@ -369,6 +362,7 @@ LIB_H += util/event.h
369LIB_H += util/exec_cmd.h 362LIB_H += util/exec_cmd.h
370LIB_H += util/types.h 363LIB_H += util/types.h
371LIB_H += util/levenshtein.h 364LIB_H += util/levenshtein.h
365LIB_H += util/map.h
372LIB_H += util/parse-options.h 366LIB_H += util/parse-options.h
373LIB_H += util/parse-events.h 367LIB_H += util/parse-events.h
374LIB_H += util/quote.h 368LIB_H += util/quote.h
@@ -435,8 +429,8 @@ LIB_OBJS += util/trace-event-perl.o
435LIB_OBJS += util/svghelper.o 429LIB_OBJS += util/svghelper.o
436LIB_OBJS += util/sort.o 430LIB_OBJS += util/sort.o
437LIB_OBJS += util/hist.o 431LIB_OBJS += util/hist.o
438LIB_OBJS += util/data_map.o
439LIB_OBJS += util/probe-event.o 432LIB_OBJS += util/probe-event.o
433LIB_OBJS += util/util.o
440 434
441BUILTIN_OBJS += builtin-annotate.o 435BUILTIN_OBJS += builtin-annotate.o
442 436
@@ -451,6 +445,7 @@ BUILTIN_OBJS += builtin-diff.o
451BUILTIN_OBJS += builtin-help.o 445BUILTIN_OBJS += builtin-help.o
452BUILTIN_OBJS += builtin-sched.o 446BUILTIN_OBJS += builtin-sched.o
453BUILTIN_OBJS += builtin-buildid-list.o 447BUILTIN_OBJS += builtin-buildid-list.o
448BUILTIN_OBJS += builtin-buildid-cache.o
454BUILTIN_OBJS += builtin-list.o 449BUILTIN_OBJS += builtin-list.o
455BUILTIN_OBJS += builtin-record.o 450BUILTIN_OBJS += builtin-record.o
456BUILTIN_OBJS += builtin-report.o 451BUILTIN_OBJS += builtin-report.o
@@ -1009,6 +1004,7 @@ install: all
1009 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 1004 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
1010 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 1005 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1011 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 1006 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1007 $(INSTALL) perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1012 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 1008 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1013 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl' 1009 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
1014 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 1010 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 593ff25006de..73c202ee0882 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -132,8 +132,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
132{ 132{
133 struct addr_location al; 133 struct addr_location al;
134 134
135 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 135 dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
136 event->ip.pid, (void *)(long)event->ip.ip); 136 event->ip.pid, event->ip.ip);
137 137
138 if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) { 138 if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) {
139 fprintf(stderr, "problem processing %d event, skipping it.\n", 139 fprintf(stderr, "problem processing %d event, skipping it.\n",
@@ -451,10 +451,10 @@ static void perf_session__find_annotations(struct perf_session *self)
451} 451}
452 452
453static struct perf_event_ops event_ops = { 453static struct perf_event_ops event_ops = {
454 .process_sample_event = process_sample_event, 454 .sample = process_sample_event,
455 .process_mmap_event = event__process_mmap, 455 .mmap = event__process_mmap,
456 .process_comm_event = event__process_comm, 456 .comm = event__process_comm,
457 .process_fork_event = event__process_task, 457 .fork = event__process_task,
458}; 458};
459 459
460static int __cmd_annotate(void) 460static int __cmd_annotate(void)
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
new file mode 100644
index 000000000000..30a05f552c96
--- /dev/null
+++ b/tools/perf/builtin-buildid-cache.c
@@ -0,0 +1,133 @@
1/*
2 * builtin-buildid-cache.c
3 *
4 * Builtin buildid-cache command: Manages build-id cache
5 *
6 * Copyright (C) 2010, Red Hat Inc.
7 * Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "builtin.h"
10#include "perf.h"
11#include "util/cache.h"
12#include "util/debug.h"
13#include "util/header.h"
14#include "util/parse-options.h"
15#include "util/strlist.h"
16#include "util/symbol.h"
17
18static char const *add_name_list_str, *remove_name_list_str;
19
20static const char * const buildid_cache_usage[] = {
21 "perf buildid-cache [<options>]",
22 NULL
23};
24
25static const struct option buildid_cache_options[] = {
26 OPT_STRING('a', "add", &add_name_list_str,
27 "file list", "file(s) to add"),
28 OPT_STRING('r', "remove", &remove_name_list_str, "file list",
29 "file(s) to remove"),
30 OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose"),
31 OPT_END()
32};
33
34static int build_id_cache__add_file(const char *filename, const char *debugdir)
35{
36 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
37 u8 build_id[BUILD_ID_SIZE];
38 int err;
39
40 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
41 pr_debug("Couldn't read a build-id in %s\n", filename);
42 return -1;
43 }
44
45 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
46 err = build_id_cache__add_s(sbuild_id, debugdir, filename, false);
47 if (verbose)
48 pr_info("Adding %s %s: %s\n", sbuild_id, filename,
49 err ? "FAIL" : "Ok");
50 return err;
51}
52
53static int build_id_cache__remove_file(const char *filename __used,
54 const char *debugdir __used)
55{
56 u8 build_id[BUILD_ID_SIZE];
57 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
58
59 int err;
60
61 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
62 pr_debug("Couldn't read a build-id in %s\n", filename);
63 return -1;
64 }
65
66 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
67 err = build_id_cache__remove_s(sbuild_id, debugdir);
68 if (verbose)
69 pr_info("Removing %s %s: %s\n", sbuild_id, filename,
70 err ? "FAIL" : "Ok");
71
72 return err;
73}
74
75static int __cmd_buildid_cache(void)
76{
77 struct strlist *list;
78 struct str_node *pos;
79 char debugdir[PATH_MAX];
80
81 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
82 DEBUG_CACHE_DIR);
83
84 if (add_name_list_str) {
85 list = strlist__new(true, add_name_list_str);
86 if (list) {
87 strlist__for_each(pos, list)
88 if (build_id_cache__add_file(pos->s, debugdir)) {
89 if (errno == EEXIST) {
90 pr_debug("%s already in the cache\n",
91 pos->s);
92 continue;
93 }
94 pr_warning("Couldn't add %s: %s\n",
95 pos->s, strerror(errno));
96 }
97
98 strlist__delete(list);
99 }
100 }
101
102 if (remove_name_list_str) {
103 list = strlist__new(true, remove_name_list_str);
104 if (list) {
105 strlist__for_each(pos, list)
106 if (build_id_cache__remove_file(pos->s, debugdir)) {
107 if (errno == ENOENT) {
108 pr_debug("%s wasn't in the cache\n",
109 pos->s);
110 continue;
111 }
112 pr_warning("Couldn't remove %s: %s\n",
113 pos->s, strerror(errno));
114 }
115
116 strlist__delete(list);
117 }
118 }
119
120 return 0;
121}
122
123int cmd_buildid_cache(int argc, const char **argv, const char *prefix __used)
124{
125 argc = parse_options(argc, argv, buildid_cache_options,
126 buildid_cache_usage, 0);
127
128 if (symbol__init() < 0)
129 return -1;
130
131 setup_pager();
132 return __cmd_buildid_cache();
133}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 1e99ac806913..431f204bde64 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -16,6 +16,7 @@
16 16
17static char const *input_name = "perf.data"; 17static char const *input_name = "perf.data";
18static int force; 18static int force;
19static bool with_hits;
19 20
20static const char * const buildid_list_usage[] = { 21static const char * const buildid_list_usage[] = {
21 "perf buildid-list [<options>]", 22 "perf buildid-list [<options>]",
@@ -23,6 +24,7 @@ static const char * const buildid_list_usage[] = {
23}; 24};
24 25
25static const struct option options[] = { 26static const struct option options[] = {
27 OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"),
26 OPT_STRING('i', "input", &input_name, "file", 28 OPT_STRING('i', "input", &input_name, "file",
27 "input file name"), 29 "input file name"),
28 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 30 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
@@ -31,26 +33,34 @@ static const struct option options[] = {
31 OPT_END() 33 OPT_END()
32}; 34};
33 35
34static int perf_file_section__process_buildids(struct perf_file_section *self, 36static int build_id_list__process_event(event_t *event,
35 int feat, int fd) 37 struct perf_session *session)
36{ 38{
37 if (feat != HEADER_BUILD_ID) 39 struct addr_location al;
38 return 0; 40 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
41 struct thread *thread = perf_session__findnew(session, event->ip.pid);
39 42
40 if (lseek(fd, self->offset, SEEK_SET) < 0) { 43 if (thread == NULL) {
41 pr_warning("Failed to lseek to %Ld offset for buildids!\n", 44 pr_err("problem processing %d event, skipping it.\n",
42 self->offset); 45 event->header.type);
43 return -1; 46 return -1;
44 } 47 }
45 48
46 if (perf_header__read_build_ids(fd, self->offset, self->size)) { 49 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
47 pr_warning("Failed to read buildids!\n"); 50 event->ip.ip, &al);
48 return -1; 51
49 } 52 if (al.map != NULL)
53 al.map->dso->hit = 1;
50 54
51 return 0; 55 return 0;
52} 56}
53 57
58static struct perf_event_ops build_id_list__event_ops = {
59 .sample = build_id_list__process_event,
60 .mmap = event__process_mmap,
61 .fork = event__process_task,
62};
63
54static int __cmd_buildid_list(void) 64static int __cmd_buildid_list(void)
55{ 65{
56 int err = -1; 66 int err = -1;
@@ -60,10 +70,10 @@ static int __cmd_buildid_list(void)
60 if (session == NULL) 70 if (session == NULL)
61 return -1; 71 return -1;
62 72
63 err = perf_header__process_sections(&session->header, session->fd, 73 if (with_hits)
64 perf_file_section__process_buildids); 74 perf_session__process_events(session, &build_id_list__event_ops);
65 if (err >= 0) 75
66 dsos__fprintf_buildid(stdout); 76 dsos__fprintf_buildid(stdout, with_hits);
67 77
68 perf_session__delete(session); 78 perf_session__delete(session);
69 return err; 79 return err;
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index bd71b8ceafb7..18b3f505f9db 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -42,8 +42,8 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
42 struct addr_location al; 42 struct addr_location al;
43 struct sample_data data = { .period = 1, }; 43 struct sample_data data = { .period = 1, };
44 44
45 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 45 dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
46 event->ip.pid, (void *)(long)event->ip.ip); 46 event->ip.pid, event->ip.ip);
47 47
48 if (event__preprocess_sample(event, session, &al, NULL) < 0) { 48 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
49 pr_warning("problem processing %d event, skipping it.\n", 49 pr_warning("problem processing %d event, skipping it.\n",
@@ -51,12 +51,12 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
51 return -1; 51 return -1;
52 } 52 }
53 53
54 if (al.filtered) 54 if (al.filtered || al.sym == NULL)
55 return 0; 55 return 0;
56 56
57 event__parse_sample(event, session->sample_type, &data); 57 event__parse_sample(event, session->sample_type, &data);
58 58
59 if (al.sym && perf_session__add_hist_entry(session, &al, data.period)) { 59 if (perf_session__add_hist_entry(session, &al, data.period)) {
60 pr_warning("problem incrementing symbol count, skipping event\n"); 60 pr_warning("problem incrementing symbol count, skipping event\n");
61 return -1; 61 return -1;
62 } 62 }
@@ -66,12 +66,12 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
66} 66}
67 67
68static struct perf_event_ops event_ops = { 68static struct perf_event_ops event_ops = {
69 .process_sample_event = diff__process_sample_event, 69 .sample = diff__process_sample_event,
70 .process_mmap_event = event__process_mmap, 70 .mmap = event__process_mmap,
71 .process_comm_event = event__process_comm, 71 .comm = event__process_comm,
72 .process_exit_event = event__process_task, 72 .exit = event__process_task,
73 .process_fork_event = event__process_task, 73 .fork = event__process_task,
74 .process_lost_event = event__process_lost, 74 .lost = event__process_lost,
75}; 75};
76 76
77static void perf_session__insert_hist_entry_by_name(struct rb_root *root, 77static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
@@ -82,29 +82,19 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
82 struct hist_entry *iter; 82 struct hist_entry *iter;
83 83
84 while (*p != NULL) { 84 while (*p != NULL) {
85 int cmp;
86 parent = *p; 85 parent = *p;
87 iter = rb_entry(parent, struct hist_entry, rb_node); 86 iter = rb_entry(parent, struct hist_entry, rb_node);
88 87 if (hist_entry__cmp(he, iter) < 0)
89 cmp = strcmp(he->map->dso->name, iter->map->dso->name);
90 if (cmp > 0)
91 p = &(*p)->rb_left; 88 p = &(*p)->rb_left;
92 else if (cmp < 0) 89 else
93 p = &(*p)->rb_right; 90 p = &(*p)->rb_right;
94 else {
95 cmp = strcmp(he->sym->name, iter->sym->name);
96 if (cmp > 0)
97 p = &(*p)->rb_left;
98 else
99 p = &(*p)->rb_right;
100 }
101 } 91 }
102 92
103 rb_link_node(&he->rb_node, parent, p); 93 rb_link_node(&he->rb_node, parent, p);
104 rb_insert_color(&he->rb_node, root); 94 rb_insert_color(&he->rb_node, root);
105} 95}
106 96
107static void perf_session__resort_by_name(struct perf_session *self) 97static void perf_session__resort_hist_entries(struct perf_session *self)
108{ 98{
109 unsigned long position = 1; 99 unsigned long position = 1;
110 struct rb_root tmp = RB_ROOT; 100 struct rb_root tmp = RB_ROOT;
@@ -122,29 +112,28 @@ static void perf_session__resort_by_name(struct perf_session *self)
122 self->hists = tmp; 112 self->hists = tmp;
123} 113}
124 114
115static void perf_session__set_hist_entries_positions(struct perf_session *self)
116{
117 perf_session__output_resort(self, self->events_stats.total);
118 perf_session__resort_hist_entries(self);
119}
120
125static struct hist_entry * 121static struct hist_entry *
126perf_session__find_hist_entry_by_name(struct perf_session *self, 122perf_session__find_hist_entry(struct perf_session *self,
127 struct hist_entry *he) 123 struct hist_entry *he)
128{ 124{
129 struct rb_node *n = self->hists.rb_node; 125 struct rb_node *n = self->hists.rb_node;
130 126
131 while (n) { 127 while (n) {
132 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); 128 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
133 int cmp = strcmp(he->map->dso->name, iter->map->dso->name); 129 int64_t cmp = hist_entry__cmp(he, iter);
134 130
135 if (cmp > 0) 131 if (cmp < 0)
136 n = n->rb_left; 132 n = n->rb_left;
137 else if (cmp < 0) 133 else if (cmp > 0)
138 n = n->rb_right; 134 n = n->rb_right;
139 else { 135 else
140 cmp = strcmp(he->sym->name, iter->sym->name); 136 return iter;
141 if (cmp > 0)
142 n = n->rb_left;
143 else if (cmp < 0)
144 n = n->rb_right;
145 else
146 return iter;
147 }
148 } 137 }
149 138
150 return NULL; 139 return NULL;
@@ -155,11 +144,9 @@ static void perf_session__match_hists(struct perf_session *old_session,
155{ 144{
156 struct rb_node *nd; 145 struct rb_node *nd;
157 146
158 perf_session__resort_by_name(old_session);
159
160 for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) { 147 for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) {
161 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node); 148 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
162 pos->pair = perf_session__find_hist_entry_by_name(old_session, pos); 149 pos->pair = perf_session__find_hist_entry(old_session, pos);
163 } 150 }
164} 151}
165 152
@@ -177,9 +164,12 @@ static int __cmd_diff(void)
177 ret = perf_session__process_events(session[i], &event_ops); 164 ret = perf_session__process_events(session[i], &event_ops);
178 if (ret) 165 if (ret)
179 goto out_delete; 166 goto out_delete;
180 perf_session__output_resort(session[i], session[i]->events_stats.total);
181 } 167 }
182 168
169 perf_session__output_resort(session[1], session[1]->events_stats.total);
170 if (show_displacement)
171 perf_session__set_hist_entries_positions(session[0]);
172
183 perf_session__match_hists(session[0], session[1]); 173 perf_session__match_hists(session[0], session[1]);
184 perf_session__fprintf_hists(session[1], session[0], 174 perf_session__fprintf_hists(session[1], session[0],
185 show_displacement, stdout); 175 show_displacement, stdout);
@@ -204,7 +194,7 @@ static const struct option options[] = {
204 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 194 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
205 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 195 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
206 "load module symbols - WARNING: use only with -k and LIVE kernel"), 196 "load module symbols - WARNING: use only with -k and LIVE kernel"),
207 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, 197 OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
208 "Don't shorten the pathnames taking into account the cwd"), 198 "Don't shorten the pathnames taking into account the cwd"),
209 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 199 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
210 "only consider symbols in these dsos"), 200 "only consider symbols in these dsos"),
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 9f810b17c25c..215b584007b1 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -286,8 +286,7 @@ void list_common_cmds_help(void)
286 286
287 puts(" The most commonly used perf commands are:"); 287 puts(" The most commonly used perf commands are:");
288 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { 288 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
289 printf(" %s ", common_cmds[i].name); 289 printf(" %-*s ", longest, common_cmds[i].name);
290 mput_char(' ', longest - strlen(common_cmds[i].name));
291 puts(common_cmds[i].help); 290 puts(common_cmds[i].help);
292 } 291 }
293} 292}
@@ -314,8 +313,6 @@ static const char *cmd_to_page(const char *perf_cmd)
314 return "perf"; 313 return "perf";
315 else if (!prefixcmp(perf_cmd, "perf")) 314 else if (!prefixcmp(perf_cmd, "perf"))
316 return perf_cmd; 315 return perf_cmd;
317 else if (is_perf_command(perf_cmd))
318 return prepend("perf-", perf_cmd);
319 else 316 else
320 return prepend("perf-", perf_cmd); 317 return prepend("perf-", perf_cmd);
321} 318}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 93c67bf53d2c..5d5dc6b09617 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -92,23 +92,18 @@ static void setup_cpunode_map(void)
92 if (!dir1) 92 if (!dir1)
93 return; 93 return;
94 94
95 while (true) { 95 while ((dent1 = readdir(dir1)) != NULL) {
96 dent1 = readdir(dir1); 96 if (dent1->d_type != DT_DIR ||
97 if (!dent1) 97 sscanf(dent1->d_name, "node%u", &mem) < 1)
98 break;
99
100 if (sscanf(dent1->d_name, "node%u", &mem) < 1)
101 continue; 98 continue;
102 99
103 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name); 100 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
104 dir2 = opendir(buf); 101 dir2 = opendir(buf);
105 if (!dir2) 102 if (!dir2)
106 continue; 103 continue;
107 while (true) { 104 while ((dent2 = readdir(dir2)) != NULL) {
108 dent2 = readdir(dir2); 105 if (dent2->d_type != DT_LNK ||
109 if (!dent2) 106 sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
110 break;
111 if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
112 continue; 107 continue;
113 cpunode_map[cpu] = mem; 108 cpunode_map[cpu] = mem;
114 } 109 }
@@ -321,11 +316,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
321 316
322 event__parse_sample(event, session->sample_type, &data); 317 event__parse_sample(event, session->sample_type, &data);
323 318
324 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 319 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
325 event->header.misc, 320 data.pid, data.tid, data.ip, data.period);
326 data.pid, data.tid,
327 (void *)(long)data.ip,
328 (long long)data.period);
329 321
330 thread = perf_session__findnew(session, event->ip.pid); 322 thread = perf_session__findnew(session, event->ip.pid);
331 if (thread == NULL) { 323 if (thread == NULL) {
@@ -342,22 +334,9 @@ static int process_sample_event(event_t *event, struct perf_session *session)
342 return 0; 334 return 0;
343} 335}
344 336
345static int sample_type_check(struct perf_session *session)
346{
347 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
348 fprintf(stderr,
349 "No trace sample to read. Did you call perf record "
350 "without -R?");
351 return -1;
352 }
353
354 return 0;
355}
356
357static struct perf_event_ops event_ops = { 337static struct perf_event_ops event_ops = {
358 .process_sample_event = process_sample_event, 338 .sample = process_sample_event,
359 .process_comm_event = event__process_comm, 339 .comm = event__process_comm,
360 .sample_type_check = sample_type_check,
361}; 340};
362 341
363static double fragmentation(unsigned long n_req, unsigned long n_alloc) 342static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -504,11 +483,14 @@ static void sort_result(void)
504 483
505static int __cmd_kmem(void) 484static int __cmd_kmem(void)
506{ 485{
507 int err; 486 int err = -EINVAL;
508 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 487 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
509 if (session == NULL) 488 if (session == NULL)
510 return -ENOMEM; 489 return -ENOMEM;
511 490
491 if (!perf_session__has_traces(session, "kmem record"))
492 goto out_delete;
493
512 setup_pager(); 494 setup_pager();
513 err = perf_session__process_events(session, &event_ops); 495 err = perf_session__process_events(session, &event_ops);
514 if (err != 0) 496 if (err != 0)
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index c1e6774fd3ed..34f2acb1cc88 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -55,11 +55,13 @@ static struct {
55 bool need_dwarf; 55 bool need_dwarf;
56 bool list_events; 56 bool list_events;
57 bool force_add; 57 bool force_add;
58 bool show_lines;
58 int nr_probe; 59 int nr_probe;
59 struct probe_point probes[MAX_PROBES]; 60 struct probe_point probes[MAX_PROBES];
60 struct strlist *dellist; 61 struct strlist *dellist;
61 struct perf_session *psession; 62 struct perf_session *psession;
62 struct map *kmap; 63 struct map *kmap;
64 struct line_range line_range;
63} session; 65} session;
64 66
65 67
@@ -137,6 +139,16 @@ static int open_vmlinux(void)
137 pr_debug("Try to open %s\n", session.kmap->dso->long_name); 139 pr_debug("Try to open %s\n", session.kmap->dso->long_name);
138 return open(session.kmap->dso->long_name, O_RDONLY); 140 return open(session.kmap->dso->long_name, O_RDONLY);
139} 141}
142
143static int opt_show_lines(const struct option *opt __used,
144 const char *str, int unset __used)
145{
146 if (str)
147 parse_line_range_desc(str, &session.line_range);
148 INIT_LIST_HEAD(&session.line_range.line_list);
149 session.show_lines = true;
150 return 0;
151}
140#endif 152#endif
141 153
142static const char * const probe_usage[] = { 154static const char * const probe_usage[] = {
@@ -144,6 +156,7 @@ static const char * const probe_usage[] = {
144 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 156 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
145 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 157 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
146 "perf probe --list", 158 "perf probe --list",
159 "perf probe --line 'LINEDESC'",
147 NULL 160 NULL
148}; 161};
149 162
@@ -182,9 +195,32 @@ static const struct option options[] = {
182 opt_add_probe_event), 195 opt_add_probe_event),
183 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events" 196 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events"
184 " with existing name"), 197 " with existing name"),
198#ifndef NO_LIBDWARF
199 OPT_CALLBACK('L', "line", NULL,
200 "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]",
201 "Show source code lines.", opt_show_lines),
202#endif
185 OPT_END() 203 OPT_END()
186}; 204};
187 205
206/* Initialize symbol maps for vmlinux */
207static void init_vmlinux(void)
208{
209 symbol_conf.sort_by_name = true;
210 if (symbol_conf.vmlinux_name == NULL)
211 symbol_conf.try_vmlinux_path = true;
212 else
213 pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
214 if (symbol__init() < 0)
215 die("Failed to init symbol map.");
216 session.psession = perf_session__new(NULL, O_WRONLY, false);
217 if (session.psession == NULL)
218 die("Failed to init perf_session.");
219 session.kmap = session.psession->vmlinux_maps[MAP__FUNCTION];
220 if (!session.kmap)
221 die("Could not find kernel map.\n");
222}
223
188int cmd_probe(int argc, const char **argv, const char *prefix __used) 224int cmd_probe(int argc, const char **argv, const char *prefix __used)
189{ 225{
190 int i, ret; 226 int i, ret;
@@ -203,7 +239,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
203 parse_probe_event_argv(argc, argv); 239 parse_probe_event_argv(argc, argv);
204 } 240 }
205 241
206 if ((!session.nr_probe && !session.dellist && !session.list_events)) 242 if ((!session.nr_probe && !session.dellist && !session.list_events &&
243 !session.show_lines))
207 usage_with_options(probe_usage, options); 244 usage_with_options(probe_usage, options);
208 245
209 if (debugfs_valid_mountpoint(debugfs_path) < 0) 246 if (debugfs_valid_mountpoint(debugfs_path) < 0)
@@ -215,10 +252,34 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
215 " --add/--del.\n"); 252 " --add/--del.\n");
216 usage_with_options(probe_usage, options); 253 usage_with_options(probe_usage, options);
217 } 254 }
255 if (session.show_lines) {
256 pr_warning(" Error: Don't use --list with --line.\n");
257 usage_with_options(probe_usage, options);
258 }
218 show_perf_probe_events(); 259 show_perf_probe_events();
219 return 0; 260 return 0;
220 } 261 }
221 262
263#ifndef NO_LIBDWARF
264 if (session.show_lines) {
265 if (session.nr_probe != 0 || session.dellist) {
266 pr_warning(" Error: Don't use --line with"
267 " --add/--del.\n");
268 usage_with_options(probe_usage, options);
269 }
270 init_vmlinux();
271 fd = open_vmlinux();
272 if (fd < 0)
273 die("Could not open debuginfo file.");
274 ret = find_line_range(fd, &session.line_range);
275 if (ret <= 0)
276 die("Source line is not found.\n");
277 close(fd);
278 show_line_range(&session.line_range);
279 return 0;
280 }
281#endif
282
222 if (session.dellist) { 283 if (session.dellist) {
223 del_trace_kprobe_events(session.dellist); 284 del_trace_kprobe_events(session.dellist);
224 strlist__delete(session.dellist); 285 strlist__delete(session.dellist);
@@ -226,20 +287,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
226 return 0; 287 return 0;
227 } 288 }
228 289
229 /* Initialize symbol maps for vmlinux */ 290 /* Add probes */
230 symbol_conf.sort_by_name = true; 291 init_vmlinux();
231 if (symbol_conf.vmlinux_name == NULL)
232 symbol_conf.try_vmlinux_path = true;
233 if (symbol__init() < 0)
234 die("Failed to init symbol map.");
235 session.psession = perf_session__new(NULL, O_WRONLY, false);
236 if (session.psession == NULL)
237 die("Failed to init perf_session.");
238 session.kmap = map_groups__find_by_name(&session.psession->kmaps,
239 MAP__FUNCTION,
240 "[kernel.kallsyms]");
241 if (!session.kmap)
242 die("Could not find kernel map.\n");
243 292
244 if (session.need_dwarf) 293 if (session.need_dwarf)
245#ifdef NO_LIBDWARF 294#ifdef NO_LIBDWARF
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 265425322734..90345223908c 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -113,12 +113,24 @@ static void write_output(void *buf, size_t size)
113 113
114static void write_event(event_t *buf, size_t size) 114static void write_event(event_t *buf, size_t size)
115{ 115{
116 /* 116 size_t processed_size = buf->header.size;
117 * Add it to the list of DSOs, so that when we finish this 117 event_t *ev = buf;
118 * record session we can pick the available build-ids. 118
119 */ 119 do {
120 if (buf->header.type == PERF_RECORD_MMAP) 120 /*
121 dsos__findnew(buf->mmap.filename); 121 * Add it to the list of DSOs, so that when we finish this
122 * record session we can pick the available build-ids.
123 */
124 if (ev->header.type == PERF_RECORD_MMAP) {
125 struct list_head *head = &dsos__user;
126 if (ev->header.misc == 1)
127 head = &dsos__kernel;
128 __dsos__findnew(head, ev->mmap.filename);
129 }
130
131 ev = ((void *)ev) + ev->header.size;
132 processed_size += ev->header.size;
133 } while (processed_size < size);
122 134
123 write_output(buf, size); 135 write_output(buf, size);
124} 136}
@@ -551,6 +563,19 @@ static int __cmd_record(int argc, const char **argv)
551 return err; 563 return err;
552 } 564 }
553 565
566 err = event__synthesize_kernel_mmap(process_synthesized_event,
567 session, "_text");
568 if (err < 0) {
569 pr_err("Couldn't record kernel reference relocation symbol.\n");
570 return err;
571 }
572
573 err = event__synthesize_modules(process_synthesized_event, session);
574 if (err < 0) {
575 pr_err("Couldn't record kernel reference relocation symbol.\n");
576 return err;
577 }
578
554 if (!system_wide && profile_cpu == -1) 579 if (!system_wide && profile_cpu == -1)
555 event__synthesize_thread(pid, process_synthesized_event, 580 event__synthesize_thread(pid, process_synthesized_event,
556 session); 581 session);
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 860f1eeeea7d..cfc655d40bb7 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -34,6 +34,8 @@
34static char const *input_name = "perf.data"; 34static char const *input_name = "perf.data";
35 35
36static int force; 36static int force;
37static bool hide_unresolved;
38static bool dont_use_callchains;
37 39
38static int show_threads; 40static int show_threads;
39static struct perf_read_values show_threads_values; 41static struct perf_read_values show_threads_values;
@@ -91,11 +93,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
91 93
92 event__parse_sample(event, session->sample_type, &data); 94 event__parse_sample(event, session->sample_type, &data);
93 95
94 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 96 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
95 event->header.misc, 97 data.pid, data.tid, data.ip, data.period);
96 data.pid, data.tid,
97 (void *)(long)data.ip,
98 (long long)data.period);
99 98
100 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) { 99 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
101 unsigned int i; 100 unsigned int i;
@@ -121,7 +120,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
121 return -1; 120 return -1;
122 } 121 }
123 122
124 if (al.filtered) 123 if (al.filtered || (hide_unresolved && al.sym == NULL))
125 return 0; 124 return 0;
126 125
127 if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { 126 if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) {
@@ -156,14 +155,14 @@ static int process_read_event(event_t *event, struct perf_session *session __use
156 return 0; 155 return 0;
157} 156}
158 157
159static int sample_type_check(struct perf_session *session) 158static int perf_session__setup_sample_type(struct perf_session *self)
160{ 159{
161 if (!(session->sample_type & PERF_SAMPLE_CALLCHAIN)) { 160 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
162 if (sort__has_parent) { 161 if (sort__has_parent) {
163 fprintf(stderr, "selected --sort parent, but no" 162 fprintf(stderr, "selected --sort parent, but no"
164 " callchain data. Did you call" 163 " callchain data. Did you call"
165 " perf record without -g?\n"); 164 " perf record without -g?\n");
166 return -1; 165 return -EINVAL;
167 } 166 }
168 if (symbol_conf.use_callchain) { 167 if (symbol_conf.use_callchain) {
169 fprintf(stderr, "selected -g but no callchain data." 168 fprintf(stderr, "selected -g but no callchain data."
@@ -171,12 +170,13 @@ static int sample_type_check(struct perf_session *session)
171 " -g?\n"); 170 " -g?\n");
172 return -1; 171 return -1;
173 } 172 }
174 } else if (callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) { 173 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
174 !symbol_conf.use_callchain) {
175 symbol_conf.use_callchain = true; 175 symbol_conf.use_callchain = true;
176 if (register_callchain_param(&callchain_param) < 0) { 176 if (register_callchain_param(&callchain_param) < 0) {
177 fprintf(stderr, "Can't register callchain" 177 fprintf(stderr, "Can't register callchain"
178 " params\n"); 178 " params\n");
179 return -1; 179 return -EINVAL;
180 } 180 }
181 } 181 }
182 182
@@ -184,20 +184,18 @@ static int sample_type_check(struct perf_session *session)
184} 184}
185 185
186static struct perf_event_ops event_ops = { 186static struct perf_event_ops event_ops = {
187 .process_sample_event = process_sample_event, 187 .sample = process_sample_event,
188 .process_mmap_event = event__process_mmap, 188 .mmap = event__process_mmap,
189 .process_comm_event = event__process_comm, 189 .comm = event__process_comm,
190 .process_exit_event = event__process_task, 190 .exit = event__process_task,
191 .process_fork_event = event__process_task, 191 .fork = event__process_task,
192 .process_lost_event = event__process_lost, 192 .lost = event__process_lost,
193 .process_read_event = process_read_event, 193 .read = process_read_event,
194 .sample_type_check = sample_type_check,
195}; 194};
196 195
197
198static int __cmd_report(void) 196static int __cmd_report(void)
199{ 197{
200 int ret; 198 int ret = -EINVAL;
201 struct perf_session *session; 199 struct perf_session *session;
202 200
203 session = perf_session__new(input_name, O_RDONLY, force); 201 session = perf_session__new(input_name, O_RDONLY, force);
@@ -207,6 +205,10 @@ static int __cmd_report(void)
207 if (show_threads) 205 if (show_threads)
208 perf_read_values_init(&show_threads_values); 206 perf_read_values_init(&show_threads_values);
209 207
208 ret = perf_session__setup_sample_type(session);
209 if (ret)
210 goto out_delete;
211
210 ret = perf_session__process_events(session, &event_ops); 212 ret = perf_session__process_events(session, &event_ops);
211 if (ret) 213 if (ret)
212 goto out_delete; 214 goto out_delete;
@@ -243,11 +245,19 @@ out_delete:
243 245
244static int 246static int
245parse_callchain_opt(const struct option *opt __used, const char *arg, 247parse_callchain_opt(const struct option *opt __used, const char *arg,
246 int unset __used) 248 int unset)
247{ 249{
248 char *tok; 250 char *tok;
249 char *endptr; 251 char *endptr;
250 252
253 /*
254 * --no-call-graph
255 */
256 if (unset) {
257 dont_use_callchains = true;
258 return 0;
259 }
260
251 symbol_conf.use_callchain = true; 261 symbol_conf.use_callchain = true;
252 262
253 if (!arg) 263 if (!arg)
@@ -319,7 +329,7 @@ static const struct option options[] = {
319 "pretty printing style key: normal raw"), 329 "pretty printing style key: normal raw"),
320 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 330 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
321 "sort by key(s): pid, comm, dso, symbol, parent"), 331 "sort by key(s): pid, comm, dso, symbol, parent"),
322 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, 332 OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
323 "Don't shorten the pathnames taking into account the cwd"), 333 "Don't shorten the pathnames taking into account the cwd"),
324 OPT_STRING('p', "parent", &parent_pattern, "regex", 334 OPT_STRING('p', "parent", &parent_pattern, "regex",
325 "regex filter to identify parent, see: '--sort parent'"), 335 "regex filter to identify parent, see: '--sort parent'"),
@@ -340,6 +350,8 @@ static const struct option options[] = {
340 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", 350 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
341 "separator for columns, no spaces will be added between " 351 "separator for columns, no spaces will be added between "
342 "columns '.' is reserved."), 352 "columns '.' is reserved."),
353 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
354 "Only display entries resolved to a symbol"),
343 OPT_END() 355 OPT_END()
344}; 356};
345 357
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 80209df6cfe8..4f5a03e43444 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1621,11 +1621,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
1621 1621
1622 event__parse_sample(event, session->sample_type, &data); 1622 event__parse_sample(event, session->sample_type, &data);
1623 1623
1624 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 1624 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
1625 event->header.misc, 1625 data.pid, data.tid, data.ip, data.period);
1626 data.pid, data.tid,
1627 (void *)(long)data.ip,
1628 (long long)data.period);
1629 1626
1630 thread = perf_session__findnew(session, data.pid); 1627 thread = perf_session__findnew(session, data.pid);
1631 if (thread == NULL) { 1628 if (thread == NULL) {
@@ -1653,33 +1650,22 @@ static int process_lost_event(event_t *event __used,
1653 return 0; 1650 return 0;
1654} 1651}
1655 1652
1656static int sample_type_check(struct perf_session *session __used)
1657{
1658 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1659 fprintf(stderr,
1660 "No trace sample to read. Did you call perf record "
1661 "without -R?");
1662 return -1;
1663 }
1664
1665 return 0;
1666}
1667
1668static struct perf_event_ops event_ops = { 1653static struct perf_event_ops event_ops = {
1669 .process_sample_event = process_sample_event, 1654 .sample = process_sample_event,
1670 .process_comm_event = event__process_comm, 1655 .comm = event__process_comm,
1671 .process_lost_event = process_lost_event, 1656 .lost = process_lost_event,
1672 .sample_type_check = sample_type_check,
1673}; 1657};
1674 1658
1675static int read_events(void) 1659static int read_events(void)
1676{ 1660{
1677 int err; 1661 int err = -EINVAL;
1678 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 1662 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1679 if (session == NULL) 1663 if (session == NULL)
1680 return -ENOMEM; 1664 return -ENOMEM;
1681 1665
1682 err = perf_session__process_events(session, &event_ops); 1666 if (perf_session__has_traces(session, "record -R"))
1667 err = perf_session__process_events(session, &event_ops);
1668
1683 perf_session__delete(session); 1669 perf_session__delete(session);
1684 return err; 1670 return err;
1685} 1671}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c70d72003557..e8c85d5aec41 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -44,6 +44,7 @@
44#include "util/parse-events.h" 44#include "util/parse-events.h"
45#include "util/event.h" 45#include "util/event.h"
46#include "util/debug.h" 46#include "util/debug.h"
47#include "util/header.h"
47 48
48#include <sys/prctl.h> 49#include <sys/prctl.h>
49#include <math.h> 50#include <math.h>
@@ -79,6 +80,8 @@ static int fd[MAX_NR_CPUS][MAX_COUNTERS];
79 80
80static int event_scaled[MAX_COUNTERS]; 81static int event_scaled[MAX_COUNTERS];
81 82
83static volatile int done = 0;
84
82struct stats 85struct stats
83{ 86{
84 double n, mean, M2; 87 double n, mean, M2;
@@ -247,61 +250,64 @@ static int run_perf_stat(int argc __used, const char **argv)
247 unsigned long long t0, t1; 250 unsigned long long t0, t1;
248 int status = 0; 251 int status = 0;
249 int counter; 252 int counter;
250 int pid; 253 int pid = target_pid;
251 int child_ready_pipe[2], go_pipe[2]; 254 int child_ready_pipe[2], go_pipe[2];
255 const bool forks = (target_pid == -1 && argc > 0);
252 char buf; 256 char buf;
253 257
254 if (!system_wide) 258 if (!system_wide)
255 nr_cpus = 1; 259 nr_cpus = 1;
256 260
257 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) { 261 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
258 perror("failed to create pipes"); 262 perror("failed to create pipes");
259 exit(1); 263 exit(1);
260 } 264 }
261 265
262 if ((pid = fork()) < 0) 266 if (forks) {
263 perror("failed to fork"); 267 if ((pid = fork()) < 0)
268 perror("failed to fork");
269
270 if (!pid) {
271 close(child_ready_pipe[0]);
272 close(go_pipe[1]);
273 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
274
275 /*
276 * Do a dummy execvp to get the PLT entry resolved,
277 * so we avoid the resolver overhead on the real
278 * execvp call.
279 */
280 execvp("", (char **)argv);
281
282 /*
283 * Tell the parent we're ready to go
284 */
285 close(child_ready_pipe[1]);
286
287 /*
288 * Wait until the parent tells us to go.
289 */
290 if (read(go_pipe[0], &buf, 1) == -1)
291 perror("unable to read pipe");
292
293 execvp(argv[0], (char **)argv);
294
295 perror(argv[0]);
296 exit(-1);
297 }
264 298
265 if (!pid) { 299 child_pid = pid;
266 close(child_ready_pipe[0]);
267 close(go_pipe[1]);
268 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
269 300
270 /* 301 /*
271 * Do a dummy execvp to get the PLT entry resolved, 302 * Wait for the child to be ready to exec.
272 * so we avoid the resolver overhead on the real
273 * execvp call.
274 */
275 execvp("", (char **)argv);
276
277 /*
278 * Tell the parent we're ready to go
279 */ 303 */
280 close(child_ready_pipe[1]); 304 close(child_ready_pipe[1]);
281 305 close(go_pipe[0]);
282 /* 306 if (read(child_ready_pipe[0], &buf, 1) == -1)
283 * Wait until the parent tells us to go.
284 */
285 if (read(go_pipe[0], &buf, 1) == -1)
286 perror("unable to read pipe"); 307 perror("unable to read pipe");
287 308 close(child_ready_pipe[0]);
288 execvp(argv[0], (char **)argv);
289
290 perror(argv[0]);
291 exit(-1);
292 } 309 }
293 310
294 child_pid = pid;
295
296 /*
297 * Wait for the child to be ready to exec.
298 */
299 close(child_ready_pipe[1]);
300 close(go_pipe[0]);
301 if (read(child_ready_pipe[0], &buf, 1) == -1)
302 perror("unable to read pipe");
303 close(child_ready_pipe[0]);
304
305 for (counter = 0; counter < nr_counters; counter++) 311 for (counter = 0; counter < nr_counters; counter++)
306 create_perf_stat_counter(counter, pid); 312 create_perf_stat_counter(counter, pid);
307 313
@@ -310,8 +316,12 @@ static int run_perf_stat(int argc __used, const char **argv)
310 */ 316 */
311 t0 = rdclock(); 317 t0 = rdclock();
312 318
313 close(go_pipe[1]); 319 if (forks) {
314 wait(&status); 320 close(go_pipe[1]);
321 wait(&status);
322 } else {
323 while(!done);
324 }
315 325
316 t1 = rdclock(); 326 t1 = rdclock();
317 327
@@ -417,10 +427,13 @@ static void print_stat(int argc, const char **argv)
417 fflush(stdout); 427 fflush(stdout);
418 428
419 fprintf(stderr, "\n"); 429 fprintf(stderr, "\n");
420 fprintf(stderr, " Performance counter stats for \'%s", argv[0]); 430 fprintf(stderr, " Performance counter stats for ");
421 431 if(target_pid == -1) {
422 for (i = 1; i < argc; i++) 432 fprintf(stderr, "\'%s", argv[0]);
423 fprintf(stderr, " %s", argv[i]); 433 for (i = 1; i < argc; i++)
434 fprintf(stderr, " %s", argv[i]);
435 }else
436 fprintf(stderr, "task pid \'%d", target_pid);
424 437
425 fprintf(stderr, "\'"); 438 fprintf(stderr, "\'");
426 if (run_count > 1) 439 if (run_count > 1)
@@ -445,6 +458,9 @@ static volatile int signr = -1;
445 458
446static void skip_signal(int signo) 459static void skip_signal(int signo)
447{ 460{
461 if(target_pid != -1)
462 done = 1;
463
448 signr = signo; 464 signr = signo;
449} 465}
450 466
@@ -461,7 +477,7 @@ static void sig_atexit(void)
461} 477}
462 478
463static const char * const stat_usage[] = { 479static const char * const stat_usage[] = {
464 "perf stat [<options>] <command>", 480 "perf stat [<options>] [<command>]",
465 NULL 481 NULL
466}; 482};
467 483
@@ -492,7 +508,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
492 508
493 argc = parse_options(argc, argv, options, stat_usage, 509 argc = parse_options(argc, argv, options, stat_usage,
494 PARSE_OPT_STOP_AT_NON_OPTION); 510 PARSE_OPT_STOP_AT_NON_OPTION);
495 if (!argc) 511 if (!argc && target_pid == -1)
496 usage_with_options(stat_usage, options); 512 usage_with_options(stat_usage, options);
497 if (run_count <= 0) 513 if (run_count <= 0)
498 usage_with_options(stat_usage, options); 514 usage_with_options(stat_usage, options);
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 3f8bbcfb1e9b..0d4d8ff7914b 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1029,33 +1029,24 @@ static void process_samples(struct perf_session *session)
1029 } 1029 }
1030} 1030}
1031 1031
1032static int sample_type_check(struct perf_session *session)
1033{
1034 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1035 fprintf(stderr, "No trace samples found in the file.\n"
1036 "Have you used 'perf timechart record' to record it?\n");
1037 return -1;
1038 }
1039
1040 return 0;
1041}
1042
1043static struct perf_event_ops event_ops = { 1032static struct perf_event_ops event_ops = {
1044 .process_comm_event = process_comm_event, 1033 .comm = process_comm_event,
1045 .process_fork_event = process_fork_event, 1034 .fork = process_fork_event,
1046 .process_exit_event = process_exit_event, 1035 .exit = process_exit_event,
1047 .process_sample_event = queue_sample_event, 1036 .sample = queue_sample_event,
1048 .sample_type_check = sample_type_check,
1049}; 1037};
1050 1038
1051static int __cmd_timechart(void) 1039static int __cmd_timechart(void)
1052{ 1040{
1053 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 1041 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1054 int ret; 1042 int ret = -EINVAL;
1055 1043
1056 if (session == NULL) 1044 if (session == NULL)
1057 return -ENOMEM; 1045 return -ENOMEM;
1058 1046
1047 if (!perf_session__has_traces(session, "timechart record"))
1048 goto out_delete;
1049
1059 ret = perf_session__process_events(session, &event_ops); 1050 ret = perf_session__process_events(session, &event_ops);
1060 if (ret) 1051 if (ret)
1061 goto out_delete; 1052 goto out_delete;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ddc584b64871..1fc018e048e1 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -667,7 +667,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
667 } 667 }
668 668
669 if (!found) { 669 if (!found) {
670 fprintf(stderr, "Sorry, %s is not active.\n", sym_filter); 670 fprintf(stderr, "Sorry, %s is not active.\n", buf);
671 sleep(1); 671 sleep(1);
672 return; 672 return;
673 } else 673 } else
@@ -934,8 +934,11 @@ static void event__process_sample(const event_t *self,
934 struct addr_location al; 934 struct addr_location al;
935 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 935 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
936 936
937 ++samples;
938
937 switch (origin) { 939 switch (origin) {
938 case PERF_RECORD_MISC_USER: 940 case PERF_RECORD_MISC_USER:
941 ++userspace_samples;
939 if (hide_user_symbols) 942 if (hide_user_symbols)
940 return; 943 return;
941 break; 944 break;
@@ -948,9 +951,31 @@ static void event__process_sample(const event_t *self,
948 } 951 }
949 952
950 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || 953 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
951 al.sym == NULL || al.filtered) 954 al.filtered)
952 return; 955 return;
953 956
957 if (al.sym == NULL) {
958 /*
959 * As we do lazy loading of symtabs we only will know if the
960 * specified vmlinux file is invalid when we actually have a
961 * hit in kernel space and then try to load it. So if we get
962 * here and there are _no_ symbols in the DSO backing the
963 * kernel map, bail out.
964 *
965 * We may never get here, for instance, if we use -K/
966 * --hide-kernel-symbols, even if the user specifies an
967 * invalid --vmlinux ;-)
968 */
969 if (al.map == session->vmlinux_maps[MAP__FUNCTION] &&
970 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
971 pr_err("The %s file can't be used\n",
972 symbol_conf.vmlinux_name);
973 exit(1);
974 }
975
976 return;
977 }
978
954 syme = symbol__priv(al.sym); 979 syme = symbol__priv(al.sym);
955 if (!syme->skip) { 980 if (!syme->skip) {
956 syme->count[counter]++; 981 syme->count[counter]++;
@@ -960,9 +985,6 @@ static void event__process_sample(const event_t *self,
960 if (list_empty(&syme->node) || !syme->node.next) 985 if (list_empty(&syme->node) || !syme->node.next)
961 __list_insert_active_sym(syme); 986 __list_insert_active_sym(syme);
962 pthread_mutex_unlock(&active_symbols_lock); 987 pthread_mutex_unlock(&active_symbols_lock);
963 if (origin == PERF_RECORD_MISC_USER)
964 ++userspace_samples;
965 ++samples;
966 } 988 }
967} 989}
968 990
@@ -975,6 +997,10 @@ static int event__process(event_t *event, struct perf_session *session)
975 case PERF_RECORD_MMAP: 997 case PERF_RECORD_MMAP:
976 event__process_mmap(event, session); 998 event__process_mmap(event, session);
977 break; 999 break;
1000 case PERF_RECORD_FORK:
1001 case PERF_RECORD_EXIT:
1002 event__process_task(event, session);
1003 break;
978 default: 1004 default:
979 break; 1005 break;
980 } 1006 }
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 574a215e800b..0b65779e3c10 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -75,11 +75,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
75 75
76 event__parse_sample(event, session->sample_type, &data); 76 event__parse_sample(event, session->sample_type, &data);
77 77
78 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 78 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
79 event->header.misc, 79 data.pid, data.tid, data.ip, data.period);
80 data.pid, data.tid,
81 (void *)(long)data.ip,
82 (long long)data.period);
83 80
84 thread = perf_session__findnew(session, event->ip.pid); 81 thread = perf_session__findnew(session, event->ip.pid);
85 if (thread == NULL) { 82 if (thread == NULL) {
@@ -103,22 +100,9 @@ static int process_sample_event(event_t *event, struct perf_session *session)
103 return 0; 100 return 0;
104} 101}
105 102
106static int sample_type_check(struct perf_session *session)
107{
108 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
109 fprintf(stderr,
110 "No trace sample to read. Did you call perf record "
111 "without -R?");
112 return -1;
113 }
114
115 return 0;
116}
117
118static struct perf_event_ops event_ops = { 103static struct perf_event_ops event_ops = {
119 .process_sample_event = process_sample_event, 104 .sample = process_sample_event,
120 .process_comm_event = event__process_comm, 105 .comm = event__process_comm,
121 .sample_type_check = sample_type_check,
122}; 106};
123 107
124static int __cmd_trace(struct perf_session *session) 108static int __cmd_trace(struct perf_session *session)
@@ -531,6 +515,8 @@ static const struct option options[] = {
531 parse_scriptname), 515 parse_scriptname),
532 OPT_STRING('g', "gen-script", &generate_script_lang, "lang", 516 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
533 "generate perf-trace.xx script in specified language"), 517 "generate perf-trace.xx script in specified language"),
518 OPT_STRING('i', "input", &input_name, "file",
519 "input file name"),
534 520
535 OPT_END() 521 OPT_END()
536}; 522};
@@ -592,6 +578,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
592 if (session == NULL) 578 if (session == NULL)
593 return -ENOMEM; 579 return -ENOMEM;
594 580
581 if (!perf_session__has_traces(session, "record -R"))
582 return -EINVAL;
583
595 if (generate_script_lang) { 584 if (generate_script_lang) {
596 struct stat perf_stat; 585 struct stat perf_stat;
597 586
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 18035b1f16c7..dee97cfe3794 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -16,6 +16,7 @@ extern int check_pager_config(const char *cmd);
16 16
17extern int cmd_annotate(int argc, const char **argv, const char *prefix); 17extern int cmd_annotate(int argc, const char **argv, const char *prefix);
18extern int cmd_bench(int argc, const char **argv, const char *prefix); 18extern int cmd_bench(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); 20extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
20extern int cmd_diff(int argc, const char **argv, const char *prefix); 21extern int cmd_diff(int argc, const char **argv, const char *prefix);
21extern int cmd_help(int argc, const char **argv, const char *prefix); 22extern int cmd_help(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 71dc7c3fe7b2..9afcff2e3ae5 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -3,7 +3,9 @@
3# command name category [deprecated] [common] 3# command name category [deprecated] [common]
4# 4#
5perf-annotate mainporcelain common 5perf-annotate mainporcelain common
6perf-archive mainporcelain common
6perf-bench mainporcelain common 7perf-bench mainporcelain common
8perf-buildid-cache mainporcelain common
7perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
8perf-diff mainporcelain common 10perf-diff mainporcelain common
9perf-list mainporcelain common 11perf-list mainporcelain common
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index 8d0de5130db3..bd0bb1b1279b 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -101,10 +101,10 @@ enum hw_event_ids {
101 */ 101 */
102 PERF_COUNT_HW_CPU_CYCLES = 0, 102 PERF_COUNT_HW_CPU_CYCLES = 0,
103 PERF_COUNT_HW_INSTRUCTIONS = 1, 103 PERF_COUNT_HW_INSTRUCTIONS = 1,
104 PERF_COUNT_HW_CACHE_REFERENCES = 2, 104 PERF_COUNT_HW_CACHE_REFERENCES = 2,
105 PERF_COUNT_HW_CACHE_MISSES = 3, 105 PERF_COUNT_HW_CACHE_MISSES = 3,
106 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, 106 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
107 PERF_COUNT_HW_BRANCH_MISSES = 5, 107 PERF_COUNT_HW_BRANCH_MISSES = 5,
108 PERF_COUNT_HW_BUS_CYCLES = 6, 108 PERF_COUNT_HW_BUS_CYCLES = 6,
109}; 109};
110 110
@@ -131,8 +131,8 @@ software events, selected by 'event_id':
131 */ 131 */
132enum sw_event_ids { 132enum sw_event_ids {
133 PERF_COUNT_SW_CPU_CLOCK = 0, 133 PERF_COUNT_SW_CPU_CLOCK = 0,
134 PERF_COUNT_SW_TASK_CLOCK = 1, 134 PERF_COUNT_SW_TASK_CLOCK = 1,
135 PERF_COUNT_SW_PAGE_FAULTS = 2, 135 PERF_COUNT_SW_PAGE_FAULTS = 2,
136 PERF_COUNT_SW_CONTEXT_SWITCHES = 3, 136 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
137 PERF_COUNT_SW_CPU_MIGRATIONS = 4, 137 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, 138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh
new file mode 100644
index 000000000000..45fbe2f07b15
--- /dev/null
+++ b/tools/perf/perf-archive.sh
@@ -0,0 +1,32 @@
1#!/bin/bash
2# perf archive
3# Arnaldo Carvalho de Melo <acme@redhat.com>
4
5PERF_DATA=perf.data
6if [ $# -ne 0 ] ; then
7 PERF_DATA=$1
8fi
9
10DEBUGDIR=~/.debug/
11BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX)
12
13perf buildid-list -i $PERF_DATA --with-hits > $BUILDIDS
14if [ ! -s $BUILDIDS ] ; then
15 echo "perf archive: no build-ids found"
16 rm -f $BUILDIDS
17 exit 1
18fi
19
20MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX)
21
22cut -d ' ' -f 1 $BUILDIDS | \
23while read build_id ; do
24 linkname=$DEBUGDIR.build-id/${build_id:0:2}/${build_id:2}
25 filename=$(readlink -f $linkname)
26 echo ${linkname#$DEBUGDIR} >> $MANIFEST
27 echo ${filename#$DEBUGDIR} >> $MANIFEST
28done
29
30tar cfj $PERF_DATA.tar.bz2 -C $DEBUGDIR -T $MANIFEST
31rm -f $MANIFEST $BUILDIDS
32exit 0
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 873e55fab375..05c861c045d5 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -285,6 +285,7 @@ static void handle_internal_command(int argc, const char **argv)
285{ 285{
286 const char *cmd = argv[0]; 286 const char *cmd = argv[0];
287 static struct cmd_struct commands[] = { 287 static struct cmd_struct commands[] = {
288 { "buildid-cache", cmd_buildid_cache, 0 },
288 { "buildid-list", cmd_buildid_list, 0 }, 289 { "buildid-list", cmd_buildid_list, 0 },
289 { "diff", cmd_diff, 0 }, 290 { "diff", cmd_diff, 0 },
290 { "help", cmd_help, 0 }, 291 { "help", cmd_help, 0 },
@@ -388,7 +389,7 @@ static int run_argv(int *argcp, const char ***argv)
388/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ 389/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
389static void get_debugfs_mntpt(void) 390static void get_debugfs_mntpt(void)
390{ 391{
391 const char *path = debugfs_find_mountpoint(); 392 const char *path = debugfs_mount(NULL);
392 393
393 if (path) 394 if (path)
394 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt)); 395 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
deleted file mode 100644
index b557b836de3d..000000000000
--- a/tools/perf/util/data_map.c
+++ /dev/null
@@ -1,252 +0,0 @@
1#include "symbol.h"
2#include "util.h"
3#include "debug.h"
4#include "thread.h"
5#include "session.h"
6
7static int process_event_stub(event_t *event __used,
8 struct perf_session *session __used)
9{
10 dump_printf(": unhandled!\n");
11 return 0;
12}
13
14static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
15{
16 if (!handler->process_sample_event)
17 handler->process_sample_event = process_event_stub;
18 if (!handler->process_mmap_event)
19 handler->process_mmap_event = process_event_stub;
20 if (!handler->process_comm_event)
21 handler->process_comm_event = process_event_stub;
22 if (!handler->process_fork_event)
23 handler->process_fork_event = process_event_stub;
24 if (!handler->process_exit_event)
25 handler->process_exit_event = process_event_stub;
26 if (!handler->process_lost_event)
27 handler->process_lost_event = process_event_stub;
28 if (!handler->process_read_event)
29 handler->process_read_event = process_event_stub;
30 if (!handler->process_throttle_event)
31 handler->process_throttle_event = process_event_stub;
32 if (!handler->process_unthrottle_event)
33 handler->process_unthrottle_event = process_event_stub;
34}
35
36static const char *event__name[] = {
37 [0] = "TOTAL",
38 [PERF_RECORD_MMAP] = "MMAP",
39 [PERF_RECORD_LOST] = "LOST",
40 [PERF_RECORD_COMM] = "COMM",
41 [PERF_RECORD_EXIT] = "EXIT",
42 [PERF_RECORD_THROTTLE] = "THROTTLE",
43 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
44 [PERF_RECORD_FORK] = "FORK",
45 [PERF_RECORD_READ] = "READ",
46 [PERF_RECORD_SAMPLE] = "SAMPLE",
47};
48
49unsigned long event__total[PERF_RECORD_MAX];
50
51void event__print_totals(void)
52{
53 int i;
54 for (i = 0; i < PERF_RECORD_MAX; ++i)
55 pr_info("%10s events: %10ld\n",
56 event__name[i], event__total[i]);
57}
58
59static int process_event(event_t *event, struct perf_session *session,
60 struct perf_event_ops *ops,
61 unsigned long offset, unsigned long head)
62{
63 trace_event(event);
64
65 if (event->header.type < PERF_RECORD_MAX) {
66 dump_printf("%p [%p]: PERF_RECORD_%s",
67 (void *)(offset + head),
68 (void *)(long)(event->header.size),
69 event__name[event->header.type]);
70 ++event__total[0];
71 ++event__total[event->header.type];
72 }
73
74 switch (event->header.type) {
75 case PERF_RECORD_SAMPLE:
76 return ops->process_sample_event(event, session);
77 case PERF_RECORD_MMAP:
78 return ops->process_mmap_event(event, session);
79 case PERF_RECORD_COMM:
80 return ops->process_comm_event(event, session);
81 case PERF_RECORD_FORK:
82 return ops->process_fork_event(event, session);
83 case PERF_RECORD_EXIT:
84 return ops->process_exit_event(event, session);
85 case PERF_RECORD_LOST:
86 return ops->process_lost_event(event, session);
87 case PERF_RECORD_READ:
88 return ops->process_read_event(event, session);
89 case PERF_RECORD_THROTTLE:
90 return ops->process_throttle_event(event, session);
91 case PERF_RECORD_UNTHROTTLE:
92 return ops->process_unthrottle_event(event, session);
93 default:
94 ops->total_unknown++;
95 return -1;
96 }
97}
98
99int perf_header__read_build_ids(int input, u64 offset, u64 size)
100{
101 struct build_id_event bev;
102 char filename[PATH_MAX];
103 u64 limit = offset + size;
104 int err = -1;
105
106 while (offset < limit) {
107 struct dso *dso;
108 ssize_t len;
109
110 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
111 goto out;
112
113 len = bev.header.size - sizeof(bev);
114 if (read(input, filename, len) != len)
115 goto out;
116
117 dso = dsos__findnew(filename);
118 if (dso != NULL)
119 dso__set_build_id(dso, &bev.build_id);
120
121 offset += bev.header.size;
122 }
123 err = 0;
124out:
125 return err;
126}
127
128static struct thread *perf_session__register_idle_thread(struct perf_session *self)
129{
130 struct thread *thread = perf_session__findnew(self, 0);
131
132 if (!thread || thread__set_comm(thread, "swapper")) {
133 pr_err("problem inserting idle task.\n");
134 thread = NULL;
135 }
136
137 return thread;
138}
139
140int perf_session__process_events(struct perf_session *self,
141 struct perf_event_ops *ops)
142{
143 int err;
144 unsigned long head, shift;
145 unsigned long offset = 0;
146 size_t page_size;
147 event_t *event;
148 uint32_t size;
149 char *buf;
150
151 if (perf_session__register_idle_thread(self) == NULL)
152 return -ENOMEM;
153
154 perf_event_ops__fill_defaults(ops);
155
156 page_size = getpagesize();
157
158 head = self->header.data_offset;
159 self->sample_type = perf_header__sample_type(&self->header);
160
161 err = -EINVAL;
162 if (ops->sample_type_check && ops->sample_type_check(self) < 0)
163 goto out_err;
164
165 if (!ops->full_paths) {
166 char bf[PATH_MAX];
167
168 if (getcwd(bf, sizeof(bf)) == NULL) {
169 err = -errno;
170out_getcwd_err:
171 pr_err("failed to get the current directory\n");
172 goto out_err;
173 }
174 self->cwd = strdup(bf);
175 if (self->cwd == NULL) {
176 err = -ENOMEM;
177 goto out_getcwd_err;
178 }
179 self->cwdlen = strlen(self->cwd);
180 }
181
182 shift = page_size * (head / page_size);
183 offset += shift;
184 head -= shift;
185
186remap:
187 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
188 MAP_SHARED, self->fd, offset);
189 if (buf == MAP_FAILED) {
190 pr_err("failed to mmap file\n");
191 err = -errno;
192 goto out_err;
193 }
194
195more:
196 event = (event_t *)(buf + head);
197
198 size = event->header.size;
199 if (!size)
200 size = 8;
201
202 if (head + event->header.size >= page_size * self->mmap_window) {
203 int munmap_ret;
204
205 shift = page_size * (head / page_size);
206
207 munmap_ret = munmap(buf, page_size * self->mmap_window);
208 assert(munmap_ret == 0);
209
210 offset += shift;
211 head -= shift;
212 goto remap;
213 }
214
215 size = event->header.size;
216
217 dump_printf("\n%p [%p]: event: %d\n",
218 (void *)(offset + head),
219 (void *)(long)event->header.size,
220 event->header.type);
221
222 if (!size || process_event(event, self, ops, offset, head) < 0) {
223
224 dump_printf("%p [%p]: skipping unknown header type: %d\n",
225 (void *)(offset + head),
226 (void *)(long)(event->header.size),
227 event->header.type);
228
229 /*
230 * assume we lost track of the stream, check alignment, and
231 * increment a single u64 in the hope to catch on again 'soon'.
232 */
233
234 if (unlikely(head & 7))
235 head &= ~7ULL;
236
237 size = 8;
238 }
239
240 head += size;
241
242 if (offset + head >= self->header.data_offset + self->header.data_size)
243 goto done;
244
245 if (offset + head < self->size)
246 goto more;
247
248done:
249 err = 0;
250out_err:
251 return err;
252}
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 28d520d5a1fb..0905600c3851 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -9,6 +9,7 @@
9#include "color.h" 9#include "color.h"
10#include "event.h" 10#include "event.h"
11#include "debug.h" 11#include "debug.h"
12#include "util.h"
12 13
13int verbose = 0; 14int verbose = 0;
14int dump_trace = 0; 15int dump_trace = 0;
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index 06b73ee02c49..a88fefc0cc0a 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -106,16 +106,14 @@ int debugfs_valid_entry(const char *path)
106 return 0; 106 return 0;
107} 107}
108 108
109/* mount the debugfs somewhere */ 109/* mount the debugfs somewhere if it's not mounted */
110 110
111int debugfs_mount(const char *mountpoint) 111char *debugfs_mount(const char *mountpoint)
112{ 112{
113 char mountcmd[128];
114
115 /* see if it's already mounted */ 113 /* see if it's already mounted */
116 if (debugfs_find_mountpoint()) { 114 if (debugfs_find_mountpoint()) {
117 debugfs_premounted = 1; 115 debugfs_premounted = 1;
118 return 0; 116 return debugfs_mountpoint;
119 } 117 }
120 118
121 /* if not mounted and no argument */ 119 /* if not mounted and no argument */
@@ -127,13 +125,14 @@ int debugfs_mount(const char *mountpoint)
127 mountpoint = "/sys/kernel/debug"; 125 mountpoint = "/sys/kernel/debug";
128 } 126 }
129 127
128 if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
129 return NULL;
130
130 /* save the mountpoint */ 131 /* save the mountpoint */
131 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); 132 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
133 debugfs_found = 1;
132 134
133 /* mount it */ 135 return debugfs_mountpoint;
134 snprintf(mountcmd, sizeof(mountcmd),
135 "/bin/mount -t debugfs debugfs %s", mountpoint);
136 return system(mountcmd);
137} 136}
138 137
139/* umount the debugfs */ 138/* umount the debugfs */
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 3cd14f9ae784..83a02879745f 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -15,7 +15,7 @@
15extern const char *debugfs_find_mountpoint(void); 15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs); 16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path); 17extern int debugfs_valid_entry(const char *path);
18extern int debugfs_mount(const char *mountpoint); 18extern char *debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void); 19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value); 20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size); 21extern int debugfs_read(const char *entry, char *buffer, size_t size);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index bb0fd6da2d56..bbaee61c1683 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -8,8 +8,7 @@
8#include "thread.h" 8#include "thread.h"
9 9
10static pid_t event__synthesize_comm(pid_t pid, int full, 10static pid_t event__synthesize_comm(pid_t pid, int full,
11 int (*process)(event_t *event, 11 event__handler_t process,
12 struct perf_session *session),
13 struct perf_session *session) 12 struct perf_session *session)
14{ 13{
15 event_t ev; 14 event_t ev;
@@ -91,8 +90,7 @@ out_failure:
91} 90}
92 91
93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 92static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
94 int (*process)(event_t *event, 93 event__handler_t process,
95 struct perf_session *session),
96 struct perf_session *session) 94 struct perf_session *session)
97{ 95{
98 char filename[PATH_MAX]; 96 char filename[PATH_MAX];
@@ -112,7 +110,10 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
112 while (1) { 110 while (1) {
113 char bf[BUFSIZ], *pbf = bf; 111 char bf[BUFSIZ], *pbf = bf;
114 event_t ev = { 112 event_t ev = {
115 .header = { .type = PERF_RECORD_MMAP }, 113 .header = {
114 .type = PERF_RECORD_MMAP,
115 .misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */
116 },
116 }; 117 };
117 int n; 118 int n;
118 size_t size; 119 size_t size;
@@ -156,9 +157,38 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
156 return 0; 157 return 0;
157} 158}
158 159
159int event__synthesize_thread(pid_t pid, 160int event__synthesize_modules(event__handler_t process,
160 int (*process)(event_t *event, 161 struct perf_session *session)
161 struct perf_session *session), 162{
163 struct rb_node *nd;
164
165 for (nd = rb_first(&session->kmaps.maps[MAP__FUNCTION]);
166 nd; nd = rb_next(nd)) {
167 event_t ev;
168 size_t size;
169 struct map *pos = rb_entry(nd, struct map, rb_node);
170
171 if (pos->dso->kernel)
172 continue;
173
174 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
175 memset(&ev, 0, sizeof(ev));
176 ev.mmap.header.misc = 1; /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
177 ev.mmap.header.type = PERF_RECORD_MMAP;
178 ev.mmap.header.size = (sizeof(ev.mmap) -
179 (sizeof(ev.mmap.filename) - size));
180 ev.mmap.start = pos->start;
181 ev.mmap.len = pos->end - pos->start;
182
183 memcpy(ev.mmap.filename, pos->dso->long_name,
184 pos->dso->long_name_len + 1);
185 process(&ev, session);
186 }
187
188 return 0;
189}
190
191int event__synthesize_thread(pid_t pid, event__handler_t process,
162 struct perf_session *session) 192 struct perf_session *session)
163{ 193{
164 pid_t tgid = event__synthesize_comm(pid, 1, process, session); 194 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
@@ -167,8 +197,7 @@ int event__synthesize_thread(pid_t pid,
167 return event__synthesize_mmap_events(pid, tgid, process, session); 197 return event__synthesize_mmap_events(pid, tgid, process, session);
168} 198}
169 199
170void event__synthesize_threads(int (*process)(event_t *event, 200void event__synthesize_threads(event__handler_t process,
171 struct perf_session *session),
172 struct perf_session *session) 201 struct perf_session *session)
173{ 202{
174 DIR *proc; 203 DIR *proc;
@@ -189,6 +218,59 @@ void event__synthesize_threads(int (*process)(event_t *event,
189 closedir(proc); 218 closedir(proc);
190} 219}
191 220
221struct process_symbol_args {
222 const char *name;
223 u64 start;
224};
225
226static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
227{
228 struct process_symbol_args *args = arg;
229
230 /*
231 * Must be a function or at least an alias, as in PARISC64, where "_text" is
232 * an 'A' to the same address as "_stext".
233 */
234 if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
235 type == 'A') || strcmp(name, args->name))
236 return 0;
237
238 args->start = start;
239 return 1;
240}
241
242int event__synthesize_kernel_mmap(event__handler_t process,
243 struct perf_session *session,
244 const char *symbol_name)
245{
246 size_t size;
247 event_t ev = {
248 .header = {
249 .type = PERF_RECORD_MMAP,
250 .misc = 1, /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
251 },
252 };
253 /*
254 * We should get this from /sys/kernel/sections/.text, but till that is
255 * available use this, and after it is use this as a fallback for older
256 * kernels.
257 */
258 struct process_symbol_args args = { .name = symbol_name, };
259
260 if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0)
261 return -ENOENT;
262
263 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
264 "[kernel.kallsyms.%s]", symbol_name) + 1;
265 size = ALIGN(size, sizeof(u64));
266 ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size));
267 ev.mmap.pgoff = args.start;
268 ev.mmap.start = session->vmlinux_maps[MAP__FUNCTION]->start;
269 ev.mmap.len = session->vmlinux_maps[MAP__FUNCTION]->end - ev.mmap.start ;
270
271 return process(&ev, session);
272}
273
192static void thread__comm_adjust(struct thread *self) 274static void thread__comm_adjust(struct thread *self)
193{ 275{
194 char *comm = self->comm; 276 char *comm = self->comm;
@@ -240,22 +322,84 @@ int event__process_lost(event_t *self, struct perf_session *session)
240 322
241int event__process_mmap(event_t *self, struct perf_session *session) 323int event__process_mmap(event_t *self, struct perf_session *session)
242{ 324{
243 struct thread *thread = perf_session__findnew(session, self->mmap.pid); 325 struct thread *thread;
244 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 326 struct map *map;
245 session->cwd, session->cwdlen); 327
328 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
329 self->mmap.pid, self->mmap.tid, self->mmap.start,
330 self->mmap.len, self->mmap.pgoff, self->mmap.filename);
331
332 if (self->mmap.pid == 0) {
333 static const char kmmap_prefix[] = "[kernel.kallsyms.";
334
335 if (self->mmap.filename[0] == '/') {
336 char short_module_name[1024];
337 char *name = strrchr(self->mmap.filename, '/'), *dot;
338
339 if (name == NULL)
340 goto out_problem;
341
342 ++name; /* skip / */
343 dot = strrchr(name, '.');
344 if (dot == NULL)
345 goto out_problem;
346
347 snprintf(short_module_name, sizeof(short_module_name),
348 "[%.*s]", (int)(dot - name), name);
349 strxfrchar(short_module_name, '-', '_');
350
351 map = perf_session__new_module_map(session,
352 self->mmap.start,
353 self->mmap.filename);
354 if (map == NULL)
355 goto out_problem;
356
357 name = strdup(short_module_name);
358 if (name == NULL)
359 goto out_problem;
360
361 map->dso->short_name = name;
362 map->end = map->start + self->mmap.len;
363 } else if (memcmp(self->mmap.filename, kmmap_prefix,
364 sizeof(kmmap_prefix) - 1) == 0) {
365 const char *symbol_name = (self->mmap.filename +
366 sizeof(kmmap_prefix) - 1);
367 /*
368 * Should be there already, from the build-id table in
369 * the header.
370 */
371 struct dso *kernel = __dsos__findnew(&dsos__kernel,
372 "[kernel.kallsyms]");
373 if (kernel == NULL)
374 goto out_problem;
375
376 kernel->kernel = 1;
377 if (__map_groups__create_kernel_maps(&session->kmaps,
378 session->vmlinux_maps,
379 kernel) < 0)
380 goto out_problem;
381
382 session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start;
383 session->vmlinux_maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
384
385 perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name,
386 self->mmap.pgoff);
387 }
388 return 0;
389 }
246 390
247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 391 thread = perf_session__findnew(session, self->mmap.pid);
248 self->mmap.pid, self->mmap.tid, 392 map = map__new(&self->mmap, MAP__FUNCTION,
249 (void *)(long)self->mmap.start, 393 session->cwd, session->cwdlen);
250 (void *)(long)self->mmap.len,
251 (void *)(long)self->mmap.pgoff,
252 self->mmap.filename);
253 394
254 if (thread == NULL || map == NULL) 395 if (thread == NULL || map == NULL)
255 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); 396 goto out_problem;
256 else
257 thread__insert_map(thread, map);
258 397
398 thread__insert_map(thread, map);
399 return 0;
400
401out_problem:
402 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
259 return 0; 403 return 0;
260} 404}
261 405
@@ -284,11 +428,10 @@ int event__process_task(event_t *self, struct perf_session *session)
284 return 0; 428 return 0;
285} 429}
286 430
287void thread__find_addr_location(struct thread *self, 431void thread__find_addr_map(struct thread *self,
288 struct perf_session *session, u8 cpumode, 432 struct perf_session *session, u8 cpumode,
289 enum map_type type, u64 addr, 433 enum map_type type, u64 addr,
290 struct addr_location *al, 434 struct addr_location *al)
291 symbol_filter_t filter)
292{ 435{
293 struct map_groups *mg = &self->mg; 436 struct map_groups *mg = &self->mg;
294 437
@@ -303,7 +446,6 @@ void thread__find_addr_location(struct thread *self,
303 else { 446 else {
304 al->level = 'H'; 447 al->level = 'H';
305 al->map = NULL; 448 al->map = NULL;
306 al->sym = NULL;
307 return; 449 return;
308 } 450 }
309try_again: 451try_again:
@@ -322,11 +464,21 @@ try_again:
322 mg = &session->kmaps; 464 mg = &session->kmaps;
323 goto try_again; 465 goto try_again;
324 } 466 }
325 al->sym = NULL; 467 } else
326 } else {
327 al->addr = al->map->map_ip(al->map, al->addr); 468 al->addr = al->map->map_ip(al->map, al->addr);
469}
470
471void thread__find_addr_location(struct thread *self,
472 struct perf_session *session, u8 cpumode,
473 enum map_type type, u64 addr,
474 struct addr_location *al,
475 symbol_filter_t filter)
476{
477 thread__find_addr_map(self, session, cpumode, type, addr, al);
478 if (al->map != NULL)
328 al->sym = map__find_symbol(al->map, session, al->addr, filter); 479 al->sym = map__find_symbol(al->map, session, al->addr, filter);
329 } 480 else
481 al->sym = NULL;
330} 482}
331 483
332static void dso__calc_col_width(struct dso *self) 484static void dso__calc_col_width(struct dso *self)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 690a96d0467c..50a7132887f5 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,10 +1,10 @@
1#ifndef __PERF_RECORD_H 1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3 3
4#include <limits.h>
5
4#include "../perf.h" 6#include "../perf.h"
5#include "util.h" 7#include "map.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8 8
9/* 9/*
10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -101,74 +101,19 @@ struct events_stats {
101 101
102void event__print_totals(void); 102void event__print_totals(void);
103 103
104enum map_type {
105 MAP__FUNCTION = 0,
106 MAP__VARIABLE,
107};
108
109#define MAP__NR_TYPES (MAP__VARIABLE + 1)
110
111struct map {
112 union {
113 struct rb_node rb_node;
114 struct list_head node;
115 };
116 u64 start;
117 u64 end;
118 enum map_type type;
119 u64 pgoff;
120 u64 (*map_ip)(struct map *, u64);
121 u64 (*unmap_ip)(struct map *, u64);
122 struct dso *dso;
123};
124
125static inline u64 map__map_ip(struct map *map, u64 ip)
126{
127 return ip - map->start + map->pgoff;
128}
129
130static inline u64 map__unmap_ip(struct map *map, u64 ip)
131{
132 return ip + map->start - map->pgoff;
133}
134
135static inline u64 identity__map_ip(struct map *map __used, u64 ip)
136{
137 return ip;
138}
139
140struct symbol;
141
142typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
143
144void map__init(struct map *self, enum map_type type,
145 u64 start, u64 end, u64 pgoff, struct dso *dso);
146struct map *map__new(struct mmap_event *event, enum map_type,
147 char *cwd, int cwdlen);
148void map__delete(struct map *self);
149struct map *map__clone(struct map *self);
150int map__overlap(struct map *l, struct map *r);
151size_t map__fprintf(struct map *self, FILE *fp);
152
153struct perf_session; 104struct perf_session;
154 105
155int map__load(struct map *self, struct perf_session *session, 106typedef int (*event__handler_t)(event_t *event, struct perf_session *session);
156 symbol_filter_t filter); 107
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session, 108int event__synthesize_thread(pid_t pid, event__handler_t process,
158 u64 addr, symbol_filter_t filter);
159struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
160 struct perf_session *session,
161 symbol_filter_t filter);
162void map__fixup_start(struct map *self);
163void map__fixup_end(struct map *self);
164
165int event__synthesize_thread(pid_t pid,
166 int (*process)(event_t *event,
167 struct perf_session *session),
168 struct perf_session *session); 109 struct perf_session *session);
169void event__synthesize_threads(int (*process)(event_t *event, 110void event__synthesize_threads(event__handler_t process,
170 struct perf_session *session),
171 struct perf_session *session); 111 struct perf_session *session);
112int event__synthesize_kernel_mmap(event__handler_t process,
113 struct perf_session *session,
114 const char *symbol_name);
115int event__synthesize_modules(event__handler_t process,
116 struct perf_session *session);
172 117
173int event__process_comm(event_t *self, struct perf_session *session); 118int event__process_comm(event_t *self, struct perf_session *session);
174int event__process_lost(event_t *self, struct perf_session *session); 119int event__process_lost(event_t *self, struct perf_session *session);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 8a0bca55106f..2bb2bdb1f456 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,8 +1,10 @@
1#include <sys/types.h> 1#include <sys/types.h>
2#include <byteswap.h>
2#include <unistd.h> 3#include <unistd.h>
3#include <stdio.h> 4#include <stdio.h>
4#include <stdlib.h> 5#include <stdlib.h>
5#include <linux/list.h> 6#include <linux/list.h>
7#include <linux/kernel.h>
6 8
7#include "util.h" 9#include "util.h"
8#include "header.h" 10#include "header.h"
@@ -105,24 +107,28 @@ struct perf_trace_event_type {
105static int event_count; 107static int event_count;
106static struct perf_trace_event_type *events; 108static struct perf_trace_event_type *events;
107 109
108void perf_header__push_event(u64 id, const char *name) 110int perf_header__push_event(u64 id, const char *name)
109{ 111{
110 if (strlen(name) > MAX_EVENT_NAME) 112 if (strlen(name) > MAX_EVENT_NAME)
111 pr_warning("Event %s will be truncated\n", name); 113 pr_warning("Event %s will be truncated\n", name);
112 114
113 if (!events) { 115 if (!events) {
114 events = malloc(sizeof(struct perf_trace_event_type)); 116 events = malloc(sizeof(struct perf_trace_event_type));
115 if (!events) 117 if (events == NULL)
116 die("nomem"); 118 return -ENOMEM;
117 } else { 119 } else {
118 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); 120 struct perf_trace_event_type *nevents;
119 if (!events) 121
120 die("nomem"); 122 nevents = realloc(events, (event_count + 1) * sizeof(*events));
123 if (nevents == NULL)
124 return -ENOMEM;
125 events = nevents;
121 } 126 }
122 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 127 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
123 events[event_count].event_id = id; 128 events[event_count].event_id = id;
124 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 129 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
125 event_count++; 130 event_count++;
131 return 0;
126} 132}
127 133
128char *perf_header__find_event(u64 id) 134char *perf_header__find_event(u64 id)
@@ -169,31 +175,45 @@ static int do_write(int fd, const void *buf, size_t size)
169 return 0; 175 return 0;
170} 176}
171 177
172static int __dsos__write_buildid_table(struct list_head *head, int fd) 178#define NAME_ALIGN 64
179
180static int write_padded(int fd, const void *bf, size_t count,
181 size_t count_aligned)
173{ 182{
174#define NAME_ALIGN 64
175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN]; 183 static const char zero_buf[NAME_ALIGN];
184 int err = do_write(fd, bf, count);
185
186 if (!err)
187 err = do_write(fd, zero_buf, count_aligned - count);
188
189 return err;
190}
177 191
178 list_for_each_entry(pos, head, node) { 192#define dsos__for_each_with_build_id(pos, head) \
193 list_for_each_entry(pos, head, node) \
194 if (!pos->has_build_id) \
195 continue; \
196 else
197
198static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
199{
200 struct dso *pos;
201
202 dsos__for_each_with_build_id(pos, head) {
179 int err; 203 int err;
180 struct build_id_event b; 204 struct build_id_event b;
181 size_t len; 205 size_t len = pos->long_name_len + 1;
182 206
183 if (!pos->has_build_id)
184 continue;
185 len = pos->long_name_len + 1;
186 len = ALIGN(len, NAME_ALIGN); 207 len = ALIGN(len, NAME_ALIGN);
187 memset(&b, 0, sizeof(b)); 208 memset(&b, 0, sizeof(b));
188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 209 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
210 b.header.misc = misc;
189 b.header.size = sizeof(b) + len; 211 b.header.size = sizeof(b) + len;
190 err = do_write(fd, &b, sizeof(b)); 212 err = do_write(fd, &b, sizeof(b));
191 if (err < 0) 213 if (err < 0)
192 return err; 214 return err;
193 err = do_write(fd, pos->long_name, pos->long_name_len + 1); 215 err = write_padded(fd, pos->long_name,
194 if (err < 0) 216 pos->long_name_len + 1, len);
195 return err;
196 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
197 if (err < 0) 217 if (err < 0)
198 return err; 218 return err;
199 } 219 }
@@ -203,12 +223,143 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)
203 223
204static int dsos__write_buildid_table(int fd) 224static int dsos__write_buildid_table(int fd)
205{ 225{
206 int err = __dsos__write_buildid_table(&dsos__kernel, fd); 226 int err = __dsos__write_buildid_table(&dsos__kernel,
227 PERF_RECORD_MISC_KERNEL, fd);
207 if (err == 0) 228 if (err == 0)
208 err = __dsos__write_buildid_table(&dsos__user, fd); 229 err = __dsos__write_buildid_table(&dsos__user,
230 PERF_RECORD_MISC_USER, fd);
231 return err;
232}
233
234int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
235 const char *name, bool is_kallsyms)
236{
237 const size_t size = PATH_MAX;
238 char *filename = malloc(size),
239 *linkname = malloc(size), *targetname;
240 int len, err = -1;
241
242 if (filename == NULL || linkname == NULL)
243 goto out_free;
244
245 len = snprintf(filename, size, "%s%s%s",
246 debugdir, is_kallsyms ? "/" : "", name);
247 if (mkdir_p(filename, 0755))
248 goto out_free;
249
250 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
251
252 if (access(filename, F_OK)) {
253 if (is_kallsyms) {
254 if (copyfile("/proc/kallsyms", filename))
255 goto out_free;
256 } else if (link(name, filename) && copyfile(name, filename))
257 goto out_free;
258 }
259
260 len = snprintf(linkname, size, "%s/.build-id/%.2s",
261 debugdir, sbuild_id);
262
263 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
264 goto out_free;
265
266 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
267 targetname = filename + strlen(debugdir) - 5;
268 memcpy(targetname, "../..", 5);
269
270 if (symlink(targetname, linkname) == 0)
271 err = 0;
272out_free:
273 free(filename);
274 free(linkname);
275 return err;
276}
277
278static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
279 const char *name, const char *debugdir,
280 bool is_kallsyms)
281{
282 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
283
284 build_id__sprintf(build_id, build_id_size, sbuild_id);
285
286 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
287}
288
289int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
290{
291 const size_t size = PATH_MAX;
292 char *filename = malloc(size),
293 *linkname = malloc(size);
294 int err = -1;
295
296 if (filename == NULL || linkname == NULL)
297 goto out_free;
298
299 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
300 debugdir, sbuild_id, sbuild_id + 2);
301
302 if (access(linkname, F_OK))
303 goto out_free;
304
305 if (readlink(linkname, filename, size) < 0)
306 goto out_free;
307
308 if (unlink(linkname))
309 goto out_free;
310
311 /*
312 * Since the link is relative, we must make it absolute:
313 */
314 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
315 debugdir, sbuild_id, filename);
316
317 if (unlink(linkname))
318 goto out_free;
319
320 err = 0;
321out_free:
322 free(filename);
323 free(linkname);
324 return err;
325}
326
327static int dso__cache_build_id(struct dso *self, const char *debugdir)
328{
329 bool is_kallsyms = self->kernel && self->long_name[0] != '/';
330
331 return build_id_cache__add_b(self->build_id, sizeof(self->build_id),
332 self->long_name, debugdir, is_kallsyms);
333}
334
335static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
336{
337 struct dso *pos;
338 int err = 0;
339
340 dsos__for_each_with_build_id(pos, head)
341 if (dso__cache_build_id(pos, debugdir))
342 err = -1;
343
209 return err; 344 return err;
210} 345}
211 346
347static int dsos__cache_build_ids(void)
348{
349 int err_kernel, err_user;
350 char debugdir[PATH_MAX];
351
352 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
353 DEBUG_CACHE_DIR);
354
355 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
356 return -1;
357
358 err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir);
359 err_user = __dsos__cache_build_ids(&dsos__user, debugdir);
360 return err_kernel || err_user ? -1 : 0;
361}
362
212static int perf_header__adds_write(struct perf_header *self, int fd) 363static int perf_header__adds_write(struct perf_header *self, int fd)
213{ 364{
214 int nr_sections; 365 int nr_sections;
@@ -258,6 +409,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
258 goto out_free; 409 goto out_free;
259 } 410 }
260 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; 411 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
412 dsos__cache_build_ids();
261 } 413 }
262 414
263 lseek(fd, sec_start, SEEK_SET); 415 lseek(fd, sec_start, SEEK_SET);
@@ -360,30 +512,43 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
360 return 0; 512 return 0;
361} 513}
362 514
363static void do_read(int fd, void *buf, size_t size) 515static int do_read(int fd, void *buf, size_t size)
364{ 516{
365 while (size) { 517 while (size) {
366 int ret = read(fd, buf, size); 518 int ret = read(fd, buf, size);
367 519
368 if (ret < 0) 520 if (ret <= 0)
369 die("failed to read"); 521 return -1;
370 if (ret == 0)
371 die("failed to read: missing data");
372 522
373 size -= ret; 523 size -= ret;
374 buf += ret; 524 buf += ret;
375 } 525 }
526
527 return 0;
528}
529
530static int perf_header__getbuffer64(struct perf_header *self,
531 int fd, void *buf, size_t size)
532{
533 if (do_read(fd, buf, size))
534 return -1;
535
536 if (self->needs_swap)
537 mem_bswap_64(buf, size);
538
539 return 0;
376} 540}
377 541
378int perf_header__process_sections(struct perf_header *self, int fd, 542int perf_header__process_sections(struct perf_header *self, int fd,
379 int (*process)(struct perf_file_section *self, 543 int (*process)(struct perf_file_section *self,
544 struct perf_header *ph,
380 int feat, int fd)) 545 int feat, int fd))
381{ 546{
382 struct perf_file_section *feat_sec; 547 struct perf_file_section *feat_sec;
383 int nr_sections; 548 int nr_sections;
384 int sec_size; 549 int sec_size;
385 int idx = 0; 550 int idx = 0;
386 int err = 0, feat = 1; 551 int err = -1, feat = 1;
387 552
388 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 553 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
389 if (!nr_sections) 554 if (!nr_sections)
@@ -397,33 +562,45 @@ int perf_header__process_sections(struct perf_header *self, int fd,
397 562
398 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 563 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
399 564
400 do_read(fd, feat_sec, sec_size); 565 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
566 goto out_free;
401 567
568 err = 0;
402 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 569 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
403 if (perf_header__has_feat(self, feat)) { 570 if (perf_header__has_feat(self, feat)) {
404 struct perf_file_section *sec = &feat_sec[idx++]; 571 struct perf_file_section *sec = &feat_sec[idx++];
405 572
406 err = process(sec, feat, fd); 573 err = process(sec, self, feat, fd);
407 if (err < 0) 574 if (err < 0)
408 break; 575 break;
409 } 576 }
410 ++feat; 577 ++feat;
411 } 578 }
412 579out_free:
413 free(feat_sec); 580 free(feat_sec);
414 return err; 581 return err;
415}; 582}
416 583
417int perf_file_header__read(struct perf_file_header *self, 584int perf_file_header__read(struct perf_file_header *self,
418 struct perf_header *ph, int fd) 585 struct perf_header *ph, int fd)
419{ 586{
420 lseek(fd, 0, SEEK_SET); 587 lseek(fd, 0, SEEK_SET);
421 do_read(fd, self, sizeof(*self));
422 588
423 if (self->magic != PERF_MAGIC || 589 if (do_read(fd, self, sizeof(*self)) ||
424 self->attr_size != sizeof(struct perf_file_attr)) 590 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
425 return -1; 591 return -1;
426 592
593 if (self->attr_size != sizeof(struct perf_file_attr)) {
594 u64 attr_size = bswap_64(self->attr_size);
595
596 if (attr_size != sizeof(struct perf_file_attr))
597 return -1;
598
599 mem_bswap_64(self, offsetof(struct perf_file_header,
600 adds_features));
601 ph->needs_swap = true;
602 }
603
427 if (self->size != sizeof(*self)) { 604 if (self->size != sizeof(*self)) {
428 /* Support the previous format */ 605 /* Support the previous format */
429 if (self->size == offsetof(typeof(*self), adds_features)) 606 if (self->size == offsetof(typeof(*self), adds_features))
@@ -433,16 +610,28 @@ int perf_file_header__read(struct perf_file_header *self,
433 } 610 }
434 611
435 memcpy(&ph->adds_features, &self->adds_features, 612 memcpy(&ph->adds_features, &self->adds_features,
436 sizeof(self->adds_features)); 613 sizeof(ph->adds_features));
614 /*
615 * FIXME: hack that assumes that if we need swap the perf.data file
616 * may be coming from an arch with a different word-size, ergo different
617 * DEFINE_BITMAP format, investigate more later, but for now its mostly
618 * safe to assume that we have a build-id section. Trace files probably
619 * have several other issues in this realm anyway...
620 */
621 if (ph->needs_swap) {
622 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
623 perf_header__set_feat(ph, HEADER_BUILD_ID);
624 }
437 625
438 ph->event_offset = self->event_types.offset; 626 ph->event_offset = self->event_types.offset;
439 ph->event_size = self->event_types.size; 627 ph->event_size = self->event_types.size;
440 ph->data_offset = self->data.offset; 628 ph->data_offset = self->data.offset;
441 ph->data_size = self->data.size; 629 ph->data_size = self->data.size;
442 return 0; 630 return 0;
443} 631}
444 632
445static int perf_file_section__process(struct perf_file_section *self, 633static int perf_file_section__process(struct perf_file_section *self,
634 struct perf_header *ph,
446 int feat, int fd) 635 int feat, int fd)
447{ 636{
448 if (lseek(fd, self->offset, SEEK_SET) < 0) { 637 if (lseek(fd, self->offset, SEEK_SET) < 0) {
@@ -457,7 +646,7 @@ static int perf_file_section__process(struct perf_file_section *self,
457 break; 646 break;
458 647
459 case HEADER_BUILD_ID: 648 case HEADER_BUILD_ID:
460 if (perf_header__read_build_ids(fd, self->offset, self->size)) 649 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
461 pr_debug("Failed to read buildids, continuing...\n"); 650 pr_debug("Failed to read buildids, continuing...\n");
462 break; 651 break;
463 default: 652 default:
@@ -469,7 +658,7 @@ static int perf_file_section__process(struct perf_file_section *self,
469 658
470int perf_header__read(struct perf_header *self, int fd) 659int perf_header__read(struct perf_header *self, int fd)
471{ 660{
472 struct perf_file_header f_header; 661 struct perf_file_header f_header;
473 struct perf_file_attr f_attr; 662 struct perf_file_attr f_attr;
474 u64 f_id; 663 u64 f_id;
475 int nr_attrs, nr_ids, i, j; 664 int nr_attrs, nr_ids, i, j;
@@ -486,7 +675,9 @@ int perf_header__read(struct perf_header *self, int fd)
486 struct perf_header_attr *attr; 675 struct perf_header_attr *attr;
487 off_t tmp; 676 off_t tmp;
488 677
489 do_read(fd, &f_attr, sizeof(f_attr)); 678 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
679 goto out_errno;
680
490 tmp = lseek(fd, 0, SEEK_CUR); 681 tmp = lseek(fd, 0, SEEK_CUR);
491 682
492 attr = perf_header_attr__new(&f_attr.attr); 683 attr = perf_header_attr__new(&f_attr.attr);
@@ -497,7 +688,8 @@ int perf_header__read(struct perf_header *self, int fd)
497 lseek(fd, f_attr.ids.offset, SEEK_SET); 688 lseek(fd, f_attr.ids.offset, SEEK_SET);
498 689
499 for (j = 0; j < nr_ids; j++) { 690 for (j = 0; j < nr_ids; j++) {
500 do_read(fd, &f_id, sizeof(f_id)); 691 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
692 goto out_errno;
501 693
502 if (perf_header_attr__add_id(attr, f_id) < 0) { 694 if (perf_header_attr__add_id(attr, f_id) < 0) {
503 perf_header_attr__delete(attr); 695 perf_header_attr__delete(attr);
@@ -517,7 +709,9 @@ int perf_header__read(struct perf_header *self, int fd)
517 events = malloc(f_header.event_types.size); 709 events = malloc(f_header.event_types.size);
518 if (events == NULL) 710 if (events == NULL)
519 return -ENOMEM; 711 return -ENOMEM;
520 do_read(fd, events, f_header.event_types.size); 712 if (perf_header__getbuffer64(self, fd, events,
713 f_header.event_types.size))
714 goto out_errno;
521 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 715 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
522 } 716 }
523 717
@@ -527,6 +721,8 @@ int perf_header__read(struct perf_header *self, int fd)
527 721
528 self->frozen = 1; 722 self->frozen = 1;
529 return 0; 723 return 0;
724out_errno:
725 return -errno;
530} 726}
531 727
532u64 perf_header__sample_type(struct perf_header *header) 728u64 perf_header__sample_type(struct perf_header *header)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d118d05d3abe..82a6af72d4cc 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -5,6 +5,7 @@
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include "types.h"
8#include "event.h"
8 9
9#include <linux/bitmap.h> 10#include <linux/bitmap.h>
10 11
@@ -52,6 +53,7 @@ struct perf_header {
52 u64 data_size; 53 u64 data_size;
53 u64 event_offset; 54 u64 event_offset;
54 u64 event_size; 55 u64 event_size;
56 bool needs_swap;
55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 57 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
56}; 58};
57 59
@@ -64,7 +66,7 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit);
64int perf_header__add_attr(struct perf_header *self, 66int perf_header__add_attr(struct perf_header *self,
65 struct perf_header_attr *attr); 67 struct perf_header_attr *attr);
66 68
67void perf_header__push_event(u64 id, const char *name); 69int perf_header__push_event(u64 id, const char *name);
68char *perf_header__find_event(u64 id); 70char *perf_header__find_event(u64 id);
69 71
70struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr); 72struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
@@ -80,6 +82,11 @@ bool perf_header__has_feat(const struct perf_header *self, int feat);
80 82
81int perf_header__process_sections(struct perf_header *self, int fd, 83int perf_header__process_sections(struct perf_header *self, int fd,
82 int (*process)(struct perf_file_section *self, 84 int (*process)(struct perf_file_section *self,
85 struct perf_header *ph,
83 int feat, int fd)); 86 int feat, int fd));
84 87
88int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
89 const char *name, bool is_kallsyms);
90int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
91
85#endif /* __PERF_HEADER_H */ 92#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
new file mode 100644
index 000000000000..72f0b6ab5ea5
--- /dev/null
+++ b/tools/perf/util/map.h
@@ -0,0 +1,73 @@
1#ifndef __PERF_MAP_H
2#define __PERF_MAP_H
3
4#include <linux/compiler.h>
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include <linux/types.h>
8
9enum map_type {
10 MAP__FUNCTION = 0,
11 MAP__VARIABLE,
12};
13
14#define MAP__NR_TYPES (MAP__VARIABLE + 1)
15
16struct dso;
17
18struct map {
19 union {
20 struct rb_node rb_node;
21 struct list_head node;
22 };
23 u64 start;
24 u64 end;
25 enum map_type type;
26 u64 pgoff;
27 u64 (*map_ip)(struct map *, u64);
28 u64 (*unmap_ip)(struct map *, u64);
29 struct dso *dso;
30};
31
32static inline u64 map__map_ip(struct map *map, u64 ip)
33{
34 return ip - map->start + map->pgoff;
35}
36
37static inline u64 map__unmap_ip(struct map *map, u64 ip)
38{
39 return ip + map->start - map->pgoff;
40}
41
42static inline u64 identity__map_ip(struct map *map __used, u64 ip)
43{
44 return ip;
45}
46
47struct symbol;
48struct mmap_event;
49
50typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
51
52void map__init(struct map *self, enum map_type type,
53 u64 start, u64 end, u64 pgoff, struct dso *dso);
54struct map *map__new(struct mmap_event *event, enum map_type,
55 char *cwd, int cwdlen);
56void map__delete(struct map *self);
57struct map *map__clone(struct map *self);
58int map__overlap(struct map *l, struct map *r);
59size_t map__fprintf(struct map *self, FILE *fp);
60
61struct perf_session;
62
63int map__load(struct map *self, struct perf_session *session,
64 symbol_filter_t filter);
65struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
66 u64 addr, symbol_filter_t filter);
67struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
68 struct perf_session *session,
69 symbol_filter_t filter);
70void map__fixup_start(struct map *self);
71void map__fixup_end(struct map *self);
72
73#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index e5bc0fb016b2..05d0c5c2030c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -450,7 +450,8 @@ parse_single_tracepoint_event(char *sys_name,
450/* sys + ':' + event + ':' + flags*/ 450/* sys + ':' + event + ':' + flags*/
451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
452static enum event_result 452static enum event_result
453parse_subsystem_tracepoint_event(char *sys_name, char *flags) 453parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
454 char *flags)
454{ 455{
455 char evt_path[MAXPATHLEN]; 456 char evt_path[MAXPATHLEN];
456 struct dirent *evt_ent; 457 struct dirent *evt_ent;
@@ -474,6 +475,9 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
474 || !strcmp(evt_ent->d_name, "filter")) 475 || !strcmp(evt_ent->d_name, "filter"))
475 continue; 476 continue;
476 477
478 if (!strglobmatch(evt_ent->d_name, evt_exp))
479 continue;
480
477 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, 481 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
478 evt_ent->d_name, flags ? ":" : "", 482 evt_ent->d_name, flags ? ":" : "",
479 flags ?: ""); 483 flags ?: "");
@@ -522,9 +526,10 @@ static enum event_result parse_tracepoint_event(const char **strp,
522 if (evt_length >= MAX_EVENT_LENGTH) 526 if (evt_length >= MAX_EVENT_LENGTH)
523 return EVT_FAILED; 527 return EVT_FAILED;
524 528
525 if (!strcmp(evt_name, "*")) { 529 if (strpbrk(evt_name, "*?")) {
526 *strp = evt_name + evt_length; 530 *strp = evt_name + evt_length;
527 return parse_subsystem_tracepoint_event(sys_name, flags); 531 return parse_multiple_tracepoint_event(sys_name, evt_name,
532 flags);
528 } else 533 } else
529 return parse_single_tracepoint_event(sys_name, evt_name, 534 return parse_single_tracepoint_event(sys_name, evt_name,
530 evt_length, flags, 535 evt_length, flags,
@@ -753,11 +758,11 @@ modifier:
753 return ret; 758 return ret;
754} 759}
755 760
756static void store_event_type(const char *orgname) 761static int store_event_type(const char *orgname)
757{ 762{
758 char filename[PATH_MAX], *c; 763 char filename[PATH_MAX], *c;
759 FILE *file; 764 FILE *file;
760 int id; 765 int id, n;
761 766
762 sprintf(filename, "%s/", debugfs_path); 767 sprintf(filename, "%s/", debugfs_path);
763 strncat(filename, orgname, strlen(orgname)); 768 strncat(filename, orgname, strlen(orgname));
@@ -769,11 +774,14 @@ static void store_event_type(const char *orgname)
769 774
770 file = fopen(filename, "r"); 775 file = fopen(filename, "r");
771 if (!file) 776 if (!file)
772 return; 777 return 0;
773 if (fscanf(file, "%i", &id) < 1) 778 n = fscanf(file, "%i", &id);
774 die("cannot store event ID");
775 fclose(file); 779 fclose(file);
776 perf_header__push_event(id, orgname); 780 if (n < 1) {
781 pr_err("cannot store event ID\n");
782 return -EINVAL;
783 }
784 return perf_header__push_event(id, orgname);
777} 785}
778 786
779int parse_events(const struct option *opt __used, const char *str, int unset __used) 787int parse_events(const struct option *opt __used, const char *str, int unset __used)
@@ -782,7 +790,8 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
782 enum event_result ret; 790 enum event_result ret;
783 791
784 if (strchr(str, ':')) 792 if (strchr(str, ':'))
785 store_event_type(str); 793 if (store_event_type(str) < 0)
794 return -1;
786 795
787 for (;;) { 796 for (;;) {
788 if (nr_counters == MAX_COUNTERS) 797 if (nr_counters == MAX_COUNTERS)
@@ -835,11 +844,12 @@ int parse_filter(const struct option *opt __used, const char *str,
835} 844}
836 845
837static const char * const event_type_descriptors[] = { 846static const char * const event_type_descriptors[] = {
838 "",
839 "Hardware event", 847 "Hardware event",
840 "Software event", 848 "Software event",
841 "Tracepoint event", 849 "Tracepoint event",
842 "Hardware cache event", 850 "Hardware cache event",
851 "Raw hardware event descriptor",
852 "Hardware breakpoint",
843}; 853};
844 854
845/* 855/*
@@ -872,7 +882,7 @@ static void print_tracepoint_events(void)
872 snprintf(evt_path, MAXPATHLEN, "%s:%s", 882 snprintf(evt_path, MAXPATHLEN, "%s:%s",
873 sys_dirent.d_name, evt_dirent.d_name); 883 sys_dirent.d_name, evt_dirent.d_name);
874 printf(" %-42s [%s]\n", evt_path, 884 printf(" %-42s [%s]\n", evt_path,
875 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 885 event_type_descriptors[PERF_TYPE_TRACEPOINT]);
876 } 886 }
877 closedir(evt_dir); 887 closedir(evt_dir);
878 } 888 }
@@ -892,9 +902,7 @@ void print_events(void)
892 printf("List of pre-defined events (to be used in -e):\n"); 902 printf("List of pre-defined events (to be used in -e):\n");
893 903
894 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 904 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
895 type = syms->type + 1; 905 type = syms->type;
896 if (type >= ARRAY_SIZE(event_type_descriptors))
897 type = 0;
898 906
899 if (type != prev_type) 907 if (type != prev_type)
900 printf("\n"); 908 printf("\n");
@@ -919,17 +927,19 @@ void print_events(void)
919 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 927 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
920 printf(" %-42s [%s]\n", 928 printf(" %-42s [%s]\n",
921 event_cache_name(type, op, i), 929 event_cache_name(type, op, i),
922 event_type_descriptors[4]); 930 event_type_descriptors[PERF_TYPE_HW_CACHE]);
923 } 931 }
924 } 932 }
925 } 933 }
926 934
927 printf("\n"); 935 printf("\n");
928 printf(" %-42s [raw hardware event descriptor]\n", 936 printf(" %-42s [%s]\n",
929 "rNNN"); 937 "rNNN", event_type_descriptors[PERF_TYPE_RAW]);
930 printf("\n"); 938 printf("\n");
931 939
932 printf(" %-42s [hardware breakpoint]\n", "mem:<addr>[:access]"); 940 printf(" %-42s [%s]\n",
941 "mem:<addr>[:access]",
942 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
933 printf("\n"); 943 printf("\n");
934 944
935 print_tracepoint_events(); 945 print_tracepoint_events();
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 29465d440043..71b0dd590a37 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -37,6 +37,8 @@
37#include "string.h" 37#include "string.h"
38#include "strlist.h" 38#include "strlist.h"
39#include "debug.h" 39#include "debug.h"
40#include "cache.h"
41#include "color.h"
40#include "parse-events.h" /* For debugfs_path */ 42#include "parse-events.h" /* For debugfs_path */
41#include "probe-event.h" 43#include "probe-event.h"
42 44
@@ -62,6 +64,42 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
62 return ret; 64 return ret;
63} 65}
64 66
67void parse_line_range_desc(const char *arg, struct line_range *lr)
68{
69 const char *ptr;
70 char *tmp;
71 /*
72 * <Syntax>
73 * SRC:SLN[+NUM|-ELN]
74 * FUNC[:SLN[+NUM|-ELN]]
75 */
76 ptr = strchr(arg, ':');
77 if (ptr) {
78 lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0);
79 if (*tmp == '+')
80 lr->end = lr->start + (unsigned int)strtoul(tmp + 1,
81 &tmp, 0);
82 else if (*tmp == '-')
83 lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0);
84 else
85 lr->end = 0;
86 pr_debug("Line range is %u to %u\n", lr->start, lr->end);
87 if (lr->end && lr->start > lr->end)
88 semantic_error("Start line must be smaller"
89 " than end line.");
90 if (*tmp != '\0')
91 semantic_error("Tailing with invalid character '%d'.",
92 *tmp);
93 tmp = strndup(arg, (ptr - arg));
94 } else
95 tmp = strdup(arg);
96
97 if (strchr(tmp, '.'))
98 lr->file = tmp;
99 else
100 lr->function = tmp;
101}
102
65/* Check the name is good for event/group */ 103/* Check the name is good for event/group */
66static bool check_event_name(const char *name) 104static bool check_event_name(const char *name)
67{ 105{
@@ -368,7 +406,7 @@ static int open_kprobe_events(int flags, int mode)
368 if (ret < 0) { 406 if (ret < 0) {
369 if (errno == ENOENT) 407 if (errno == ENOENT)
370 die("kprobe_events file does not exist -" 408 die("kprobe_events file does not exist -"
371 " please rebuild with CONFIG_KPROBE_TRACER."); 409 " please rebuild with CONFIG_KPROBE_EVENT.");
372 else 410 else
373 die("Could not open kprobe_events file: %s", 411 die("Could not open kprobe_events file: %s",
374 strerror(errno)); 412 strerror(errno));
@@ -455,6 +493,8 @@ void show_perf_probe_events(void)
455 struct strlist *rawlist; 493 struct strlist *rawlist;
456 struct str_node *ent; 494 struct str_node *ent;
457 495
496 setup_pager();
497
458 fd = open_kprobe_events(O_RDONLY, 0); 498 fd = open_kprobe_events(O_RDONLY, 0);
459 rawlist = get_trace_kprobe_event_rawlist(fd); 499 rawlist = get_trace_kprobe_event_rawlist(fd);
460 close(fd); 500 close(fd);
@@ -675,3 +715,66 @@ void del_trace_kprobe_events(struct strlist *dellist)
675 close(fd); 715 close(fd);
676} 716}
677 717
718#define LINEBUF_SIZE 256
719
720static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
721{
722 char buf[LINEBUF_SIZE];
723 const char *color = PERF_COLOR_BLUE;
724
725 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
726 goto error;
727 if (!skip) {
728 if (show_num)
729 fprintf(stdout, "%7u %s", l, buf);
730 else
731 color_fprintf(stdout, color, " %s", buf);
732 }
733
734 while (strlen(buf) == LINEBUF_SIZE - 1 &&
735 buf[LINEBUF_SIZE - 2] != '\n') {
736 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
737 goto error;
738 if (!skip) {
739 if (show_num)
740 fprintf(stdout, "%s", buf);
741 else
742 color_fprintf(stdout, color, "%s", buf);
743 }
744 }
745 return;
746error:
747 if (feof(fp))
748 die("Source file is shorter than expected.");
749 else
750 die("File read error: %s", strerror(errno));
751}
752
753void show_line_range(struct line_range *lr)
754{
755 unsigned int l = 1;
756 struct line_node *ln;
757 FILE *fp;
758
759 setup_pager();
760
761 if (lr->function)
762 fprintf(stdout, "<%s:%d>\n", lr->function,
763 lr->start - lr->offset);
764 else
765 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
766
767 fp = fopen(lr->path, "r");
768 if (fp == NULL)
769 die("Failed to open %s: %s", lr->path, strerror(errno));
770 /* Skip to starting line number */
771 while (l < lr->start)
772 show_one_line(fp, l++, true, false);
773
774 list_for_each_entry(ln, &lr->line_list, list) {
775 while (ln->line > l)
776 show_one_line(fp, (l++) - lr->offset, false, false);
777 show_one_line(fp, (l++) - lr->offset, false, true);
778 }
779 fclose(fp);
780}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 7f1d499118c0..711287d4baea 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -5,6 +5,7 @@
5#include "probe-finder.h" 5#include "probe-finder.h"
6#include "strlist.h" 6#include "strlist.h"
7 7
8extern void parse_line_range_desc(const char *arg, struct line_range *lr);
8extern void parse_perf_probe_event(const char *str, struct probe_point *pp, 9extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
9 bool *need_dwarf); 10 bool *need_dwarf);
10extern int synthesize_perf_probe_point(struct probe_point *pp); 11extern int synthesize_perf_probe_point(struct probe_point *pp);
@@ -15,6 +16,7 @@ extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
15 bool force_add); 16 bool force_add);
16extern void del_trace_kprobe_events(struct strlist *dellist); 17extern void del_trace_kprobe_events(struct strlist *dellist);
17extern void show_perf_probe_events(void); 18extern void show_perf_probe_events(void);
19extern void show_line_range(struct line_range *lr);
18 20
19/* Maximum index number of event-name postfix */ 21/* Maximum index number of event-name postfix */
20#define MAX_EVENT_INDEX 1024 22#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4b852c0d16a5..1b2124d12f68 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -140,6 +140,31 @@ static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
140 return found; 140 return found;
141} 141}
142 142
143static int cu_get_filename(Dwarf_Die cu_die, Dwarf_Unsigned fno, char **buf)
144{
145 Dwarf_Signed cnt, i;
146 char **srcs;
147 int ret = 0;
148
149 if (!buf || !fno)
150 return -EINVAL;
151
152 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
153 if (ret == DW_DLV_OK) {
154 if ((Dwarf_Unsigned)cnt > fno - 1) {
155 *buf = strdup(srcs[fno - 1]);
156 ret = 0;
157 pr_debug("found filename: %s\n", *buf);
158 } else
159 ret = -ENOENT;
160 for (i = 0; i < cnt; i++)
161 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
162 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
163 } else
164 ret = -EINVAL;
165 return ret;
166}
167
143/* Compare diename and tname */ 168/* Compare diename and tname */
144static int die_compare_name(Dwarf_Die dw_die, const char *tname) 169static int die_compare_name(Dwarf_Die dw_die, const char *tname)
145{ 170{
@@ -402,11 +427,11 @@ static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
402 } else if (op == DW_OP_regx) { 427 } else if (op == DW_OP_regx) {
403 regn = loc->lr_number; 428 regn = loc->lr_number;
404 } else 429 } else
405 die("Dwarf_OP %d is not supported.\n", op); 430 die("Dwarf_OP %d is not supported.", op);
406 431
407 regs = get_arch_regstr(regn); 432 regs = get_arch_regstr(regn);
408 if (!regs) 433 if (!regs)
409 die("%lld exceeds max register number.\n", regn); 434 die("%lld exceeds max register number.", regn);
410 435
411 if (deref) 436 if (deref)
412 ret = snprintf(pf->buf, pf->len, 437 ret = snprintf(pf->buf, pf->len,
@@ -438,7 +463,7 @@ static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf)
438 return ; 463 return ;
439error: 464error:
440 die("Failed to find the location of %s at this address.\n" 465 die("Failed to find the location of %s at this address.\n"
441 " Perhaps, it has been optimized out.\n", pf->var); 466 " Perhaps, it has been optimized out.", pf->var);
442} 467}
443 468
444static int variable_callback(struct die_link *dlink, void *data) 469static int variable_callback(struct die_link *dlink, void *data)
@@ -476,7 +501,7 @@ static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
476 /* Search child die for local variables and parameters. */ 501 /* Search child die for local variables and parameters. */
477 ret = search_die_from_children(sp_die, variable_callback, pf); 502 ret = search_die_from_children(sp_die, variable_callback, pf);
478 if (!ret) 503 if (!ret)
479 die("Failed to find '%s' in this function.\n", pf->var); 504 die("Failed to find '%s' in this function.", pf->var);
480} 505}
481 506
482/* Get a frame base on the address */ 507/* Get a frame base on the address */
@@ -567,7 +592,7 @@ static int probeaddr_callback(struct die_link *dlink, void *data)
567} 592}
568 593
569/* Find probe point from its line number */ 594/* Find probe point from its line number */
570static void find_by_line(struct probe_finder *pf) 595static void find_probe_point_by_line(struct probe_finder *pf)
571{ 596{
572 Dwarf_Signed cnt, i, clm; 597 Dwarf_Signed cnt, i, clm;
573 Dwarf_Line *lines; 598 Dwarf_Line *lines;
@@ -602,7 +627,7 @@ static void find_by_line(struct probe_finder *pf)
602 ret = search_die_from_children(pf->cu_die, 627 ret = search_die_from_children(pf->cu_die,
603 probeaddr_callback, pf); 628 probeaddr_callback, pf);
604 if (ret == 0) 629 if (ret == 0)
605 die("Probe point is not found in subprograms.\n"); 630 die("Probe point is not found in subprograms.");
606 /* Continuing, because target line might be inlined. */ 631 /* Continuing, because target line might be inlined. */
607 } 632 }
608 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 633 dwarf_srclines_dealloc(__dw_debug, lines, cnt);
@@ -626,7 +651,7 @@ static int probefunc_callback(struct die_link *dlink, void *data)
626 pf->fno = die_get_decl_file(dlink->die); 651 pf->fno = die_get_decl_file(dlink->die);
627 pf->lno = die_get_decl_line(dlink->die) 652 pf->lno = die_get_decl_line(dlink->die)
628 + pp->line; 653 + pp->line;
629 find_by_line(pf); 654 find_probe_point_by_line(pf);
630 return 1; 655 return 1;
631 } 656 }
632 if (die_inlined_subprogram(dlink->die)) { 657 if (die_inlined_subprogram(dlink->die)) {
@@ -661,7 +686,7 @@ static int probefunc_callback(struct die_link *dlink, void *data)
661 !die_inlined_subprogram(lk->die)) 686 !die_inlined_subprogram(lk->die))
662 goto found; 687 goto found;
663 } 688 }
664 die("Failed to find real subprogram.\n"); 689 die("Failed to find real subprogram.");
665found: 690found:
666 /* Get offset from subprogram */ 691 /* Get offset from subprogram */
667 ret = die_within_subprogram(lk->die, pf->addr, &offs); 692 ret = die_within_subprogram(lk->die, pf->addr, &offs);
@@ -673,7 +698,7 @@ found:
673 return 0; 698 return 0;
674} 699}
675 700
676static void find_by_func(struct probe_finder *pf) 701static void find_probe_point_by_func(struct probe_finder *pf)
677{ 702{
678 search_die_from_children(pf->cu_die, probefunc_callback, pf); 703 search_die_from_children(pf->cu_die, probefunc_callback, pf);
679} 704}
@@ -714,10 +739,10 @@ int find_probepoint(int fd, struct probe_point *pp)
714 if (ret == DW_DLV_NO_ENTRY) 739 if (ret == DW_DLV_NO_ENTRY)
715 pf.cu_base = 0; 740 pf.cu_base = 0;
716 if (pp->function) 741 if (pp->function)
717 find_by_func(&pf); 742 find_probe_point_by_func(&pf);
718 else { 743 else {
719 pf.lno = pp->line; 744 pf.lno = pp->line;
720 find_by_line(&pf); 745 find_probe_point_by_line(&pf);
721 } 746 }
722 } 747 }
723 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); 748 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE);
@@ -728,3 +753,159 @@ int find_probepoint(int fd, struct probe_point *pp)
728 return pp->found; 753 return pp->found;
729} 754}
730 755
756
757static void line_range_add_line(struct line_range *lr, unsigned int line)
758{
759 struct line_node *ln;
760 struct list_head *p;
761
762 /* Reverse search, because new line will be the last one */
763 list_for_each_entry_reverse(ln, &lr->line_list, list) {
764 if (ln->line < line) {
765 p = &ln->list;
766 goto found;
767 } else if (ln->line == line) /* Already exist */
768 return ;
769 }
770 /* List is empty, or the smallest entry */
771 p = &lr->line_list;
772found:
773 pr_debug("Debug: add a line %u\n", line);
774 ln = zalloc(sizeof(struct line_node));
775 DIE_IF(ln == NULL);
776 ln->line = line;
777 INIT_LIST_HEAD(&ln->list);
778 list_add(&ln->list, p);
779}
780
781/* Find line range from its line number */
782static void find_line_range_by_line(struct line_finder *lf)
783{
784 Dwarf_Signed cnt, i;
785 Dwarf_Line *lines;
786 Dwarf_Unsigned lineno = 0;
787 Dwarf_Unsigned fno;
788 Dwarf_Addr addr;
789 int ret;
790
791 ret = dwarf_srclines(lf->cu_die, &lines, &cnt, &__dw_error);
792 DIE_IF(ret != DW_DLV_OK);
793
794 for (i = 0; i < cnt; i++) {
795 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
796 DIE_IF(ret != DW_DLV_OK);
797 if (fno != lf->fno)
798 continue;
799
800 ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
801 DIE_IF(ret != DW_DLV_OK);
802 if (lf->lno_s > lineno || lf->lno_e < lineno)
803 continue;
804
805 /* Filter line in the function address range */
806 if (lf->addr_s && lf->addr_e) {
807 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
808 DIE_IF(ret != DW_DLV_OK);
809 if (lf->addr_s > addr || lf->addr_e <= addr)
810 continue;
811 }
812 line_range_add_line(lf->lr, (unsigned int)lineno);
813 }
814 dwarf_srclines_dealloc(__dw_debug, lines, cnt);
815 if (!list_empty(&lf->lr->line_list))
816 lf->found = 1;
817}
818
819/* Search function from function name */
820static int linefunc_callback(struct die_link *dlink, void *data)
821{
822 struct line_finder *lf = (struct line_finder *)data;
823 struct line_range *lr = lf->lr;
824 Dwarf_Half tag;
825 int ret;
826
827 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
828 DIE_IF(ret == DW_DLV_ERROR);
829 if (tag == DW_TAG_subprogram &&
830 die_compare_name(dlink->die, lr->function) == 0) {
831 /* Get the address range of this function */
832 ret = dwarf_highpc(dlink->die, &lf->addr_e, &__dw_error);
833 if (ret == DW_DLV_OK)
834 ret = dwarf_lowpc(dlink->die, &lf->addr_s, &__dw_error);
835 DIE_IF(ret == DW_DLV_ERROR);
836 if (ret == DW_DLV_NO_ENTRY) {
837 lf->addr_s = 0;
838 lf->addr_e = 0;
839 }
840
841 lf->fno = die_get_decl_file(dlink->die);
842 lr->offset = die_get_decl_line(dlink->die);;
843 lf->lno_s = lr->offset + lr->start;
844 if (!lr->end)
845 lf->lno_e = (Dwarf_Unsigned)-1;
846 else
847 lf->lno_e = lr->offset + lr->end;
848 lr->start = lf->lno_s;
849 lr->end = lf->lno_e;
850 find_line_range_by_line(lf);
851 /* If we find a target function, this should be end. */
852 lf->found = 1;
853 return 1;
854 }
855 return 0;
856}
857
858static void find_line_range_by_func(struct line_finder *lf)
859{
860 search_die_from_children(lf->cu_die, linefunc_callback, lf);
861}
862
863int find_line_range(int fd, struct line_range *lr)
864{
865 Dwarf_Half addr_size = 0;
866 Dwarf_Unsigned next_cuh = 0;
867 int ret;
868 struct line_finder lf = {.lr = lr};
869
870 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
871 if (ret != DW_DLV_OK)
872 return -ENOENT;
873
874 while (!lf.found) {
875 /* Search CU (Compilation Unit) */
876 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
877 &addr_size, &next_cuh, &__dw_error);
878 DIE_IF(ret == DW_DLV_ERROR);
879 if (ret == DW_DLV_NO_ENTRY)
880 break;
881
882 /* Get the DIE(Debugging Information Entry) of this CU */
883 ret = dwarf_siblingof(__dw_debug, 0, &lf.cu_die, &__dw_error);
884 DIE_IF(ret != DW_DLV_OK);
885
886 /* Check if target file is included. */
887 if (lr->file)
888 lf.fno = cu_find_fileno(lf.cu_die, lr->file);
889
890 if (!lr->file || lf.fno) {
891 if (lr->function)
892 find_line_range_by_func(&lf);
893 else {
894 lf.lno_s = lr->start;
895 if (!lr->end)
896 lf.lno_e = (Dwarf_Unsigned)-1;
897 else
898 lf.lno_e = lr->end;
899 find_line_range_by_line(&lf);
900 }
901 /* Get the real file path */
902 if (lf.found)
903 cu_get_filename(lf.cu_die, lf.fno, &lr->path);
904 }
905 dwarf_dealloc(__dw_debug, lf.cu_die, DW_DLA_DIE);
906 }
907 ret = dwarf_finish(__dw_debug, &__dw_error);
908 DIE_IF(ret != DW_DLV_OK);
909 return lf.found;
910}
911
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index a4086aaddb73..972b386116f1 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -1,6 +1,8 @@
1#ifndef _PROBE_FINDER_H 1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H 2#define _PROBE_FINDER_H
3 3
4#include "util.h"
5
4#define MAX_PATH_LEN 256 6#define MAX_PATH_LEN 256
5#define MAX_PROBE_BUFFER 1024 7#define MAX_PROBE_BUFFER 1024
6#define MAX_PROBES 128 8#define MAX_PROBES 128
@@ -32,8 +34,26 @@ struct probe_point {
32 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ 34 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
33}; 35};
34 36
37/* Line number container */
38struct line_node {
39 struct list_head list;
40 unsigned int line;
41};
42
43/* Line range */
44struct line_range {
45 char *file; /* File name */
46 char *function; /* Function name */
47 unsigned int start; /* Start line number */
48 unsigned int end; /* End line number */
49 unsigned int offset; /* Start line offset */
50 char *path; /* Real path name */
51 struct list_head line_list; /* Visible lines */
52};
53
35#ifndef NO_LIBDWARF 54#ifndef NO_LIBDWARF
36extern int find_probepoint(int fd, struct probe_point *pp); 55extern int find_probepoint(int fd, struct probe_point *pp);
56extern int find_line_range(int fd, struct line_range *lr);
37 57
38/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */ 58/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */
39#ifndef _MIPS_SZLONG 59#ifndef _MIPS_SZLONG
@@ -60,6 +80,19 @@ struct probe_finder {
60 char *buf; /* Current output buffer */ 80 char *buf; /* Current output buffer */
61 int len; /* Length of output buffer */ 81 int len; /* Length of output buffer */
62}; 82};
83
84struct line_finder {
85 struct line_range *lr; /* Target line range */
86
87 Dwarf_Unsigned fno; /* File number */
88 Dwarf_Unsigned lno_s; /* Start line number */
89 Dwarf_Unsigned lno_e; /* End line number */
90 Dwarf_Addr addr_s; /* Start address */
91 Dwarf_Addr addr_e; /* End address */
92 Dwarf_Die cu_die; /* Current CU */
93 int found;
94};
95
63#endif /* NO_LIBDWARF */ 96#endif /* NO_LIBDWARF */
64 97
65#endif /*_PROBE_FINDER_H */ 98#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ce3a6c8abe76..8e7c1896eaa2 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,5 +1,6 @@
1#include <linux/kernel.h> 1#include <linux/kernel.h>
2 2
3#include <byteswap.h>
3#include <unistd.h> 4#include <unistd.h>
4#include <sys/types.h> 5#include <sys/types.h>
5 6
@@ -66,13 +67,22 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
66 self->mmap_window = 32; 67 self->mmap_window = 32;
67 self->cwd = NULL; 68 self->cwd = NULL;
68 self->cwdlen = 0; 69 self->cwdlen = 0;
70 self->unknown_events = 0;
69 map_groups__init(&self->kmaps); 71 map_groups__init(&self->kmaps);
70 72
71 if (perf_session__create_kernel_maps(self) < 0) 73 if (mode == O_RDONLY) {
72 goto out_delete; 74 if (perf_session__open(self, force) < 0)
75 goto out_delete;
76 } else if (mode == O_WRONLY) {
77 /*
78 * In O_RDONLY mode this will be performed when reading the
79 * kernel MMAP event, in event__process_mmap().
80 */
81 if (perf_session__create_kernel_maps(self) < 0)
82 goto out_delete;
83 }
73 84
74 if (mode == O_RDONLY && perf_session__open(self, force) < 0) 85 self->sample_type = perf_header__sample_type(&self->header);
75 goto out_delete;
76out: 86out:
77 return self; 87 return self;
78out_free: 88out_free:
@@ -148,3 +158,389 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
148 158
149 return syms; 159 return syms;
150} 160}
161
162static int process_event_stub(event_t *event __used,
163 struct perf_session *session __used)
164{
165 dump_printf(": unhandled!\n");
166 return 0;
167}
168
169static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
170{
171 if (handler->sample == NULL)
172 handler->sample = process_event_stub;
173 if (handler->mmap == NULL)
174 handler->mmap = process_event_stub;
175 if (handler->comm == NULL)
176 handler->comm = process_event_stub;
177 if (handler->fork == NULL)
178 handler->fork = process_event_stub;
179 if (handler->exit == NULL)
180 handler->exit = process_event_stub;
181 if (handler->lost == NULL)
182 handler->lost = process_event_stub;
183 if (handler->read == NULL)
184 handler->read = process_event_stub;
185 if (handler->throttle == NULL)
186 handler->throttle = process_event_stub;
187 if (handler->unthrottle == NULL)
188 handler->unthrottle = process_event_stub;
189}
190
191static const char *event__name[] = {
192 [0] = "TOTAL",
193 [PERF_RECORD_MMAP] = "MMAP",
194 [PERF_RECORD_LOST] = "LOST",
195 [PERF_RECORD_COMM] = "COMM",
196 [PERF_RECORD_EXIT] = "EXIT",
197 [PERF_RECORD_THROTTLE] = "THROTTLE",
198 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
199 [PERF_RECORD_FORK] = "FORK",
200 [PERF_RECORD_READ] = "READ",
201 [PERF_RECORD_SAMPLE] = "SAMPLE",
202};
203
204unsigned long event__total[PERF_RECORD_MAX];
205
206void event__print_totals(void)
207{
208 int i;
209 for (i = 0; i < PERF_RECORD_MAX; ++i)
210 pr_info("%10s events: %10ld\n",
211 event__name[i], event__total[i]);
212}
213
214void mem_bswap_64(void *src, int byte_size)
215{
216 u64 *m = src;
217
218 while (byte_size > 0) {
219 *m = bswap_64(*m);
220 byte_size -= sizeof(u64);
221 ++m;
222 }
223}
224
225static void event__all64_swap(event_t *self)
226{
227 struct perf_event_header *hdr = &self->header;
228 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
229}
230
231static void event__comm_swap(event_t *self)
232{
233 self->comm.pid = bswap_32(self->comm.pid);
234 self->comm.tid = bswap_32(self->comm.tid);
235}
236
237static void event__mmap_swap(event_t *self)
238{
239 self->mmap.pid = bswap_32(self->mmap.pid);
240 self->mmap.tid = bswap_32(self->mmap.tid);
241 self->mmap.start = bswap_64(self->mmap.start);
242 self->mmap.len = bswap_64(self->mmap.len);
243 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
244}
245
246static void event__task_swap(event_t *self)
247{
248 self->fork.pid = bswap_32(self->fork.pid);
249 self->fork.tid = bswap_32(self->fork.tid);
250 self->fork.ppid = bswap_32(self->fork.ppid);
251 self->fork.ptid = bswap_32(self->fork.ptid);
252 self->fork.time = bswap_64(self->fork.time);
253}
254
255static void event__read_swap(event_t *self)
256{
257 self->read.pid = bswap_32(self->read.pid);
258 self->read.tid = bswap_32(self->read.tid);
259 self->read.value = bswap_64(self->read.value);
260 self->read.time_enabled = bswap_64(self->read.time_enabled);
261 self->read.time_running = bswap_64(self->read.time_running);
262 self->read.id = bswap_64(self->read.id);
263}
264
265typedef void (*event__swap_op)(event_t *self);
266
267static event__swap_op event__swap_ops[] = {
268 [PERF_RECORD_MMAP] = event__mmap_swap,
269 [PERF_RECORD_COMM] = event__comm_swap,
270 [PERF_RECORD_FORK] = event__task_swap,
271 [PERF_RECORD_EXIT] = event__task_swap,
272 [PERF_RECORD_LOST] = event__all64_swap,
273 [PERF_RECORD_READ] = event__read_swap,
274 [PERF_RECORD_SAMPLE] = event__all64_swap,
275 [PERF_RECORD_MAX] = NULL,
276};
277
278static int perf_session__process_event(struct perf_session *self,
279 event_t *event,
280 struct perf_event_ops *ops,
281 u64 offset, u64 head)
282{
283 trace_event(event);
284
285 if (event->header.type < PERF_RECORD_MAX) {
286 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
287 offset + head, event->header.size,
288 event__name[event->header.type]);
289 ++event__total[0];
290 ++event__total[event->header.type];
291 }
292
293 if (self->header.needs_swap && event__swap_ops[event->header.type])
294 event__swap_ops[event->header.type](event);
295
296 switch (event->header.type) {
297 case PERF_RECORD_SAMPLE:
298 return ops->sample(event, self);
299 case PERF_RECORD_MMAP:
300 return ops->mmap(event, self);
301 case PERF_RECORD_COMM:
302 return ops->comm(event, self);
303 case PERF_RECORD_FORK:
304 return ops->fork(event, self);
305 case PERF_RECORD_EXIT:
306 return ops->exit(event, self);
307 case PERF_RECORD_LOST:
308 return ops->lost(event, self);
309 case PERF_RECORD_READ:
310 return ops->read(event, self);
311 case PERF_RECORD_THROTTLE:
312 return ops->throttle(event, self);
313 case PERF_RECORD_UNTHROTTLE:
314 return ops->unthrottle(event, self);
315 default:
316 self->unknown_events++;
317 return -1;
318 }
319}
320
321void perf_event_header__bswap(struct perf_event_header *self)
322{
323 self->type = bswap_32(self->type);
324 self->misc = bswap_16(self->misc);
325 self->size = bswap_16(self->size);
326}
327
328int perf_header__read_build_ids(struct perf_header *self,
329 int input, u64 offset, u64 size)
330{
331 struct build_id_event bev;
332 char filename[PATH_MAX];
333 u64 limit = offset + size;
334 int err = -1;
335
336 while (offset < limit) {
337 struct dso *dso;
338 ssize_t len;
339 struct list_head *head = &dsos__user;
340
341 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
342 goto out;
343
344 if (self->needs_swap)
345 perf_event_header__bswap(&bev.header);
346
347 len = bev.header.size - sizeof(bev);
348 if (read(input, filename, len) != len)
349 goto out;
350
351 if (bev.header.misc & PERF_RECORD_MISC_KERNEL)
352 head = &dsos__kernel;
353
354 dso = __dsos__findnew(head, filename);
355 if (dso != NULL) {
356 dso__set_build_id(dso, &bev.build_id);
357 if (head == &dsos__kernel && filename[0] == '[')
358 dso->kernel = 1;
359 }
360
361 offset += bev.header.size;
362 }
363 err = 0;
364out:
365 return err;
366}
367
368static struct thread *perf_session__register_idle_thread(struct perf_session *self)
369{
370 struct thread *thread = perf_session__findnew(self, 0);
371
372 if (thread == NULL || thread__set_comm(thread, "swapper")) {
373 pr_err("problem inserting idle task.\n");
374 thread = NULL;
375 }
376
377 return thread;
378}
379
380int perf_session__process_events(struct perf_session *self,
381 struct perf_event_ops *ops)
382{
383 int err, mmap_prot, mmap_flags;
384 u64 head, shift;
385 u64 offset = 0;
386 size_t page_size;
387 event_t *event;
388 uint32_t size;
389 char *buf;
390
391 if (perf_session__register_idle_thread(self) == NULL)
392 return -ENOMEM;
393
394 perf_event_ops__fill_defaults(ops);
395
396 page_size = sysconf(_SC_PAGESIZE);
397
398 head = self->header.data_offset;
399
400 if (!symbol_conf.full_paths) {
401 char bf[PATH_MAX];
402
403 if (getcwd(bf, sizeof(bf)) == NULL) {
404 err = -errno;
405out_getcwd_err:
406 pr_err("failed to get the current directory\n");
407 goto out_err;
408 }
409 self->cwd = strdup(bf);
410 if (self->cwd == NULL) {
411 err = -ENOMEM;
412 goto out_getcwd_err;
413 }
414 self->cwdlen = strlen(self->cwd);
415 }
416
417 shift = page_size * (head / page_size);
418 offset += shift;
419 head -= shift;
420
421 mmap_prot = PROT_READ;
422 mmap_flags = MAP_SHARED;
423
424 if (self->header.needs_swap) {
425 mmap_prot |= PROT_WRITE;
426 mmap_flags = MAP_PRIVATE;
427 }
428remap:
429 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
430 mmap_flags, self->fd, offset);
431 if (buf == MAP_FAILED) {
432 pr_err("failed to mmap file\n");
433 err = -errno;
434 goto out_err;
435 }
436
437more:
438 event = (event_t *)(buf + head);
439
440 if (self->header.needs_swap)
441 perf_event_header__bswap(&event->header);
442 size = event->header.size;
443 if (size == 0)
444 size = 8;
445
446 if (head + event->header.size >= page_size * self->mmap_window) {
447 int munmap_ret;
448
449 shift = page_size * (head / page_size);
450
451 munmap_ret = munmap(buf, page_size * self->mmap_window);
452 assert(munmap_ret == 0);
453
454 offset += shift;
455 head -= shift;
456 goto remap;
457 }
458
459 size = event->header.size;
460
461 dump_printf("\n%#Lx [%#x]: event: %d\n",
462 offset + head, event->header.size, event->header.type);
463
464 if (size == 0 ||
465 perf_session__process_event(self, event, ops, offset, head) < 0) {
466 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
467 offset + head, event->header.size,
468 event->header.type);
469 /*
470 * assume we lost track of the stream, check alignment, and
471 * increment a single u64 in the hope to catch on again 'soon'.
472 */
473 if (unlikely(head & 7))
474 head &= ~7ULL;
475
476 size = 8;
477 }
478
479 head += size;
480
481 if (offset + head >= self->header.data_offset + self->header.data_size)
482 goto done;
483
484 if (offset + head < self->size)
485 goto more;
486done:
487 err = 0;
488out_err:
489 return err;
490}
491
492bool perf_session__has_traces(struct perf_session *self, const char *msg)
493{
494 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
495 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
496 return false;
497 }
498
499 return true;
500}
501
502int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
503 const char *symbol_name,
504 u64 addr)
505{
506 char *bracket;
507
508 self->ref_reloc_sym.name = strdup(symbol_name);
509 if (self->ref_reloc_sym.name == NULL)
510 return -ENOMEM;
511
512 bracket = strchr(self->ref_reloc_sym.name, ']');
513 if (bracket)
514 *bracket = '\0';
515
516 self->ref_reloc_sym.addr = addr;
517 return 0;
518}
519
520static u64 map__reloc_map_ip(struct map *map, u64 ip)
521{
522 return ip + (s64)map->pgoff;
523}
524
525static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
526{
527 return ip - (s64)map->pgoff;
528}
529
530void perf_session__reloc_vmlinux_maps(struct perf_session *self,
531 u64 unrelocated_addr)
532{
533 enum map_type type;
534 s64 reloc = unrelocated_addr - self->ref_reloc_sym.addr;
535
536 if (!reloc)
537 return;
538
539 for (type = 0; type < MAP__NR_TYPES; ++type) {
540 struct map *map = self->vmlinux_maps[type];
541
542 map->map_ip = map__reloc_map_ip;
543 map->unmap_ip = map__reloc_unmap_ip;
544 map->pgoff = reloc;
545 }
546}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 32eaa1bada06..36d1a80c0b6c 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -18,10 +18,16 @@ struct perf_session {
18 struct map_groups kmaps; 18 struct map_groups kmaps;
19 struct rb_root threads; 19 struct rb_root threads;
20 struct thread *last_match; 20 struct thread *last_match;
21 struct map *vmlinux_maps[MAP__NR_TYPES];
21 struct events_stats events_stats; 22 struct events_stats events_stats;
22 unsigned long event_total[PERF_RECORD_MAX]; 23 unsigned long event_total[PERF_RECORD_MAX];
24 unsigned long unknown_events;
23 struct rb_root hists; 25 struct rb_root hists;
24 u64 sample_type; 26 u64 sample_type;
27 struct {
28 const char *name;
29 u64 addr;
30 } ref_reloc_sym;
25 int fd; 31 int fd;
26 int cwdlen; 32 int cwdlen;
27 char *cwd; 33 char *cwd;
@@ -31,23 +37,22 @@ struct perf_session {
31typedef int (*event_op)(event_t *self, struct perf_session *session); 37typedef int (*event_op)(event_t *self, struct perf_session *session);
32 38
33struct perf_event_ops { 39struct perf_event_ops {
34 event_op process_sample_event; 40 event_op sample,
35 event_op process_mmap_event; 41 mmap,
36 event_op process_comm_event; 42 comm,
37 event_op process_fork_event; 43 fork,
38 event_op process_exit_event; 44 exit,
39 event_op process_lost_event; 45 lost,
40 event_op process_read_event; 46 read,
41 event_op process_throttle_event; 47 throttle,
42 event_op process_unthrottle_event; 48 unthrottle;
43 int (*sample_type_check)(struct perf_session *session);
44 unsigned long total_unknown;
45 bool full_paths;
46}; 49};
47 50
48struct perf_session *perf_session__new(const char *filename, int mode, bool force); 51struct perf_session *perf_session__new(const char *filename, int mode, bool force);
49void perf_session__delete(struct perf_session *self); 52void perf_session__delete(struct perf_session *self);
50 53
54void perf_event_header__bswap(struct perf_event_header *self);
55
51int perf_session__process_events(struct perf_session *self, 56int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops); 57 struct perf_event_ops *event_ops);
53 58
@@ -56,6 +61,17 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
56 struct ip_callchain *chain, 61 struct ip_callchain *chain,
57 struct symbol **parent); 62 struct symbol **parent);
58 63
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size); 64bool perf_session__has_traces(struct perf_session *self, const char *msg);
65
66int perf_header__read_build_ids(struct perf_header *self, int input,
67 u64 offset, u64 file_size);
68
69int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
70 const char *symbol_name,
71 u64 addr);
72void perf_session__reloc_vmlinux_maps(struct perf_session *self,
73 u64 unrelocated_addr);
74
75void mem_bswap_64(void *src, int byte_size);
60 76
61#endif /* __PERF_SESSION_H */ 77#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 5352d7dccc61..c397d4f6f748 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -227,16 +227,73 @@ fail:
227 return NULL; 227 return NULL;
228} 228}
229 229
230/* Glob expression pattern matching */ 230/* Character class matching */
231static bool __match_charclass(const char *pat, char c, const char **npat)
232{
233 bool complement = false, ret = true;
234
235 if (*pat == '!') {
236 complement = true;
237 pat++;
238 }
239 if (*pat++ == c) /* First character is special */
240 goto end;
241
242 while (*pat && *pat != ']') { /* Matching */
243 if (*pat == '-' && *(pat + 1) != ']') { /* Range */
244 if (*(pat - 1) <= c && c <= *(pat + 1))
245 goto end;
246 if (*(pat - 1) > *(pat + 1))
247 goto error;
248 pat += 2;
249 } else if (*pat++ == c)
250 goto end;
251 }
252 if (!*pat)
253 goto error;
254 ret = false;
255
256end:
257 while (*pat && *pat != ']') /* Searching closing */
258 pat++;
259 if (!*pat)
260 goto error;
261 *npat = pat + 1;
262 return complement ? !ret : ret;
263
264error:
265 return false;
266}
267
268/**
269 * strglobmatch - glob expression pattern matching
270 * @str: the target string to match
271 * @pat: the pattern string to match
272 *
273 * This returns true if the @str matches @pat. @pat can includes wildcards
274 * ('*','?') and character classes ([CHARS], complementation and ranges are
275 * also supported). Also, this supports escape character ('\') to use special
276 * characters as normal character.
277 *
278 * Note: if @pat syntax is broken, this always returns false.
279 */
231bool strglobmatch(const char *str, const char *pat) 280bool strglobmatch(const char *str, const char *pat)
232{ 281{
233 while (*str && *pat && *pat != '*') { 282 while (*str && *pat && *pat != '*') {
234 if (*pat == '?') { 283 if (*pat == '?') { /* Matches any single character */
235 str++; 284 str++;
236 pat++; 285 pat++;
237 } else 286 continue;
238 if (*str++ != *pat++) 287 } else if (*pat == '[') /* Character classes/Ranges */
288 if (__match_charclass(pat + 1, *str, &pat)) {
289 str++;
290 continue;
291 } else
239 return false; 292 return false;
293 else if (*pat == '\\') /* Escaped char match as normal char */
294 pat++;
295 if (*str++ != *pat++)
296 return false;
240 } 297 }
241 /* Check wild card */ 298 /* Check wild card */
242 if (*pat == '*') { 299 if (*pat == '*') {
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ab92763edb03..f9049d12ead6 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -22,6 +22,7 @@
22enum dso_origin { 22enum dso_origin {
23 DSO__ORIG_KERNEL = 0, 23 DSO__ORIG_KERNEL = 0,
24 DSO__ORIG_JAVA_JIT, 24 DSO__ORIG_JAVA_JIT,
25 DSO__ORIG_BUILD_ID_CACHE,
25 DSO__ORIG_FEDORA, 26 DSO__ORIG_FEDORA,
26 DSO__ORIG_UBUNTU, 27 DSO__ORIG_UBUNTU,
27 DSO__ORIG_BUILDID, 28 DSO__ORIG_BUILDID,
@@ -63,7 +64,7 @@ static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
63 self->sorted_by_name |= (1 << type); 64 self->sorted_by_name |= (1 << type);
64} 65}
65 66
66static bool symbol_type__is_a(char symbol_type, enum map_type map_type) 67bool symbol_type__is_a(char symbol_type, enum map_type map_type)
67{ 68{
68 switch (map_type) { 69 switch (map_type) {
69 case MAP__FUNCTION: 70 case MAP__FUNCTION:
@@ -160,7 +161,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp)
160 self->start, self->end, self->name); 161 self->start, self->end, self->name);
161} 162}
162 163
163static void dso__set_long_name(struct dso *self, char *name) 164void dso__set_long_name(struct dso *self, char *name)
164{ 165{
165 if (name == NULL) 166 if (name == NULL)
166 return; 167 return;
@@ -175,7 +176,7 @@ static void dso__set_basename(struct dso *self)
175 176
176struct dso *dso__new(const char *name) 177struct dso *dso__new(const char *name)
177{ 178{
178 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 179 struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1);
179 180
180 if (self != NULL) { 181 if (self != NULL) {
181 int i; 182 int i;
@@ -344,10 +345,10 @@ void dso__sort_by_name(struct dso *self, enum map_type type)
344 &self->symbols[type]); 345 &self->symbols[type]);
345} 346}
346 347
347int build_id__sprintf(u8 *self, int len, char *bf) 348int build_id__sprintf(const u8 *self, int len, char *bf)
348{ 349{
349 char *bid = bf; 350 char *bid = bf;
350 u8 *raw = self; 351 const u8 *raw = self;
351 int i; 352 int i;
352 353
353 for (i = 0; i < len; ++i) { 354 for (i = 0; i < len; ++i) {
@@ -382,24 +383,20 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
382 return ret; 383 return ret;
383} 384}
384 385
385/* 386int kallsyms__parse(const char *filename, void *arg,
386 * Loads the function entries in /proc/kallsyms into kernel_map->dso, 387 int (*process_symbol)(void *arg, const char *name,
387 * so that we can in the next step set the symbol ->end address and then 388 char type, u64 start))
388 * call kernel_maps__split_kallsyms.
389 */
390static int dso__load_all_kallsyms(struct dso *self, struct map *map)
391{ 389{
392 char *line = NULL; 390 char *line = NULL;
393 size_t n; 391 size_t n;
394 struct rb_root *root = &self->symbols[map->type]; 392 int err = 0;
395 FILE *file = fopen("/proc/kallsyms", "r"); 393 FILE *file = fopen(filename, "r");
396 394
397 if (file == NULL) 395 if (file == NULL)
398 goto out_failure; 396 goto out_failure;
399 397
400 while (!feof(file)) { 398 while (!feof(file)) {
401 u64 start; 399 u64 start;
402 struct symbol *sym;
403 int line_len, len; 400 int line_len, len;
404 char symbol_type; 401 char symbol_type;
405 char *symbol_name; 402 char *symbol_name;
@@ -420,35 +417,63 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
420 continue; 417 continue;
421 418
422 symbol_type = toupper(line[len]); 419 symbol_type = toupper(line[len]);
423 if (!symbol_type__is_a(symbol_type, map->type))
424 continue;
425
426 symbol_name = line + len + 2; 420 symbol_name = line + len + 2;
427 /*
428 * Will fix up the end later, when we have all symbols sorted.
429 */
430 sym = symbol__new(start, 0, symbol_name);
431 421
432 if (sym == NULL) 422 err = process_symbol(arg, symbol_name, symbol_type, start);
433 goto out_delete_line; 423 if (err)
434 /* 424 break;
435 * We will pass the symbols to the filter later, in
436 * map__split_kallsyms, when we have split the maps per module
437 */
438 symbols__insert(root, sym);
439 } 425 }
440 426
441 free(line); 427 free(line);
442 fclose(file); 428 fclose(file);
429 return err;
443 430
444 return 0;
445
446out_delete_line:
447 free(line);
448out_failure: 431out_failure:
449 return -1; 432 return -1;
450} 433}
451 434
435struct process_kallsyms_args {
436 struct map *map;
437 struct dso *dso;
438};
439
440static int map__process_kallsym_symbol(void *arg, const char *name,
441 char type, u64 start)
442{
443 struct symbol *sym;
444 struct process_kallsyms_args *a = arg;
445 struct rb_root *root = &a->dso->symbols[a->map->type];
446
447 if (!symbol_type__is_a(type, a->map->type))
448 return 0;
449
450 /*
451 * Will fix up the end later, when we have all symbols sorted.
452 */
453 sym = symbol__new(start, 0, name);
454
455 if (sym == NULL)
456 return -ENOMEM;
457 /*
458 * We will pass the symbols to the filter later, in
459 * map__split_kallsyms, when we have split the maps per module
460 */
461 symbols__insert(root, sym);
462 return 0;
463}
464
465/*
466 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
467 * so that we can in the next step set the symbol ->end address and then
468 * call kernel_maps__split_kallsyms.
469 */
470static int dso__load_all_kallsyms(struct dso *self, const char *filename,
471 struct map *map)
472{
473 struct process_kallsyms_args args = { .map = map, .dso = self, };
474 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
475}
476
452/* 477/*
453 * Split the symbols into maps, making sure there are no overlaps, i.e. the 478 * Split the symbols into maps, making sure there are no overlaps, i.e. the
454 * kernel range is broken in several maps, named [kernel].N, as we don't have 479 * kernel range is broken in several maps, named [kernel].N, as we don't have
@@ -477,13 +502,17 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
477 502
478 *module++ = '\0'; 503 *module++ = '\0';
479 504
480 if (strcmp(self->name, module)) { 505 if (strcmp(curr_map->dso->short_name, module)) {
481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); 506 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
482 if (curr_map == NULL) { 507 if (curr_map == NULL) {
483 pr_debug("/proc/{kallsyms,modules} " 508 pr_debug("/proc/{kallsyms,modules} "
484 "inconsistency!\n"); 509 "inconsistency while looking "
510 "for \"%s\" module!\n", module);
485 return -1; 511 return -1;
486 } 512 }
513
514 if (curr_map->dso->loaded)
515 goto discard_symbol;
487 } 516 }
488 /* 517 /*
489 * So that we look just like we get from .ko files, 518 * So that we look just like we get from .ko files,
@@ -529,10 +558,10 @@ discard_symbol: rb_erase(&pos->rb_node, root);
529} 558}
530 559
531 560
532static int dso__load_kallsyms(struct dso *self, struct map *map, 561static int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
533 struct perf_session *session, symbol_filter_t filter) 562 struct perf_session *session, symbol_filter_t filter)
534{ 563{
535 if (dso__load_all_kallsyms(self, map) < 0) 564 if (dso__load_all_kallsyms(self, filename, map) < 0)
536 return -1; 565 return -1;
537 566
538 symbols__fixup_end(&self->symbols[map->type]); 567 symbols__fixup_end(&self->symbols[map->type]);
@@ -933,11 +962,15 @@ static int dso__load_sym(struct dso *self, struct map *map,
933 962
934 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 963 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
935 struct symbol *f; 964 struct symbol *f;
936 const char *elf_name; 965 const char *elf_name = elf_sym__name(&sym, symstrs);
937 char *demangled = NULL; 966 char *demangled = NULL;
938 int is_label = elf_sym__is_label(&sym); 967 int is_label = elf_sym__is_label(&sym);
939 const char *section_name; 968 const char *section_name;
940 969
970 if (kernel && session->ref_reloc_sym.name != NULL &&
971 strcmp(elf_name, session->ref_reloc_sym.name) == 0)
972 perf_session__reloc_vmlinux_maps(session, sym.st_value);
973
941 if (!is_label && !elf_sym__is_a(&sym, map->type)) 974 if (!is_label && !elf_sym__is_a(&sym, map->type))
942 continue; 975 continue;
943 976
@@ -950,7 +983,6 @@ static int dso__load_sym(struct dso *self, struct map *map,
950 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 983 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
951 continue; 984 continue;
952 985
953 elf_name = elf_sym__name(&sym, symstrs);
954 section_name = elf_sec__name(&shdr, secstrs); 986 section_name = elf_sec__name(&shdr, secstrs);
955 987
956 if (kernel || kmodule) { 988 if (kernel || kmodule) {
@@ -1191,6 +1223,7 @@ char dso__symtab_origin(const struct dso *self)
1191 static const char origin[] = { 1223 static const char origin[] = {
1192 [DSO__ORIG_KERNEL] = 'k', 1224 [DSO__ORIG_KERNEL] = 'k',
1193 [DSO__ORIG_JAVA_JIT] = 'j', 1225 [DSO__ORIG_JAVA_JIT] = 'j',
1226 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
1194 [DSO__ORIG_FEDORA] = 'f', 1227 [DSO__ORIG_FEDORA] = 'f',
1195 [DSO__ORIG_UBUNTU] = 'u', 1228 [DSO__ORIG_UBUNTU] = 'u',
1196 [DSO__ORIG_BUILDID] = 'b', 1229 [DSO__ORIG_BUILDID] = 'b',
@@ -1209,6 +1242,7 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1209 int size = PATH_MAX; 1242 int size = PATH_MAX;
1210 char *name; 1243 char *name;
1211 u8 build_id[BUILD_ID_SIZE]; 1244 u8 build_id[BUILD_ID_SIZE];
1245 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1212 int ret = -1; 1246 int ret = -1;
1213 int fd; 1247 int fd;
1214 1248
@@ -1230,8 +1264,16 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1230 return ret; 1264 return ret;
1231 } 1265 }
1232 1266
1233 self->origin = DSO__ORIG_FEDORA - 1; 1267 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1234 1268
1269 if (self->has_build_id) {
1270 build_id__sprintf(self->build_id, sizeof(self->build_id),
1271 build_id_hex);
1272 snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
1273 getenv("HOME"), DEBUG_CACHE_DIR,
1274 build_id_hex, build_id_hex + 2);
1275 goto open_file;
1276 }
1235more: 1277more:
1236 do { 1278 do {
1237 self->origin++; 1279 self->origin++;
@@ -1247,8 +1289,6 @@ more:
1247 case DSO__ORIG_BUILDID: 1289 case DSO__ORIG_BUILDID:
1248 if (filename__read_build_id(self->long_name, build_id, 1290 if (filename__read_build_id(self->long_name, build_id,
1249 sizeof(build_id))) { 1291 sizeof(build_id))) {
1250 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1251
1252 build_id__sprintf(build_id, sizeof(build_id), 1292 build_id__sprintf(build_id, sizeof(build_id),
1253 build_id_hex); 1293 build_id_hex);
1254 snprintf(name, size, 1294 snprintf(name, size,
@@ -1276,7 +1316,7 @@ compare_build_id:
1276 if (!dso__build_id_equal(self, build_id)) 1316 if (!dso__build_id_equal(self, build_id))
1277 goto more; 1317 goto more;
1278 } 1318 }
1279 1319open_file:
1280 fd = open(name, O_RDONLY); 1320 fd = open(name, O_RDONLY);
1281 } while (fd < 0); 1321 } while (fd < 0);
1282 1322
@@ -1309,13 +1349,33 @@ struct map *map_groups__find_by_name(struct map_groups *self,
1309 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1349 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1310 struct map *map = rb_entry(nd, struct map, rb_node); 1350 struct map *map = rb_entry(nd, struct map, rb_node);
1311 1351
1312 if (map->dso && strcmp(map->dso->name, name) == 0) 1352 if (map->dso && strcmp(map->dso->short_name, name) == 0)
1313 return map; 1353 return map;
1314 } 1354 }
1315 1355
1316 return NULL; 1356 return NULL;
1317} 1357}
1318 1358
1359static int dso__kernel_module_get_build_id(struct dso *self)
1360{
1361 char filename[PATH_MAX];
1362 /*
1363 * kernel module short names are of the form "[module]" and
1364 * we need just "module" here.
1365 */
1366 const char *name = self->short_name + 1;
1367
1368 snprintf(filename, sizeof(filename),
1369 "/sys/module/%.*s/notes/.note.gnu.build-id",
1370 (int)strlen(name - 1), name);
1371
1372 if (sysfs__read_build_id(filename, self->build_id,
1373 sizeof(self->build_id)) == 0)
1374 self->has_build_id = true;
1375
1376 return 0;
1377}
1378
1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) 1379static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
1320{ 1380{
1321 struct dirent *dent; 1381 struct dirent *dent;
@@ -1361,6 +1421,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
1361 if (long_name == NULL) 1421 if (long_name == NULL)
1362 goto failure; 1422 goto failure;
1363 dso__set_long_name(map->dso, long_name); 1423 dso__set_long_name(map->dso, long_name);
1424 dso__kernel_module_get_build_id(map->dso);
1364 } 1425 }
1365 } 1426 }
1366 1427
@@ -1403,6 +1464,24 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1403 return self; 1464 return self;
1404} 1465}
1405 1466
1467struct map *perf_session__new_module_map(struct perf_session *self, u64 start,
1468 const char *filename)
1469{
1470 struct map *map;
1471 struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
1472
1473 if (dso == NULL)
1474 return NULL;
1475
1476 map = map__new2(start, dso, MAP__FUNCTION);
1477 if (map == NULL)
1478 return NULL;
1479
1480 dso->origin = DSO__ORIG_KMODULE;
1481 map_groups__insert(&self->kmaps, map);
1482 return map;
1483}
1484
1406static int perf_session__create_module_maps(struct perf_session *self) 1485static int perf_session__create_module_maps(struct perf_session *self)
1407{ 1486{
1408 char *line = NULL; 1487 char *line = NULL;
@@ -1416,7 +1495,6 @@ static int perf_session__create_module_maps(struct perf_session *self)
1416 while (!feof(file)) { 1495 while (!feof(file)) {
1417 char name[PATH_MAX]; 1496 char name[PATH_MAX];
1418 u64 start; 1497 u64 start;
1419 struct dso *dso;
1420 char *sep; 1498 char *sep;
1421 int line_len; 1499 int line_len;
1422 1500
@@ -1442,26 +1520,10 @@ static int perf_session__create_module_maps(struct perf_session *self)
1442 *sep = '\0'; 1520 *sep = '\0';
1443 1521
1444 snprintf(name, sizeof(name), "[%s]", line); 1522 snprintf(name, sizeof(name), "[%s]", line);
1445 dso = dso__new(name); 1523 map = perf_session__new_module_map(self, start, name);
1446 1524 if (map == NULL)
1447 if (dso == NULL)
1448 goto out_delete_line; 1525 goto out_delete_line;
1449 1526 dso__kernel_module_get_build_id(map->dso);
1450 map = map__new2(start, dso, MAP__FUNCTION);
1451 if (map == NULL) {
1452 dso__delete(dso);
1453 goto out_delete_line;
1454 }
1455
1456 snprintf(name, sizeof(name),
1457 "/sys/module/%s/notes/.note.gnu.build-id", line);
1458 if (sysfs__read_build_id(name, dso->build_id,
1459 sizeof(dso->build_id)) == 0)
1460 dso->has_build_id = true;
1461
1462 dso->origin = DSO__ORIG_KMODULE;
1463 map_groups__insert(&self->kmaps, map);
1464 dsos__add(&dsos__kernel, dso);
1465 } 1527 }
1466 1528
1467 free(line); 1529 free(line);
@@ -1510,51 +1572,117 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1510 return -1; 1572 return -1;
1511 1573
1512 dso__set_loaded(self, map->type); 1574 dso__set_loaded(self, map->type);
1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0); 1575 err = dso__load_sym(self, map, session, vmlinux, fd, filter, 1, 0);
1514 close(fd); 1576 close(fd);
1515 1577
1516 return err; 1578 return err;
1517} 1579}
1518 1580
1581int dso__load_vmlinux_path(struct dso *self, struct map *map,
1582 struct perf_session *session, symbol_filter_t filter)
1583{
1584 int i, err = 0;
1585
1586 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1587 vmlinux_path__nr_entries);
1588
1589 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1590 err = dso__load_vmlinux(self, map, session, vmlinux_path[i],
1591 filter);
1592 if (err > 0) {
1593 pr_debug("Using %s for symbols\n", vmlinux_path[i]);
1594 dso__set_long_name(self, strdup(vmlinux_path[i]));
1595 break;
1596 }
1597 }
1598
1599 return err;
1600}
1601
1519static int dso__load_kernel_sym(struct dso *self, struct map *map, 1602static int dso__load_kernel_sym(struct dso *self, struct map *map,
1520 struct perf_session *session, symbol_filter_t filter) 1603 struct perf_session *session, symbol_filter_t filter)
1521{ 1604{
1522 int err; 1605 int err;
1523 bool is_kallsyms; 1606 const char *kallsyms_filename = NULL;
1607 char *kallsyms_allocated_filename = NULL;
1608 /*
1609 * Step 1: if the user specified a vmlinux filename, use it and only
1610 * it, reporting errors to the user if it cannot be used.
1611 *
1612 * For instance, try to analyse an ARM perf.data file _without_ a
1613 * build-id, or if the user specifies the wrong path to the right
1614 * vmlinux file, obviously we can't fallback to another vmlinux (a
1615 * x86_86 one, on the machine where analysis is being performed, say),
1616 * or worse, /proc/kallsyms.
1617 *
1618 * If the specified file _has_ a build-id and there is a build-id
1619 * section in the perf.data file, we will still do the expected
1620 * validation in dso__load_vmlinux and will bail out if they don't
1621 * match.
1622 */
1623 if (symbol_conf.vmlinux_name != NULL) {
1624 err = dso__load_vmlinux(self, map, session,
1625 symbol_conf.vmlinux_name, filter);
1626 goto out_try_fixup;
1627 }
1524 1628
1525 if (vmlinux_path != NULL) { 1629 if (vmlinux_path != NULL) {
1526 int i; 1630 err = dso__load_vmlinux_path(self, map, session, filter);
1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1631 if (err > 0)
1528 vmlinux_path__nr_entries); 1632 goto out_fixup;
1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1633 }
1530 err = dso__load_vmlinux(self, map, session, 1634
1531 vmlinux_path[i], filter); 1635 /*
1532 if (err > 0) { 1636 * Say the kernel DSO was created when processing the build-id header table,
1533 pr_debug("Using %s for symbols\n", 1637 * we have a build-id, so check if it is the same as the running kernel,
1534 vmlinux_path[i]); 1638 * using it if it is.
1535 dso__set_long_name(self, 1639 */
1536 strdup(vmlinux_path[i])); 1640 if (self->has_build_id) {
1537 goto out_fixup; 1641 u8 kallsyms_build_id[BUILD_ID_SIZE];
1642 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1643
1644 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1645 sizeof(kallsyms_build_id)) == 0) {
1646 if (dso__build_id_equal(self, kallsyms_build_id)) {
1647 kallsyms_filename = "/proc/kallsyms";
1648 goto do_kallsyms;
1538 } 1649 }
1539 } 1650 }
1540 } 1651 /*
1652 * Now look if we have it on the build-id cache in
1653 * $HOME/.debug/[kernel.kallsyms].
1654 */
1655 build_id__sprintf(self->build_id, sizeof(self->build_id),
1656 sbuild_id);
1657
1658 if (asprintf(&kallsyms_allocated_filename,
1659 "%s/.debug/[kernel.kallsyms]/%s",
1660 getenv("HOME"), sbuild_id) == -1)
1661 return -1;
1541 1662
1542 is_kallsyms = self->long_name[0] == '['; 1663 kallsyms_filename = kallsyms_allocated_filename;
1543 if (is_kallsyms)
1544 goto do_kallsyms;
1545 1664
1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter); 1665 if (access(kallsyms_filename, F_OK)) {
1547 if (err <= 0) { 1666 free(kallsyms_allocated_filename);
1548 pr_info("The file %s cannot be used, " 1667 return -1;
1549 "trying to use /proc/kallsyms...", self->long_name); 1668 }
1550do_kallsyms: 1669 } else {
1551 err = dso__load_kallsyms(self, map, session, filter); 1670 /*
1552 if (err > 0 && !is_kallsyms) 1671 * Last resort, if we don't have a build-id and couldn't find
1553 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1672 * any vmlinux file, try the running kernel kallsyms table.
1673 */
1674 kallsyms_filename = "/proc/kallsyms";
1554 } 1675 }
1555 1676
1677do_kallsyms:
1678 err = dso__load_kallsyms(self, kallsyms_filename, map, session, filter);
1679 free(kallsyms_allocated_filename);
1680
1681out_try_fixup:
1556 if (err > 0) { 1682 if (err > 0) {
1557out_fixup: 1683out_fixup:
1684 if (kallsyms_filename != NULL)
1685 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1558 map__fixup_start(map); 1686 map__fixup_start(map);
1559 map__fixup_end(map); 1687 map__fixup_end(map);
1560 } 1688 }
@@ -1576,19 +1704,19 @@ static struct dso *dsos__find(struct list_head *head, const char *name)
1576 struct dso *pos; 1704 struct dso *pos;
1577 1705
1578 list_for_each_entry(pos, head, node) 1706 list_for_each_entry(pos, head, node)
1579 if (strcmp(pos->name, name) == 0) 1707 if (strcmp(pos->long_name, name) == 0)
1580 return pos; 1708 return pos;
1581 return NULL; 1709 return NULL;
1582} 1710}
1583 1711
1584struct dso *dsos__findnew(const char *name) 1712struct dso *__dsos__findnew(struct list_head *head, const char *name)
1585{ 1713{
1586 struct dso *dso = dsos__find(&dsos__user, name); 1714 struct dso *dso = dsos__find(head, name);
1587 1715
1588 if (!dso) { 1716 if (!dso) {
1589 dso = dso__new(name); 1717 dso = dso__new(name);
1590 if (dso != NULL) { 1718 if (dso != NULL) {
1591 dsos__add(&dsos__user, dso); 1719 dsos__add(head, dso);
1592 dso__set_basename(dso); 1720 dso__set_basename(dso);
1593 } 1721 }
1594 } 1722 }
@@ -1613,42 +1741,59 @@ void dsos__fprintf(FILE *fp)
1613 __dsos__fprintf(&dsos__user, fp); 1741 __dsos__fprintf(&dsos__user, fp);
1614} 1742}
1615 1743
1616static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 1744static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1745 bool with_hits)
1617{ 1746{
1618 struct dso *pos; 1747 struct dso *pos;
1619 size_t ret = 0; 1748 size_t ret = 0;
1620 1749
1621 list_for_each_entry(pos, head, node) { 1750 list_for_each_entry(pos, head, node) {
1751 if (with_hits && !pos->hit)
1752 continue;
1622 ret += dso__fprintf_buildid(pos, fp); 1753 ret += dso__fprintf_buildid(pos, fp);
1623 ret += fprintf(fp, " %s\n", pos->long_name); 1754 ret += fprintf(fp, " %s\n", pos->long_name);
1624 } 1755 }
1625 return ret; 1756 return ret;
1626} 1757}
1627 1758
1628size_t dsos__fprintf_buildid(FILE *fp) 1759size_t dsos__fprintf_buildid(FILE *fp, bool with_hits)
1629{ 1760{
1630 return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 1761 return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) +
1631 __dsos__fprintf_buildid(&dsos__user, fp)); 1762 __dsos__fprintf_buildid(&dsos__user, fp, with_hits));
1632} 1763}
1633 1764
1634static struct dso *dsos__create_kernel( const char *vmlinux) 1765struct dso *dso__new_kernel(const char *name)
1635{ 1766{
1636 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1767 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1768
1769 if (self != NULL) {
1770 self->short_name = "[kernel]";
1771 self->kernel = 1;
1772 }
1773
1774 return self;
1775}
1776
1777void dso__read_running_kernel_build_id(struct dso *self)
1778{
1779 if (sysfs__read_build_id("/sys/kernel/notes", self->build_id,
1780 sizeof(self->build_id)) == 0)
1781 self->has_build_id = true;
1782}
1783
1784static struct dso *dsos__create_kernel(const char *vmlinux)
1785{
1786 struct dso *kernel = dso__new_kernel(vmlinux);
1637 1787
1638 if (kernel == NULL) 1788 if (kernel == NULL)
1639 return NULL; 1789 return NULL;
1640 1790
1641 kernel->short_name = "[kernel]";
1642 kernel->kernel = 1;
1643
1644 vdso = dso__new("[vdso]"); 1791 vdso = dso__new("[vdso]");
1645 if (vdso == NULL) 1792 if (vdso == NULL)
1646 goto out_delete_kernel_dso; 1793 goto out_delete_kernel_dso;
1647 dso__set_loaded(vdso, MAP__FUNCTION); 1794 dso__set_loaded(vdso, MAP__FUNCTION);
1648 1795
1649 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 1796 dso__read_running_kernel_build_id(kernel);
1650 sizeof(kernel->build_id)) == 0)
1651 kernel->has_build_id = true;
1652 1797
1653 dsos__add(&dsos__kernel, kernel); 1798 dsos__add(&dsos__kernel, kernel);
1654 dsos__add(&dsos__user, vdso); 1799 dsos__add(&dsos__user, vdso);
@@ -1660,32 +1805,37 @@ out_delete_kernel_dso:
1660 return NULL; 1805 return NULL;
1661} 1806}
1662 1807
1663static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux) 1808int __map_groups__create_kernel_maps(struct map_groups *self,
1809 struct map *vmlinux_maps[MAP__NR_TYPES],
1810 struct dso *kernel)
1664{ 1811{
1665 struct map *functions, *variables; 1812 enum map_type type;
1666 struct dso *kernel = dsos__create_kernel(vmlinux);
1667
1668 if (kernel == NULL)
1669 return -1;
1670 1813
1671 functions = map__new2(0, kernel, MAP__FUNCTION); 1814 for (type = 0; type < MAP__NR_TYPES; ++type) {
1672 if (functions == NULL) 1815 vmlinux_maps[type] = map__new2(0, kernel, type);
1673 return -1; 1816 if (vmlinux_maps[type] == NULL)
1817 return -1;
1674 1818
1675 variables = map__new2(0, kernel, MAP__VARIABLE); 1819 vmlinux_maps[type]->map_ip =
1676 if (variables == NULL) { 1820 vmlinux_maps[type]->unmap_ip = identity__map_ip;
1677 map__delete(functions); 1821 map_groups__insert(self, vmlinux_maps[type]);
1678 return -1;
1679 } 1822 }
1680 1823
1681 functions->map_ip = functions->unmap_ip =
1682 variables->map_ip = variables->unmap_ip = identity__map_ip;
1683 map_groups__insert(self, functions);
1684 map_groups__insert(self, variables);
1685
1686 return 0; 1824 return 0;
1687} 1825}
1688 1826
1827static int map_groups__create_kernel_maps(struct map_groups *self,
1828 struct map *vmlinux_maps[MAP__NR_TYPES],
1829 const char *vmlinux)
1830{
1831 struct dso *kernel = dsos__create_kernel(vmlinux);
1832
1833 if (kernel == NULL)
1834 return -1;
1835
1836 return __map_groups__create_kernel_maps(self, vmlinux_maps, kernel);
1837}
1838
1689static void vmlinux_path__exit(void) 1839static void vmlinux_path__exit(void)
1690{ 1840{
1691 while (--vmlinux_path__nr_entries >= 0) { 1841 while (--vmlinux_path__nr_entries >= 0) {
@@ -1793,7 +1943,7 @@ out_free_comm_list:
1793 1943
1794int perf_session__create_kernel_maps(struct perf_session *self) 1944int perf_session__create_kernel_maps(struct perf_session *self)
1795{ 1945{
1796 if (map_groups__create_kernel_maps(&self->kmaps, 1946 if (map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps,
1797 symbol_conf.vmlinux_name) < 0) 1947 symbol_conf.vmlinux_name) < 0)
1798 return -1; 1948 return -1;
1799 1949
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 8aded2356f79..124302778c09 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -8,6 +8,8 @@
8#include <linux/rbtree.h> 8#include <linux/rbtree.h>
9#include "event.h" 9#include "event.h"
10 10
11#define DEBUG_CACHE_DIR ".debug"
12
11#ifdef HAVE_CPLUS_DEMANGLE 13#ifdef HAVE_CPLUS_DEMANGLE
12extern char *cplus_demangle(const char *, int); 14extern char *cplus_demangle(const char *, int);
13 15
@@ -58,7 +60,8 @@ struct symbol_conf {
58 sort_by_name, 60 sort_by_name,
59 show_nr_samples, 61 show_nr_samples,
60 use_callchain, 62 use_callchain,
61 exclude_other; 63 exclude_other,
64 full_paths;
62 const char *vmlinux_name, 65 const char *vmlinux_name,
63 *field_sep; 66 *field_sep;
64 char *dso_list_str, 67 char *dso_list_str,
@@ -94,6 +97,7 @@ struct dso {
94 u8 slen_calculated:1; 97 u8 slen_calculated:1;
95 u8 has_build_id:1; 98 u8 has_build_id:1;
96 u8 kernel:1; 99 u8 kernel:1;
100 u8 hit:1;
97 unsigned char origin; 101 unsigned char origin;
98 u8 sorted_by_name; 102 u8 sorted_by_name;
99 u8 loaded; 103 u8 loaded;
@@ -105,6 +109,7 @@ struct dso {
105}; 109};
106 110
107struct dso *dso__new(const char *name); 111struct dso *dso__new(const char *name);
112struct dso *dso__new_kernel(const char *name);
108void dso__delete(struct dso *self); 113void dso__delete(struct dso *self);
109 114
110bool dso__loaded(const struct dso *self, enum map_type type); 115bool dso__loaded(const struct dso *self, enum map_type type);
@@ -112,18 +117,30 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type);
112 117
113void dso__sort_by_name(struct dso *self, enum map_type type); 118void dso__sort_by_name(struct dso *self, enum map_type type);
114 119
120extern struct list_head dsos__user, dsos__kernel;
121
122struct dso *__dsos__findnew(struct list_head *head, const char *name);
123
124static inline struct dso *dsos__findnew(const char *name)
125{
126 return __dsos__findnew(&dsos__user, name);
127}
128
115struct perf_session; 129struct perf_session;
116 130
117struct dso *dsos__findnew(const char *name);
118int dso__load(struct dso *self, struct map *map, struct perf_session *session, 131int dso__load(struct dso *self, struct map *map, struct perf_session *session,
119 symbol_filter_t filter); 132 symbol_filter_t filter);
133int dso__load_vmlinux_path(struct dso *self, struct map *map,
134 struct perf_session *session, symbol_filter_t filter);
120void dsos__fprintf(FILE *fp); 135void dsos__fprintf(FILE *fp);
121size_t dsos__fprintf_buildid(FILE *fp); 136size_t dsos__fprintf_buildid(FILE *fp, bool with_hits);
122 137
123size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 138size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
124size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 139size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
125char dso__symtab_origin(const struct dso *self); 140char dso__symtab_origin(const struct dso *self);
141void dso__set_long_name(struct dso *self, char *name);
126void dso__set_build_id(struct dso *self, void *build_id); 142void dso__set_build_id(struct dso *self, void *build_id);
143void dso__read_running_kernel_build_id(struct dso *self);
127struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 144struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
128struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 145struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
129 const char *name); 146 const char *name);
@@ -131,11 +148,17 @@ struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
131int filename__read_build_id(const char *filename, void *bf, size_t size); 148int filename__read_build_id(const char *filename, void *bf, size_t size);
132int sysfs__read_build_id(const char *filename, void *bf, size_t size); 149int sysfs__read_build_id(const char *filename, void *bf, size_t size);
133bool dsos__read_build_ids(void); 150bool dsos__read_build_ids(void);
134int build_id__sprintf(u8 *self, int len, char *bf); 151int build_id__sprintf(const u8 *self, int len, char *bf);
152int kallsyms__parse(const char *filename, void *arg,
153 int (*process_symbol)(void *arg, const char *name,
154 char type, u64 start));
135 155
136int symbol__init(void); 156int symbol__init(void);
157bool symbol_type__is_a(char symbol_type, enum map_type map_type);
158
137int perf_session__create_kernel_maps(struct perf_session *self); 159int perf_session__create_kernel_maps(struct perf_session *self);
138 160
139extern struct list_head dsos__user, dsos__kernel; 161struct map *perf_session__new_module_map(struct perf_session *self, u64 start,
162 const char *filename);
140extern struct dso *vdso; 163extern struct dso *vdso;
141#endif /* __PERF_SYMBOL */ 164#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index c206f72c8881..e35653c1817c 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -48,6 +48,11 @@ static inline struct map *thread__find_map(struct thread *self,
48 return self ? map_groups__find(&self->mg, type, addr) : NULL; 48 return self ? map_groups__find(&self->mg, type, addr) : NULL;
49} 49}
50 50
51void thread__find_addr_map(struct thread *self,
52 struct perf_session *session, u8 cpumode,
53 enum map_type type, u64 addr,
54 struct addr_location *al);
55
51void thread__find_addr_location(struct thread *self, 56void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode, 57 struct perf_session *session, u8 cpumode,
53 enum map_type type, u64 addr, 58 enum map_type type, u64 addr,
@@ -67,4 +72,8 @@ map_groups__find_function(struct map_groups *self, struct perf_session *session,
67 72
68struct map *map_groups__find_by_name(struct map_groups *self, 73struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name); 74 enum map_type type, const char *name);
75
76int __map_groups__create_kernel_maps(struct map_groups *self,
77 struct map *vmlinux_maps[MAP__NR_TYPES],
78 struct dso *kernel);
70#endif /* __PERF_THREAD_H */ 79#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index cace35595530..5ea8973ad331 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -20,6 +20,7 @@
20 */ 20 */
21#define _GNU_SOURCE 21#define _GNU_SOURCE
22#include <dirent.h> 22#include <dirent.h>
23#include <mntent.h>
23#include <stdio.h> 24#include <stdio.h>
24#include <stdlib.h> 25#include <stdlib.h>
25#include <string.h> 26#include <string.h>
@@ -37,6 +38,7 @@
37 38
38#include "../perf.h" 39#include "../perf.h"
39#include "trace-event.h" 40#include "trace-event.h"
41#include "debugfs.h"
40 42
41#define VERSION "0.5" 43#define VERSION "0.5"
42 44
@@ -101,32 +103,12 @@ void *malloc_or_die(unsigned int size)
101 103
102static const char *find_debugfs(void) 104static const char *find_debugfs(void)
103{ 105{
104 static char debugfs[MAX_PATH+1]; 106 const char *path = debugfs_mount(NULL);
105 static int debugfs_found;
106 char type[100];
107 FILE *fp;
108
109 if (debugfs_found)
110 return debugfs;
111
112 if ((fp = fopen("/proc/mounts","r")) == NULL)
113 die("Can't open /proc/mounts for read");
114
115 while (fscanf(fp, "%*s %"
116 STR(MAX_PATH)
117 "s %99s %*s %*d %*d\n",
118 debugfs, type) == 2) {
119 if (strcmp(type, "debugfs") == 0)
120 break;
121 }
122 fclose(fp);
123
124 if (strcmp(type, "debugfs") != 0)
125 die("debugfs not mounted, please mount");
126 107
127 debugfs_found = 1; 108 if (!path)
109 die("Your kernel not support debugfs filesystem");
128 110
129 return debugfs; 111 return path;
130} 112}
131 113
132/* 114/*
@@ -271,6 +253,8 @@ static void read_header_files(void)
271 write_or_die("header_page", 12); 253 write_or_die("header_page", 12);
272 write_or_die(&size, 8); 254 write_or_die(&size, 8);
273 check_size = copy_file_fd(fd); 255 check_size = copy_file_fd(fd);
256 close(fd);
257
274 if (size != check_size) 258 if (size != check_size)
275 die("wrong size for '%s' size=%lld read=%lld", 259 die("wrong size for '%s' size=%lld read=%lld",
276 path, size, check_size); 260 path, size, check_size);
@@ -289,6 +273,7 @@ static void read_header_files(void)
289 if (size != check_size) 273 if (size != check_size)
290 die("wrong size for '%s'", path); 274 die("wrong size for '%s'", path);
291 put_tracing_file(path); 275 put_tracing_file(path);
276 close(fd);
292} 277}
293 278
294static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 279static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -317,7 +302,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
317 die("can't read directory '%s'", sys); 302 die("can't read directory '%s'", sys);
318 303
319 while ((dent = readdir(dir))) { 304 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 || 305 if (dent->d_type != DT_DIR ||
306 strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0 || 307 strcmp(dent->d_name, "..") == 0 ||
322 !name_in_tp_list(dent->d_name, tps)) 308 !name_in_tp_list(dent->d_name, tps))
323 continue; 309 continue;
@@ -334,7 +320,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
334 320
335 rewinddir(dir); 321 rewinddir(dir);
336 while ((dent = readdir(dir))) { 322 while ((dent = readdir(dir))) {
337 if (strcmp(dent->d_name, ".") == 0 || 323 if (dent->d_type != DT_DIR ||
324 strcmp(dent->d_name, ".") == 0 ||
338 strcmp(dent->d_name, "..") == 0 || 325 strcmp(dent->d_name, "..") == 0 ||
339 !name_in_tp_list(dent->d_name, tps)) 326 !name_in_tp_list(dent->d_name, tps))
340 continue; 327 continue;
@@ -353,6 +340,7 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
353 340
354 free(format); 341 free(format);
355 } 342 }
343 closedir(dir);
356} 344}
357 345
358static void read_ftrace_files(struct tracepoint_path *tps) 346static void read_ftrace_files(struct tracepoint_path *tps)
@@ -394,26 +382,21 @@ static void read_event_files(struct tracepoint_path *tps)
394 die("can't read directory '%s'", path); 382 die("can't read directory '%s'", path);
395 383
396 while ((dent = readdir(dir))) { 384 while ((dent = readdir(dir))) {
397 if (strcmp(dent->d_name, ".") == 0 || 385 if (dent->d_type != DT_DIR ||
386 strcmp(dent->d_name, ".") == 0 ||
398 strcmp(dent->d_name, "..") == 0 || 387 strcmp(dent->d_name, "..") == 0 ||
399 strcmp(dent->d_name, "ftrace") == 0 || 388 strcmp(dent->d_name, "ftrace") == 0 ||
400 !system_in_tp_list(dent->d_name, tps)) 389 !system_in_tp_list(dent->d_name, tps))
401 continue; 390 continue;
402 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 391 count++;
403 sprintf(sys, "%s/%s", path, dent->d_name);
404 ret = stat(sys, &st);
405 free(sys);
406 if (ret < 0)
407 continue;
408 if (S_ISDIR(st.st_mode))
409 count++;
410 } 392 }
411 393
412 write_or_die(&count, 4); 394 write_or_die(&count, 4);
413 395
414 rewinddir(dir); 396 rewinddir(dir);
415 while ((dent = readdir(dir))) { 397 while ((dent = readdir(dir))) {
416 if (strcmp(dent->d_name, ".") == 0 || 398 if (dent->d_type != DT_DIR ||
399 strcmp(dent->d_name, ".") == 0 ||
417 strcmp(dent->d_name, "..") == 0 || 400 strcmp(dent->d_name, "..") == 0 ||
418 strcmp(dent->d_name, "ftrace") == 0 || 401 strcmp(dent->d_name, "ftrace") == 0 ||
419 !system_in_tp_list(dent->d_name, tps)) 402 !system_in_tp_list(dent->d_name, tps))
@@ -422,14 +405,13 @@ static void read_event_files(struct tracepoint_path *tps)
422 sprintf(sys, "%s/%s", path, dent->d_name); 405 sprintf(sys, "%s/%s", path, dent->d_name);
423 ret = stat(sys, &st); 406 ret = stat(sys, &st);
424 if (ret >= 0) { 407 if (ret >= 0) {
425 if (S_ISDIR(st.st_mode)) { 408 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
426 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 409 copy_event_system(sys, tps);
427 copy_event_system(sys, tps);
428 }
429 } 410 }
430 free(sys); 411 free(sys);
431 } 412 }
432 413
414 closedir(dir);
433 put_tracing_file(path); 415 put_tracing_file(path);
434} 416}
435 417
@@ -533,7 +515,7 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
533 write_or_die(buf, 1); 515 write_or_die(buf, 1);
534 516
535 /* save page_size */ 517 /* save page_size */
536 page_size = getpagesize(); 518 page_size = sysconf(_SC_PAGESIZE);
537 write_or_die(&page_size, 4); 519 write_or_die(&page_size, 4);
538 520
539 read_header_files(); 521 read_header_files();
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
new file mode 100644
index 000000000000..f9b890fde681
--- /dev/null
+++ b/tools/perf/util/util.c
@@ -0,0 +1,94 @@
1#include "util.h"
2#include <sys/mman.h>
3
4int mkdir_p(char *path, mode_t mode)
5{
6 struct stat st;
7 int err;
8 char *d = path;
9
10 if (*d != '/')
11 return -1;
12
13 if (stat(path, &st) == 0)
14 return 0;
15
16 while (*++d == '/');
17
18 while ((d = strchr(d, '/'))) {
19 *d = '\0';
20 err = stat(path, &st) && mkdir(path, mode);
21 *d++ = '/';
22 if (err)
23 return -1;
24 while (*d == '/')
25 ++d;
26 }
27 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
28}
29
30static int slow_copyfile(const char *from, const char *to)
31{
32 int err = 0;
33 char *line = NULL;
34 size_t n;
35 FILE *from_fp = fopen(from, "r"), *to_fp;
36
37 if (from_fp == NULL)
38 goto out;
39
40 to_fp = fopen(to, "w");
41 if (to_fp == NULL)
42 goto out_fclose_from;
43
44 while (getline(&line, &n, from_fp) > 0)
45 if (fputs(line, to_fp) == EOF)
46 goto out_fclose_to;
47 err = 0;
48out_fclose_to:
49 fclose(to_fp);
50 free(line);
51out_fclose_from:
52 fclose(from_fp);
53out:
54 return err;
55}
56
57int copyfile(const char *from, const char *to)
58{
59 int fromfd, tofd;
60 struct stat st;
61 void *addr;
62 int err = -1;
63
64 if (stat(from, &st))
65 goto out;
66
67 if (st.st_size == 0) /* /proc? do it slowly... */
68 return slow_copyfile(from, to);
69
70 fromfd = open(from, O_RDONLY);
71 if (fromfd < 0)
72 goto out;
73
74 tofd = creat(to, 0755);
75 if (tofd < 0)
76 goto out_close_from;
77
78 addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
79 if (addr == MAP_FAILED)
80 goto out_close_to;
81
82 if (write(tofd, addr, st.st_size) == st.st_size)
83 err = 0;
84
85 munmap(addr, st.st_size);
86out_close_to:
87 close(tofd);
88 if (err)
89 unlink(to);
90out_close_from:
91 close(fromfd);
92out:
93 return err;
94}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c673d8825883..0f5b2a6f1080 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -403,4 +403,7 @@ void git_qsort(void *base, size_t nmemb, size_t size,
403#endif 403#endif
404#endif 404#endif
405 405
406int mkdir_p(char *path, mode_t mode);
407int copyfile(const char *from, const char *to);
408
406#endif 409#endif
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 1c15e39f99e3..cfa55d686e3b 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -169,6 +169,7 @@ static void perf_read_values__display_pretty(FILE *fp,
169 counterwidth[j], values->value[i][j]); 169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n"); 170 fprintf(fp, "\n");
171 } 171 }
172 free(counterwidth);
172} 173}
173 174
174static void perf_read_values__display_raw(FILE *fp, 175static void perf_read_values__display_raw(FILE *fp,