aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2011-01-04 03:43:42 -0500
committerIngo Molnar <mingo@elte.hu>2011-01-04 03:43:42 -0500
commitbc030d6cb9532877c1c5a3f5e7123344fa24a285 (patch)
treed223d410b868b80d4c0deec192d354a5d06b201a /tools/perf
parentd3bd058826aa8b79590cca6c8e6d1557bf576ada (diff)
parent387c31c7e5c9805b0aef8833d1731a5fe7bdea14 (diff)
Merge commit 'v2.6.37-rc8' into x86/apic
Conflicts: arch/x86/include/asm/io_apic.h Merge reason: move to a fresh -rc, resolve the conflict. Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-list.txt17
-rw-r--r--tools/perf/Documentation/perf-probe.txt18
-rw-r--r--tools/perf/Documentation/perf-record.txt4
-rw-r--r--tools/perf/Documentation/perf-trace.txt57
-rw-r--r--tools/perf/builtin-buildid-list.c3
-rw-r--r--tools/perf/builtin-probe.c83
-rw-r--r--tools/perf/builtin-record.c39
-rw-r--r--tools/perf/builtin-top.c12
-rw-r--r--tools/perf/builtin-trace.c216
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-record2
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-report2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-report2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report2
-rw-r--r--tools/perf/scripts/perl/bin/rwtop-record2
-rw-r--r--tools/perf/scripts/perl/bin/rwtop-report2
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-record2
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-record2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report2
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py58
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-record2
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-report2
-rw-r--r--tools/perf/scripts/python/bin/futex-contention-record2
-rw-r--r--tools/perf/scripts/python/bin/futex-contention-report4
-rw-r--r--tools/perf/scripts/python/bin/netdev-times-record2
-rw-r--r--tools/perf/scripts/python/bin/netdev-times-report2
-rw-r--r--tools/perf/scripts/python/bin/sched-migration-record2
-rw-r--r--tools/perf/scripts/python/bin/sched-migration-report2
-rw-r--r--tools/perf/scripts/python/bin/sctop-record2
-rw-r--r--tools/perf/scripts/python/bin/sctop-report2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-record2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-report2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-record2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-report2
-rw-r--r--tools/perf/scripts/python/failed-syscalls-by-pid.py21
-rw-r--r--tools/perf/scripts/python/futex-contention.py50
-rw-r--r--tools/perf/scripts/python/sctop.py9
-rw-r--r--tools/perf/scripts/python/syscall-counts-by-pid.py21
-rw-r--r--tools/perf/scripts/python/syscall-counts.py5
-rw-r--r--tools/perf/util/debug.c4
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/header.c21
-rw-r--r--tools/perf/util/map.h10
-rw-r--r--tools/perf/util/probe-event.c198
-rw-r--r--tools/perf/util/probe-event.h16
-rw-r--r--tools/perf/util/probe-finder.c670
-rw-r--r--tools/perf/util/probe-finder.h31
-rw-r--r--tools/perf/util/string.c2
-rw-r--r--tools/perf/util/symbol.c67
-rw-r--r--tools/perf/util/symbol.h2
-rw-r--r--tools/perf/util/ui/browser.c1
-rw-r--r--tools/perf/util/ui/util.c5
54 files changed, 1337 insertions, 359 deletions
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index 43e3dd284b90..399751befeed 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -15,6 +15,23 @@ DESCRIPTION
15This command displays the symbolic event types which can be selected in the 15This command displays the symbolic event types which can be selected in the
16various perf commands with the -e option. 16various perf commands with the -e option.
17 17
18EVENT MODIFIERS
19---------------
20
21Events can optionally have a modifer by appending a colon and one or
22more modifiers. Modifiers allow the user to restrict when events are
23counted with 'u' for user-space, 'k' for kernel, 'h' for hypervisor.
24
25The 'p' modifier can be used for specifying how precise the instruction
26address should be. The 'p' modifier is currently only implemented for
27Intel PEBS and can be specified multiple times:
28 0 - SAMPLE_IP can have arbitrary skid
29 1 - SAMPLE_IP must have constant skid
30 2 - SAMPLE_IP requested to have 0 skid
31 3 - SAMPLE_IP must have 0 skid
32
33The PEBS implementation now supports up to 2.
34
18RAW HARDWARE EVENT DESCRIPTOR 35RAW HARDWARE EVENT DESCRIPTOR
19----------------------------- 36-----------------------------
20Even when an event is not available in a symbolic form within perf right now, 37Even when an event is not available in a symbolic form within perf right now,
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 27d52dae5a43..62de1b7f4e76 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -16,7 +16,9 @@ or
16or 16or
17'perf probe' --list 17'perf probe' --list
18or 18or
19'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' 19'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
20or
21'perf probe' [options] --vars='PROBEPOINT'
20 22
21DESCRIPTION 23DESCRIPTION
22----------- 24-----------
@@ -31,6 +33,11 @@ OPTIONS
31--vmlinux=PATH:: 33--vmlinux=PATH::
32 Specify vmlinux path which has debuginfo (Dwarf binary). 34 Specify vmlinux path which has debuginfo (Dwarf binary).
33 35
36-m::
37--module=MODNAME::
38 Specify module name in which perf-probe searches probe points
39 or lines.
40
34-s:: 41-s::
35--source=PATH:: 42--source=PATH::
36 Specify path to kernel source. 43 Specify path to kernel source.
@@ -57,6 +64,15 @@ OPTIONS
57 Show source code lines which can be probed. This needs an argument 64 Show source code lines which can be probed. This needs an argument
58 which specifies a range of the source code. (see LINE SYNTAX for detail) 65 which specifies a range of the source code. (see LINE SYNTAX for detail)
59 66
67-V::
68--vars=::
69 Show available local variables at given probe point. The argument
70 syntax is same as PROBE SYNTAX, but NO ARGs.
71
72--externs::
73 (Only for --vars) Show external defined variables in addition to local
74 variables.
75
60-f:: 76-f::
61--force:: 77--force::
62 Forcibly add events with existing name. 78 Forcibly add events with existing name.
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 3ee27dccfde9..a91f9f9e6e5c 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -83,6 +83,10 @@ OPTIONS
83--call-graph:: 83--call-graph::
84 Do call-graph (stack chain/backtrace) recording. 84 Do call-graph (stack chain/backtrace) recording.
85 85
86-q::
87--quiet::
88 Don't print any message, useful for scripting.
89
86-v:: 90-v::
87--verbose:: 91--verbose::
88 Be more verbose (show counter open errors, etc). 92 Be more verbose (show counter open errors, etc).
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 122ec9dc4853..26aff6bf9e50 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -8,7 +8,11 @@ perf-trace - Read perf.data (created by perf record) and display trace output
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' {record <script> | report <script> [args] } 11'perf trace' [<options>]
12'perf trace' [<options>] record <script> [<record-options>] <command>
13'perf trace' [<options>] report <script> [script-args]
14'perf trace' [<options>] <script> <required-script-args> [<record-options>] <command>
15'perf trace' [<options>] <top-script> [script-args]
12 16
13DESCRIPTION 17DESCRIPTION
14----------- 18-----------
@@ -24,23 +28,53 @@ There are several variants of perf trace:
24 available via 'perf trace -l'). The following variants allow you to 28 available via 'perf trace -l'). The following variants allow you to
25 record and run those scripts: 29 record and run those scripts:
26 30
27 'perf trace record <script>' to record the events required for 'perf 31 'perf trace record <script> <command>' to record the events required
28 trace report'. <script> is the name displayed in the output of 32 for 'perf trace report'. <script> is the name displayed in the
29 'perf trace --list' i.e. the actual script name minus any language 33 output of 'perf trace --list' i.e. the actual script name minus any
30 extension. 34 language extension. If <command> is not specified, the events are
35 recorded using the -a (system-wide) 'perf record' option.
31 36
32 'perf trace report <script>' to run and display the results of 37 'perf trace report <script> [args]' to run and display the results
33 <script>. <script> is the name displayed in the output of 'perf 38 of <script>. <script> is the name displayed in the output of 'perf
34 trace --list' i.e. the actual script name minus any language 39 trace --list' i.e. the actual script name minus any language
35 extension. The perf.data output from a previous run of 'perf trace 40 extension. The perf.data output from a previous run of 'perf trace
36 record <script>' is used and should be present for this command to 41 record <script>' is used and should be present for this command to
37 succeed. 42 succeed. [args] refers to the (mainly optional) args expected by
43 the script.
44
45 'perf trace <script> <required-script-args> <command>' to both
46 record the events required for <script> and to run the <script>
47 using 'live-mode' i.e. without writing anything to disk. <script>
48 is the name displayed in the output of 'perf trace --list' i.e. the
49 actual script name minus any language extension. If <command> is
50 not specified, the events are recorded using the -a (system-wide)
51 'perf record' option. If <script> has any required args, they
52 should be specified before <command>. This mode doesn't allow for
53 optional script args to be specified; if optional script args are
54 desired, they can be specified using separate 'perf trace record'
55 and 'perf trace report' commands, with the stdout of the record step
56 piped to the stdin of the report script, using the '-o -' and '-i -'
57 options of the corresponding commands.
58
59 'perf trace <top-script>' to both record the events required for
60 <top-script> and to run the <top-script> using 'live-mode'
61 i.e. without writing anything to disk. <top-script> is the name
62 displayed in the output of 'perf trace --list' i.e. the actual
63 script name minus any language extension; a <top-script> is defined
64 as any script name ending with the string 'top'.
65
66 [<record-options>] can be passed to the record steps of 'perf trace
67 record' and 'live-mode' variants; this isn't possible however for
68 <top-script> 'live-mode' or 'perf trace report' variants.
38 69
39 See the 'SEE ALSO' section for links to language-specific 70 See the 'SEE ALSO' section for links to language-specific
40 information on how to write and run your own trace scripts. 71 information on how to write and run your own trace scripts.
41 72
42OPTIONS 73OPTIONS
43------- 74-------
75<command>...::
76 Any command you can specify in a shell.
77
44-D:: 78-D::
45--dump-raw-trace=:: 79--dump-raw-trace=::
46 Display verbose dump of the trace data. 80 Display verbose dump of the trace data.
@@ -64,6 +98,13 @@ OPTIONS
64 Generate perf-trace.[ext] starter script for given language, 98 Generate perf-trace.[ext] starter script for given language,
65 using current perf.data. 99 using current perf.data.
66 100
101-a::
102 Force system-wide collection. Scripts run without a <command>
103 normally use -a by default, while scripts run with a <command>
104 normally don't - this option allows the latter to be run in
105 system-wide mode.
106
107
67SEE ALSO 108SEE ALSO
68-------- 109--------
69linkperf:perf-record[1], linkperf:perf-trace-perl[1], 110linkperf:perf-record[1], linkperf:perf-trace-perl[1],
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 44a47e13bd67..c49837de7d3f 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -36,7 +36,6 @@ static const struct option options[] = {
36 36
37static int __cmd_buildid_list(void) 37static int __cmd_buildid_list(void)
38{ 38{
39 int err = -1;
40 struct perf_session *session; 39 struct perf_session *session;
41 40
42 session = perf_session__new(input_name, O_RDONLY, force, false); 41 session = perf_session__new(input_name, O_RDONLY, force, false);
@@ -49,7 +48,7 @@ static int __cmd_buildid_list(void)
49 perf_session__fprintf_dsos_buildid(session, stdout, with_hits); 48 perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
50 49
51 perf_session__delete(session); 50 perf_session__delete(session);
52 return err; 51 return 0;
53} 52}
54 53
55int cmd_buildid_list(int argc, const char **argv, const char *prefix __used) 54int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 199d5e19554f..add163c9f0e7 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -50,14 +50,17 @@ static struct {
50 bool list_events; 50 bool list_events;
51 bool force_add; 51 bool force_add;
52 bool show_lines; 52 bool show_lines;
53 bool show_vars;
54 bool show_ext_vars;
55 bool mod_events;
53 int nevents; 56 int nevents;
54 struct perf_probe_event events[MAX_PROBES]; 57 struct perf_probe_event events[MAX_PROBES];
55 struct strlist *dellist; 58 struct strlist *dellist;
56 struct line_range line_range; 59 struct line_range line_range;
60 const char *target_module;
57 int max_probe_points; 61 int max_probe_points;
58} params; 62} params;
59 63
60
61/* Parse an event definition. Note that any error must die. */ 64/* Parse an event definition. Note that any error must die. */
62static int parse_probe_event(const char *str) 65static int parse_probe_event(const char *str)
63{ 66{
@@ -92,6 +95,7 @@ static int parse_probe_event_argv(int argc, const char **argv)
92 len = 0; 95 len = 0;
93 for (i = 0; i < argc; i++) 96 for (i = 0; i < argc; i++)
94 len += sprintf(&buf[len], "%s ", argv[i]); 97 len += sprintf(&buf[len], "%s ", argv[i]);
98 params.mod_events = true;
95 ret = parse_probe_event(buf); 99 ret = parse_probe_event(buf);
96 free(buf); 100 free(buf);
97 return ret; 101 return ret;
@@ -100,9 +104,10 @@ static int parse_probe_event_argv(int argc, const char **argv)
100static int opt_add_probe_event(const struct option *opt __used, 104static int opt_add_probe_event(const struct option *opt __used,
101 const char *str, int unset __used) 105 const char *str, int unset __used)
102{ 106{
103 if (str) 107 if (str) {
108 params.mod_events = true;
104 return parse_probe_event(str); 109 return parse_probe_event(str);
105 else 110 } else
106 return 0; 111 return 0;
107} 112}
108 113
@@ -110,6 +115,7 @@ static int opt_del_probe_event(const struct option *opt __used,
110 const char *str, int unset __used) 115 const char *str, int unset __used)
111{ 116{
112 if (str) { 117 if (str) {
118 params.mod_events = true;
113 if (!params.dellist) 119 if (!params.dellist)
114 params.dellist = strlist__new(true, NULL); 120 params.dellist = strlist__new(true, NULL);
115 strlist__add(params.dellist, str); 121 strlist__add(params.dellist, str);
@@ -130,6 +136,25 @@ static int opt_show_lines(const struct option *opt __used,
130 136
131 return ret; 137 return ret;
132} 138}
139
140static int opt_show_vars(const struct option *opt __used,
141 const char *str, int unset __used)
142{
143 struct perf_probe_event *pev = &params.events[params.nevents];
144 int ret;
145
146 if (!str)
147 return 0;
148
149 ret = parse_probe_event(str);
150 if (!ret && pev->nargs != 0) {
151 pr_err(" Error: '--vars' doesn't accept arguments.\n");
152 return -EINVAL;
153 }
154 params.show_vars = true;
155
156 return ret;
157}
133#endif 158#endif
134 159
135static const char * const probe_usage[] = { 160static const char * const probe_usage[] = {
@@ -138,7 +163,8 @@ static const char * const probe_usage[] = {
138 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 163 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
139 "perf probe --list", 164 "perf probe --list",
140#ifdef DWARF_SUPPORT 165#ifdef DWARF_SUPPORT
141 "perf probe --line 'LINEDESC'", 166 "perf probe [<options>] --line 'LINEDESC'",
167 "perf probe [<options>] --vars 'PROBEPOINT'",
142#endif 168#endif
143 NULL 169 NULL
144}; 170};
@@ -180,10 +206,17 @@ static const struct option options[] = {
180 OPT_CALLBACK('L', "line", NULL, 206 OPT_CALLBACK('L', "line", NULL,
181 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", 207 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
182 "Show source code lines.", opt_show_lines), 208 "Show source code lines.", opt_show_lines),
209 OPT_CALLBACK('V', "vars", NULL,
210 "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
211 "Show accessible variables on PROBEDEF", opt_show_vars),
212 OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
213 "Show external variables too (with --vars only)"),
183 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 214 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
184 "file", "vmlinux pathname"), 215 "file", "vmlinux pathname"),
185 OPT_STRING('s', "source", &symbol_conf.source_prefix, 216 OPT_STRING('s', "source", &symbol_conf.source_prefix,
186 "directory", "path to kernel source"), 217 "directory", "path to kernel source"),
218 OPT_STRING('m', "module", &params.target_module,
219 "modname", "target module name"),
187#endif 220#endif
188 OPT__DRY_RUN(&probe_event_dry_run), 221 OPT__DRY_RUN(&probe_event_dry_run),
189 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 222 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -216,8 +249,13 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
216 !params.show_lines)) 249 !params.show_lines))
217 usage_with_options(probe_usage, options); 250 usage_with_options(probe_usage, options);
218 251
252 /*
253 * Only consider the user's kernel image path if given.
254 */
255 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
256
219 if (params.list_events) { 257 if (params.list_events) {
220 if (params.nevents != 0 || params.dellist) { 258 if (params.mod_events) {
221 pr_err(" Error: Don't use --list with --add/--del.\n"); 259 pr_err(" Error: Don't use --list with --add/--del.\n");
222 usage_with_options(probe_usage, options); 260 usage_with_options(probe_usage, options);
223 } 261 }
@@ -225,6 +263,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
225 pr_err(" Error: Don't use --list with --line.\n"); 263 pr_err(" Error: Don't use --list with --line.\n");
226 usage_with_options(probe_usage, options); 264 usage_with_options(probe_usage, options);
227 } 265 }
266 if (params.show_vars) {
267 pr_err(" Error: Don't use --list with --vars.\n");
268 usage_with_options(probe_usage, options);
269 }
228 ret = show_perf_probe_events(); 270 ret = show_perf_probe_events();
229 if (ret < 0) 271 if (ret < 0)
230 pr_err(" Error: Failed to show event list. (%d)\n", 272 pr_err(" Error: Failed to show event list. (%d)\n",
@@ -234,17 +276,35 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
234 276
235#ifdef DWARF_SUPPORT 277#ifdef DWARF_SUPPORT
236 if (params.show_lines) { 278 if (params.show_lines) {
237 if (params.nevents != 0 || params.dellist) { 279 if (params.mod_events) {
238 pr_warning(" Error: Don't use --line with" 280 pr_err(" Error: Don't use --line with"
239 " --add/--del.\n"); 281 " --add/--del.\n");
282 usage_with_options(probe_usage, options);
283 }
284 if (params.show_vars) {
285 pr_err(" Error: Don't use --line with --vars.\n");
240 usage_with_options(probe_usage, options); 286 usage_with_options(probe_usage, options);
241 } 287 }
242 288
243 ret = show_line_range(&params.line_range); 289 ret = show_line_range(&params.line_range, params.target_module);
244 if (ret < 0) 290 if (ret < 0)
245 pr_err(" Error: Failed to show lines. (%d)\n", ret); 291 pr_err(" Error: Failed to show lines. (%d)\n", ret);
246 return ret; 292 return ret;
247 } 293 }
294 if (params.show_vars) {
295 if (params.mod_events) {
296 pr_err(" Error: Don't use --vars with"
297 " --add/--del.\n");
298 usage_with_options(probe_usage, options);
299 }
300 ret = show_available_vars(params.events, params.nevents,
301 params.max_probe_points,
302 params.target_module,
303 params.show_ext_vars);
304 if (ret < 0)
305 pr_err(" Error: Failed to show vars. (%d)\n", ret);
306 return ret;
307 }
248#endif 308#endif
249 309
250 if (params.dellist) { 310 if (params.dellist) {
@@ -258,8 +318,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
258 318
259 if (params.nevents) { 319 if (params.nevents) {
260 ret = add_perf_probe_events(params.events, params.nevents, 320 ret = add_perf_probe_events(params.events, params.nevents,
261 params.force_add, 321 params.max_probe_points,
262 params.max_probe_points); 322 params.target_module,
323 params.force_add);
263 if (ret < 0) { 324 if (ret < 0) {
264 pr_err(" Error: Failed to add events. (%d)\n", ret); 325 pr_err(" Error: Failed to add events. (%d)\n", ret);
265 return ret; 326 return ret;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ff77b805de71..564491fa18b2 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -197,7 +197,7 @@ static void sig_atexit(void)
197 if (child_pid > 0) 197 if (child_pid > 0)
198 kill(child_pid, SIGTERM); 198 kill(child_pid, SIGTERM);
199 199
200 if (signr == -1) 200 if (signr == -1 || signr == SIGUSR1)
201 return; 201 return;
202 202
203 signal(signr, SIG_DFL); 203 signal(signr, SIG_DFL);
@@ -353,7 +353,7 @@ try_again:
353 } 353 }
354 354
355 if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) { 355 if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) {
356 perror("Unable to read perf file descriptor\n"); 356 perror("Unable to read perf file descriptor");
357 exit(-1); 357 exit(-1);
358 } 358 }
359 359
@@ -515,6 +515,7 @@ static int __cmd_record(int argc, const char **argv)
515 atexit(sig_atexit); 515 atexit(sig_atexit);
516 signal(SIGCHLD, sig_handler); 516 signal(SIGCHLD, sig_handler);
517 signal(SIGINT, sig_handler); 517 signal(SIGINT, sig_handler);
518 signal(SIGUSR1, sig_handler);
518 519
519 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { 520 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
520 perror("failed to create pipes"); 521 perror("failed to create pipes");
@@ -606,6 +607,7 @@ static int __cmd_record(int argc, const char **argv)
606 execvp(argv[0], (char **)argv); 607 execvp(argv[0], (char **)argv);
607 608
608 perror(argv[0]); 609 perror(argv[0]);
610 kill(getppid(), SIGUSR1);
609 exit(-1); 611 exit(-1);
610 } 612 }
611 613
@@ -626,7 +628,7 @@ static int __cmd_record(int argc, const char **argv)
626 628
627 nr_cpus = read_cpu_map(cpu_list); 629 nr_cpus = read_cpu_map(cpu_list);
628 if (nr_cpus < 1) { 630 if (nr_cpus < 1) {
629 perror("failed to collect number of CPUs\n"); 631 perror("failed to collect number of CPUs");
630 return -1; 632 return -1;
631 } 633 }
632 634
@@ -697,17 +699,18 @@ static int __cmd_record(int argc, const char **argv)
697 if (err < 0) 699 if (err < 0)
698 err = event__synthesize_kernel_mmap(process_synthesized_event, 700 err = event__synthesize_kernel_mmap(process_synthesized_event,
699 session, machine, "_stext"); 701 session, machine, "_stext");
700 if (err < 0) { 702 if (err < 0)
701 pr_err("Couldn't record kernel reference relocation symbol.\n"); 703 pr_err("Couldn't record kernel reference relocation symbol\n"
702 return err; 704 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
703 } 705 "Check /proc/kallsyms permission or run as root.\n");
704 706
705 err = event__synthesize_modules(process_synthesized_event, 707 err = event__synthesize_modules(process_synthesized_event,
706 session, machine); 708 session, machine);
707 if (err < 0) { 709 if (err < 0)
708 pr_err("Couldn't record kernel reference relocation symbol.\n"); 710 pr_err("Couldn't record kernel module information.\n"
709 return err; 711 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
710 } 712 "Check /proc/modules permission or run as root.\n");
713
711 if (perf_guest) 714 if (perf_guest)
712 perf_session__process_machines(session, event__synthesize_guest_os); 715 perf_session__process_machines(session, event__synthesize_guest_os);
713 716
@@ -761,6 +764,9 @@ static int __cmd_record(int argc, const char **argv)
761 } 764 }
762 } 765 }
763 766
767 if (quiet || signr == SIGUSR1)
768 return 0;
769
764 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); 770 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
765 771
766 /* 772 /*
@@ -787,7 +793,7 @@ static const char * const record_usage[] = {
787 793
788static bool force, append_file; 794static bool force, append_file;
789 795
790static const struct option options[] = { 796const struct option record_options[] = {
791 OPT_CALLBACK('e', "event", NULL, "event", 797 OPT_CALLBACK('e', "event", NULL, "event",
792 "event selector. use 'perf list' to list available events", 798 "event selector. use 'perf list' to list available events",
793 parse_events), 799 parse_events),
@@ -820,6 +826,7 @@ static const struct option options[] = {
820 "do call-graph (stack chain/backtrace) recording"), 826 "do call-graph (stack chain/backtrace) recording"),
821 OPT_INCR('v', "verbose", &verbose, 827 OPT_INCR('v', "verbose", &verbose,
822 "be more verbose (show counter open errors, etc)"), 828 "be more verbose (show counter open errors, etc)"),
829 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
823 OPT_BOOLEAN('s', "stat", &inherit_stat, 830 OPT_BOOLEAN('s', "stat", &inherit_stat,
824 "per thread counts"), 831 "per thread counts"),
825 OPT_BOOLEAN('d', "data", &sample_address, 832 OPT_BOOLEAN('d', "data", &sample_address,
@@ -835,16 +842,16 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
835{ 842{
836 int i, j, err = -ENOMEM; 843 int i, j, err = -ENOMEM;
837 844
838 argc = parse_options(argc, argv, options, record_usage, 845 argc = parse_options(argc, argv, record_options, record_usage,
839 PARSE_OPT_STOP_AT_NON_OPTION); 846 PARSE_OPT_STOP_AT_NON_OPTION);
840 if (!argc && target_pid == -1 && target_tid == -1 && 847 if (!argc && target_pid == -1 && target_tid == -1 &&
841 !system_wide && !cpu_list) 848 !system_wide && !cpu_list)
842 usage_with_options(record_usage, options); 849 usage_with_options(record_usage, record_options);
843 850
844 if (force && append_file) { 851 if (force && append_file) {
845 fprintf(stderr, "Can't overwrite and append at the same time." 852 fprintf(stderr, "Can't overwrite and append at the same time."
846 " You need to choose between -f and -A"); 853 " You need to choose between -f and -A");
847 usage_with_options(record_usage, options); 854 usage_with_options(record_usage, record_options);
848 } else if (append_file) { 855 } else if (append_file) {
849 write_mode = WRITE_APPEND; 856 write_mode = WRITE_APPEND;
850 } else { 857 } else {
@@ -867,7 +874,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
867 if (thread_num <= 0) { 874 if (thread_num <= 0) {
868 fprintf(stderr, "Can't find all threads of pid %d\n", 875 fprintf(stderr, "Can't find all threads of pid %d\n",
869 target_pid); 876 target_pid);
870 usage_with_options(record_usage, options); 877 usage_with_options(record_usage, record_options);
871 } 878 }
872 } else { 879 } else {
873 all_tids=malloc(sizeof(pid_t)); 880 all_tids=malloc(sizeof(pid_t));
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index b513e40974f4..dd625808c2a5 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -69,7 +69,6 @@ static int target_tid = -1;
69static pid_t *all_tids = NULL; 69static pid_t *all_tids = NULL;
70static int thread_num = 0; 70static int thread_num = 0;
71static bool inherit = false; 71static bool inherit = false;
72static int profile_cpu = -1;
73static int nr_cpus = 0; 72static int nr_cpus = 0;
74static int realtime_prio = 0; 73static int realtime_prio = 0;
75static bool group = false; 74static bool group = false;
@@ -558,13 +557,13 @@ static void print_sym_table(void)
558 else 557 else
559 printf(" (all"); 558 printf(" (all");
560 559
561 if (profile_cpu != -1) 560 if (cpu_list)
562 printf(", cpu: %d)\n", profile_cpu); 561 printf(", CPU%s: %s)\n", nr_cpus > 1 ? "s" : "", cpu_list);
563 else { 562 else {
564 if (target_tid != -1) 563 if (target_tid != -1)
565 printf(")\n"); 564 printf(")\n");
566 else 565 else
567 printf(", %d CPUs)\n", nr_cpus); 566 printf(", %d CPU%s)\n", nr_cpus, nr_cpus > 1 ? "s" : "");
568 } 567 }
569 568
570 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 569 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
@@ -1187,11 +1186,10 @@ int group_fd;
1187static void start_counter(int i, int counter) 1186static void start_counter(int i, int counter)
1188{ 1187{
1189 struct perf_event_attr *attr; 1188 struct perf_event_attr *attr;
1190 int cpu; 1189 int cpu = -1;
1191 int thread_index; 1190 int thread_index;
1192 1191
1193 cpu = profile_cpu; 1192 if (target_tid == -1)
1194 if (target_tid == -1 && profile_cpu == -1)
1195 cpu = cpumap[i]; 1193 cpu = cpumap[i];
1196 1194
1197 attr = attrs + counter; 1195 attr = attrs + counter;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 40a6a2992d15..86cfe3800e6b 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -10,6 +10,7 @@
10#include "util/symbol.h" 10#include "util/symbol.h"
11#include "util/thread.h" 11#include "util/thread.h"
12#include "util/trace-event.h" 12#include "util/trace-event.h"
13#include "util/parse-options.h"
13#include "util/util.h" 14#include "util/util.h"
14 15
15static char const *script_name; 16static char const *script_name;
@@ -17,6 +18,7 @@ static char const *generate_script_lang;
17static bool debug_mode; 18static bool debug_mode;
18static u64 last_timestamp; 19static u64 last_timestamp;
19static u64 nr_unordered; 20static u64 nr_unordered;
21extern const struct option record_options[];
20 22
21static int default_start_script(const char *script __unused, 23static int default_start_script(const char *script __unused,
22 int argc __unused, 24 int argc __unused,
@@ -46,9 +48,6 @@ static struct scripting_ops *scripting_ops;
46 48
47static void setup_scripting(void) 49static void setup_scripting(void)
48{ 50{
49 /* make sure PERF_EXEC_PATH is set for scripts */
50 perf_set_argv_exec_path(perf_exec_path());
51
52 setup_perl_scripting(); 51 setup_perl_scripting();
53 setup_python_scripting(); 52 setup_python_scripting();
54 53
@@ -285,7 +284,7 @@ static int parse_scriptname(const struct option *opt __used,
285 script++; 284 script++;
286 } else { 285 } else {
287 script = str; 286 script = str;
288 ext = strchr(script, '.'); 287 ext = strrchr(script, '.');
289 if (!ext) { 288 if (!ext) {
290 fprintf(stderr, "invalid script extension"); 289 fprintf(stderr, "invalid script extension");
291 return -1; 290 return -1;
@@ -331,7 +330,7 @@ static struct script_desc *script_desc__new(const char *name)
331{ 330{
332 struct script_desc *s = zalloc(sizeof(*s)); 331 struct script_desc *s = zalloc(sizeof(*s));
333 332
334 if (s != NULL) 333 if (s != NULL && name)
335 s->name = strdup(name); 334 s->name = strdup(name);
336 335
337 return s; 336 return s;
@@ -340,6 +339,8 @@ static struct script_desc *script_desc__new(const char *name)
340static void script_desc__delete(struct script_desc *s) 339static void script_desc__delete(struct script_desc *s)
341{ 340{
342 free(s->name); 341 free(s->name);
342 free(s->half_liner);
343 free(s->args);
343 free(s); 344 free(s);
344} 345}
345 346
@@ -540,8 +541,40 @@ static char *get_script_path(const char *script_root, const char *suffix)
540 return path; 541 return path;
541} 542}
542 543
544static bool is_top_script(const char *script_path)
545{
546 return ends_with((char *)script_path, "top") == NULL ? false : true;
547}
548
549static int has_required_arg(char *script_path)
550{
551 struct script_desc *desc;
552 int n_args = 0;
553 char *p;
554
555 desc = script_desc__new(NULL);
556
557 if (read_script_info(desc, script_path))
558 goto out;
559
560 if (!desc->args)
561 goto out;
562
563 for (p = desc->args; *p; p++)
564 if (*p == '<')
565 n_args++;
566out:
567 script_desc__delete(desc);
568
569 return n_args;
570}
571
543static const char * const trace_usage[] = { 572static const char * const trace_usage[] = {
544 "perf trace [<options>] <command>", 573 "perf trace [<options>]",
574 "perf trace [<options>] record <script> [<record-options>] <command>",
575 "perf trace [<options>] report <script> [script-args]",
576 "perf trace [<options>] <script> [<record-options>] <command>",
577 "perf trace [<options>] <top-script> [script-args]",
545 NULL 578 NULL
546}; 579};
547 580
@@ -567,47 +600,81 @@ static const struct option options[] = {
567 OPT_END() 600 OPT_END()
568}; 601};
569 602
603static bool have_cmd(int argc, const char **argv)
604{
605 char **__argv = malloc(sizeof(const char *) * argc);
606
607 if (!__argv)
608 die("malloc");
609 memcpy(__argv, argv, sizeof(const char *) * argc);
610 argc = parse_options(argc, (const char **)__argv, record_options,
611 NULL, PARSE_OPT_STOP_AT_NON_OPTION);
612 free(__argv);
613
614 return argc != 0;
615}
616
570int cmd_trace(int argc, const char **argv, const char *prefix __used) 617int cmd_trace(int argc, const char **argv, const char *prefix __used)
571{ 618{
619 char *rec_script_path = NULL;
620 char *rep_script_path = NULL;
572 struct perf_session *session; 621 struct perf_session *session;
573 const char *suffix = NULL; 622 char *script_path = NULL;
574 const char **__argv; 623 const char **__argv;
575 char *script_path; 624 bool system_wide;
576 int i, err; 625 int i, j, err;
577 626
578 if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) { 627 setup_scripting();
579 if (argc < 3) { 628
580 fprintf(stderr, 629 argc = parse_options(argc, argv, options, trace_usage,
581 "Please specify a record script\n"); 630 PARSE_OPT_STOP_AT_NON_OPTION);
582 return -1; 631
583 } 632 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
584 suffix = RECORD_SUFFIX; 633 rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
634 if (!rec_script_path)
635 return cmd_record(argc, argv, NULL);
585 } 636 }
586 637
587 if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) { 638 if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
588 if (argc < 3) { 639 rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
640 if (!rep_script_path) {
589 fprintf(stderr, 641 fprintf(stderr,
590 "Please specify a report script\n"); 642 "Please specify a valid report script"
643 "(see 'perf trace -l' for listing)\n");
591 return -1; 644 return -1;
592 } 645 }
593 suffix = REPORT_SUFFIX;
594 } 646 }
595 647
596 if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) { 648 /* make sure PERF_EXEC_PATH is set for scripts */
597 char *record_script_path, *report_script_path; 649 perf_set_argv_exec_path(perf_exec_path());
650
651 if (argc && !script_name && !rec_script_path && !rep_script_path) {
598 int live_pipe[2]; 652 int live_pipe[2];
653 int rep_args;
599 pid_t pid; 654 pid_t pid;
600 655
601 record_script_path = get_script_path(argv[1], RECORD_SUFFIX); 656 rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
602 if (!record_script_path) { 657 rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
603 fprintf(stderr, "record script not found\n"); 658
604 return -1; 659 if (!rec_script_path && !rep_script_path) {
660 fprintf(stderr, " Couldn't find script %s\n\n See perf"
661 " trace -l for available scripts.\n", argv[0]);
662 usage_with_options(trace_usage, options);
605 } 663 }
606 664
607 report_script_path = get_script_path(argv[1], REPORT_SUFFIX); 665 if (is_top_script(argv[0])) {
608 if (!report_script_path) { 666 rep_args = argc - 1;
609 fprintf(stderr, "report script not found\n"); 667 } else {
610 return -1; 668 int rec_args;
669
670 rep_args = has_required_arg(rep_script_path);
671 rec_args = (argc - 1) - rep_args;
672 if (rec_args < 0) {
673 fprintf(stderr, " %s script requires options."
674 "\n\n See perf trace -l for available "
675 "scripts and options.\n", argv[0]);
676 usage_with_options(trace_usage, options);
677 }
611 } 678 }
612 679
613 if (pipe(live_pipe) < 0) { 680 if (pipe(live_pipe) < 0) {
@@ -622,59 +689,84 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
622 } 689 }
623 690
624 if (!pid) { 691 if (!pid) {
692 system_wide = true;
693 j = 0;
694
625 dup2(live_pipe[1], 1); 695 dup2(live_pipe[1], 1);
626 close(live_pipe[0]); 696 close(live_pipe[0]);
627 697
628 __argv = malloc(5 * sizeof(const char *)); 698 if (!is_top_script(argv[0]))
629 __argv[0] = "/bin/sh"; 699 system_wide = !have_cmd(argc - rep_args,
630 __argv[1] = record_script_path; 700 &argv[rep_args]);
631 __argv[2] = "-o"; 701
632 __argv[3] = "-"; 702 __argv = malloc((argc + 6) * sizeof(const char *));
633 __argv[4] = NULL; 703 if (!__argv)
704 die("malloc");
705
706 __argv[j++] = "/bin/sh";
707 __argv[j++] = rec_script_path;
708 if (system_wide)
709 __argv[j++] = "-a";
710 __argv[j++] = "-q";
711 __argv[j++] = "-o";
712 __argv[j++] = "-";
713 for (i = rep_args + 1; i < argc; i++)
714 __argv[j++] = argv[i];
715 __argv[j++] = NULL;
634 716
635 execvp("/bin/sh", (char **)__argv); 717 execvp("/bin/sh", (char **)__argv);
718 free(__argv);
636 exit(-1); 719 exit(-1);
637 } 720 }
638 721
639 dup2(live_pipe[0], 0); 722 dup2(live_pipe[0], 0);
640 close(live_pipe[1]); 723 close(live_pipe[1]);
641 724
642 __argv = malloc((argc + 3) * sizeof(const char *)); 725 __argv = malloc((argc + 4) * sizeof(const char *));
643 __argv[0] = "/bin/sh"; 726 if (!__argv)
644 __argv[1] = report_script_path; 727 die("malloc");
645 for (i = 2; i < argc; i++) 728 j = 0;
646 __argv[i] = argv[i]; 729 __argv[j++] = "/bin/sh";
647 __argv[i++] = "-i"; 730 __argv[j++] = rep_script_path;
648 __argv[i++] = "-"; 731 for (i = 1; i < rep_args + 1; i++)
649 __argv[i++] = NULL; 732 __argv[j++] = argv[i];
733 __argv[j++] = "-i";
734 __argv[j++] = "-";
735 __argv[j++] = NULL;
650 736
651 execvp("/bin/sh", (char **)__argv); 737 execvp("/bin/sh", (char **)__argv);
738 free(__argv);
652 exit(-1); 739 exit(-1);
653 } 740 }
654 741
655 if (suffix) { 742 if (rec_script_path)
656 script_path = get_script_path(argv[2], suffix); 743 script_path = rec_script_path;
657 if (!script_path) { 744 if (rep_script_path)
658 fprintf(stderr, "script not found\n"); 745 script_path = rep_script_path;
659 return -1; 746
660 } 747 if (script_path) {
661 748 system_wide = false;
662 __argv = malloc((argc + 1) * sizeof(const char *)); 749 j = 0;
663 __argv[0] = "/bin/sh"; 750
664 __argv[1] = script_path; 751 if (rec_script_path)
665 for (i = 3; i < argc; i++) 752 system_wide = !have_cmd(argc - 1, &argv[1]);
666 __argv[i - 1] = argv[i]; 753
667 __argv[argc - 1] = NULL; 754 __argv = malloc((argc + 2) * sizeof(const char *));
755 if (!__argv)
756 die("malloc");
757 __argv[j++] = "/bin/sh";
758 __argv[j++] = script_path;
759 if (system_wide)
760 __argv[j++] = "-a";
761 for (i = 2; i < argc; i++)
762 __argv[j++] = argv[i];
763 __argv[j++] = NULL;
668 764
669 execvp("/bin/sh", (char **)__argv); 765 execvp("/bin/sh", (char **)__argv);
766 free(__argv);
670 exit(-1); 767 exit(-1);
671 } 768 }
672 769
673 setup_scripting();
674
675 argc = parse_options(argc, argv, options, trace_usage,
676 PARSE_OPT_STOP_AT_NON_OPTION);
677
678 if (symbol__init() < 0) 770 if (symbol__init() < 0)
679 return -1; 771 return -1;
680 if (!script_name) 772 if (!script_name)
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record
index eb5846bcb565..8104895a7b67 100644
--- a/tools/perf/scripts/perl/bin/failed-syscalls-record
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e raw_syscalls:sys_exit $@ 2perf record -e raw_syscalls:sys_exit $@
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-report b/tools/perf/scripts/perl/bin/failed-syscalls-report
index e3a5e55d54ff..4028d92dc4ae 100644
--- a/tools/perf/scripts/perl/bin/failed-syscalls-report
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
7 shift 7 shift
8 fi 8 fi
9fi 9fi
10perf trace $@ -s ~/libexec/perf-core/scripts/perl/failed-syscalls.pl $comm 10perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/failed-syscalls.pl $comm
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-record b/tools/perf/scripts/perl/bin/rw-by-file-record
index 5bfaae5a6cba..33efc8673aae 100644
--- a/tools/perf/scripts/perl/bin/rw-by-file-record
+++ b/tools/perf/scripts/perl/bin/rw-by-file-record
@@ -1,3 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@ 2perf record -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@
3 3
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report
index d83070b7eeb5..ba25f4d41fb0 100644
--- a/tools/perf/scripts/perl/bin/rw-by-file-report
+++ b/tools/perf/scripts/perl/bin/rw-by-file-report
@@ -7,7 +7,7 @@ if [ $# -lt 1 ] ; then
7fi 7fi
8comm=$1 8comm=$1
9shift 9shift
10perf trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $comm 10perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-file.pl $comm
11 11
12 12
13 13
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record
index 6e0b2f7755ac..7cb9db230448 100644
--- a/tools/perf/scripts/perl/bin/rw-by-pid-record
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ 2perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
index 7ef46983f62f..641a3f5d085c 100644
--- a/tools/perf/scripts/perl/bin/rw-by-pid-report
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-report
@@ -1,6 +1,6 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide r/w activity 2# description: system-wide r/w activity
3perf trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl 3perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-pid.pl
4 4
5 5
6 6
diff --git a/tools/perf/scripts/perl/bin/rwtop-record b/tools/perf/scripts/perl/bin/rwtop-record
index 6e0b2f7755ac..7cb9db230448 100644
--- a/tools/perf/scripts/perl/bin/rwtop-record
+++ b/tools/perf/scripts/perl/bin/rwtop-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ 2perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
diff --git a/tools/perf/scripts/perl/bin/rwtop-report b/tools/perf/scripts/perl/bin/rwtop-report
index 93e698cd3f38..4918dba77021 100644
--- a/tools/perf/scripts/perl/bin/rwtop-report
+++ b/tools/perf/scripts/perl/bin/rwtop-report
@@ -17,7 +17,7 @@ if [ "$n_args" -gt 0 ] ; then
17 interval=$1 17 interval=$1
18 shift 18 shift
19fi 19fi
20perf trace $@ -s ~/libexec/perf-core/scripts/perl/rwtop.pl $interval 20perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/rwtop.pl $interval
21 21
22 22
23 23
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record
index 9f2acaaae9f0..464251a1bd7e 100644
--- a/tools/perf/scripts/perl/bin/wakeup-latency-record
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-record
@@ -1,5 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e sched:sched_switch -e sched:sched_wakeup $@ 2perf record -e sched:sched_switch -e sched:sched_wakeup $@
3 3
4 4
5 5
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
index a0d898f9ca1d..49052ebcb632 100644
--- a/tools/perf/scripts/perl/bin/wakeup-latency-report
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-report
@@ -1,6 +1,6 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide min/max/avg wakeup latency 2# description: system-wide min/max/avg wakeup latency
3perf trace $@ -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl 3perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/wakeup-latency.pl
4 4
5 5
6 6
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
index 85301f2471ff..8edda9078d5d 100644
--- a/tools/perf/scripts/perl/bin/workqueue-stats-record
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@ 2perf record -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
index 35081132ef97..df0c65f4ca93 100644
--- a/tools/perf/scripts/perl/bin/workqueue-stats-report
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-report
@@ -1,6 +1,6 @@
1#!/bin/bash 1#!/bin/bash
2# description: workqueue stats (ins/exe/create/destroy) 2# description: workqueue stats (ins/exe/create/destroy)
3perf trace $@ -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl 3perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl
4 4
5 5
6 6
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
index 9689bc0acd9f..13cc02b5893a 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
@@ -6,6 +6,14 @@
6# Public License ("GPL") version 2 as published by the Free Software 6# Public License ("GPL") version 2 as published by the Free Software
7# Foundation. 7# Foundation.
8 8
9import errno, os
10
11FUTEX_WAIT = 0
12FUTEX_WAKE = 1
13FUTEX_PRIVATE_FLAG = 128
14FUTEX_CLOCK_REALTIME = 256
15FUTEX_CMD_MASK = ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
16
9NSECS_PER_SEC = 1000000000 17NSECS_PER_SEC = 1000000000
10 18
11def avg(total, n): 19def avg(total, n):
@@ -24,5 +32,55 @@ def nsecs_str(nsecs):
24 str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)), 32 str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)),
25 return str 33 return str
26 34
35def add_stats(dict, key, value):
36 if not dict.has_key(key):
37 dict[key] = (value, value, value, 1)
38 else:
39 min, max, avg, count = dict[key]
40 if value < min:
41 min = value
42 if value > max:
43 max = value
44 avg = (avg + value) / 2
45 dict[key] = (min, max, avg, count + 1)
46
27def clear_term(): 47def clear_term():
28 print("\x1b[H\x1b[2J") 48 print("\x1b[H\x1b[2J")
49
50audit_package_warned = False
51
52try:
53 import audit
54 machine_to_id = {
55 'x86_64': audit.MACH_86_64,
56 'alpha' : audit.MACH_ALPHA,
57 'ia64' : audit.MACH_IA64,
58 'ppc' : audit.MACH_PPC,
59 'ppc64' : audit.MACH_PPC64,
60 's390' : audit.MACH_S390,
61 's390x' : audit.MACH_S390X,
62 'i386' : audit.MACH_X86,
63 'i586' : audit.MACH_X86,
64 'i686' : audit.MACH_X86,
65 }
66 try:
67 machine_to_id['armeb'] = audit.MACH_ARMEB
68 except:
69 pass
70 machine_id = machine_to_id[os.uname()[4]]
71except:
72 if not audit_package_warned:
73 audit_package_warned = True
74 print "Install the audit-libs-python package to get syscall names"
75
76def syscall_name(id):
77 try:
78 return audit.audit_syscall_to_name(id, machine_id)
79 except:
80 return str(id)
81
82def strerror(nr):
83 try:
84 return errno.errorcode[abs(nr)]
85 except:
86 return "Unknown %d errno" % nr
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
index eb5846bcb565..8104895a7b67 100644
--- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e raw_syscalls:sys_exit $@ 2perf record -e raw_syscalls:sys_exit $@
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
index 30293545fcc2..03587021463d 100644
--- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
7 shift 7 shift
8 fi 8 fi
9fi 9fi
10perf trace $@ -s ~/libexec/perf-core/scripts/python/failed-syscalls-by-pid.py $comm 10perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/failed-syscalls-by-pid.py $comm
diff --git a/tools/perf/scripts/python/bin/futex-contention-record b/tools/perf/scripts/python/bin/futex-contention-record
new file mode 100644
index 000000000000..b1495c9a9b20
--- /dev/null
+++ b/tools/perf/scripts/python/bin/futex-contention-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e syscalls:sys_enter_futex -e syscalls:sys_exit_futex $@
diff --git a/tools/perf/scripts/python/bin/futex-contention-report b/tools/perf/scripts/python/bin/futex-contention-report
new file mode 100644
index 000000000000..c8268138fb7e
--- /dev/null
+++ b/tools/perf/scripts/python/bin/futex-contention-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: futext contention measurement
3
4perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/futex-contention.py
diff --git a/tools/perf/scripts/python/bin/netdev-times-record b/tools/perf/scripts/python/bin/netdev-times-record
index d931a828126b..558754b840a9 100644
--- a/tools/perf/scripts/python/bin/netdev-times-record
+++ b/tools/perf/scripts/python/bin/netdev-times-record
@@ -1,5 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e net:net_dev_xmit -e net:net_dev_queue \ 2perf record -e net:net_dev_xmit -e net:net_dev_queue \
3 -e net:netif_receive_skb -e net:netif_rx \ 3 -e net:netif_receive_skb -e net:netif_rx \
4 -e skb:consume_skb -e skb:kfree_skb \ 4 -e skb:consume_skb -e skb:kfree_skb \
5 -e skb:skb_copy_datagram_iovec -e napi:napi_poll \ 5 -e skb:skb_copy_datagram_iovec -e napi:napi_poll \
diff --git a/tools/perf/scripts/python/bin/netdev-times-report b/tools/perf/scripts/python/bin/netdev-times-report
index c3d0a638123d..4ad361b31249 100644
--- a/tools/perf/scripts/python/bin/netdev-times-report
+++ b/tools/perf/scripts/python/bin/netdev-times-report
@@ -2,4 +2,4 @@
2# description: display a process of packet and processing time 2# description: display a process of packet and processing time
3# args: [tx] [rx] [dev=] [debug] 3# args: [tx] [rx] [dev=] [debug]
4 4
5perf trace -s ~/libexec/perf-core/scripts/python/netdev-times.py $@ 5perf trace -s "$PERF_EXEC_PATH"/scripts/python/netdev-times.py $@
diff --git a/tools/perf/scripts/python/bin/sched-migration-record b/tools/perf/scripts/python/bin/sched-migration-record
index 17a3e9bd9e8f..7493fddbe995 100644
--- a/tools/perf/scripts/python/bin/sched-migration-record
+++ b/tools/perf/scripts/python/bin/sched-migration-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -m 16384 -a -e sched:sched_wakeup -e sched:sched_wakeup_new -e sched:sched_switch -e sched:sched_migrate_task $@ 2perf record -m 16384 -e sched:sched_wakeup -e sched:sched_wakeup_new -e sched:sched_switch -e sched:sched_migrate_task $@
diff --git a/tools/perf/scripts/python/bin/sched-migration-report b/tools/perf/scripts/python/bin/sched-migration-report
index 61d05f72e443..df1791f07c24 100644
--- a/tools/perf/scripts/python/bin/sched-migration-report
+++ b/tools/perf/scripts/python/bin/sched-migration-report
@@ -1,3 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2# description: sched migration overview 2# description: sched migration overview
3perf trace $@ -s ~/libexec/perf-core/scripts/python/sched-migration.py 3perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/sched-migration.py
diff --git a/tools/perf/scripts/python/bin/sctop-record b/tools/perf/scripts/python/bin/sctop-record
index 1fc5998b721d..4efbfaa7f6a5 100644
--- a/tools/perf/scripts/python/bin/sctop-record
+++ b/tools/perf/scripts/python/bin/sctop-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e raw_syscalls:sys_enter $@ 2perf record -e raw_syscalls:sys_enter $@
diff --git a/tools/perf/scripts/python/bin/sctop-report b/tools/perf/scripts/python/bin/sctop-report
index b01c842ae7b4..36b409c05e50 100644
--- a/tools/perf/scripts/python/bin/sctop-report
+++ b/tools/perf/scripts/python/bin/sctop-report
@@ -21,4 +21,4 @@ elif [ "$n_args" -gt 0 ] ; then
21 interval=$1 21 interval=$1
22 shift 22 shift
23fi 23fi
24perf trace $@ -s ~/libexec/perf-core/scripts/python/sctop.py $comm $interval 24perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/sctop.py $comm $interval
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
index 1fc5998b721d..4efbfaa7f6a5 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e raw_syscalls:sys_enter $@ 2perf record -e raw_syscalls:sys_enter $@
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-report b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
index 9e9d8ddd72ce..4eb88c9fc83c 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
7 shift 7 shift
8 fi 8 fi
9fi 9fi
10perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts-by-pid.py $comm 10perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/syscall-counts-by-pid.py $comm
diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record
index 1fc5998b721d..4efbfaa7f6a5 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-record
+++ b/tools/perf/scripts/python/bin/syscall-counts-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -a -e raw_syscalls:sys_enter $@ 2perf record -e raw_syscalls:sys_enter $@
diff --git a/tools/perf/scripts/python/bin/syscall-counts-report b/tools/perf/scripts/python/bin/syscall-counts-report
index dc076b618796..cb2f9c5cf17e 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-report
+++ b/tools/perf/scripts/python/bin/syscall-counts-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
7 shift 7 shift
8 fi 8 fi
9fi 9fi
10perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts.py $comm 10perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/syscall-counts.py $comm
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py
index 0ca02278fe69..acd7848717b3 100644
--- a/tools/perf/scripts/python/failed-syscalls-by-pid.py
+++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py
@@ -13,21 +13,26 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
13 13
14from perf_trace_context import * 14from perf_trace_context import *
15from Core import * 15from Core import *
16from Util import *
16 17
17usage = "perf trace -s syscall-counts-by-pid.py [comm]\n"; 18usage = "perf trace -s syscall-counts-by-pid.py [comm|pid]\n";
18 19
19for_comm = None 20for_comm = None
21for_pid = None
20 22
21if len(sys.argv) > 2: 23if len(sys.argv) > 2:
22 sys.exit(usage) 24 sys.exit(usage)
23 25
24if len(sys.argv) > 1: 26if len(sys.argv) > 1:
25 for_comm = sys.argv[1] 27 try:
28 for_pid = int(sys.argv[1])
29 except:
30 for_comm = sys.argv[1]
26 31
27syscalls = autodict() 32syscalls = autodict()
28 33
29def trace_begin(): 34def trace_begin():
30 pass 35 print "Press control+C to stop and show the summary"
31 36
32def trace_end(): 37def trace_end():
33 print_error_totals() 38 print_error_totals()
@@ -35,9 +40,9 @@ def trace_end():
35def raw_syscalls__sys_exit(event_name, context, common_cpu, 40def raw_syscalls__sys_exit(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm, 41 common_secs, common_nsecs, common_pid, common_comm,
37 id, ret): 42 id, ret):
38 if for_comm is not None: 43 if (for_comm and common_comm != for_comm) or \
39 if common_comm != for_comm: 44 (for_pid and common_pid != for_pid ):
40 return 45 return
41 46
42 if ret < 0: 47 if ret < 0:
43 try: 48 try:
@@ -62,7 +67,7 @@ def print_error_totals():
62 print "\n%s [%d]\n" % (comm, pid), 67 print "\n%s [%d]\n" % (comm, pid),
63 id_keys = syscalls[comm][pid].keys() 68 id_keys = syscalls[comm][pid].keys()
64 for id in id_keys: 69 for id in id_keys:
65 print " syscall: %-16d\n" % (id), 70 print " syscall: %-16s\n" % syscall_name(id),
66 ret_keys = syscalls[comm][pid][id].keys() 71 ret_keys = syscalls[comm][pid][id].keys()
67 for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k), reverse = True): 72 for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k), reverse = True):
68 print " err = %-20d %10d\n" % (ret, val), 73 print " err = %-20s %10d\n" % (strerror(ret), val),
diff --git a/tools/perf/scripts/python/futex-contention.py b/tools/perf/scripts/python/futex-contention.py
new file mode 100644
index 000000000000..11e70a388d41
--- /dev/null
+++ b/tools/perf/scripts/python/futex-contention.py
@@ -0,0 +1,50 @@
1# futex contention
2# (c) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Translation of:
6#
7# http://sourceware.org/systemtap/wiki/WSFutexContention
8#
9# to perf python scripting.
10#
11# Measures futex contention
12
13import os, sys
14sys.path.append(os.environ['PERF_EXEC_PATH'] + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
15from Util import *
16
17process_names = {}
18thread_thislock = {}
19thread_blocktime = {}
20
21lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time
22process_names = {} # long-lived pid-to-execname mapping
23
24def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm,
25 nr, uaddr, op, val, utime, uaddr2, val3):
26 cmd = op & FUTEX_CMD_MASK
27 if cmd != FUTEX_WAIT:
28 return # we don't care about originators of WAKE events
29
30 process_names[tid] = comm
31 thread_thislock[tid] = uaddr
32 thread_blocktime[tid] = nsecs(s, ns)
33
34def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm,
35 nr, ret):
36 if thread_blocktime.has_key(tid):
37 elapsed = nsecs(s, ns) - thread_blocktime[tid]
38 add_stats(lock_waits, (tid, thread_thislock[tid]), elapsed)
39 del thread_blocktime[tid]
40 del thread_thislock[tid]
41
42def trace_begin():
43 print "Press control+C to stop and show the summary"
44
45def trace_end():
46 for (tid, lock) in lock_waits:
47 min, max, avg, count = lock_waits[tid, lock]
48 print "%s[%d] lock %x contended %d times, %d avg ns" % \
49 (process_names[tid], tid, lock, count, avg)
50
diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py
index 6cafad40c296..7a6ec2c7d8ab 100644
--- a/tools/perf/scripts/python/sctop.py
+++ b/tools/perf/scripts/python/sctop.py
@@ -8,10 +8,7 @@
8# will be refreshed every [interval] seconds. The default interval is 8# will be refreshed every [interval] seconds. The default interval is
9# 3 seconds. 9# 3 seconds.
10 10
11import thread 11import os, sys, thread, time
12import time
13import os
14import sys
15 12
16sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 13sys.path.append(os.environ['PERF_EXEC_PATH'] + \
17 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 14 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
@@ -20,7 +17,7 @@ from perf_trace_context import *
20from Core import * 17from Core import *
21from Util import * 18from Util import *
22 19
23usage = "perf trace -s syscall-counts.py [comm] [interval]\n"; 20usage = "perf trace -s sctop.py [comm] [interval]\n";
24 21
25for_comm = None 22for_comm = None
26default_interval = 3 23default_interval = 3
@@ -71,7 +68,7 @@ def print_syscall_totals(interval):
71 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \ 68 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
72 reverse = True): 69 reverse = True):
73 try: 70 try:
74 print "%-40d %10d\n" % (id, val), 71 print "%-40s %10d\n" % (syscall_name(id), val),
75 except TypeError: 72 except TypeError:
76 pass 73 pass
77 syscalls.clear() 74 syscalls.clear()
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py
index af722d6a4b3f..d1ee3ec10cf2 100644
--- a/tools/perf/scripts/python/syscall-counts-by-pid.py
+++ b/tools/perf/scripts/python/syscall-counts-by-pid.py
@@ -5,29 +5,33 @@
5# Displays system-wide system call totals, broken down by syscall. 5# Displays system-wide system call totals, broken down by syscall.
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed. 6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7 7
8import os 8import os, sys
9import sys
10 9
11sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 10sys.path.append(os.environ['PERF_EXEC_PATH'] + \
12 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 11 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
13 12
14from perf_trace_context import * 13from perf_trace_context import *
15from Core import * 14from Core import *
15from Util import syscall_name
16 16
17usage = "perf trace -s syscall-counts-by-pid.py [comm]\n"; 17usage = "perf trace -s syscall-counts-by-pid.py [comm]\n";
18 18
19for_comm = None 19for_comm = None
20for_pid = None
20 21
21if len(sys.argv) > 2: 22if len(sys.argv) > 2:
22 sys.exit(usage) 23 sys.exit(usage)
23 24
24if len(sys.argv) > 1: 25if len(sys.argv) > 1:
25 for_comm = sys.argv[1] 26 try:
27 for_pid = int(sys.argv[1])
28 except:
29 for_comm = sys.argv[1]
26 30
27syscalls = autodict() 31syscalls = autodict()
28 32
29def trace_begin(): 33def trace_begin():
30 pass 34 print "Press control+C to stop and show the summary"
31 35
32def trace_end(): 36def trace_end():
33 print_syscall_totals() 37 print_syscall_totals()
@@ -35,9 +39,10 @@ def trace_end():
35def raw_syscalls__sys_enter(event_name, context, common_cpu, 39def raw_syscalls__sys_enter(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm, 40 common_secs, common_nsecs, common_pid, common_comm,
37 id, args): 41 id, args):
38 if for_comm is not None: 42
39 if common_comm != for_comm: 43 if (for_comm and common_comm != for_comm) or \
40 return 44 (for_pid and common_pid != for_pid ):
45 return
41 try: 46 try:
42 syscalls[common_comm][common_pid][id] += 1 47 syscalls[common_comm][common_pid][id] += 1
43 except TypeError: 48 except TypeError:
@@ -61,4 +66,4 @@ def print_syscall_totals():
61 id_keys = syscalls[comm][pid].keys() 66 id_keys = syscalls[comm][pid].keys()
62 for id, val in sorted(syscalls[comm][pid].iteritems(), \ 67 for id, val in sorted(syscalls[comm][pid].iteritems(), \
63 key = lambda(k, v): (v, k), reverse = True): 68 key = lambda(k, v): (v, k), reverse = True):
64 print " %-38d %10d\n" % (id, val), 69 print " %-38s %10d\n" % (syscall_name(id), val),
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py
index f977e85ff049..ea183dc82d29 100644
--- a/tools/perf/scripts/python/syscall-counts.py
+++ b/tools/perf/scripts/python/syscall-counts.py
@@ -13,6 +13,7 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
13 13
14from perf_trace_context import * 14from perf_trace_context import *
15from Core import * 15from Core import *
16from Util import syscall_name
16 17
17usage = "perf trace -s syscall-counts.py [comm]\n"; 18usage = "perf trace -s syscall-counts.py [comm]\n";
18 19
@@ -27,7 +28,7 @@ if len(sys.argv) > 1:
27syscalls = autodict() 28syscalls = autodict()
28 29
29def trace_begin(): 30def trace_begin():
30 pass 31 print "Press control+C to stop and show the summary"
31 32
32def trace_end(): 33def trace_end():
33 print_syscall_totals() 34 print_syscall_totals()
@@ -55,4 +56,4 @@ def print_syscall_totals():
55 56
56 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \ 57 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
57 reverse = True): 58 reverse = True):
58 print "%-40d %10d\n" % (id, val), 59 print "%-40s %10d\n" % (syscall_name(id), val),
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index f9c7e3ad1aa7..c8d81b00089d 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -12,8 +12,8 @@
12#include "debug.h" 12#include "debug.h"
13#include "util.h" 13#include "util.h"
14 14
15int verbose = 0; 15int verbose;
16bool dump_trace = false; 16bool dump_trace = false, quiet = false;
17 17
18int eprintf(int level, const char *fmt, ...) 18int eprintf(int level, const char *fmt, ...)
19{ 19{
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 7a17ee061bcb..7b514082bbaf 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -6,7 +6,7 @@
6#include "event.h" 6#include "event.h"
7 7
8extern int verbose; 8extern int verbose;
9extern bool dump_trace; 9extern bool quiet, dump_trace;
10 10
11int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 11int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
12void trace_event(event_t *event); 12void trace_event(event_t *event);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index d7e67b167ea3..7cba0551a565 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -265,15 +265,16 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
265 const char *name, bool is_kallsyms) 265 const char *name, bool is_kallsyms)
266{ 266{
267 const size_t size = PATH_MAX; 267 const size_t size = PATH_MAX;
268 char *filename = malloc(size), 268 char *realname = realpath(name, NULL),
269 *filename = malloc(size),
269 *linkname = malloc(size), *targetname; 270 *linkname = malloc(size), *targetname;
270 int len, err = -1; 271 int len, err = -1;
271 272
272 if (filename == NULL || linkname == NULL) 273 if (realname == NULL || filename == NULL || linkname == NULL)
273 goto out_free; 274 goto out_free;
274 275
275 len = snprintf(filename, size, "%s%s%s", 276 len = snprintf(filename, size, "%s%s%s",
276 debugdir, is_kallsyms ? "/" : "", name); 277 debugdir, is_kallsyms ? "/" : "", realname);
277 if (mkdir_p(filename, 0755)) 278 if (mkdir_p(filename, 0755))
278 goto out_free; 279 goto out_free;
279 280
@@ -283,7 +284,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
283 if (is_kallsyms) { 284 if (is_kallsyms) {
284 if (copyfile("/proc/kallsyms", filename)) 285 if (copyfile("/proc/kallsyms", filename))
285 goto out_free; 286 goto out_free;
286 } else if (link(name, filename) && copyfile(name, filename)) 287 } else if (link(realname, filename) && copyfile(name, filename))
287 goto out_free; 288 goto out_free;
288 } 289 }
289 290
@@ -300,6 +301,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
300 if (symlink(targetname, linkname) == 0) 301 if (symlink(targetname, linkname) == 0)
301 err = 0; 302 err = 0;
302out_free: 303out_free:
304 free(realname);
303 free(filename); 305 free(filename);
304 free(linkname); 306 free(linkname);
305 return err; 307 return err;
@@ -946,11 +948,16 @@ perf_header__find_attr(u64 id, struct perf_header *header)
946 948
947 /* 949 /*
948 * We set id to -1 if the data file doesn't contain sample 950 * We set id to -1 if the data file doesn't contain sample
949 * ids. Check for this and avoid walking through the entire 951 * ids. This can happen when the data file contains one type
950 * list of ids which may be large. 952 * of event and in that case, the header can still store the
953 * event attribute information. Check for this and avoid
954 * walking through the entire list of ids which may be large.
951 */ 955 */
952 if (id == -1ULL) 956 if (id == -1ULL) {
957 if (header->attrs > 0)
958 return &header->attr[0]->attr;
953 return NULL; 959 return NULL;
960 }
954 961
955 for (i = 0; i < header->attrs; i++) { 962 for (i = 0; i < header->attrs; i++) {
956 struct perf_header_attr *attr = header->attr[i]; 963 struct perf_header_attr *attr = header->attr[i];
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 78575796d5f3..b397c0383728 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -215,6 +215,16 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *self,
215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); 215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
216} 216}
217 217
218static inline
219struct symbol *machine__find_kernel_function_by_name(struct machine *self,
220 const char *name,
221 struct map **mapp,
222 symbol_filter_t filter)
223{
224 return map_groups__find_function_by_name(&self->kmaps, name, mapp,
225 filter);
226}
227
218int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, 228int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
219 int verbose, FILE *fp); 229 int verbose, FILE *fp);
220 230
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fcc16e4349df..61191c6cbe7a 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -74,10 +74,9 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
74static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 74static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
75static struct machine machine; 75static struct machine machine;
76 76
77/* Initialize symbol maps and path of vmlinux */ 77/* Initialize symbol maps and path of vmlinux/modules */
78static int init_vmlinux(void) 78static int init_vmlinux(void)
79{ 79{
80 struct dso *kernel;
81 int ret; 80 int ret;
82 81
83 symbol_conf.sort_by_name = true; 82 symbol_conf.sort_by_name = true;
@@ -91,33 +90,70 @@ static int init_vmlinux(void)
91 goto out; 90 goto out;
92 } 91 }
93 92
94 ret = machine__init(&machine, "/", 0); 93 ret = machine__init(&machine, "", HOST_KERNEL_ID);
95 if (ret < 0) 94 if (ret < 0)
96 goto out; 95 goto out;
97 96
98 kernel = dso__new_kernel(symbol_conf.vmlinux_name); 97 if (machine__create_kernel_maps(&machine) < 0) {
99 if (kernel == NULL) 98 pr_debug("machine__create_kernel_maps ");
100 die("Failed to create kernel dso."); 99 goto out;
101 100 }
102 ret = __machine__create_kernel_maps(&machine, kernel);
103 if (ret < 0)
104 pr_debug("Failed to create kernel maps.\n");
105
106out: 101out:
107 if (ret < 0) 102 if (ret < 0)
108 pr_warning("Failed to init vmlinux path.\n"); 103 pr_warning("Failed to init vmlinux path.\n");
109 return ret; 104 return ret;
110} 105}
111 106
107static struct symbol *__find_kernel_function_by_name(const char *name,
108 struct map **mapp)
109{
110 return machine__find_kernel_function_by_name(&machine, name, mapp,
111 NULL);
112}
113
114const char *kernel_get_module_path(const char *module)
115{
116 struct dso *dso;
117 struct map *map;
118 const char *vmlinux_name;
119
120 if (module) {
121 list_for_each_entry(dso, &machine.kernel_dsos, node) {
122 if (strncmp(dso->short_name + 1, module,
123 dso->short_name_len - 2) == 0)
124 goto found;
125 }
126 pr_debug("Failed to find module %s.\n", module);
127 return NULL;
128 }
129
130 map = machine.vmlinux_maps[MAP__FUNCTION];
131 dso = map->dso;
132
133 vmlinux_name = symbol_conf.vmlinux_name;
134 if (vmlinux_name) {
135 if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0)
136 return NULL;
137 } else {
138 if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
139 pr_debug("Failed to load kernel map.\n");
140 return NULL;
141 }
142 }
143found:
144 return dso->long_name;
145}
146
112#ifdef DWARF_SUPPORT 147#ifdef DWARF_SUPPORT
113static int open_vmlinux(void) 148static int open_vmlinux(const char *module)
114{ 149{
115 if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) { 150 const char *path = kernel_get_module_path(module);
116 pr_debug("Failed to load kernel map.\n"); 151 if (!path) {
117 return -EINVAL; 152 pr_err("Failed to find path of %s module", module ?: "kernel");
153 return -ENOENT;
118 } 154 }
119 pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name); 155 pr_debug("Try to open %s\n", path);
120 return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY); 156 return open(path, O_RDONLY);
121} 157}
122 158
123/* 159/*
@@ -125,20 +161,19 @@ static int open_vmlinux(void)
125 * Currently only handles kprobes. 161 * Currently only handles kprobes.
126 */ 162 */
127static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 163static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
128 struct perf_probe_point *pp) 164 struct perf_probe_point *pp)
129{ 165{
130 struct symbol *sym; 166 struct symbol *sym;
131 int fd, ret = -ENOENT; 167 struct map *map;
168 u64 addr;
169 int ret = -ENOENT;
132 170
133 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], 171 sym = __find_kernel_function_by_name(tp->symbol, &map);
134 tp->symbol, NULL);
135 if (sym) { 172 if (sym) {
136 fd = open_vmlinux(); 173 addr = map->unmap_ip(map, sym->start + tp->offset);
137 if (fd >= 0) { 174 pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
138 ret = find_perf_probe_point(fd, 175 tp->offset, addr);
139 sym->start + tp->offset, pp); 176 ret = find_perf_probe_point((unsigned long)addr, pp);
140 close(fd);
141 }
142 } 177 }
143 if (ret <= 0) { 178 if (ret <= 0) {
144 pr_debug("Failed to find corresponding probes from " 179 pr_debug("Failed to find corresponding probes from "
@@ -156,12 +191,12 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
156/* Try to find perf_probe_event with debuginfo */ 191/* Try to find perf_probe_event with debuginfo */
157static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 192static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
158 struct probe_trace_event **tevs, 193 struct probe_trace_event **tevs,
159 int max_tevs) 194 int max_tevs, const char *module)
160{ 195{
161 bool need_dwarf = perf_probe_event_need_dwarf(pev); 196 bool need_dwarf = perf_probe_event_need_dwarf(pev);
162 int fd, ntevs; 197 int fd, ntevs;
163 198
164 fd = open_vmlinux(); 199 fd = open_vmlinux(module);
165 if (fd < 0) { 200 if (fd < 0) {
166 if (need_dwarf) { 201 if (need_dwarf) {
167 pr_warning("Failed to open debuginfo file.\n"); 202 pr_warning("Failed to open debuginfo file.\n");
@@ -300,7 +335,7 @@ error:
300 * Show line-range always requires debuginfo to find source file and 335 * Show line-range always requires debuginfo to find source file and
301 * line number. 336 * line number.
302 */ 337 */
303int show_line_range(struct line_range *lr) 338int show_line_range(struct line_range *lr, const char *module)
304{ 339{
305 int l = 1; 340 int l = 1;
306 struct line_node *ln; 341 struct line_node *ln;
@@ -313,7 +348,7 @@ int show_line_range(struct line_range *lr)
313 if (ret < 0) 348 if (ret < 0)
314 return ret; 349 return ret;
315 350
316 fd = open_vmlinux(); 351 fd = open_vmlinux(module);
317 if (fd < 0) { 352 if (fd < 0) {
318 pr_warning("Failed to open debuginfo file.\n"); 353 pr_warning("Failed to open debuginfo file.\n");
319 return fd; 354 return fd;
@@ -378,11 +413,84 @@ end:
378 return ret; 413 return ret;
379} 414}
380 415
416static int show_available_vars_at(int fd, struct perf_probe_event *pev,
417 int max_vls, bool externs)
418{
419 char *buf;
420 int ret, i;
421 struct str_node *node;
422 struct variable_list *vls = NULL, *vl;
423
424 buf = synthesize_perf_probe_point(&pev->point);
425 if (!buf)
426 return -EINVAL;
427 pr_debug("Searching variables at %s\n", buf);
428
429 ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
430 if (ret > 0) {
431 /* Some variables were found */
432 fprintf(stdout, "Available variables at %s\n", buf);
433 for (i = 0; i < ret; i++) {
434 vl = &vls[i];
435 /*
436 * A probe point might be converted to
437 * several trace points.
438 */
439 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
440 vl->point.offset);
441 free(vl->point.symbol);
442 if (vl->vars) {
443 strlist__for_each(node, vl->vars)
444 fprintf(stdout, "\t\t%s\n", node->s);
445 strlist__delete(vl->vars);
446 } else
447 fprintf(stdout, "(No variables)\n");
448 }
449 free(vls);
450 } else
451 pr_err("Failed to find variables at %s (%d)\n", buf, ret);
452
453 free(buf);
454 return ret;
455}
456
457/* Show available variables on given probe point */
458int show_available_vars(struct perf_probe_event *pevs, int npevs,
459 int max_vls, const char *module, bool externs)
460{
461 int i, fd, ret = 0;
462
463 ret = init_vmlinux();
464 if (ret < 0)
465 return ret;
466
467 fd = open_vmlinux(module);
468 if (fd < 0) {
469 pr_warning("Failed to open debuginfo file.\n");
470 return fd;
471 }
472
473 setup_pager();
474
475 for (i = 0; i < npevs && ret >= 0; i++)
476 ret = show_available_vars_at(fd, &pevs[i], max_vls, externs);
477
478 close(fd);
479 return ret;
480}
481
381#else /* !DWARF_SUPPORT */ 482#else /* !DWARF_SUPPORT */
382 483
383static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 484static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
384 struct perf_probe_point *pp) 485 struct perf_probe_point *pp)
385{ 486{
487 struct symbol *sym;
488
489 sym = __find_kernel_function_by_name(tp->symbol, NULL);
490 if (!sym) {
491 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
492 return -ENOENT;
493 }
386 pp->function = strdup(tp->symbol); 494 pp->function = strdup(tp->symbol);
387 if (pp->function == NULL) 495 if (pp->function == NULL)
388 return -ENOMEM; 496 return -ENOMEM;
@@ -394,7 +502,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
394 502
395static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 503static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
396 struct probe_trace_event **tevs __unused, 504 struct probe_trace_event **tevs __unused,
397 int max_tevs __unused) 505 int max_tevs __unused, const char *mod __unused)
398{ 506{
399 if (perf_probe_event_need_dwarf(pev)) { 507 if (perf_probe_event_need_dwarf(pev)) {
400 pr_warning("Debuginfo-analysis is not supported.\n"); 508 pr_warning("Debuginfo-analysis is not supported.\n");
@@ -403,12 +511,19 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
403 return 0; 511 return 0;
404} 512}
405 513
406int show_line_range(struct line_range *lr __unused) 514int show_line_range(struct line_range *lr __unused, const char *module __unused)
407{ 515{
408 pr_warning("Debuginfo-analysis is not supported.\n"); 516 pr_warning("Debuginfo-analysis is not supported.\n");
409 return -ENOSYS; 517 return -ENOSYS;
410} 518}
411 519
520int show_available_vars(struct perf_probe_event *pevs __unused,
521 int npevs __unused, int max_vls __unused,
522 const char *module __unused, bool externs __unused)
523{
524 pr_warning("Debuginfo-analysis is not supported.\n");
525 return -ENOSYS;
526}
412#endif 527#endif
413 528
414int parse_line_range_desc(const char *arg, struct line_range *lr) 529int parse_line_range_desc(const char *arg, struct line_range *lr)
@@ -1087,7 +1202,7 @@ error:
1087} 1202}
1088 1203
1089static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1204static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1090 struct perf_probe_event *pev) 1205 struct perf_probe_event *pev)
1091{ 1206{
1092 char buf[64] = ""; 1207 char buf[64] = "";
1093 int i, ret; 1208 int i, ret;
@@ -1516,14 +1631,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1516 1631
1517static int convert_to_probe_trace_events(struct perf_probe_event *pev, 1632static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1518 struct probe_trace_event **tevs, 1633 struct probe_trace_event **tevs,
1519 int max_tevs) 1634 int max_tevs, const char *module)
1520{ 1635{
1521 struct symbol *sym; 1636 struct symbol *sym;
1522 int ret = 0, i; 1637 int ret = 0, i;
1523 struct probe_trace_event *tev; 1638 struct probe_trace_event *tev;
1524 1639
1525 /* Convert perf_probe_event with debuginfo */ 1640 /* Convert perf_probe_event with debuginfo */
1526 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs); 1641 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
1527 if (ret != 0) 1642 if (ret != 0)
1528 return ret; 1643 return ret;
1529 1644
@@ -1572,8 +1687,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1572 } 1687 }
1573 1688
1574 /* Currently just checking function name from symbol map */ 1689 /* Currently just checking function name from symbol map */
1575 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], 1690 sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1576 tev->point.symbol, NULL);
1577 if (!sym) { 1691 if (!sym) {
1578 pr_warning("Kernel symbol \'%s\' not found.\n", 1692 pr_warning("Kernel symbol \'%s\' not found.\n",
1579 tev->point.symbol); 1693 tev->point.symbol);
@@ -1596,7 +1710,7 @@ struct __event_package {
1596}; 1710};
1597 1711
1598int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 1712int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1599 bool force_add, int max_tevs) 1713 int max_tevs, const char *module, bool force_add)
1600{ 1714{
1601 int i, j, ret; 1715 int i, j, ret;
1602 struct __event_package *pkgs; 1716 struct __event_package *pkgs;
@@ -1617,7 +1731,9 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1617 pkgs[i].pev = &pevs[i]; 1731 pkgs[i].pev = &pevs[i];
1618 /* Convert with or without debuginfo */ 1732 /* Convert with or without debuginfo */
1619 ret = convert_to_probe_trace_events(pkgs[i].pev, 1733 ret = convert_to_probe_trace_events(pkgs[i].pev,
1620 &pkgs[i].tevs, max_tevs); 1734 &pkgs[i].tevs,
1735 max_tevs,
1736 module);
1621 if (ret < 0) 1737 if (ret < 0)
1622 goto end; 1738 goto end;
1623 pkgs[i].ntevs = ret; 1739 pkgs[i].ntevs = ret;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5af39243a25b..5accbedfea37 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -90,6 +90,12 @@ struct line_range {
90 struct list_head line_list; /* Visible lines */ 90 struct list_head line_list; /* Visible lines */
91}; 91};
92 92
93/* List of variables */
94struct variable_list {
95 struct probe_trace_point point; /* Actual probepoint */
96 struct strlist *vars; /* Available variables */
97};
98
93/* Command string to events */ 99/* Command string to events */
94extern int parse_perf_probe_command(const char *cmd, 100extern int parse_perf_probe_command(const char *cmd,
95 struct perf_probe_event *pev); 101 struct perf_probe_event *pev);
@@ -109,12 +115,18 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
109/* Command string to line-range */ 115/* Command string to line-range */
110extern int parse_line_range_desc(const char *cmd, struct line_range *lr); 116extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
111 117
118/* Internal use: Return kernel/module path */
119extern const char *kernel_get_module_path(const char *module);
112 120
113extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 121extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
114 bool force_add, int max_probe_points); 122 int max_probe_points, const char *module,
123 bool force_add);
115extern int del_perf_probe_events(struct strlist *dellist); 124extern int del_perf_probe_events(struct strlist *dellist);
116extern int show_perf_probe_events(void); 125extern int show_perf_probe_events(void);
117extern int show_line_range(struct line_range *lr); 126extern int show_line_range(struct line_range *lr, const char *module);
127extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
128 int max_probe_points, const char *module,
129 bool externs);
118 130
119 131
120/* Maximum index number of event-name postfix */ 132/* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 32b81f707ff5..ddf4d4556321 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -116,6 +116,126 @@ static void line_list__free(struct list_head *head)
116 } 116 }
117} 117}
118 118
119/* Dwarf FL wrappers */
120static char *debuginfo_path; /* Currently dummy */
121
122static const Dwfl_Callbacks offline_callbacks = {
123 .find_debuginfo = dwfl_standard_find_debuginfo,
124 .debuginfo_path = &debuginfo_path,
125
126 .section_address = dwfl_offline_section_address,
127
128 /* We use this table for core files too. */
129 .find_elf = dwfl_build_id_find_elf,
130};
131
132/* Get a Dwarf from offline image */
133static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
134{
135 Dwfl_Module *mod;
136 Dwarf *dbg = NULL;
137
138 if (!dwflp)
139 return NULL;
140
141 *dwflp = dwfl_begin(&offline_callbacks);
142 if (!*dwflp)
143 return NULL;
144
145 mod = dwfl_report_offline(*dwflp, "", "", fd);
146 if (!mod)
147 goto error;
148
149 dbg = dwfl_module_getdwarf(mod, bias);
150 if (!dbg) {
151error:
152 dwfl_end(*dwflp);
153 *dwflp = NULL;
154 }
155 return dbg;
156}
157
158#if _ELFUTILS_PREREQ(0, 148)
159/* This method is buggy if elfutils is older than 0.148 */
160static int __linux_kernel_find_elf(Dwfl_Module *mod,
161 void **userdata,
162 const char *module_name,
163 Dwarf_Addr base,
164 char **file_name, Elf **elfp)
165{
166 int fd;
167 const char *path = kernel_get_module_path(module_name);
168
169 pr_debug2("Use file %s for %s\n", path, module_name);
170 if (path) {
171 fd = open(path, O_RDONLY);
172 if (fd >= 0) {
173 *file_name = strdup(path);
174 return fd;
175 }
176 }
177 /* If failed, try to call standard method */
178 return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
179 file_name, elfp);
180}
181
182static const Dwfl_Callbacks kernel_callbacks = {
183 .find_debuginfo = dwfl_standard_find_debuginfo,
184 .debuginfo_path = &debuginfo_path,
185
186 .find_elf = __linux_kernel_find_elf,
187 .section_address = dwfl_linux_kernel_module_section_address,
188};
189
190/* Get a Dwarf from live kernel image */
191static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
192 Dwarf_Addr *bias)
193{
194 Dwarf *dbg;
195
196 if (!dwflp)
197 return NULL;
198
199 *dwflp = dwfl_begin(&kernel_callbacks);
200 if (!*dwflp)
201 return NULL;
202
203 /* Load the kernel dwarves: Don't care the result here */
204 dwfl_linux_kernel_report_kernel(*dwflp);
205 dwfl_linux_kernel_report_modules(*dwflp);
206
207 dbg = dwfl_addrdwarf(*dwflp, addr, bias);
208 /* Here, check whether we could get a real dwarf */
209 if (!dbg) {
210 pr_debug("Failed to find kernel dwarf at %lx\n",
211 (unsigned long)addr);
212 dwfl_end(*dwflp);
213 *dwflp = NULL;
214 }
215 return dbg;
216}
217#else
218/* With older elfutils, this just support kernel module... */
219static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp,
220 Dwarf_Addr *bias)
221{
222 int fd;
223 const char *path = kernel_get_module_path("kernel");
224
225 if (!path) {
226 pr_err("Failed to find vmlinux path\n");
227 return NULL;
228 }
229
230 pr_debug2("Use file %s for debuginfo\n", path);
231 fd = open(path, O_RDONLY);
232 if (fd < 0)
233 return NULL;
234
235 return dwfl_init_offline_dwarf(fd, dwflp, bias);
236}
237#endif
238
119/* Dwarf wrappers */ 239/* Dwarf wrappers */
120 240
121/* Find the realpath of the target file. */ 241/* Find the realpath of the target file. */
@@ -160,26 +280,44 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
160 return name ? (strcmp(tname, name) == 0) : false; 280 return name ? (strcmp(tname, name) == 0) : false;
161} 281}
162 282
163/* Get type die, but skip qualifiers and typedef */ 283/* Get type die */
164static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 284static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
165{ 285{
166 Dwarf_Attribute attr; 286 Dwarf_Attribute attr;
287
288 if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
289 dwarf_formref_die(&attr, die_mem))
290 return die_mem;
291 else
292 return NULL;
293}
294
295/* Get a type die, but skip qualifiers */
296static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
297{
167 int tag; 298 int tag;
168 299
169 do { 300 do {
170 if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL || 301 vr_die = die_get_type(vr_die, die_mem);
171 dwarf_formref_die(&attr, die_mem) == NULL) 302 if (!vr_die)
172 return NULL; 303 break;
173 304 tag = dwarf_tag(vr_die);
174 tag = dwarf_tag(die_mem);
175 vr_die = die_mem;
176 } while (tag == DW_TAG_const_type || 305 } while (tag == DW_TAG_const_type ||
177 tag == DW_TAG_restrict_type || 306 tag == DW_TAG_restrict_type ||
178 tag == DW_TAG_volatile_type || 307 tag == DW_TAG_volatile_type ||
179 tag == DW_TAG_shared_type || 308 tag == DW_TAG_shared_type);
180 tag == DW_TAG_typedef); 309
310 return vr_die;
311}
312
313/* Get a type die, but skip qualifiers and typedef */
314static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
315{
316 do {
317 vr_die = __die_get_real_type(vr_die, die_mem);
318 } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
181 319
182 return die_mem; 320 return vr_die;
183} 321}
184 322
185static bool die_is_signed_type(Dwarf_Die *tp_die) 323static bool die_is_signed_type(Dwarf_Die *tp_die)
@@ -320,25 +458,35 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
320 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); 458 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
321} 459}
322 460
461struct __find_variable_param {
462 const char *name;
463 Dwarf_Addr addr;
464};
465
323static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) 466static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
324{ 467{
325 const char *name = data; 468 struct __find_variable_param *fvp = data;
326 int tag; 469 int tag;
327 470
328 tag = dwarf_tag(die_mem); 471 tag = dwarf_tag(die_mem);
329 if ((tag == DW_TAG_formal_parameter || 472 if ((tag == DW_TAG_formal_parameter ||
330 tag == DW_TAG_variable) && 473 tag == DW_TAG_variable) &&
331 die_compare_name(die_mem, name)) 474 die_compare_name(die_mem, fvp->name))
332 return DIE_FIND_CB_FOUND; 475 return DIE_FIND_CB_FOUND;
333 476
334 return DIE_FIND_CB_CONTINUE; 477 if (dwarf_haspc(die_mem, fvp->addr))
478 return DIE_FIND_CB_CONTINUE;
479 else
480 return DIE_FIND_CB_SIBLING;
335} 481}
336 482
337/* Find a variable called 'name' */ 483/* Find a variable called 'name' at given address */
338static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, 484static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
339 Dwarf_Die *die_mem) 485 Dwarf_Addr addr, Dwarf_Die *die_mem)
340{ 486{
341 return die_find_child(sp_die, __die_find_variable_cb, (void *)name, 487 struct __find_variable_param fvp = { .name = name, .addr = addr};
488
489 return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
342 die_mem); 490 die_mem);
343} 491}
344 492
@@ -361,6 +509,60 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
361 die_mem); 509 die_mem);
362} 510}
363 511
512/* Get the name of given variable DIE */
513static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
514{
515 Dwarf_Die type;
516 int tag, ret, ret2;
517 const char *tmp = "";
518
519 if (__die_get_real_type(vr_die, &type) == NULL)
520 return -ENOENT;
521
522 tag = dwarf_tag(&type);
523 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
524 tmp = "*";
525 else if (tag == DW_TAG_subroutine_type) {
526 /* Function pointer */
527 ret = snprintf(buf, len, "(function_type)");
528 return (ret >= len) ? -E2BIG : ret;
529 } else {
530 if (!dwarf_diename(&type))
531 return -ENOENT;
532 if (tag == DW_TAG_union_type)
533 tmp = "union ";
534 else if (tag == DW_TAG_structure_type)
535 tmp = "struct ";
536 /* Write a base name */
537 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
538 return (ret >= len) ? -E2BIG : ret;
539 }
540 ret = die_get_typename(&type, buf, len);
541 if (ret > 0) {
542 ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
543 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
544 }
545 return ret;
546}
547
548/* Get the name and type of given variable DIE, stored as "type\tname" */
549static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
550{
551 int ret, ret2;
552
553 ret = die_get_typename(vr_die, buf, len);
554 if (ret < 0) {
555 pr_debug("Failed to get type, make it unknown.\n");
556 ret = snprintf(buf, len, "(unknown_type)");
557 }
558 if (ret > 0) {
559 ret2 = snprintf(buf + ret, len - ret, "\t%s",
560 dwarf_diename(vr_die));
561 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
562 }
563 return ret;
564}
565
364/* 566/*
365 * Probe finder related functions 567 * Probe finder related functions
366 */ 568 */
@@ -374,8 +576,13 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
374 return ref; 576 return ref;
375} 577}
376 578
377/* Show a location */ 579/*
378static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf) 580 * Convert a location into trace_arg.
581 * If tvar == NULL, this just checks variable can be converted.
582 */
583static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
584 Dwarf_Op *fb_ops,
585 struct probe_trace_arg *tvar)
379{ 586{
380 Dwarf_Attribute attr; 587 Dwarf_Attribute attr;
381 Dwarf_Op *op; 588 Dwarf_Op *op;
@@ -384,20 +591,23 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
384 Dwarf_Word offs = 0; 591 Dwarf_Word offs = 0;
385 bool ref = false; 592 bool ref = false;
386 const char *regs; 593 const char *regs;
387 struct probe_trace_arg *tvar = pf->tvar;
388 int ret; 594 int ret;
389 595
596 if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
597 goto static_var;
598
390 /* TODO: handle more than 1 exprs */ 599 /* TODO: handle more than 1 exprs */
391 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || 600 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
392 dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 || 601 dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
393 nops == 0) { 602 nops == 0) {
394 /* TODO: Support const_value */ 603 /* TODO: Support const_value */
395 pr_err("Failed to find the location of %s at this address.\n"
396 " Perhaps, it has been optimized out.\n", pf->pvar->var);
397 return -ENOENT; 604 return -ENOENT;
398 } 605 }
399 606
400 if (op->atom == DW_OP_addr) { 607 if (op->atom == DW_OP_addr) {
608static_var:
609 if (!tvar)
610 return 0;
401 /* Static variables on memory (not stack), make @varname */ 611 /* Static variables on memory (not stack), make @varname */
402 ret = strlen(dwarf_diename(vr_die)); 612 ret = strlen(dwarf_diename(vr_die));
403 tvar->value = zalloc(ret + 2); 613 tvar->value = zalloc(ret + 2);
@@ -412,14 +622,11 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
412 622
413 /* If this is based on frame buffer, set the offset */ 623 /* If this is based on frame buffer, set the offset */
414 if (op->atom == DW_OP_fbreg) { 624 if (op->atom == DW_OP_fbreg) {
415 if (pf->fb_ops == NULL) { 625 if (fb_ops == NULL)
416 pr_warning("The attribute of frame base is not "
417 "supported.\n");
418 return -ENOTSUP; 626 return -ENOTSUP;
419 }
420 ref = true; 627 ref = true;
421 offs = op->number; 628 offs = op->number;
422 op = &pf->fb_ops[0]; 629 op = &fb_ops[0];
423 } 630 }
424 631
425 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 632 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
@@ -435,13 +642,18 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
435 } else if (op->atom == DW_OP_regx) { 642 } else if (op->atom == DW_OP_regx) {
436 regn = op->number; 643 regn = op->number;
437 } else { 644 } else {
438 pr_warning("DW_OP %x is not supported.\n", op->atom); 645 pr_debug("DW_OP %x is not supported.\n", op->atom);
439 return -ENOTSUP; 646 return -ENOTSUP;
440 } 647 }
441 648
649 if (!tvar)
650 return 0;
651
442 regs = get_arch_regstr(regn); 652 regs = get_arch_regstr(regn);
443 if (!regs) { 653 if (!regs) {
444 pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn); 654 /* This should be a bug in DWARF or this tool */
655 pr_warning("Mapping for DWARF register number %u "
656 "missing on this architecture.", regn);
445 return -ERANGE; 657 return -ERANGE;
446 } 658 }
447 659
@@ -666,8 +878,14 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
666 pr_debug("Converting variable %s into trace event.\n", 878 pr_debug("Converting variable %s into trace event.\n",
667 dwarf_diename(vr_die)); 879 dwarf_diename(vr_die));
668 880
669 ret = convert_variable_location(vr_die, pf); 881 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
670 if (ret == 0 && pf->pvar->field) { 882 pf->tvar);
883 if (ret == -ENOENT)
884 pr_err("Failed to find the location of %s at this address.\n"
885 " Perhaps, it has been optimized out.\n", pf->pvar->var);
886 else if (ret == -ENOTSUP)
887 pr_err("Sorry, we don't support this variable location yet.\n");
888 else if (pf->pvar->field) {
671 ret = convert_variable_fields(vr_die, pf->pvar->var, 889 ret = convert_variable_fields(vr_die, pf->pvar->var,
672 pf->pvar->field, &pf->tvar->ref, 890 pf->pvar->field, &pf->tvar->ref,
673 &die_mem); 891 &die_mem);
@@ -722,56 +940,39 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
722 pr_debug("Searching '%s' variable in context.\n", 940 pr_debug("Searching '%s' variable in context.\n",
723 pf->pvar->var); 941 pf->pvar->var);
724 /* Search child die for local variables and parameters. */ 942 /* Search child die for local variables and parameters. */
725 if (die_find_variable(sp_die, pf->pvar->var, &vr_die)) 943 if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))
726 ret = convert_variable(&vr_die, pf); 944 ret = convert_variable(&vr_die, pf);
727 else { 945 else {
728 /* Search upper class */ 946 /* Search upper class */
729 nscopes = dwarf_getscopes_die(sp_die, &scopes); 947 nscopes = dwarf_getscopes_die(sp_die, &scopes);
730 if (nscopes > 0) { 948 while (nscopes-- > 1) {
731 ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var, 949 pr_debug("Searching variables in %s\n",
732 0, NULL, 0, 0, &vr_die); 950 dwarf_diename(&scopes[nscopes]));
733 if (ret >= 0) 951 /* We should check this scope, so give dummy address */
952 if (die_find_variable_at(&scopes[nscopes],
953 pf->pvar->var, 0,
954 &vr_die)) {
734 ret = convert_variable(&vr_die, pf); 955 ret = convert_variable(&vr_die, pf);
735 else 956 goto found;
736 ret = -ENOENT; 957 }
958 }
959 if (scopes)
737 free(scopes); 960 free(scopes);
738 } else 961 ret = -ENOENT;
739 ret = -ENOENT;
740 } 962 }
963found:
741 if (ret < 0) 964 if (ret < 0)
742 pr_warning("Failed to find '%s' in this function.\n", 965 pr_warning("Failed to find '%s' in this function.\n",
743 pf->pvar->var); 966 pf->pvar->var);
744 return ret; 967 return ret;
745} 968}
746 969
747/* Show a probe point to output buffer */ 970/* Convert subprogram DIE to trace point */
748static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) 971static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
972 bool retprobe, struct probe_trace_point *tp)
749{ 973{
750 struct probe_trace_event *tev;
751 Dwarf_Addr eaddr; 974 Dwarf_Addr eaddr;
752 Dwarf_Die die_mem;
753 const char *name; 975 const char *name;
754 int ret, i;
755 Dwarf_Attribute fb_attr;
756 size_t nops;
757
758 if (pf->ntevs == pf->max_tevs) {
759 pr_warning("Too many( > %d) probe point found.\n",
760 pf->max_tevs);
761 return -ERANGE;
762 }
763 tev = &pf->tevs[pf->ntevs++];
764
765 /* If no real subprogram, find a real one */
766 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
767 sp_die = die_find_real_subprogram(&pf->cu_die,
768 pf->addr, &die_mem);
769 if (!sp_die) {
770 pr_warning("Failed to find probe point in any "
771 "functions.\n");
772 return -ENOENT;
773 }
774 }
775 976
776 /* Copy the name of probe point */ 977 /* Copy the name of probe point */
777 name = dwarf_diename(sp_die); 978 name = dwarf_diename(sp_die);
@@ -781,26 +982,45 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
781 dwarf_diename(sp_die)); 982 dwarf_diename(sp_die));
782 return -ENOENT; 983 return -ENOENT;
783 } 984 }
784 tev->point.symbol = strdup(name); 985 tp->symbol = strdup(name);
785 if (tev->point.symbol == NULL) 986 if (tp->symbol == NULL)
786 return -ENOMEM; 987 return -ENOMEM;
787 tev->point.offset = (unsigned long)(pf->addr - eaddr); 988 tp->offset = (unsigned long)(paddr - eaddr);
788 } else 989 } else
789 /* This function has no name. */ 990 /* This function has no name. */
790 tev->point.offset = (unsigned long)pf->addr; 991 tp->offset = (unsigned long)paddr;
791 992
792 /* Return probe must be on the head of a subprogram */ 993 /* Return probe must be on the head of a subprogram */
793 if (pf->pev->point.retprobe) { 994 if (retprobe) {
794 if (tev->point.offset != 0) { 995 if (eaddr != paddr) {
795 pr_warning("Return probe must be on the head of" 996 pr_warning("Return probe must be on the head of"
796 " a real function\n"); 997 " a real function\n");
797 return -EINVAL; 998 return -EINVAL;
798 } 999 }
799 tev->point.retprobe = true; 1000 tp->retprobe = true;
800 } 1001 }
801 1002
802 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1003 return 0;
803 tev->point.offset); 1004}
1005
1006/* Call probe_finder callback with real subprogram DIE */
1007static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1008{
1009 Dwarf_Die die_mem;
1010 Dwarf_Attribute fb_attr;
1011 size_t nops;
1012 int ret;
1013
1014 /* If no real subprogram, find a real one */
1015 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
1016 sp_die = die_find_real_subprogram(&pf->cu_die,
1017 pf->addr, &die_mem);
1018 if (!sp_die) {
1019 pr_warning("Failed to find probe point in any "
1020 "functions.\n");
1021 return -ENOENT;
1022 }
1023 }
804 1024
805 /* Get the frame base attribute/ops */ 1025 /* Get the frame base attribute/ops */
806 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 1026 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
@@ -820,22 +1040,13 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
820#endif 1040#endif
821 } 1041 }
822 1042
823 /* Find each argument */ 1043 /* Call finder's callback handler */
824 tev->nargs = pf->pev->nargs; 1044 ret = pf->callback(sp_die, pf);
825 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
826 if (tev->args == NULL)
827 return -ENOMEM;
828 for (i = 0; i < pf->pev->nargs; i++) {
829 pf->pvar = &pf->pev->args[i];
830 pf->tvar = &tev->args[i];
831 ret = find_variable(sp_die, pf);
832 if (ret != 0)
833 return ret;
834 }
835 1045
836 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 1046 /* *pf->fb_ops will be cached in libdw. Don't free it. */
837 pf->fb_ops = NULL; 1047 pf->fb_ops = NULL;
838 return 0; 1048
1049 return ret;
839} 1050}
840 1051
841/* Find probe point from its line number */ 1052/* Find probe point from its line number */
@@ -871,7 +1082,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
871 (int)i, lineno, (uintmax_t)addr); 1082 (int)i, lineno, (uintmax_t)addr);
872 pf->addr = addr; 1083 pf->addr = addr;
873 1084
874 ret = convert_probe_point(NULL, pf); 1085 ret = call_probe_finder(NULL, pf);
875 /* Continuing, because target line might be inlined. */ 1086 /* Continuing, because target line might be inlined. */
876 } 1087 }
877 return ret; 1088 return ret;
@@ -984,7 +1195,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
984 (int)i, lineno, (unsigned long long)addr); 1195 (int)i, lineno, (unsigned long long)addr);
985 pf->addr = addr; 1196 pf->addr = addr;
986 1197
987 ret = convert_probe_point(sp_die, pf); 1198 ret = call_probe_finder(sp_die, pf);
988 /* Continuing, because target line might be inlined. */ 1199 /* Continuing, because target line might be inlined. */
989 } 1200 }
990 /* TODO: deallocate lines, but how? */ 1201 /* TODO: deallocate lines, but how? */
@@ -1019,7 +1230,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
1019 pr_debug("found inline addr: 0x%jx\n", 1230 pr_debug("found inline addr: 0x%jx\n",
1020 (uintmax_t)pf->addr); 1231 (uintmax_t)pf->addr);
1021 1232
1022 param->retval = convert_probe_point(in_die, pf); 1233 param->retval = call_probe_finder(in_die, pf);
1023 if (param->retval < 0) 1234 if (param->retval < 0)
1024 return DWARF_CB_ABORT; 1235 return DWARF_CB_ABORT;
1025 } 1236 }
@@ -1057,7 +1268,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1057 } 1268 }
1058 pf->addr += pp->offset; 1269 pf->addr += pp->offset;
1059 /* TODO: Check the address in this function */ 1270 /* TODO: Check the address in this function */
1060 param->retval = convert_probe_point(sp_die, pf); 1271 param->retval = call_probe_finder(sp_die, pf);
1061 } 1272 }
1062 } else { 1273 } else {
1063 struct dwarf_callback_param _param = {.data = (void *)pf, 1274 struct dwarf_callback_param _param = {.data = (void *)pf,
@@ -1079,90 +1290,276 @@ static int find_probe_point_by_func(struct probe_finder *pf)
1079 return _param.retval; 1290 return _param.retval;
1080} 1291}
1081 1292
1082/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1293/* Find probe points from debuginfo */
1083int find_probe_trace_events(int fd, struct perf_probe_event *pev, 1294static int find_probes(int fd, struct probe_finder *pf)
1084 struct probe_trace_event **tevs, int max_tevs)
1085{ 1295{
1086 struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs}; 1296 struct perf_probe_point *pp = &pf->pev->point;
1087 struct perf_probe_point *pp = &pev->point;
1088 Dwarf_Off off, noff; 1297 Dwarf_Off off, noff;
1089 size_t cuhl; 1298 size_t cuhl;
1090 Dwarf_Die *diep; 1299 Dwarf_Die *diep;
1091 Dwarf *dbg; 1300 Dwarf *dbg = NULL;
1301 Dwfl *dwfl;
1302 Dwarf_Addr bias; /* Currently ignored */
1092 int ret = 0; 1303 int ret = 0;
1093 1304
1094 pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); 1305 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1095 if (pf.tevs == NULL)
1096 return -ENOMEM;
1097 *tevs = pf.tevs;
1098 pf.ntevs = 0;
1099
1100 dbg = dwarf_begin(fd, DWARF_C_READ);
1101 if (!dbg) { 1306 if (!dbg) {
1102 pr_warning("No dwarf info found in the vmlinux - " 1307 pr_warning("No dwarf info found in the vmlinux - "
1103 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1308 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1104 free(pf.tevs);
1105 *tevs = NULL;
1106 return -EBADF; 1309 return -EBADF;
1107 } 1310 }
1108 1311
1109#if _ELFUTILS_PREREQ(0, 142) 1312#if _ELFUTILS_PREREQ(0, 142)
1110 /* Get the call frame information from this dwarf */ 1313 /* Get the call frame information from this dwarf */
1111 pf.cfi = dwarf_getcfi(dbg); 1314 pf->cfi = dwarf_getcfi(dbg);
1112#endif 1315#endif
1113 1316
1114 off = 0; 1317 off = 0;
1115 line_list__init(&pf.lcache); 1318 line_list__init(&pf->lcache);
1116 /* Loop on CUs (Compilation Unit) */ 1319 /* Loop on CUs (Compilation Unit) */
1117 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && 1320 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
1118 ret >= 0) { 1321 ret >= 0) {
1119 /* Get the DIE(Debugging Information Entry) of this CU */ 1322 /* Get the DIE(Debugging Information Entry) of this CU */
1120 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); 1323 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
1121 if (!diep) 1324 if (!diep)
1122 continue; 1325 continue;
1123 1326
1124 /* Check if target file is included. */ 1327 /* Check if target file is included. */
1125 if (pp->file) 1328 if (pp->file)
1126 pf.fname = cu_find_realpath(&pf.cu_die, pp->file); 1329 pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
1127 else 1330 else
1128 pf.fname = NULL; 1331 pf->fname = NULL;
1129 1332
1130 if (!pp->file || pf.fname) { 1333 if (!pp->file || pf->fname) {
1131 if (pp->function) 1334 if (pp->function)
1132 ret = find_probe_point_by_func(&pf); 1335 ret = find_probe_point_by_func(pf);
1133 else if (pp->lazy_line) 1336 else if (pp->lazy_line)
1134 ret = find_probe_point_lazy(NULL, &pf); 1337 ret = find_probe_point_lazy(NULL, pf);
1135 else { 1338 else {
1136 pf.lno = pp->line; 1339 pf->lno = pp->line;
1137 ret = find_probe_point_by_line(&pf); 1340 ret = find_probe_point_by_line(pf);
1138 } 1341 }
1139 } 1342 }
1140 off = noff; 1343 off = noff;
1141 } 1344 }
1142 line_list__free(&pf.lcache); 1345 line_list__free(&pf->lcache);
1143 dwarf_end(dbg); 1346 if (dwfl)
1347 dwfl_end(dwfl);
1348
1349 return ret;
1350}
1351
1352/* Add a found probe point into trace event list */
1353static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1354{
1355 struct trace_event_finder *tf =
1356 container_of(pf, struct trace_event_finder, pf);
1357 struct probe_trace_event *tev;
1358 int ret, i;
1144 1359
1145 return (ret < 0) ? ret : pf.ntevs; 1360 /* Check number of tevs */
1361 if (tf->ntevs == tf->max_tevs) {
1362 pr_warning("Too many( > %d) probe point found.\n",
1363 tf->max_tevs);
1364 return -ERANGE;
1365 }
1366 tev = &tf->tevs[tf->ntevs++];
1367
1368 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
1369 &tev->point);
1370 if (ret < 0)
1371 return ret;
1372
1373 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1374 tev->point.offset);
1375
1376 /* Find each argument */
1377 tev->nargs = pf->pev->nargs;
1378 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1379 if (tev->args == NULL)
1380 return -ENOMEM;
1381 for (i = 0; i < pf->pev->nargs; i++) {
1382 pf->pvar = &pf->pev->args[i];
1383 pf->tvar = &tev->args[i];
1384 ret = find_variable(sp_die, pf);
1385 if (ret != 0)
1386 return ret;
1387 }
1388
1389 return 0;
1390}
1391
1392/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1393int find_probe_trace_events(int fd, struct perf_probe_event *pev,
1394 struct probe_trace_event **tevs, int max_tevs)
1395{
1396 struct trace_event_finder tf = {
1397 .pf = {.pev = pev, .callback = add_probe_trace_event},
1398 .max_tevs = max_tevs};
1399 int ret;
1400
1401 /* Allocate result tevs array */
1402 *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
1403 if (*tevs == NULL)
1404 return -ENOMEM;
1405
1406 tf.tevs = *tevs;
1407 tf.ntevs = 0;
1408
1409 ret = find_probes(fd, &tf.pf);
1410 if (ret < 0) {
1411 free(*tevs);
1412 *tevs = NULL;
1413 return ret;
1414 }
1415
1416 return (ret < 0) ? ret : tf.ntevs;
1417}
1418
1419#define MAX_VAR_LEN 64
1420
1421/* Collect available variables in this scope */
1422static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1423{
1424 struct available_var_finder *af = data;
1425 struct variable_list *vl;
1426 char buf[MAX_VAR_LEN];
1427 int tag, ret;
1428
1429 vl = &af->vls[af->nvls - 1];
1430
1431 tag = dwarf_tag(die_mem);
1432 if (tag == DW_TAG_formal_parameter ||
1433 tag == DW_TAG_variable) {
1434 ret = convert_variable_location(die_mem, af->pf.addr,
1435 af->pf.fb_ops, NULL);
1436 if (ret == 0) {
1437 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
1438 pr_debug2("Add new var: %s\n", buf);
1439 if (ret > 0)
1440 strlist__add(vl->vars, buf);
1441 }
1442 }
1443
1444 if (af->child && dwarf_haspc(die_mem, af->pf.addr))
1445 return DIE_FIND_CB_CONTINUE;
1446 else
1447 return DIE_FIND_CB_SIBLING;
1448}
1449
1450/* Add a found vars into available variables list */
1451static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
1452{
1453 struct available_var_finder *af =
1454 container_of(pf, struct available_var_finder, pf);
1455 struct variable_list *vl;
1456 Dwarf_Die die_mem, *scopes = NULL;
1457 int ret, nscopes;
1458
1459 /* Check number of tevs */
1460 if (af->nvls == af->max_vls) {
1461 pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
1462 return -ERANGE;
1463 }
1464 vl = &af->vls[af->nvls++];
1465
1466 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
1467 &vl->point);
1468 if (ret < 0)
1469 return ret;
1470
1471 pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
1472 vl->point.offset);
1473
1474 /* Find local variables */
1475 vl->vars = strlist__new(true, NULL);
1476 if (vl->vars == NULL)
1477 return -ENOMEM;
1478 af->child = true;
1479 die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
1480
1481 /* Find external variables */
1482 if (!af->externs)
1483 goto out;
1484 /* Don't need to search child DIE for externs. */
1485 af->child = false;
1486 nscopes = dwarf_getscopes_die(sp_die, &scopes);
1487 while (nscopes-- > 1)
1488 die_find_child(&scopes[nscopes], collect_variables_cb,
1489 (void *)af, &die_mem);
1490 if (scopes)
1491 free(scopes);
1492
1493out:
1494 if (strlist__empty(vl->vars)) {
1495 strlist__delete(vl->vars);
1496 vl->vars = NULL;
1497 }
1498
1499 return ret;
1500}
1501
1502/* Find available variables at given probe point */
1503int find_available_vars_at(int fd, struct perf_probe_event *pev,
1504 struct variable_list **vls, int max_vls,
1505 bool externs)
1506{
1507 struct available_var_finder af = {
1508 .pf = {.pev = pev, .callback = add_available_vars},
1509 .max_vls = max_vls, .externs = externs};
1510 int ret;
1511
1512 /* Allocate result vls array */
1513 *vls = zalloc(sizeof(struct variable_list) * max_vls);
1514 if (*vls == NULL)
1515 return -ENOMEM;
1516
1517 af.vls = *vls;
1518 af.nvls = 0;
1519
1520 ret = find_probes(fd, &af.pf);
1521 if (ret < 0) {
1522 /* Free vlist for error */
1523 while (af.nvls--) {
1524 if (af.vls[af.nvls].point.symbol)
1525 free(af.vls[af.nvls].point.symbol);
1526 if (af.vls[af.nvls].vars)
1527 strlist__delete(af.vls[af.nvls].vars);
1528 }
1529 free(af.vls);
1530 *vls = NULL;
1531 return ret;
1532 }
1533
1534 return (ret < 0) ? ret : af.nvls;
1146} 1535}
1147 1536
1148/* Reverse search */ 1537/* Reverse search */
1149int find_perf_probe_point(int fd, unsigned long addr, 1538int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
1150 struct perf_probe_point *ppt)
1151{ 1539{
1152 Dwarf_Die cudie, spdie, indie; 1540 Dwarf_Die cudie, spdie, indie;
1153 Dwarf *dbg; 1541 Dwarf *dbg = NULL;
1542 Dwfl *dwfl = NULL;
1154 Dwarf_Line *line; 1543 Dwarf_Line *line;
1155 Dwarf_Addr laddr, eaddr; 1544 Dwarf_Addr laddr, eaddr, bias = 0;
1156 const char *tmp; 1545 const char *tmp;
1157 int lineno, ret = 0; 1546 int lineno, ret = 0;
1158 bool found = false; 1547 bool found = false;
1159 1548
1160 dbg = dwarf_begin(fd, DWARF_C_READ); 1549 /* Open the live linux kernel */
1161 if (!dbg) 1550 dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
1162 return -EBADF; 1551 if (!dbg) {
1552 pr_warning("No dwarf info found in the vmlinux - "
1553 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1554 ret = -EINVAL;
1555 goto end;
1556 }
1163 1557
1558 /* Adjust address with bias */
1559 addr += bias;
1164 /* Find cu die */ 1560 /* Find cu die */
1165 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { 1561 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
1562 pr_warning("No CU DIE is found at %lx\n", addr);
1166 ret = -EINVAL; 1563 ret = -EINVAL;
1167 goto end; 1564 goto end;
1168 } 1565 }
@@ -1225,7 +1622,8 @@ found:
1225 } 1622 }
1226 1623
1227end: 1624end:
1228 dwarf_end(dbg); 1625 if (dwfl)
1626 dwfl_end(dwfl);
1229 if (ret >= 0) 1627 if (ret >= 0)
1230 ret = found ? 1 : 0; 1628 ret = found ? 1 : 0;
1231 return ret; 1629 return ret;
@@ -1358,6 +1756,9 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1358 struct line_finder *lf = param->data; 1756 struct line_finder *lf = param->data;
1359 struct line_range *lr = lf->lr; 1757 struct line_range *lr = lf->lr;
1360 1758
1759 pr_debug("find (%llx) %s\n",
1760 (unsigned long long)dwarf_dieoffset(sp_die),
1761 dwarf_diename(sp_die));
1361 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1762 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1362 die_compare_name(sp_die, lr->function)) { 1763 die_compare_name(sp_die, lr->function)) {
1363 lf->fname = dwarf_decl_file(sp_die); 1764 lf->fname = dwarf_decl_file(sp_die);
@@ -1401,10 +1802,12 @@ int find_line_range(int fd, struct line_range *lr)
1401 Dwarf_Off off = 0, noff; 1802 Dwarf_Off off = 0, noff;
1402 size_t cuhl; 1803 size_t cuhl;
1403 Dwarf_Die *diep; 1804 Dwarf_Die *diep;
1404 Dwarf *dbg; 1805 Dwarf *dbg = NULL;
1806 Dwfl *dwfl;
1807 Dwarf_Addr bias; /* Currently ignored */
1405 const char *comp_dir; 1808 const char *comp_dir;
1406 1809
1407 dbg = dwarf_begin(fd, DWARF_C_READ); 1810 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1408 if (!dbg) { 1811 if (!dbg) {
1409 pr_warning("No dwarf info found in the vmlinux - " 1812 pr_warning("No dwarf info found in the vmlinux - "
1410 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1813 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
@@ -1450,8 +1853,7 @@ int find_line_range(int fd, struct line_range *lr)
1450 } 1853 }
1451 1854
1452 pr_debug("path: %s\n", lr->path); 1855 pr_debug("path: %s\n", lr->path);
1453 dwarf_end(dbg); 1856 dwfl_end(dwfl);
1454
1455 return (ret < 0) ? ret : lf.found; 1857 return (ret < 0) ? ret : lf.found;
1456} 1858}
1457 1859
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 4507d519f183..bba69d455699 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -22,20 +22,27 @@ extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
22 int max_tevs); 22 int max_tevs);
23 23
24/* Find a perf_probe_point from debuginfo */ 24/* Find a perf_probe_point from debuginfo */
25extern int find_perf_probe_point(int fd, unsigned long addr, 25extern int find_perf_probe_point(unsigned long addr,
26 struct perf_probe_point *ppt); 26 struct perf_probe_point *ppt);
27 27
28/* Find a line range */
28extern int find_line_range(int fd, struct line_range *lr); 29extern int find_line_range(int fd, struct line_range *lr);
29 30
31/* Find available variables */
32extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
33 struct variable_list **vls, int max_points,
34 bool externs);
35
30#include <dwarf.h> 36#include <dwarf.h>
31#include <libdw.h> 37#include <libdw.h>
38#include <libdwfl.h>
32#include <version.h> 39#include <version.h>
33 40
34struct probe_finder { 41struct probe_finder {
35 struct perf_probe_event *pev; /* Target probe event */ 42 struct perf_probe_event *pev; /* Target probe event */
36 struct probe_trace_event *tevs; /* Result trace events */ 43
37 int ntevs; /* Number of trace events */ 44 /* Callback when a probe point is found */
38 int max_tevs; /* Max number of trace events */ 45 int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);
39 46
40 /* For function searching */ 47 /* For function searching */
41 int lno; /* Line number */ 48 int lno; /* Line number */
@@ -53,6 +60,22 @@ struct probe_finder {
53 struct probe_trace_arg *tvar; /* Current result variable */ 60 struct probe_trace_arg *tvar; /* Current result variable */
54}; 61};
55 62
63struct trace_event_finder {
64 struct probe_finder pf;
65 struct probe_trace_event *tevs; /* Found trace events */
66 int ntevs; /* Number of trace events */
67 int max_tevs; /* Max number of trace events */
68};
69
70struct available_var_finder {
71 struct probe_finder pf;
72 struct variable_list *vls; /* Found variable lists */
73 int nvls; /* Number of variable lists */
74 int max_vls; /* Max no. of variable lists */
75 bool externs; /* Find external vars too */
76 bool child; /* Search child scopes */
77};
78
56struct line_finder { 79struct line_finder {
57 struct line_range *lr; /* Target line range */ 80 struct line_range *lr; /* Target line range */
58 81
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 0409fc7c0058..8fc0bd3a3a4a 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -259,7 +259,7 @@ static bool __match_glob(const char *str, const char *pat, bool ignore_space)
259 if (!*pat) /* Tail wild card matches all */ 259 if (!*pat) /* Tail wild card matches all */
260 return true; 260 return true;
261 while (*str) 261 while (*str)
262 if (strglobmatch(str++, pat)) 262 if (__match_glob(str++, pat, ignore_space))
263 return true; 263 return true;
264 } 264 }
265 return !*str && !*pat; 265 return !*str && !*pat;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b39f499e575a..439ab947daf4 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -295,7 +295,9 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
295{ 295{
296 struct rb_node **p = &self->rb_node; 296 struct rb_node **p = &self->rb_node;
297 struct rb_node *parent = NULL; 297 struct rb_node *parent = NULL;
298 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; 298 struct symbol_name_rb_node *symn, *s;
299
300 symn = container_of(sym, struct symbol_name_rb_node, sym);
299 301
300 while (*p != NULL) { 302 while (*p != NULL) {
301 parent = *p; 303 parent = *p;
@@ -530,7 +532,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
530 struct machine *machine = kmaps->machine; 532 struct machine *machine = kmaps->machine;
531 struct map *curr_map = map; 533 struct map *curr_map = map;
532 struct symbol *pos; 534 struct symbol *pos;
533 int count = 0; 535 int count = 0, moved = 0;
534 struct rb_root *root = &self->symbols[map->type]; 536 struct rb_root *root = &self->symbols[map->type];
535 struct rb_node *next = rb_first(root); 537 struct rb_node *next = rb_first(root);
536 int kernel_range = 0; 538 int kernel_range = 0;
@@ -588,6 +590,11 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
588 char dso_name[PATH_MAX]; 590 char dso_name[PATH_MAX];
589 struct dso *dso; 591 struct dso *dso;
590 592
593 if (count == 0) {
594 curr_map = map;
595 goto filter_symbol;
596 }
597
591 if (self->kernel == DSO_TYPE_GUEST_KERNEL) 598 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
592 snprintf(dso_name, sizeof(dso_name), 599 snprintf(dso_name, sizeof(dso_name),
593 "[guest.kernel].%d", 600 "[guest.kernel].%d",
@@ -613,7 +620,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
613 map_groups__insert(kmaps, curr_map); 620 map_groups__insert(kmaps, curr_map);
614 ++kernel_range; 621 ++kernel_range;
615 } 622 }
616 623filter_symbol:
617 if (filter && filter(curr_map, pos)) { 624 if (filter && filter(curr_map, pos)) {
618discard_symbol: rb_erase(&pos->rb_node, root); 625discard_symbol: rb_erase(&pos->rb_node, root);
619 symbol__delete(pos); 626 symbol__delete(pos);
@@ -621,8 +628,9 @@ discard_symbol: rb_erase(&pos->rb_node, root);
621 if (curr_map != map) { 628 if (curr_map != map) {
622 rb_erase(&pos->rb_node, root); 629 rb_erase(&pos->rb_node, root);
623 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 630 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
624 } 631 ++moved;
625 count++; 632 } else
633 ++count;
626 } 634 }
627 } 635 }
628 636
@@ -632,7 +640,7 @@ discard_symbol: rb_erase(&pos->rb_node, root);
632 dso__set_loaded(curr_map->dso, curr_map->type); 640 dso__set_loaded(curr_map->dso, curr_map->type);
633 } 641 }
634 642
635 return count; 643 return count + moved;
636} 644}
637 645
638int dso__load_kallsyms(struct dso *self, const char *filename, 646int dso__load_kallsyms(struct dso *self, const char *filename,
@@ -1772,8 +1780,8 @@ out_failure:
1772 return -1; 1780 return -1;
1773} 1781}
1774 1782
1775static int dso__load_vmlinux(struct dso *self, struct map *map, 1783int dso__load_vmlinux(struct dso *self, struct map *map,
1776 const char *vmlinux, symbol_filter_t filter) 1784 const char *vmlinux, symbol_filter_t filter)
1777{ 1785{
1778 int err = -1, fd; 1786 int err = -1, fd;
1779 1787
@@ -2123,14 +2131,55 @@ static struct dso *machine__create_kernel(struct machine *self)
2123 return kernel; 2131 return kernel;
2124} 2132}
2125 2133
2134struct process_args {
2135 u64 start;
2136};
2137
2138static int symbol__in_kernel(void *arg, const char *name,
2139 char type __used, u64 start)
2140{
2141 struct process_args *args = arg;
2142
2143 if (strchr(name, '['))
2144 return 0;
2145
2146 args->start = start;
2147 return 1;
2148}
2149
2150/* Figure out the start address of kernel map from /proc/kallsyms */
2151static u64 machine__get_kernel_start_addr(struct machine *machine)
2152{
2153 const char *filename;
2154 char path[PATH_MAX];
2155 struct process_args args;
2156
2157 if (machine__is_host(machine)) {
2158 filename = "/proc/kallsyms";
2159 } else {
2160 if (machine__is_default_guest(machine))
2161 filename = (char *)symbol_conf.default_guest_kallsyms;
2162 else {
2163 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2164 filename = path;
2165 }
2166 }
2167
2168 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
2169 return 0;
2170
2171 return args.start;
2172}
2173
2126int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) 2174int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
2127{ 2175{
2128 enum map_type type; 2176 enum map_type type;
2177 u64 start = machine__get_kernel_start_addr(self);
2129 2178
2130 for (type = 0; type < MAP__NR_TYPES; ++type) { 2179 for (type = 0; type < MAP__NR_TYPES; ++type) {
2131 struct kmap *kmap; 2180 struct kmap *kmap;
2132 2181
2133 self->vmlinux_maps[type] = map__new2(0, kernel, type); 2182 self->vmlinux_maps[type] = map__new2(start, kernel, type);
2134 if (self->vmlinux_maps[type] == NULL) 2183 if (self->vmlinux_maps[type] == NULL)
2135 return -1; 2184 return -1;
2136 2185
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 038f2201ee09..6c6eafdb932d 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -166,6 +166,8 @@ void dso__sort_by_name(struct dso *self, enum map_type type);
166struct dso *__dsos__findnew(struct list_head *head, const char *name); 166struct dso *__dsos__findnew(struct list_head *head, const char *name);
167 167
168int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 168int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
169int dso__load_vmlinux(struct dso *self, struct map *map,
170 const char *vmlinux, symbol_filter_t filter);
169int dso__load_vmlinux_path(struct dso *self, struct map *map, 171int dso__load_vmlinux_path(struct dso *self, struct map *map,
170 symbol_filter_t filter); 172 symbol_filter_t filter);
171int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, 173int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
index 6d0df809a2ed..8bc010edca25 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,4 +1,3 @@
1#include <slang.h>
2#include "libslang.h" 1#include "libslang.h"
3#include <linux/compiler.h> 2#include <linux/compiler.h>
4#include <linux/list.h> 3#include <linux/list.h>
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
index 9706d9d40279..056c69521a38 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/util/ui/util.c
@@ -104,9 +104,10 @@ out_destroy_form:
104 return rc; 104 return rc;
105} 105}
106 106
107static const char yes[] = "Yes", no[] = "No";
108
107bool ui__dialog_yesno(const char *msg) 109bool ui__dialog_yesno(const char *msg)
108{ 110{
109 /* newtWinChoice should really be accepting const char pointers... */ 111 /* newtWinChoice should really be accepting const char pointers... */
110 char yes[] = "Yes", no[] = "No"; 112 return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1;
111 return newtWinChoice(NULL, yes, no, (char *)msg) == 1;
112} 113}