aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/.gitignore2
-rw-r--r--tools/perf/Documentation/perf-archive.txt22
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt33
-rw-r--r--tools/perf/Documentation/perf-lock.txt29
-rw-r--r--tools/perf/Documentation/perf-probe.txt76
-rw-r--r--tools/perf/Documentation/perf-top.txt2
-rw-r--r--tools/perf/Documentation/perf-trace-perl.txt2
-rw-r--r--tools/perf/Documentation/perf-trace-python.txt625
-rw-r--r--tools/perf/Documentation/perf-trace.txt15
-rw-r--r--tools/perf/Documentation/perf.txt2
-rw-r--r--tools/perf/Makefile103
-rw-r--r--tools/perf/builtin-annotate.c240
-rw-r--r--tools/perf/builtin-buildid-cache.c133
-rw-r--r--tools/perf/builtin-buildid-list.c31
-rw-r--r--tools/perf/builtin-diff.c74
-rw-r--r--tools/perf/builtin-help.c5
-rw-r--r--tools/perf/builtin-kmem.c55
-rw-r--r--tools/perf/builtin-lock.c822
-rw-r--r--tools/perf/builtin-probe.c126
-rw-r--r--tools/perf/builtin-record.c50
-rw-r--r--tools/perf/builtin-report.c60
-rw-r--r--tools/perf/builtin-sched.c32
-rw-r--r--tools/perf/builtin-stat.c106
-rw-r--r--tools/perf/builtin-timechart.c27
-rw-r--r--tools/perf/builtin-top.c111
-rw-r--r--tools/perf/builtin-trace.c38
-rw-r--r--tools/perf/builtin.h2
-rw-r--r--tools/perf/command-list.txt3
-rw-r--r--tools/perf/design.txt8
-rw-r--r--tools/perf/perf-archive.sh33
-rw-r--r--tools/perf/perf.c27
-rw-r--r--tools/perf/perf.h4
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.c5
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.xs3
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm2
-rw-r--r--tools/perf/scripts/perl/bin/check-perf-trace-record7
-rw-r--r--tools/perf/scripts/perl/bin/check-perf-trace-report6
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-record2
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-report4
-rw-r--r--tools/perf/scripts/perl/failed-syscalls.pl38
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/Context.c88
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py91
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py25
-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-report4
-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-report4
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-record2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-report4
-rw-r--r--tools/perf/scripts/python/check-perf-trace.py83
-rw-r--r--tools/perf/scripts/python/failed-syscalls-by-pid.py68
-rw-r--r--tools/perf/scripts/python/syscall-counts-by-pid.py64
-rw-r--r--tools/perf/scripts/python/syscall-counts.py58
-rw-r--r--tools/perf/util/build-id.c39
-rw-r--r--tools/perf/util/build-id.h8
-rw-r--r--tools/perf/util/data_map.c252
-rw-r--r--tools/perf/util/debug.c1
-rw-r--r--tools/perf/util/debugfs.c17
-rw-r--r--tools/perf/util/debugfs.h2
-rw-r--r--tools/perf/util/event.c224
-rw-r--r--tools/perf/util/event.h79
-rw-r--r--tools/perf/util/header.c284
-rw-r--r--tools/perf/util/header.h9
-rw-r--r--tools/perf/util/hist.c2
-rw-r--r--tools/perf/util/include/linux/hash.h5
-rw-r--r--tools/perf/util/include/linux/kernel.h1
-rw-r--r--tools/perf/util/map.c52
-rw-r--r--tools/perf/util/map.h94
-rw-r--r--tools/perf/util/parse-events.c48
-rw-r--r--tools/perf/util/probe-event.c163
-rw-r--r--tools/perf/util/probe-event.h2
-rw-r--r--tools/perf/util/probe-finder.c963
-rw-r--r--tools/perf/util/probe-finder.h66
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c (renamed from tools/perf/util/trace-event-perl.c)115
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c573
-rw-r--r--tools/perf/util/session.c431
-rw-r--r--tools/perf/util/session.h55
-rw-r--r--tools/perf/util/string.c96
-rw-r--r--tools/perf/util/string.h1
-rw-r--r--tools/perf/util/symbol.c529
-rw-r--r--tools/perf/util/symbol.h52
-rw-r--r--tools/perf/util/thread.c52
-rw-r--r--tools/perf/util/thread.h24
-rw-r--r--tools/perf/util/trace-event-info.c64
-rw-r--r--tools/perf/util/trace-event-parse.c24
-rw-r--r--tools/perf/util/trace-event-perl.h55
-rw-r--r--tools/perf/util/trace-event-read.c18
-rw-r--r--tools/perf/util/trace-event-scripting.c167
-rw-r--r--tools/perf/util/trace-event.h10
-rw-r--r--tools/perf/util/util.c94
-rw-r--r--tools/perf/util/util.h3
-rw-r--r--tools/perf/util/values.c1
92 files changed, 6294 insertions, 1841 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index fe08660ce0bd..e1d60d780784 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -13,6 +13,8 @@ perf*.xml
13perf*.html 13perf*.html
14common-cmds.h 14common-cmds.h
15perf.data 15perf.data
16perf.data.old
17perf-archive
16tags 18tags
17TAGS 19TAGS
18cscope* 20cscope*
diff --git a/tools/perf/Documentation/perf-archive.txt b/tools/perf/Documentation/perf-archive.txt
new file mode 100644
index 000000000000..fae174dc7d01
--- /dev/null
+++ b/tools/perf/Documentation/perf-archive.txt
@@ -0,0 +1,22 @@
1perf-archive(1)
2===============
3
4NAME
5----
6perf-archive - Create archive with object files with build-ids found in perf.data file
7
8SYNOPSIS
9--------
10[verse]
11'perf archive' [file]
12
13DESCRIPTION
14-----------
15This command runs runs perf-buildid-list --with-hits, and collects the files
16with the buildids found so that analisys of perf.data contents can be possible
17on another machine.
18
19
20SEE ALSO
21--------
22linkperf:perf-record[1], linkperf:perf-buildid-list[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
new file mode 100644
index 000000000000..88bc3b519746
--- /dev/null
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -0,0 +1,33 @@
1perf-buildid-cache(1)
2=====================
3
4NAME
5----
6perf-buildid-cache - Manage build-id cache.
7
8SYNOPSIS
9--------
10[verse]
11'perf buildid-list <options>'
12
13DESCRIPTION
14-----------
15This command manages the build-id cache. It can add and remove files to the
16cache. In the future it should as well purge older entries, set upper limits
17for the space used by the cache, etc.
18
19OPTIONS
20-------
21-a::
22--add=::
23 Add specified file to the cache.
24-r::
25--remove=::
26 Remove specified file to the cache.
27-v::
28--verbose::
29 Be more verbose.
30
31SEE ALSO
32--------
33linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt
new file mode 100644
index 000000000000..b317102138c8
--- /dev/null
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -0,0 +1,29 @@
1perf-lock(1)
2============
3
4NAME
5----
6perf-lock - Analyze lock events
7
8SYNOPSIS
9--------
10[verse]
11'perf lock' {record|report|trace}
12
13DESCRIPTION
14-----------
15You can analyze various lock behaviours
16and statistics with this 'perf lock' command.
17
18 'perf lock record <command>' records lock events
19 between start and end <command>. And this command
20 produces the file "perf.data" which contains tracing
21 results of lock events.
22
23 'perf lock trace' shows raw lock events.
24
25 'perf lock report' reports statistical data.
26
27SEE ALSO
28--------
29linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 250e391b4bc8..34202b1be0bb 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -15,6 +15,8 @@ or
15'perf probe' [options] --del='[GROUP:]EVENT' [...] 15'perf probe' [options] --del='[GROUP:]EVENT' [...]
16or 16or
17'perf probe' --list 17'perf probe' --list
18or
19'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
18 20
19DESCRIPTION 21DESCRIPTION
20----------- 22-----------
@@ -39,23 +41,89 @@ OPTIONS
39 41
40-d:: 42-d::
41--del=:: 43--del=::
42 Delete a probe event. 44 Delete probe events. This accepts glob wildcards('*', '?') and character
45 classes(e.g. [a-z], [!A-Z]).
43 46
44-l:: 47-l::
45--list:: 48--list::
46 List up current probe events. 49 List up current probe events.
47 50
51-L::
52--line=::
53 Show source code lines which can be probed. This needs an argument
54 which specifies a range of the source code. (see LINE SYNTAX for detail)
55
56-f::
57--force::
58 Forcibly add events with existing name.
59
48PROBE SYNTAX 60PROBE SYNTAX
49------------ 61------------
50Probe points are defined by following syntax. 62Probe points are defined by following syntax.
51 63
52 "[EVENT=]FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]" 64 1) Define event based on function name
65 [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
66
67 2) Define event based on source file with line number
68 [EVENT=]SRC:ALN [ARG ...]
69
70 3) Define event based on source file with lazy pattern
71 [EVENT=]SRC;PTN [ARG ...]
72
53 73
54'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. 74'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'.
55'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function. 75'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function.
56It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number. 76It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern.
57'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). 77'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
58 78
79LINE SYNTAX
80-----------
81Line range is descripted by following syntax.
82
83 "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]"
84
85FUNC specifies the function name of showing lines. 'RLN' is the start line
86number from function entry line, and 'RLN2' is the end line number. As same as
87probe syntax, 'SRC' means the source file path, 'ALN' is start line number,
88and 'ALN2' is end line number in the file. It is also possible to specify how
89many lines to show by using 'NUM'.
90So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function.
91
92LAZY MATCHING
93-------------
94 The lazy line matching is similar to glob matching but ignoring spaces in both of pattern and target. So this accepts wildcards('*', '?') and character classes(e.g. [a-z], [!A-Z]).
95
96e.g.
97 'a=*' can matches 'a=b', 'a = b', 'a == b' and so on.
98
99This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.)
100
101
102EXAMPLES
103--------
104Display which lines in schedule() can be probed:
105
106 ./perf probe --line schedule
107
108Add a probe on schedule() function 12th line with recording cpu local variable:
109
110 ./perf probe schedule:12 cpu
111 or
112 ./perf probe --add='schedule:12 cpu'
113
114 this will add one or more probes which has the name start with "schedule".
115
116 Add probes on lines in schedule() function which calls update_rq_clock().
117
118 ./perf probe 'schedule;update_rq_clock*'
119 or
120 ./perf probe --add='schedule;update_rq_clock*'
121
122Delete all probes on schedule().
123
124 ./perf probe --del='schedule*'
125
126
59SEE ALSO 127SEE ALSO
60-------- 128--------
61linkperf:perf-trace[1], linkperf:perf-record[1] 129linkperf:perf-trace[1], linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 4a7d558dc309..785b9fc32a46 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -74,7 +74,7 @@ OPTIONS
74 74
75-s <symbol>:: 75-s <symbol>::
76--sym-annotate=<symbol>:: 76--sym-annotate=<symbol>::
77 Annotate this symbol. Requires -k option. 77 Annotate this symbol.
78 78
79-v:: 79-v::
80--verbose:: 80--verbose::
diff --git a/tools/perf/Documentation/perf-trace-perl.txt b/tools/perf/Documentation/perf-trace-perl.txt
index c5f55f439091..d729cee8d987 100644
--- a/tools/perf/Documentation/perf-trace-perl.txt
+++ b/tools/perf/Documentation/perf-trace-perl.txt
@@ -8,7 +8,7 @@ perf-trace-perl - Process trace data with a Perl script
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' [-s [lang]:script[.ext] ] 11'perf trace' [-s [Perl]:script[.pl] ]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
diff --git a/tools/perf/Documentation/perf-trace-python.txt b/tools/perf/Documentation/perf-trace-python.txt
new file mode 100644
index 000000000000..a241aca77184
--- /dev/null
+++ b/tools/perf/Documentation/perf-trace-python.txt
@@ -0,0 +1,625 @@
1perf-trace-python(1)
2==================
3
4NAME
5----
6perf-trace-python - Process trace data with a Python script
7
8SYNOPSIS
9--------
10[verse]
11'perf trace' [-s [Python]:script[.py] ]
12
13DESCRIPTION
14-----------
15
16This perf trace option is used to process perf trace data using perf's
17built-in Python interpreter. It reads and processes the input file and
18displays the results of the trace analysis implemented in the given
19Python script, if any.
20
21A QUICK EXAMPLE
22---------------
23
24This section shows the process, start to finish, of creating a working
25Python script that aggregates and extracts useful information from a
26raw perf trace stream. You can avoid reading the rest of this
27document if an example is enough for you; the rest of the document
28provides more details on each step and lists the library functions
29available to script writers.
30
31This example actually details the steps that were used to create the
32'syscall-counts' script you see when you list the available perf trace
33scripts via 'perf trace -l'. As such, this script also shows how to
34integrate your script into the list of general-purpose 'perf trace'
35scripts listed by that command.
36
37The syscall-counts script is a simple script, but demonstrates all the
38basic ideas necessary to create a useful script. Here's an example
39of its output (syscall names are not yet supported, they will appear
40as numbers):
41
42----
43syscall events:
44
45event count
46---------------------------------------- -----------
47sys_write 455067
48sys_getdents 4072
49sys_close 3037
50sys_swapoff 1769
51sys_read 923
52sys_sched_setparam 826
53sys_open 331
54sys_newfstat 326
55sys_mmap 217
56sys_munmap 216
57sys_futex 141
58sys_select 102
59sys_poll 84
60sys_setitimer 12
61sys_writev 8
6215 8
63sys_lseek 7
64sys_rt_sigprocmask 6
65sys_wait4 3
66sys_ioctl 3
67sys_set_robust_list 1
68sys_exit 1
6956 1
70sys_access 1
71----
72
73Basically our task is to keep a per-syscall tally that gets updated
74every time a system call occurs in the system. Our script will do
75that, but first we need to record the data that will be processed by
76that script. Theoretically, there are a couple of ways we could do
77that:
78
79- we could enable every event under the tracing/events/syscalls
80 directory, but this is over 600 syscalls, well beyond the number
81 allowable by perf. These individual syscall events will however be
82 useful if we want to later use the guidance we get from the
83 general-purpose scripts to drill down and get more detail about
84 individual syscalls of interest.
85
86- we can enable the sys_enter and/or sys_exit syscalls found under
87 tracing/events/raw_syscalls. These are called for all syscalls; the
88 'id' field can be used to distinguish between individual syscall
89 numbers.
90
91For this script, we only need to know that a syscall was entered; we
92don't care how it exited, so we'll use 'perf record' to record only
93the sys_enter events:
94
95----
96# perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter
97
98^C[ perf record: Woken up 1 times to write data ]
99[ perf record: Captured and wrote 56.545 MB perf.data (~2470503 samples) ]
100----
101
102The options basically say to collect data for every syscall event
103system-wide and multiplex the per-cpu output into a single stream.
104That single stream will be recorded in a file in the current directory
105called perf.data.
106
107Once we have a perf.data file containing our data, we can use the -g
108'perf trace' option to generate a Python script that will contain a
109callback handler for each event type found in the perf.data trace
110stream (for more details, see the STARTER SCRIPTS section).
111
112----
113# perf trace -g python
114generated Python script: perf-trace.py
115
116The output file created also in the current directory is named
117perf-trace.py. Here's the file in its entirety:
118
119# perf trace event handlers, generated by perf trace -g python
120# Licensed under the terms of the GNU GPL License version 2
121
122# The common_* event handler fields are the most useful fields common to
123# all events. They don't necessarily correspond to the 'common_*' fields
124# in the format files. Those fields not available as handler params can
125# be retrieved using Python functions of the form common_*(context).
126# See the perf-trace-python Documentation for the list of available functions.
127
128import os
129import sys
130
131sys.path.append(os.environ['PERF_EXEC_PATH'] + \
132 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
133
134from perf_trace_context import *
135from Core import *
136
137def trace_begin():
138 print "in trace_begin"
139
140def trace_end():
141 print "in trace_end"
142
143def raw_syscalls__sys_enter(event_name, context, common_cpu,
144 common_secs, common_nsecs, common_pid, common_comm,
145 id, args):
146 print_header(event_name, common_cpu, common_secs, common_nsecs,
147 common_pid, common_comm)
148
149 print "id=%d, args=%s\n" % \
150 (id, args),
151
152def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
153 common_pid, common_comm):
154 print_header(event_name, common_cpu, common_secs, common_nsecs,
155 common_pid, common_comm)
156
157def print_header(event_name, cpu, secs, nsecs, pid, comm):
158 print "%-20s %5u %05u.%09u %8u %-20s " % \
159 (event_name, cpu, secs, nsecs, pid, comm),
160----
161
162At the top is a comment block followed by some import statements and a
163path append which every perf trace script should include.
164
165Following that are a couple generated functions, trace_begin() and
166trace_end(), which are called at the beginning and the end of the
167script respectively (for more details, see the SCRIPT_LAYOUT section
168below).
169
170Following those are the 'event handler' functions generated one for
171every event in the 'perf record' output. The handler functions take
172the form subsystem__event_name, and contain named parameters, one for
173each field in the event; in this case, there's only one event,
174raw_syscalls__sys_enter(). (see the EVENT HANDLERS section below for
175more info on event handlers).
176
177The final couple of functions are, like the begin and end functions,
178generated for every script. The first, trace_unhandled(), is called
179every time the script finds an event in the perf.data file that
180doesn't correspond to any event handler in the script. This could
181mean either that the record step recorded event types that it wasn't
182really interested in, or the script was run against a trace file that
183doesn't correspond to the script.
184
185The script generated by -g option option simply prints a line for each
186event found in the trace stream i.e. it basically just dumps the event
187and its parameter values to stdout. The print_header() function is
188simply a utility function used for that purpose. Let's rename the
189script and run it to see the default output:
190
191----
192# mv perf-trace.py syscall-counts.py
193# perf trace -s syscall-counts.py
194
195raw_syscalls__sys_enter 1 00840.847582083 7506 perf id=1, args=
196raw_syscalls__sys_enter 1 00840.847595764 7506 perf id=1, args=
197raw_syscalls__sys_enter 1 00840.847620860 7506 perf id=1, args=
198raw_syscalls__sys_enter 1 00840.847710478 6533 npviewer.bin id=78, args=
199raw_syscalls__sys_enter 1 00840.847719204 6533 npviewer.bin id=142, args=
200raw_syscalls__sys_enter 1 00840.847755445 6533 npviewer.bin id=3, args=
201raw_syscalls__sys_enter 1 00840.847775601 6533 npviewer.bin id=3, args=
202raw_syscalls__sys_enter 1 00840.847781820 6533 npviewer.bin id=3, args=
203.
204.
205.
206----
207
208Of course, for this script, we're not interested in printing every
209trace event, but rather aggregating it in a useful way. So we'll get
210rid of everything to do with printing as well as the trace_begin() and
211trace_unhandled() functions, which we won't be using. That leaves us
212with this minimalistic skeleton:
213
214----
215import os
216import sys
217
218sys.path.append(os.environ['PERF_EXEC_PATH'] + \
219 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
220
221from perf_trace_context import *
222from Core import *
223
224def trace_end():
225 print "in trace_end"
226
227def raw_syscalls__sys_enter(event_name, context, common_cpu,
228 common_secs, common_nsecs, common_pid, common_comm,
229 id, args):
230----
231
232In trace_end(), we'll simply print the results, but first we need to
233generate some results to print. To do that we need to have our
234sys_enter() handler do the necessary tallying until all events have
235been counted. A hash table indexed by syscall id is a good way to
236store that information; every time the sys_enter() handler is called,
237we simply increment a count associated with that hash entry indexed by
238that syscall id:
239
240----
241 syscalls = autodict()
242
243 try:
244 syscalls[id] += 1
245 except TypeError:
246 syscalls[id] = 1
247----
248
249The syscalls 'autodict' object is a special kind of Python dictionary
250(implemented in Core.py) that implements Perl's 'autovivifying' hashes
251in Python i.e. with autovivifying hashes, you can assign nested hash
252values without having to go to the trouble of creating intermediate
253levels if they don't exist e.g syscalls[comm][pid][id] = 1 will create
254the intermediate hash levels and finally assign the value 1 to the
255hash entry for 'id' (because the value being assigned isn't a hash
256object itself, the initial value is assigned in the TypeError
257exception. Well, there may be a better way to do this in Python but
258that's what works for now).
259
260Putting that code into the raw_syscalls__sys_enter() handler, we
261effectively end up with a single-level dictionary keyed on syscall id
262and having the counts we've tallied as values.
263
264The print_syscall_totals() function iterates over the entries in the
265dictionary and displays a line for each entry containing the syscall
266name (the dictonary keys contain the syscall ids, which are passed to
267the Util function syscall_name(), which translates the raw syscall
268numbers to the corresponding syscall name strings). The output is
269displayed after all the events in the trace have been processed, by
270calling the print_syscall_totals() function from the trace_end()
271handler called at the end of script processing.
272
273The final script producing the output shown above is shown in its
274entirety below (syscall_name() helper is not yet available, you can
275only deal with id's for now):
276
277----
278import os
279import sys
280
281sys.path.append(os.environ['PERF_EXEC_PATH'] + \
282 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
283
284from perf_trace_context import *
285from Core import *
286from Util import *
287
288syscalls = autodict()
289
290def trace_end():
291 print_syscall_totals()
292
293def raw_syscalls__sys_enter(event_name, context, common_cpu,
294 common_secs, common_nsecs, common_pid, common_comm,
295 id, args):
296 try:
297 syscalls[id] += 1
298 except TypeError:
299 syscalls[id] = 1
300
301def print_syscall_totals():
302 if for_comm is not None:
303 print "\nsyscall events for %s:\n\n" % (for_comm),
304 else:
305 print "\nsyscall events:\n\n",
306
307 print "%-40s %10s\n" % ("event", "count"),
308 print "%-40s %10s\n" % ("----------------------------------------", \
309 "-----------"),
310
311 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
312 reverse = True):
313 print "%-40s %10d\n" % (syscall_name(id), val),
314----
315
316The script can be run just as before:
317
318 # perf trace -s syscall-counts.py
319
320So those are the essential steps in writing and running a script. The
321process can be generalized to any tracepoint or set of tracepoints
322you're interested in - basically find the tracepoint(s) you're
323interested in by looking at the list of available events shown by
324'perf list' and/or look in /sys/kernel/debug/tracing events for
325detailed event and field info, record the corresponding trace data
326using 'perf record', passing it the list of interesting events,
327generate a skeleton script using 'perf trace -g python' and modify the
328code to aggregate and display it for your particular needs.
329
330After you've done that you may end up with a general-purpose script
331that you want to keep around and have available for future use. By
332writing a couple of very simple shell scripts and putting them in the
333right place, you can have your script listed alongside the other
334scripts listed by the 'perf trace -l' command e.g.:
335
336----
337root@tropicana:~# perf trace -l
338List of available trace scripts:
339 workqueue-stats workqueue stats (ins/exe/create/destroy)
340 wakeup-latency system-wide min/max/avg wakeup latency
341 rw-by-file <comm> r/w activity for a program, by file
342 rw-by-pid system-wide r/w activity
343----
344
345A nice side effect of doing this is that you also then capture the
346probably lengthy 'perf record' command needed to record the events for
347the script.
348
349To have the script appear as a 'built-in' script, you write two simple
350scripts, one for recording and one for 'reporting'.
351
352The 'record' script is a shell script with the same base name as your
353script, but with -record appended. The shell script should be put
354into the perf/scripts/python/bin directory in the kernel source tree.
355In that script, you write the 'perf record' command-line needed for
356your script:
357
358----
359# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record
360
361#!/bin/bash
362perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter
363----
364
365The 'report' script is also a shell script with the same base name as
366your script, but with -report appended. It should also be located in
367the perf/scripts/python/bin directory. In that script, you write the
368'perf trace -s' command-line needed for running your script:
369
370----
371# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report
372
373#!/bin/bash
374# description: system-wide syscall counts
375perf trace -s ~/libexec/perf-core/scripts/python/syscall-counts.py
376----
377
378Note that the location of the Python script given in the shell script
379is in the libexec/perf-core/scripts/python directory - this is where
380the script will be copied by 'make install' when you install perf.
381For the installation to install your script there, your script needs
382to be located in the perf/scripts/python directory in the kernel
383source tree:
384
385----
386# ls -al kernel-source/tools/perf/scripts/python
387
388root@tropicana:/home/trz/src/tip# ls -al tools/perf/scripts/python
389total 32
390drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
391drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
392drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin
393-rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-trace.py
394drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-Util
395-rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py
396----
397
398Once you've done that (don't forget to do a new 'make install',
399otherwise your script won't show up at run-time), 'perf trace -l'
400should show a new entry for your script:
401
402----
403root@tropicana:~# perf trace -l
404List of available trace scripts:
405 workqueue-stats workqueue stats (ins/exe/create/destroy)
406 wakeup-latency system-wide min/max/avg wakeup latency
407 rw-by-file <comm> r/w activity for a program, by file
408 rw-by-pid system-wide r/w activity
409 syscall-counts system-wide syscall counts
410----
411
412You can now perform the record step via 'perf trace record':
413
414 # perf trace record syscall-counts
415
416and display the output using 'perf trace report':
417
418 # perf trace report syscall-counts
419
420STARTER SCRIPTS
421---------------
422
423You can quickly get started writing a script for a particular set of
424trace data by generating a skeleton script using 'perf trace -g
425python' in the same directory as an existing perf.data trace file.
426That will generate a starter script containing a handler for each of
427the event types in the trace file; it simply prints every available
428field for each event in the trace file.
429
430You can also look at the existing scripts in
431~/libexec/perf-core/scripts/python for typical examples showing how to
432do basic things like aggregate event data, print results, etc. Also,
433the check-perf-trace.py script, while not interesting for its results,
434attempts to exercise all of the main scripting features.
435
436EVENT HANDLERS
437--------------
438
439When perf trace is invoked using a trace script, a user-defined
440'handler function' is called for each event in the trace. If there's
441no handler function defined for a given event type, the event is
442ignored (or passed to a 'trace_handled' function, see below) and the
443next event is processed.
444
445Most of the event's field values are passed as arguments to the
446handler function; some of the less common ones aren't - those are
447available as calls back into the perf executable (see below).
448
449As an example, the following perf record command can be used to record
450all sched_wakeup events in the system:
451
452 # perf record -c 1 -f -a -M -R -e sched:sched_wakeup
453
454Traces meant to be processed using a script should be recorded with
455the above options: -c 1 says to sample every event, -a to enable
456system-wide collection, -M to multiplex the output, and -R to collect
457raw samples.
458
459The format file for the sched_wakep event defines the following fields
460(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format):
461
462----
463 format:
464 field:unsigned short common_type;
465 field:unsigned char common_flags;
466 field:unsigned char common_preempt_count;
467 field:int common_pid;
468 field:int common_lock_depth;
469
470 field:char comm[TASK_COMM_LEN];
471 field:pid_t pid;
472 field:int prio;
473 field:int success;
474 field:int target_cpu;
475----
476
477The handler function for this event would be defined as:
478
479----
480def sched__sched_wakeup(event_name, context, common_cpu, common_secs,
481 common_nsecs, common_pid, common_comm,
482 comm, pid, prio, success, target_cpu):
483 pass
484----
485
486The handler function takes the form subsystem__event_name.
487
488The common_* arguments in the handler's argument list are the set of
489arguments passed to all event handlers; some of the fields correspond
490to the common_* fields in the format file, but some are synthesized,
491and some of the common_* fields aren't common enough to to be passed
492to every event as arguments but are available as library functions.
493
494Here's a brief description of each of the invariant event args:
495
496 event_name the name of the event as text
497 context an opaque 'cookie' used in calls back into perf
498 common_cpu the cpu the event occurred on
499 common_secs the secs portion of the event timestamp
500 common_nsecs the nsecs portion of the event timestamp
501 common_pid the pid of the current task
502 common_comm the name of the current process
503
504All of the remaining fields in the event's format file have
505counterparts as handler function arguments of the same name, as can be
506seen in the example above.
507
508The above provides the basics needed to directly access every field of
509every event in a trace, which covers 90% of what you need to know to
510write a useful trace script. The sections below cover the rest.
511
512SCRIPT LAYOUT
513-------------
514
515Every perf trace Python script should start by setting up a Python
516module search path and 'import'ing a few support modules (see module
517descriptions below):
518
519----
520 import os
521 import sys
522
523 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
524 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
525
526 from perf_trace_context import *
527 from Core import *
528----
529
530The rest of the script can contain handler functions and support
531functions in any order.
532
533Aside from the event handler functions discussed above, every script
534can implement a set of optional functions:
535
536*trace_begin*, if defined, is called before any event is processed and
537gives scripts a chance to do setup tasks:
538
539----
540def trace_begin:
541 pass
542----
543
544*trace_end*, if defined, is called after all events have been
545 processed and gives scripts a chance to do end-of-script tasks, such
546 as display results:
547
548----
549def trace_end:
550 pass
551----
552
553*trace_unhandled*, if defined, is called after for any event that
554 doesn't have a handler explicitly defined for it. The standard set
555 of common arguments are passed into it:
556
557----
558def trace_unhandled(event_name, context, common_cpu, common_secs,
559 common_nsecs, common_pid, common_comm):
560 pass
561----
562
563The remaining sections provide descriptions of each of the available
564built-in perf trace Python modules and their associated functions.
565
566AVAILABLE MODULES AND FUNCTIONS
567-------------------------------
568
569The following sections describe the functions and variables available
570via the various perf trace Python modules. To use the functions and
571variables from the given module, add the corresponding 'from XXXX
572import' line to your perf trace script.
573
574Core.py Module
575~~~~~~~~~~~~~~
576
577These functions provide some essential functions to user scripts.
578
579The *flag_str* and *symbol_str* functions provide human-readable
580strings for flag and symbolic fields. These correspond to the strings
581and values parsed from the 'print fmt' fields of the event format
582files:
583
584 flag_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the flag field field_name of event event_name
585 symbol_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the symbolic field field_name of event event_name
586
587The *autodict* function returns a special special kind of Python
588dictionary that implements Perl's 'autovivifying' hashes in Python
589i.e. with autovivifying hashes, you can assign nested hash values
590without having to go to the trouble of creating intermediate levels if
591they don't exist.
592
593 autodict() - returns an autovivifying dictionary instance
594
595
596perf_trace_context Module
597~~~~~~~~~~~~~~~~~~~~~~~~~
598
599Some of the 'common' fields in the event format file aren't all that
600common, but need to be made accessible to user scripts nonetheless.
601
602perf_trace_context defines a set of functions that can be used to
603access this data in the context of the current event. Each of these
604functions expects a context variable, which is the same as the
605context variable passed into every event handler as the second
606argument.
607
608 common_pc(context) - returns common_preempt count for the current event
609 common_flags(context) - returns common_flags for the current event
610 common_lock_depth(context) - returns common_lock_depth for the current event
611
612Util.py Module
613~~~~~~~~~~~~~~
614
615Various utility functions for use with perf trace:
616
617 nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair
618 nsecs_secs(nsecs) - returns whole secs portion given nsecs
619 nsecs_nsecs(nsecs) - returns nsecs remainder given nsecs
620 nsecs_str(nsecs) - returns printable string in the form secs.nsecs
621 avg(total, n) - returns average given a sum and a total number of values
622
623SEE ALSO
624--------
625linkperf:perf-trace[1]
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 60e5900da483..8879299cd9df 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -19,6 +19,11 @@ There are several variants of perf trace:
19 'perf trace' to see a detailed trace of the workload that was 19 'perf trace' to see a detailed trace of the workload that was
20 recorded. 20 recorded.
21 21
22 You can also run a set of pre-canned scripts that aggregate and
23 summarize the raw trace data in various ways (the list of scripts is
24 available via 'perf trace -l'). The following variants allow you to
25 record and run those scripts:
26
22 'perf trace record <script>' to record the events required for 'perf 27 'perf trace record <script>' to record the events required for 'perf
23 trace report'. <script> is the name displayed in the output of 28 trace report'. <script> is the name displayed in the output of
24 'perf trace --list' i.e. the actual script name minus any language 29 'perf trace --list' i.e. the actual script name minus any language
@@ -31,6 +36,9 @@ There are several variants of perf trace:
31 record <script>' is used and should be present for this command to 36 record <script>' is used and should be present for this command to
32 succeed. 37 succeed.
33 38
39 See the 'SEE ALSO' section for links to language-specific
40 information on how to write and run your own trace scripts.
41
34OPTIONS 42OPTIONS
35------- 43-------
36-D:: 44-D::
@@ -45,9 +53,11 @@ OPTIONS
45--list=:: 53--list=::
46 Display a list of available trace scripts. 54 Display a list of available trace scripts.
47 55
48-s:: 56-s ['lang']::
49--script=:: 57--script=::
50 Process trace data with the given script ([lang]:script[.ext]). 58 Process trace data with the given script ([lang]:script[.ext]).
59 If the string 'lang' is specified in place of a script name, a
60 list of supported languages will be displayed instead.
51 61
52-g:: 62-g::
53--gen-script=:: 63--gen-script=::
@@ -56,4 +66,5 @@ OPTIONS
56 66
57SEE ALSO 67SEE ALSO
58-------- 68--------
59linkperf:perf-record[1], linkperf:perf-trace-perl[1] 69linkperf:perf-record[1], linkperf:perf-trace-perl[1],
70linkperf:perf-trace-python[1]
diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt
index 69c832557199..0eeb247dc7d2 100644
--- a/tools/perf/Documentation/perf.txt
+++ b/tools/perf/Documentation/perf.txt
@@ -12,7 +12,7 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15Performance counters for Linux are are a new kernel-based subsystem 15Performance counters for Linux are a new kernel-based subsystem
16that provide a framework for all things performance analysis. It 16that provide a framework for all things performance analysis. It
17covers hardware level (CPU/PMU, Performance Monitoring Unit) features 17covers hardware level (CPU/PMU, Performance Monitoring Unit) features
18and software features (software counters, tracepoints) as well. 18and software features (software counters, tracepoints) as well.
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 652a470b5f74..2d537382c686 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -250,7 +250,19 @@ PTHREAD_LIBS = -lpthread
250# explicitly what architecture to check for. Fix this up for yours.. 250# explicitly what architecture to check for. Fix this up for yours..
251SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 251SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
252 252
253ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o /dev/null "$(QUIET_STDERR)" && echo y"), y) 253ifeq ($(V), 2)
254 QUIET_STDERR = ">/dev/null"
255else
256 QUIET_STDERR = ">/dev/null 2>&1"
257endif
258
259BITBUCKET = "/dev/null"
260
261ifneq ($(shell sh -c "(echo '\#include <stdio.h>'; echo 'int main(void) { return puts(\"hi\"); }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y)
262 BITBUCKET = .perf.dev.null
263endif
264
265ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y)
254 CFLAGS := $(CFLAGS) -fstack-protector-all 266 CFLAGS := $(CFLAGS) -fstack-protector-all
255endif 267endif
256 268
@@ -274,11 +286,7 @@ SCRIPT_PERL =
274SCRIPT_SH = 286SCRIPT_SH =
275TEST_PROGRAMS = 287TEST_PROGRAMS =
276 288
277# 289SCRIPT_SH += perf-archive.sh
278# No scripts right now:
279#
280
281# SCRIPT_SH += perf-am.sh
282 290
283# 291#
284# No Perl scripts right now: 292# No Perl scripts right now:
@@ -303,9 +311,6 @@ PROGRAMS += perf
303# List built-in command $C whose implementation cmd_$C() is not in 311# List built-in command $C whose implementation cmd_$C() is not in
304# builtin-$C.o but is linked in as part of some other command. 312# builtin-$C.o but is linked in as part of some other command.
305# 313#
306# None right now:
307#
308# BUILT_INS += perf-init $X
309 314
310# what 'all' will build and 'install' will install, in perfexecdir 315# what 'all' will build and 'install' will install, in perfexecdir
311ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 316ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
@@ -328,6 +333,7 @@ LIB_FILE=libperf.a
328LIB_H += ../../include/linux/perf_event.h 333LIB_H += ../../include/linux/perf_event.h
329LIB_H += ../../include/linux/rbtree.h 334LIB_H += ../../include/linux/rbtree.h
330LIB_H += ../../include/linux/list.h 335LIB_H += ../../include/linux/list.h
336LIB_H += ../../include/linux/hash.h
331LIB_H += ../../include/linux/stringify.h 337LIB_H += ../../include/linux/stringify.h
332LIB_H += util/include/linux/bitmap.h 338LIB_H += util/include/linux/bitmap.h
333LIB_H += util/include/linux/bitops.h 339LIB_H += util/include/linux/bitops.h
@@ -351,12 +357,14 @@ LIB_H += util/include/asm/uaccess.h
351LIB_H += perf.h 357LIB_H += perf.h
352LIB_H += util/cache.h 358LIB_H += util/cache.h
353LIB_H += util/callchain.h 359LIB_H += util/callchain.h
360LIB_H += util/build-id.h
354LIB_H += util/debug.h 361LIB_H += util/debug.h
355LIB_H += util/debugfs.h 362LIB_H += util/debugfs.h
356LIB_H += util/event.h 363LIB_H += util/event.h
357LIB_H += util/exec_cmd.h 364LIB_H += util/exec_cmd.h
358LIB_H += util/types.h 365LIB_H += util/types.h
359LIB_H += util/levenshtein.h 366LIB_H += util/levenshtein.h
367LIB_H += util/map.h
360LIB_H += util/parse-options.h 368LIB_H += util/parse-options.h
361LIB_H += util/parse-events.h 369LIB_H += util/parse-events.h
362LIB_H += util/quote.h 370LIB_H += util/quote.h
@@ -377,12 +385,12 @@ LIB_H += util/sort.h
377LIB_H += util/hist.h 385LIB_H += util/hist.h
378LIB_H += util/thread.h 386LIB_H += util/thread.h
379LIB_H += util/trace-event.h 387LIB_H += util/trace-event.h
380LIB_H += util/trace-event-perl.h
381LIB_H += util/probe-finder.h 388LIB_H += util/probe-finder.h
382LIB_H += util/probe-event.h 389LIB_H += util/probe-event.h
383 390
384LIB_OBJS += util/abspath.o 391LIB_OBJS += util/abspath.o
385LIB_OBJS += util/alias.o 392LIB_OBJS += util/alias.o
393LIB_OBJS += util/build-id.o
386LIB_OBJS += util/config.o 394LIB_OBJS += util/config.o
387LIB_OBJS += util/ctype.o 395LIB_OBJS += util/ctype.o
388LIB_OBJS += util/debugfs.o 396LIB_OBJS += util/debugfs.o
@@ -419,12 +427,12 @@ LIB_OBJS += util/thread.o
419LIB_OBJS += util/trace-event-parse.o 427LIB_OBJS += util/trace-event-parse.o
420LIB_OBJS += util/trace-event-read.o 428LIB_OBJS += util/trace-event-read.o
421LIB_OBJS += util/trace-event-info.o 429LIB_OBJS += util/trace-event-info.o
422LIB_OBJS += util/trace-event-perl.o 430LIB_OBJS += util/trace-event-scripting.o
423LIB_OBJS += util/svghelper.o 431LIB_OBJS += util/svghelper.o
424LIB_OBJS += util/sort.o 432LIB_OBJS += util/sort.o
425LIB_OBJS += util/hist.o 433LIB_OBJS += util/hist.o
426LIB_OBJS += util/data_map.o
427LIB_OBJS += util/probe-event.o 434LIB_OBJS += util/probe-event.o
435LIB_OBJS += util/util.o
428 436
429BUILTIN_OBJS += builtin-annotate.o 437BUILTIN_OBJS += builtin-annotate.o
430 438
@@ -439,6 +447,7 @@ BUILTIN_OBJS += builtin-diff.o
439BUILTIN_OBJS += builtin-help.o 447BUILTIN_OBJS += builtin-help.o
440BUILTIN_OBJS += builtin-sched.o 448BUILTIN_OBJS += builtin-sched.o
441BUILTIN_OBJS += builtin-buildid-list.o 449BUILTIN_OBJS += builtin-buildid-list.o
450BUILTIN_OBJS += builtin-buildid-cache.o
442BUILTIN_OBJS += builtin-list.o 451BUILTIN_OBJS += builtin-list.o
443BUILTIN_OBJS += builtin-record.o 452BUILTIN_OBJS += builtin-record.o
444BUILTIN_OBJS += builtin-report.o 453BUILTIN_OBJS += builtin-report.o
@@ -448,14 +457,10 @@ BUILTIN_OBJS += builtin-top.o
448BUILTIN_OBJS += builtin-trace.o 457BUILTIN_OBJS += builtin-trace.o
449BUILTIN_OBJS += builtin-probe.o 458BUILTIN_OBJS += builtin-probe.o
450BUILTIN_OBJS += builtin-kmem.o 459BUILTIN_OBJS += builtin-kmem.o
460BUILTIN_OBJS += builtin-lock.o
451 461
452PERFLIBS = $(LIB_FILE) 462PERFLIBS = $(LIB_FILE)
453 463
454ifeq ($(V), 2)
455 QUIET_STDERR = ">/dev/null"
456else
457 QUIET_STDERR = ">/dev/null 2>&1"
458endif
459# 464#
460# Platform specific tweaks 465# Platform specific tweaks
461# 466#
@@ -483,24 +488,24 @@ ifeq ($(uname_S),Darwin)
483 PTHREAD_LIBS = 488 PTHREAD_LIBS =
484endif 489endif
485 490
486ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 491ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
487ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 492ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
488 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 493 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
489endif 494endif
490 495
491 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 496 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
492 BASIC_CFLAGS += -DLIBELF_NO_MMAP 497 BASIC_CFLAGS += -DLIBELF_NO_MMAP
493 endif 498 endif
494else 499else
495 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); 500 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
496endif 501endif
497 502
498ifneq ($(shell sh -c "(echo '\#ifndef _MIPS_SZLONG'; echo '\#define _MIPS_SZLONG 0'; echo '\#endif'; echo '\#include <dwarf.h>'; echo '\#include <libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/libdwarf -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 503ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
499 msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231); 504 msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev);
500 BASIC_CFLAGS += -DNO_LIBDWARF 505 BASIC_CFLAGS += -DNO_DWARF_SUPPORT
501else 506else
502 BASIC_CFLAGS += -I/usr/include/libdwarf 507 BASIC_CFLAGS += -I/usr/include/elfutils
503 EXTLIBS += -lelf -ldwarf 508 EXTLIBS += -lelf -ldw
504 LIB_OBJS += util/probe-finder.o 509 LIB_OBJS += util/probe-finder.o
505endif 510endif
506 511
@@ -509,30 +514,44 @@ PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
509PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 514PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
510endif 515endif
511 516
512ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) 517ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o $(BITBUCKET) $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
513 BASIC_CFLAGS += -DNO_LIBPERL 518 BASIC_CFLAGS += -DNO_LIBPERL
514else 519else
515 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS) 520 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
521 LIB_OBJS += util/scripting-engines/trace-event-perl.o
516 LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o 522 LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o
517endif 523endif
518 524
525ifndef NO_LIBPYTHON
526PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null`
527PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
528endif
529
530ifneq ($(shell sh -c "(echo '\#include <Python.h>'; echo 'int main(void) { Py_Initialize(); return 0; }') | $(CC) -x c - $(PYTHON_EMBED_CCOPTS) -o /dev/null $(PYTHON_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
531 BASIC_CFLAGS += -DNO_LIBPYTHON
532else
533 ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS)
534 LIB_OBJS += util/scripting-engines/trace-event-python.o
535 LIB_OBJS += scripts/python/Perf-Trace-Util/Context.o
536endif
537
519ifdef NO_DEMANGLE 538ifdef NO_DEMANGLE
520 BASIC_CFLAGS += -DNO_DEMANGLE 539 BASIC_CFLAGS += -DNO_DEMANGLE
521else 540else
522 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y") 541 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y")
523 542
524 ifeq ($(has_bfd),y) 543 ifeq ($(has_bfd),y)
525 EXTLIBS += -lbfd 544 EXTLIBS += -lbfd
526 else 545 else
527 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y") 546 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y")
528 ifeq ($(has_bfd_iberty),y) 547 ifeq ($(has_bfd_iberty),y)
529 EXTLIBS += -lbfd -liberty 548 EXTLIBS += -lbfd -liberty
530 else 549 else
531 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y") 550 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y")
532 ifeq ($(has_bfd_iberty_z),y) 551 ifeq ($(has_bfd_iberty_z),y)
533 EXTLIBS += -lbfd -liberty -lz 552 EXTLIBS += -lbfd -liberty -lz
534 else 553 else
535 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y") 554 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y")
536 ifeq ($(has_cplus_demangle),y) 555 ifeq ($(has_cplus_demangle),y)
537 EXTLIBS += -liberty 556 EXTLIBS += -liberty
538 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 557 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
@@ -780,7 +799,7 @@ export TAR INSTALL DESTDIR SHELL_PATH
780 799
781SHELL = $(SHELL_PATH) 800SHELL = $(SHELL_PATH)
782 801
783all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS 802all:: .perf.dev.null shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS
784ifneq (,$X) 803ifneq (,$X)
785 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) 804 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
786endif 805endif
@@ -887,12 +906,18 @@ util/hweight.o: ../../lib/hweight.c PERF-CFLAGS
887util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS 906util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS
888 $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 907 $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
889 908
890util/trace-event-perl.o: util/trace-event-perl.c PERF-CFLAGS 909util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c PERF-CFLAGS
891 $(QUIET_CC)$(CC) -o util/trace-event-perl.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< 910 $(QUIET_CC)$(CC) -o util/scripting-engines/trace-event-perl.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
892 911
893scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS 912scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS
894 $(QUIET_CC)$(CC) -o scripts/perl/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 913 $(QUIET_CC)$(CC) -o scripts/perl/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
895 914
915util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c PERF-CFLAGS
916 $(QUIET_CC)$(CC) -o util/scripting-engines/trace-event-python.o -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
917
918scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c PERF-CFLAGS
919 $(QUIET_CC)$(CC) -o scripts/python/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
920
896perf-%$X: %.o $(PERFLIBS) 921perf-%$X: %.o $(PERFLIBS)
897 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 922 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
898 923
@@ -1002,9 +1027,16 @@ install: all
1002 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 1027 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
1003 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 1028 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1004 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 1029 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1030 $(INSTALL) perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1005 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 1031 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1006 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl' 1032 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
1007 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 1033 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1034 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1035 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1036 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1037 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1038 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1039
1008ifdef BUILT_INS 1040ifdef BUILT_INS
1009 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1041 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1010 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1042 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -1107,6 +1139,11 @@ clean:
1107.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 1139.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
1108.PHONY: .FORCE-PERF-BUILD-OPTIONS 1140.PHONY: .FORCE-PERF-BUILD-OPTIONS
1109 1141
1142.perf.dev.null:
1143 touch .perf.dev.null
1144
1145.INTERMEDIATE: .perf.dev.null
1146
1110### Make sure built-ins do not have dups and listed in perf.c 1147### Make sure built-ins do not have dups and listed in perf.c
1111# 1148#
1112check-builtins:: 1149check-builtins::
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 593ff25006de..5ec5de995872 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -53,32 +53,20 @@ struct sym_priv {
53 53
54static const char *sym_hist_filter; 54static const char *sym_hist_filter;
55 55
56static int symbol_filter(struct map *map __used, struct symbol *sym) 56static int sym__alloc_hist(struct symbol *self)
57{ 57{
58 if (sym_hist_filter == NULL || 58 struct sym_priv *priv = symbol__priv(self);
59 strcmp(sym->name, sym_hist_filter) == 0) { 59 const int size = (sizeof(*priv->hist) +
60 struct sym_priv *priv = symbol__priv(sym); 60 (self->end - self->start) * sizeof(u64));
61 const int size = (sizeof(*priv->hist) +
62 (sym->end - sym->start) * sizeof(u64));
63 61
64 priv->hist = malloc(size); 62 priv->hist = zalloc(size);
65 if (priv->hist) 63 return priv->hist == NULL ? -1 : 0;
66 memset(priv->hist, 0, size);
67 return 0;
68 }
69 /*
70 * FIXME: We should really filter it out, as we don't want to go thru symbols
71 * we're not interested, and if a DSO ends up with no symbols, delete it too,
72 * but right now the kernel loading routines in symbol.c bail out if no symbols
73 * are found, fix it later.
74 */
75 return 0;
76} 64}
77 65
78/* 66/*
79 * collect histogram counts 67 * collect histogram counts
80 */ 68 */
81static void hist_hit(struct hist_entry *he, u64 ip) 69static int annotate__hist_hit(struct hist_entry *he, u64 ip)
82{ 70{
83 unsigned int sym_size, offset; 71 unsigned int sym_size, offset;
84 struct symbol *sym = he->sym; 72 struct symbol *sym = he->sym;
@@ -88,83 +76,127 @@ static void hist_hit(struct hist_entry *he, u64 ip)
88 he->count++; 76 he->count++;
89 77
90 if (!sym || !he->map) 78 if (!sym || !he->map)
91 return; 79 return 0;
92 80
93 priv = symbol__priv(sym); 81 priv = symbol__priv(sym);
94 if (!priv->hist) 82 if (priv->hist == NULL && sym__alloc_hist(sym) < 0)
95 return; 83 return -ENOMEM;
96 84
97 sym_size = sym->end - sym->start; 85 sym_size = sym->end - sym->start;
98 offset = ip - sym->start; 86 offset = ip - sym->start;
99 87
100 if (verbose) 88 pr_debug3("%s: ip=%#Lx\n", __func__, he->map->unmap_ip(he->map, ip));
101 fprintf(stderr, "%s: ip=%Lx\n", __func__,
102 he->map->unmap_ip(he->map, ip));
103 89
104 if (offset >= sym_size) 90 if (offset >= sym_size)
105 return; 91 return 0;
106 92
107 h = priv->hist; 93 h = priv->hist;
108 h->sum++; 94 h->sum++;
109 h->ip[offset]++; 95 h->ip[offset]++;
110 96
111 if (verbose >= 3) 97 pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", he->sym->start,
112 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", 98 he->sym->name, ip, ip - he->sym->start, h->ip[offset]);
113 (void *)(unsigned long)he->sym->start, 99 return 0;
114 he->sym->name,
115 (void *)(unsigned long)ip, ip - he->sym->start,
116 h->ip[offset]);
117} 100}
118 101
119static int perf_session__add_hist_entry(struct perf_session *self, 102static int perf_session__add_hist_entry(struct perf_session *self,
120 struct addr_location *al, u64 count) 103 struct addr_location *al, u64 count)
121{ 104{
122 bool hit; 105 bool hit;
123 struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL, 106 struct hist_entry *he;
124 count, &hit); 107
108 if (sym_hist_filter != NULL &&
109 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
110 /* We're only interested in a symbol named sym_hist_filter */
111 if (al->sym != NULL) {
112 rb_erase(&al->sym->rb_node,
113 &al->map->dso->symbols[al->map->type]);
114 symbol__delete(al->sym);
115 }
116 return 0;
117 }
118
119 he = __perf_session__add_hist_entry(self, al, NULL, count, &hit);
125 if (he == NULL) 120 if (he == NULL)
126 return -ENOMEM; 121 return -ENOMEM;
127 hist_hit(he, al->addr); 122
128 return 0; 123 return annotate__hist_hit(he, al->addr);
129} 124}
130 125
131static int process_sample_event(event_t *event, struct perf_session *session) 126static int process_sample_event(event_t *event, struct perf_session *session)
132{ 127{
133 struct addr_location al; 128 struct addr_location al;
134 129
135 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 130 dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
136 event->ip.pid, (void *)(long)event->ip.ip); 131 event->ip.pid, event->ip.ip);
137 132
138 if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) { 133 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
139 fprintf(stderr, "problem processing %d event, skipping it.\n", 134 pr_warning("problem processing %d event, skipping it.\n",
140 event->header.type); 135 event->header.type);
141 return -1; 136 return -1;
142 } 137 }
143 138
144 if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) { 139 if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) {
145 fprintf(stderr, "problem incrementing symbol count, " 140 pr_warning("problem incrementing symbol count, "
146 "skipping event\n"); 141 "skipping event\n");
147 return -1; 142 return -1;
148 } 143 }
149 144
150 return 0; 145 return 0;
151} 146}
152 147
153static int parse_line(FILE *file, struct hist_entry *he, u64 len) 148struct objdump_line {
149 struct list_head node;
150 s64 offset;
151 char *line;
152};
153
154static struct objdump_line *objdump_line__new(s64 offset, char *line)
155{
156 struct objdump_line *self = malloc(sizeof(*self));
157
158 if (self != NULL) {
159 self->offset = offset;
160 self->line = line;
161 }
162
163 return self;
164}
165
166static void objdump_line__free(struct objdump_line *self)
167{
168 free(self->line);
169 free(self);
170}
171
172static void objdump__add_line(struct list_head *head, struct objdump_line *line)
173{
174 list_add_tail(&line->node, head);
175}
176
177static struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
178 struct objdump_line *pos)
179{
180 list_for_each_entry_continue(pos, head, node)
181 if (pos->offset >= 0)
182 return pos;
183
184 return NULL;
185}
186
187static int parse_line(FILE *file, struct hist_entry *he,
188 struct list_head *head)
154{ 189{
155 struct symbol *sym = he->sym; 190 struct symbol *sym = he->sym;
191 struct objdump_line *objdump_line;
156 char *line = NULL, *tmp, *tmp2; 192 char *line = NULL, *tmp, *tmp2;
157 static const char *prev_line;
158 static const char *prev_color;
159 unsigned int offset;
160 size_t line_len; 193 size_t line_len;
161 u64 start; 194 s64 line_ip, offset = -1;
162 s64 line_ip;
163 int ret;
164 char *c; 195 char *c;
165 196
166 if (getline(&line, &line_len, file) < 0) 197 if (getline(&line, &line_len, file) < 0)
167 return -1; 198 return -1;
199
168 if (!line) 200 if (!line)
169 return -1; 201 return -1;
170 202
@@ -173,8 +205,6 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
173 *c = 0; 205 *c = 0;
174 206
175 line_ip = -1; 207 line_ip = -1;
176 offset = 0;
177 ret = -2;
178 208
179 /* 209 /*
180 * Strip leading spaces: 210 * Strip leading spaces:
@@ -195,9 +225,30 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
195 line_ip = -1; 225 line_ip = -1;
196 } 226 }
197 227
198 start = he->map->unmap_ip(he->map, sym->start);
199
200 if (line_ip != -1) { 228 if (line_ip != -1) {
229 u64 start = map__rip_2objdump(he->map, sym->start);
230 offset = line_ip - start;
231 }
232
233 objdump_line = objdump_line__new(offset, line);
234 if (objdump_line == NULL) {
235 free(line);
236 return -1;
237 }
238 objdump__add_line(head, objdump_line);
239
240 return 0;
241}
242
243static int objdump_line__print(struct objdump_line *self,
244 struct list_head *head,
245 struct hist_entry *he, u64 len)
246{
247 struct symbol *sym = he->sym;
248 static const char *prev_line;
249 static const char *prev_color;
250
251 if (self->offset != -1) {
201 const char *path = NULL; 252 const char *path = NULL;
202 unsigned int hits = 0; 253 unsigned int hits = 0;
203 double percent = 0.0; 254 double percent = 0.0;
@@ -205,15 +256,22 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
205 struct sym_priv *priv = symbol__priv(sym); 256 struct sym_priv *priv = symbol__priv(sym);
206 struct sym_ext *sym_ext = priv->ext; 257 struct sym_ext *sym_ext = priv->ext;
207 struct sym_hist *h = priv->hist; 258 struct sym_hist *h = priv->hist;
259 s64 offset = self->offset;
260 struct objdump_line *next = objdump__get_next_ip_line(head, self);
261
262 while (offset < (s64)len &&
263 (next == NULL || offset < next->offset)) {
264 if (sym_ext) {
265 if (path == NULL)
266 path = sym_ext[offset].path;
267 percent += sym_ext[offset].percent;
268 } else
269 hits += h->ip[offset];
270
271 ++offset;
272 }
208 273
209 offset = line_ip - start; 274 if (sym_ext == NULL && h->sum)
210 if (offset < len)
211 hits = h->ip[offset];
212
213 if (offset < len && sym_ext) {
214 path = sym_ext[offset].path;
215 percent = sym_ext[offset].percent;
216 } else if (h->sum)
217 percent = 100.0 * hits / h->sum; 275 percent = 100.0 * hits / h->sum;
218 276
219 color = get_percent_color(percent); 277 color = get_percent_color(percent);
@@ -234,12 +292,12 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
234 292
235 color_fprintf(stdout, color, " %7.2f", percent); 293 color_fprintf(stdout, color, " %7.2f", percent);
236 printf(" : "); 294 printf(" : ");
237 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); 295 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
238 } else { 296 } else {
239 if (!*line) 297 if (!*self->line)
240 printf(" :\n"); 298 printf(" :\n");
241 else 299 else
242 printf(" : %s\n", line); 300 printf(" : %s\n", self->line);
243 } 301 }
244 302
245 return 0; 303 return 0;
@@ -365,6 +423,20 @@ static void print_summary(const char *filename)
365 } 423 }
366} 424}
367 425
426static void hist_entry__print_hits(struct hist_entry *self)
427{
428 struct symbol *sym = self->sym;
429 struct sym_priv *priv = symbol__priv(sym);
430 struct sym_hist *h = priv->hist;
431 u64 len = sym->end - sym->start, offset;
432
433 for (offset = 0; offset < len; ++offset)
434 if (h->ip[offset] != 0)
435 printf("%*Lx: %Lu\n", BITS_PER_LONG / 2,
436 sym->start + offset, h->ip[offset]);
437 printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum);
438}
439
368static void annotate_sym(struct hist_entry *he) 440static void annotate_sym(struct hist_entry *he)
369{ 441{
370 struct map *map = he->map; 442 struct map *map = he->map;
@@ -374,15 +446,15 @@ static void annotate_sym(struct hist_entry *he)
374 u64 len; 446 u64 len;
375 char command[PATH_MAX*2]; 447 char command[PATH_MAX*2];
376 FILE *file; 448 FILE *file;
449 LIST_HEAD(head);
450 struct objdump_line *pos, *n;
377 451
378 if (!filename) 452 if (!filename)
379 return; 453 return;
380 454
381 if (verbose) 455 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
382 fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n", 456 filename, sym->name, map->unmap_ip(map, sym->start),
383 __func__, filename, sym->name, 457 map->unmap_ip(map, sym->end));
384 map->unmap_ip(map, sym->start),
385 map->unmap_ip(map, sym->end));
386 458
387 if (full_paths) 459 if (full_paths)
388 d_filename = filename; 460 d_filename = filename;
@@ -405,7 +477,8 @@ static void annotate_sym(struct hist_entry *he)
405 dso, dso->long_name, sym, sym->name); 477 dso, dso->long_name, sym, sym->name);
406 478
407 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", 479 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
408 map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end), 480 map__rip_2objdump(map, sym->start),
481 map__rip_2objdump(map, sym->end),
409 filename, filename); 482 filename, filename);
410 483
411 if (verbose >= 3) 484 if (verbose >= 3)
@@ -416,11 +489,21 @@ static void annotate_sym(struct hist_entry *he)
416 return; 489 return;
417 490
418 while (!feof(file)) { 491 while (!feof(file)) {
419 if (parse_line(file, he, len) < 0) 492 if (parse_line(file, he, &head) < 0)
420 break; 493 break;
421 } 494 }
422 495
423 pclose(file); 496 pclose(file);
497
498 if (verbose)
499 hist_entry__print_hits(he);
500
501 list_for_each_entry_safe(pos, n, &head, node) {
502 objdump_line__print(pos, &head, he, len);
503 list_del(&pos->node);
504 objdump_line__free(pos);
505 }
506
424 if (print_line) 507 if (print_line)
425 free_source_line(he, len); 508 free_source_line(he, len);
426} 509}
@@ -451,10 +534,10 @@ static void perf_session__find_annotations(struct perf_session *self)
451} 534}
452 535
453static struct perf_event_ops event_ops = { 536static struct perf_event_ops event_ops = {
454 .process_sample_event = process_sample_event, 537 .sample = process_sample_event,
455 .process_mmap_event = event__process_mmap, 538 .mmap = event__process_mmap,
456 .process_comm_event = event__process_comm, 539 .comm = event__process_comm,
457 .process_fork_event = event__process_task, 540 .fork = event__process_task,
458}; 541};
459 542
460static int __cmd_annotate(void) 543static int __cmd_annotate(void)
@@ -542,9 +625,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
542 setup_pager(); 625 setup_pager();
543 626
544 if (field_sep && *field_sep == '.') { 627 if (field_sep && *field_sep == '.') {
545 fputs("'.' is the only non valid --field-separator argument\n", 628 pr_err("'.' is the only non valid --field-separator argument\n");
546 stderr); 629 return -1;
547 exit(129);
548 } 630 }
549 631
550 return __cmd_annotate(); 632 return __cmd_annotate();
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
new file mode 100644
index 000000000000..30a05f552c96
--- /dev/null
+++ b/tools/perf/builtin-buildid-cache.c
@@ -0,0 +1,133 @@
1/*
2 * builtin-buildid-cache.c
3 *
4 * Builtin buildid-cache command: Manages build-id cache
5 *
6 * Copyright (C) 2010, Red Hat Inc.
7 * Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "builtin.h"
10#include "perf.h"
11#include "util/cache.h"
12#include "util/debug.h"
13#include "util/header.h"
14#include "util/parse-options.h"
15#include "util/strlist.h"
16#include "util/symbol.h"
17
18static char const *add_name_list_str, *remove_name_list_str;
19
20static const char * const buildid_cache_usage[] = {
21 "perf buildid-cache [<options>]",
22 NULL
23};
24
25static const struct option buildid_cache_options[] = {
26 OPT_STRING('a', "add", &add_name_list_str,
27 "file list", "file(s) to add"),
28 OPT_STRING('r', "remove", &remove_name_list_str, "file list",
29 "file(s) to remove"),
30 OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose"),
31 OPT_END()
32};
33
34static int build_id_cache__add_file(const char *filename, const char *debugdir)
35{
36 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
37 u8 build_id[BUILD_ID_SIZE];
38 int err;
39
40 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
41 pr_debug("Couldn't read a build-id in %s\n", filename);
42 return -1;
43 }
44
45 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
46 err = build_id_cache__add_s(sbuild_id, debugdir, filename, false);
47 if (verbose)
48 pr_info("Adding %s %s: %s\n", sbuild_id, filename,
49 err ? "FAIL" : "Ok");
50 return err;
51}
52
53static int build_id_cache__remove_file(const char *filename __used,
54 const char *debugdir __used)
55{
56 u8 build_id[BUILD_ID_SIZE];
57 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
58
59 int err;
60
61 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
62 pr_debug("Couldn't read a build-id in %s\n", filename);
63 return -1;
64 }
65
66 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
67 err = build_id_cache__remove_s(sbuild_id, debugdir);
68 if (verbose)
69 pr_info("Removing %s %s: %s\n", sbuild_id, filename,
70 err ? "FAIL" : "Ok");
71
72 return err;
73}
74
75static int __cmd_buildid_cache(void)
76{
77 struct strlist *list;
78 struct str_node *pos;
79 char debugdir[PATH_MAX];
80
81 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
82 DEBUG_CACHE_DIR);
83
84 if (add_name_list_str) {
85 list = strlist__new(true, add_name_list_str);
86 if (list) {
87 strlist__for_each(pos, list)
88 if (build_id_cache__add_file(pos->s, debugdir)) {
89 if (errno == EEXIST) {
90 pr_debug("%s already in the cache\n",
91 pos->s);
92 continue;
93 }
94 pr_warning("Couldn't add %s: %s\n",
95 pos->s, strerror(errno));
96 }
97
98 strlist__delete(list);
99 }
100 }
101
102 if (remove_name_list_str) {
103 list = strlist__new(true, remove_name_list_str);
104 if (list) {
105 strlist__for_each(pos, list)
106 if (build_id_cache__remove_file(pos->s, debugdir)) {
107 if (errno == ENOENT) {
108 pr_debug("%s wasn't in the cache\n",
109 pos->s);
110 continue;
111 }
112 pr_warning("Couldn't remove %s: %s\n",
113 pos->s, strerror(errno));
114 }
115
116 strlist__delete(list);
117 }
118 }
119
120 return 0;
121}
122
123int cmd_buildid_cache(int argc, const char **argv, const char *prefix __used)
124{
125 argc = parse_options(argc, argv, buildid_cache_options,
126 buildid_cache_usage, 0);
127
128 if (symbol__init() < 0)
129 return -1;
130
131 setup_pager();
132 return __cmd_buildid_cache();
133}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 1e99ac806913..d0675c02f81e 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -8,6 +8,7 @@
8 */ 8 */
9#include "builtin.h" 9#include "builtin.h"
10#include "perf.h" 10#include "perf.h"
11#include "util/build-id.h"
11#include "util/cache.h" 12#include "util/cache.h"
12#include "util/debug.h" 13#include "util/debug.h"
13#include "util/parse-options.h" 14#include "util/parse-options.h"
@@ -16,6 +17,7 @@
16 17
17static char const *input_name = "perf.data"; 18static char const *input_name = "perf.data";
18static int force; 19static int force;
20static bool with_hits;
19 21
20static const char * const buildid_list_usage[] = { 22static const char * const buildid_list_usage[] = {
21 "perf buildid-list [<options>]", 23 "perf buildid-list [<options>]",
@@ -23,6 +25,7 @@ static const char * const buildid_list_usage[] = {
23}; 25};
24 26
25static const struct option options[] = { 27static const struct option options[] = {
28 OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"),
26 OPT_STRING('i', "input", &input_name, "file", 29 OPT_STRING('i', "input", &input_name, "file",
27 "input file name"), 30 "input file name"),
28 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 31 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
@@ -31,26 +34,6 @@ static const struct option options[] = {
31 OPT_END() 34 OPT_END()
32}; 35};
33 36
34static int perf_file_section__process_buildids(struct perf_file_section *self,
35 int feat, int fd)
36{
37 if (feat != HEADER_BUILD_ID)
38 return 0;
39
40 if (lseek(fd, self->offset, SEEK_SET) < 0) {
41 pr_warning("Failed to lseek to %Ld offset for buildids!\n",
42 self->offset);
43 return -1;
44 }
45
46 if (perf_header__read_build_ids(fd, self->offset, self->size)) {
47 pr_warning("Failed to read buildids!\n");
48 return -1;
49 }
50
51 return 0;
52}
53
54static int __cmd_buildid_list(void) 37static int __cmd_buildid_list(void)
55{ 38{
56 int err = -1; 39 int err = -1;
@@ -60,10 +43,10 @@ static int __cmd_buildid_list(void)
60 if (session == NULL) 43 if (session == NULL)
61 return -1; 44 return -1;
62 45
63 err = perf_header__process_sections(&session->header, session->fd, 46 if (with_hits)
64 perf_file_section__process_buildids); 47 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
65 if (err >= 0) 48
66 dsos__fprintf_buildid(stdout); 49 dsos__fprintf_buildid(stdout, with_hits);
67 50
68 perf_session__delete(session); 51 perf_session__delete(session);
69 return err; 52 return err;
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index bd71b8ceafb7..18b3f505f9db 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -42,8 +42,8 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
42 struct addr_location al; 42 struct addr_location al;
43 struct sample_data data = { .period = 1, }; 43 struct sample_data data = { .period = 1, };
44 44
45 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 45 dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
46 event->ip.pid, (void *)(long)event->ip.ip); 46 event->ip.pid, event->ip.ip);
47 47
48 if (event__preprocess_sample(event, session, &al, NULL) < 0) { 48 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
49 pr_warning("problem processing %d event, skipping it.\n", 49 pr_warning("problem processing %d event, skipping it.\n",
@@ -51,12 +51,12 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
51 return -1; 51 return -1;
52 } 52 }
53 53
54 if (al.filtered) 54 if (al.filtered || al.sym == NULL)
55 return 0; 55 return 0;
56 56
57 event__parse_sample(event, session->sample_type, &data); 57 event__parse_sample(event, session->sample_type, &data);
58 58
59 if (al.sym && perf_session__add_hist_entry(session, &al, data.period)) { 59 if (perf_session__add_hist_entry(session, &al, data.period)) {
60 pr_warning("problem incrementing symbol count, skipping event\n"); 60 pr_warning("problem incrementing symbol count, skipping event\n");
61 return -1; 61 return -1;
62 } 62 }
@@ -66,12 +66,12 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
66} 66}
67 67
68static struct perf_event_ops event_ops = { 68static struct perf_event_ops event_ops = {
69 .process_sample_event = diff__process_sample_event, 69 .sample = diff__process_sample_event,
70 .process_mmap_event = event__process_mmap, 70 .mmap = event__process_mmap,
71 .process_comm_event = event__process_comm, 71 .comm = event__process_comm,
72 .process_exit_event = event__process_task, 72 .exit = event__process_task,
73 .process_fork_event = event__process_task, 73 .fork = event__process_task,
74 .process_lost_event = event__process_lost, 74 .lost = event__process_lost,
75}; 75};
76 76
77static void perf_session__insert_hist_entry_by_name(struct rb_root *root, 77static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
@@ -82,29 +82,19 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
82 struct hist_entry *iter; 82 struct hist_entry *iter;
83 83
84 while (*p != NULL) { 84 while (*p != NULL) {
85 int cmp;
86 parent = *p; 85 parent = *p;
87 iter = rb_entry(parent, struct hist_entry, rb_node); 86 iter = rb_entry(parent, struct hist_entry, rb_node);
88 87 if (hist_entry__cmp(he, iter) < 0)
89 cmp = strcmp(he->map->dso->name, iter->map->dso->name);
90 if (cmp > 0)
91 p = &(*p)->rb_left; 88 p = &(*p)->rb_left;
92 else if (cmp < 0) 89 else
93 p = &(*p)->rb_right; 90 p = &(*p)->rb_right;
94 else {
95 cmp = strcmp(he->sym->name, iter->sym->name);
96 if (cmp > 0)
97 p = &(*p)->rb_left;
98 else
99 p = &(*p)->rb_right;
100 }
101 } 91 }
102 92
103 rb_link_node(&he->rb_node, parent, p); 93 rb_link_node(&he->rb_node, parent, p);
104 rb_insert_color(&he->rb_node, root); 94 rb_insert_color(&he->rb_node, root);
105} 95}
106 96
107static void perf_session__resort_by_name(struct perf_session *self) 97static void perf_session__resort_hist_entries(struct perf_session *self)
108{ 98{
109 unsigned long position = 1; 99 unsigned long position = 1;
110 struct rb_root tmp = RB_ROOT; 100 struct rb_root tmp = RB_ROOT;
@@ -122,29 +112,28 @@ static void perf_session__resort_by_name(struct perf_session *self)
122 self->hists = tmp; 112 self->hists = tmp;
123} 113}
124 114
115static void perf_session__set_hist_entries_positions(struct perf_session *self)
116{
117 perf_session__output_resort(self, self->events_stats.total);
118 perf_session__resort_hist_entries(self);
119}
120
125static struct hist_entry * 121static struct hist_entry *
126perf_session__find_hist_entry_by_name(struct perf_session *self, 122perf_session__find_hist_entry(struct perf_session *self,
127 struct hist_entry *he) 123 struct hist_entry *he)
128{ 124{
129 struct rb_node *n = self->hists.rb_node; 125 struct rb_node *n = self->hists.rb_node;
130 126
131 while (n) { 127 while (n) {
132 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); 128 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
133 int cmp = strcmp(he->map->dso->name, iter->map->dso->name); 129 int64_t cmp = hist_entry__cmp(he, iter);
134 130
135 if (cmp > 0) 131 if (cmp < 0)
136 n = n->rb_left; 132 n = n->rb_left;
137 else if (cmp < 0) 133 else if (cmp > 0)
138 n = n->rb_right; 134 n = n->rb_right;
139 else { 135 else
140 cmp = strcmp(he->sym->name, iter->sym->name); 136 return iter;
141 if (cmp > 0)
142 n = n->rb_left;
143 else if (cmp < 0)
144 n = n->rb_right;
145 else
146 return iter;
147 }
148 } 137 }
149 138
150 return NULL; 139 return NULL;
@@ -155,11 +144,9 @@ static void perf_session__match_hists(struct perf_session *old_session,
155{ 144{
156 struct rb_node *nd; 145 struct rb_node *nd;
157 146
158 perf_session__resort_by_name(old_session);
159
160 for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) { 147 for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) {
161 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node); 148 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
162 pos->pair = perf_session__find_hist_entry_by_name(old_session, pos); 149 pos->pair = perf_session__find_hist_entry(old_session, pos);
163 } 150 }
164} 151}
165 152
@@ -177,9 +164,12 @@ static int __cmd_diff(void)
177 ret = perf_session__process_events(session[i], &event_ops); 164 ret = perf_session__process_events(session[i], &event_ops);
178 if (ret) 165 if (ret)
179 goto out_delete; 166 goto out_delete;
180 perf_session__output_resort(session[i], session[i]->events_stats.total);
181 } 167 }
182 168
169 perf_session__output_resort(session[1], session[1]->events_stats.total);
170 if (show_displacement)
171 perf_session__set_hist_entries_positions(session[0]);
172
183 perf_session__match_hists(session[0], session[1]); 173 perf_session__match_hists(session[0], session[1]);
184 perf_session__fprintf_hists(session[1], session[0], 174 perf_session__fprintf_hists(session[1], session[0],
185 show_displacement, stdout); 175 show_displacement, stdout);
@@ -204,7 +194,7 @@ static const struct option options[] = {
204 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 194 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
205 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 195 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
206 "load module symbols - WARNING: use only with -k and LIVE kernel"), 196 "load module symbols - WARNING: use only with -k and LIVE kernel"),
207 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, 197 OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
208 "Don't shorten the pathnames taking into account the cwd"), 198 "Don't shorten the pathnames taking into account the cwd"),
209 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 199 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
210 "only consider symbols in these dsos"), 200 "only consider symbols in these dsos"),
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 9f810b17c25c..215b584007b1 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -286,8 +286,7 @@ void list_common_cmds_help(void)
286 286
287 puts(" The most commonly used perf commands are:"); 287 puts(" The most commonly used perf commands are:");
288 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { 288 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
289 printf(" %s ", common_cmds[i].name); 289 printf(" %-*s ", longest, common_cmds[i].name);
290 mput_char(' ', longest - strlen(common_cmds[i].name));
291 puts(common_cmds[i].help); 290 puts(common_cmds[i].help);
292 } 291 }
293} 292}
@@ -314,8 +313,6 @@ static const char *cmd_to_page(const char *perf_cmd)
314 return "perf"; 313 return "perf";
315 else if (!prefixcmp(perf_cmd, "perf")) 314 else if (!prefixcmp(perf_cmd, "perf"))
316 return perf_cmd; 315 return perf_cmd;
317 else if (is_perf_command(perf_cmd))
318 return prepend("perf-", perf_cmd);
319 else 316 else
320 return prepend("perf-", perf_cmd); 317 return prepend("perf-", perf_cmd);
321} 318}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 7ceb7416c316..924a9518931a 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -92,23 +92,18 @@ static void setup_cpunode_map(void)
92 if (!dir1) 92 if (!dir1)
93 return; 93 return;
94 94
95 while (true) { 95 while ((dent1 = readdir(dir1)) != NULL) {
96 dent1 = readdir(dir1); 96 if (dent1->d_type != DT_DIR ||
97 if (!dent1) 97 sscanf(dent1->d_name, "node%u", &mem) < 1)
98 break;
99
100 if (sscanf(dent1->d_name, "node%u", &mem) < 1)
101 continue; 98 continue;
102 99
103 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name); 100 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
104 dir2 = opendir(buf); 101 dir2 = opendir(buf);
105 if (!dir2) 102 if (!dir2)
106 continue; 103 continue;
107 while (true) { 104 while ((dent2 = readdir(dir2)) != NULL) {
108 dent2 = readdir(dir2); 105 if (dent2->d_type != DT_LNK ||
109 if (!dent2) 106 sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
110 break;
111 if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
112 continue; 107 continue;
113 cpunode_map[cpu] = mem; 108 cpunode_map[cpu] = mem;
114 } 109 }
@@ -321,11 +316,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
321 316
322 event__parse_sample(event, session->sample_type, &data); 317 event__parse_sample(event, session->sample_type, &data);
323 318
324 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 319 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
325 event->header.misc, 320 data.pid, data.tid, data.ip, data.period);
326 data.pid, data.tid,
327 (void *)(long)data.ip,
328 (long long)data.period);
329 321
330 thread = perf_session__findnew(session, event->ip.pid); 322 thread = perf_session__findnew(session, event->ip.pid);
331 if (thread == NULL) { 323 if (thread == NULL) {
@@ -342,22 +334,9 @@ static int process_sample_event(event_t *event, struct perf_session *session)
342 return 0; 334 return 0;
343} 335}
344 336
345static int sample_type_check(struct perf_session *session)
346{
347 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
348 fprintf(stderr,
349 "No trace sample to read. Did you call perf record "
350 "without -R?");
351 return -1;
352 }
353
354 return 0;
355}
356
357static struct perf_event_ops event_ops = { 337static struct perf_event_ops event_ops = {
358 .process_sample_event = process_sample_event, 338 .sample = process_sample_event,
359 .process_comm_event = event__process_comm, 339 .comm = event__process_comm,
360 .sample_type_check = sample_type_check,
361}; 340};
362 341
363static double fragmentation(unsigned long n_req, unsigned long n_alloc) 342static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -375,7 +354,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
375 354
376 printf("%.102s\n", graph_dotted_line); 355 printf("%.102s\n", graph_dotted_line);
377 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); 356 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
378 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n"); 357 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
379 printf("%.102s\n", graph_dotted_line); 358 printf("%.102s\n", graph_dotted_line);
380 359
381 next = rb_first(root); 360 next = rb_first(root);
@@ -390,7 +369,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
390 if (is_caller) { 369 if (is_caller) {
391 addr = data->call_site; 370 addr = data->call_site;
392 if (!raw_ip) 371 if (!raw_ip)
393 sym = map_groups__find_function(&session->kmaps, session, addr, NULL); 372 sym = map_groups__find_function(&session->kmaps, addr, NULL);
394 } else 373 } else
395 addr = data->ptr; 374 addr = data->ptr;
396 375
@@ -401,7 +380,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
401 snprintf(buf, sizeof(buf), "%#Lx", addr); 380 snprintf(buf, sizeof(buf), "%#Lx", addr);
402 printf(" %-34s |", buf); 381 printf(" %-34s |", buf);
403 382
404 printf(" %9llu/%-5lu | %9llu/%-5lu | %6lu | %8lu | %6.3f%%\n", 383 printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%%\n",
405 (unsigned long long)data->bytes_alloc, 384 (unsigned long long)data->bytes_alloc,
406 (unsigned long)data->bytes_alloc / data->hit, 385 (unsigned long)data->bytes_alloc / data->hit,
407 (unsigned long long)data->bytes_req, 386 (unsigned long long)data->bytes_req,
@@ -504,11 +483,14 @@ static void sort_result(void)
504 483
505static int __cmd_kmem(void) 484static int __cmd_kmem(void)
506{ 485{
507 int err; 486 int err = -EINVAL;
508 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 487 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
509 if (session == NULL) 488 if (session == NULL)
510 return -ENOMEM; 489 return -ENOMEM;
511 490
491 if (!perf_session__has_traces(session, "kmem record"))
492 goto out_delete;
493
512 setup_pager(); 494 setup_pager();
513 err = perf_session__process_events(session, &event_ops); 495 err = perf_session__process_events(session, &event_ops);
514 if (err != 0) 496 if (err != 0)
@@ -784,7 +766,8 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __used)
784 setup_sorting(&alloc_sort, default_sort_order); 766 setup_sorting(&alloc_sort, default_sort_order);
785 767
786 return __cmd_kmem(); 768 return __cmd_kmem();
787 } 769 } else
770 usage_with_options(kmem_usage, kmem_options);
788 771
789 return 0; 772 return 0;
790} 773}
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
new file mode 100644
index 000000000000..e12c844df1e2
--- /dev/null
+++ b/tools/perf/builtin-lock.c
@@ -0,0 +1,822 @@
1#include "builtin.h"
2#include "perf.h"
3
4#include "util/util.h"
5#include "util/cache.h"
6#include "util/symbol.h"
7#include "util/thread.h"
8#include "util/header.h"
9
10#include "util/parse-options.h"
11#include "util/trace-event.h"
12
13#include "util/debug.h"
14#include "util/session.h"
15
16#include <sys/types.h>
17#include <sys/prctl.h>
18#include <semaphore.h>
19#include <pthread.h>
20#include <math.h>
21#include <limits.h>
22
23#include <linux/list.h>
24#include <linux/hash.h>
25
26/* based on kernel/lockdep.c */
27#define LOCKHASH_BITS 12
28#define LOCKHASH_SIZE (1UL << LOCKHASH_BITS)
29
30static struct list_head lockhash_table[LOCKHASH_SIZE];
31
32#define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS)
33#define lockhashentry(key) (lockhash_table + __lockhashfn((key)))
34
35#define LOCK_STATE_UNLOCKED 0 /* initial state */
36#define LOCK_STATE_LOCKED 1
37
38struct lock_stat {
39 struct list_head hash_entry;
40 struct rb_node rb; /* used for sorting */
41
42 /*
43 * FIXME: raw_field_value() returns unsigned long long,
44 * so address of lockdep_map should be dealed as 64bit.
45 * Is there more better solution?
46 */
47 void *addr; /* address of lockdep_map, used as ID */
48 char *name; /* for strcpy(), we cannot use const */
49
50 int state;
51 u64 prev_event_time; /* timestamp of previous event */
52
53 unsigned int nr_acquired;
54 unsigned int nr_acquire;
55 unsigned int nr_contended;
56 unsigned int nr_release;
57
58 /* these times are in nano sec. */
59 u64 wait_time_total;
60 u64 wait_time_min;
61 u64 wait_time_max;
62};
63
64/* build simple key function one is bigger than two */
65#define SINGLE_KEY(member) \
66 static int lock_stat_key_ ## member(struct lock_stat *one, \
67 struct lock_stat *two) \
68 { \
69 return one->member > two->member; \
70 }
71
72SINGLE_KEY(nr_acquired)
73SINGLE_KEY(nr_contended)
74SINGLE_KEY(wait_time_total)
75SINGLE_KEY(wait_time_min)
76SINGLE_KEY(wait_time_max)
77
78struct lock_key {
79 /*
80 * name: the value for specify by user
81 * this should be simpler than raw name of member
82 * e.g. nr_acquired -> acquired, wait_time_total -> wait_total
83 */
84 const char *name;
85 int (*key)(struct lock_stat*, struct lock_stat*);
86};
87
88static const char *sort_key = "acquired";
89
90static int (*compare)(struct lock_stat *, struct lock_stat *);
91
92static struct rb_root result; /* place to store sorted data */
93
94#define DEF_KEY_LOCK(name, fn_suffix) \
95 { #name, lock_stat_key_ ## fn_suffix }
96struct lock_key keys[] = {
97 DEF_KEY_LOCK(acquired, nr_acquired),
98 DEF_KEY_LOCK(contended, nr_contended),
99 DEF_KEY_LOCK(wait_total, wait_time_total),
100 DEF_KEY_LOCK(wait_min, wait_time_min),
101 DEF_KEY_LOCK(wait_max, wait_time_max),
102
103 /* extra comparisons much complicated should be here */
104
105 { NULL, NULL }
106};
107
108static void select_key(void)
109{
110 int i;
111
112 for (i = 0; keys[i].name; i++) {
113 if (!strcmp(keys[i].name, sort_key)) {
114 compare = keys[i].key;
115 return;
116 }
117 }
118
119 die("Unknown compare key:%s\n", sort_key);
120}
121
122static void insert_to_result(struct lock_stat *st,
123 int (*bigger)(struct lock_stat *, struct lock_stat *))
124{
125 struct rb_node **rb = &result.rb_node;
126 struct rb_node *parent = NULL;
127 struct lock_stat *p;
128
129 while (*rb) {
130 p = container_of(*rb, struct lock_stat, rb);
131 parent = *rb;
132
133 if (bigger(st, p))
134 rb = &(*rb)->rb_left;
135 else
136 rb = &(*rb)->rb_right;
137 }
138
139 rb_link_node(&st->rb, parent, rb);
140 rb_insert_color(&st->rb, &result);
141}
142
143/* returns left most element of result, and erase it */
144static struct lock_stat *pop_from_result(void)
145{
146 struct rb_node *node = result.rb_node;
147
148 if (!node)
149 return NULL;
150
151 while (node->rb_left)
152 node = node->rb_left;
153
154 rb_erase(node, &result);
155 return container_of(node, struct lock_stat, rb);
156}
157
158static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
159{
160 struct list_head *entry = lockhashentry(addr);
161 struct lock_stat *ret, *new;
162
163 list_for_each_entry(ret, entry, hash_entry) {
164 if (ret->addr == addr)
165 return ret;
166 }
167
168 new = zalloc(sizeof(struct lock_stat));
169 if (!new)
170 goto alloc_failed;
171
172 new->addr = addr;
173 new->name = zalloc(sizeof(char) * strlen(name) + 1);
174 if (!new->name)
175 goto alloc_failed;
176 strcpy(new->name, name);
177
178 /* LOCK_STATE_UNLOCKED == 0 isn't guaranteed forever */
179 new->state = LOCK_STATE_UNLOCKED;
180 new->wait_time_min = ULLONG_MAX;
181
182 list_add(&new->hash_entry, entry);
183 return new;
184
185alloc_failed:
186 die("memory allocation failed\n");
187}
188
189static char const *input_name = "perf.data";
190
191static int profile_cpu = -1;
192
193struct raw_event_sample {
194 u32 size;
195 char data[0];
196};
197
198struct trace_acquire_event {
199 void *addr;
200 const char *name;
201};
202
203struct trace_acquired_event {
204 void *addr;
205 const char *name;
206};
207
208struct trace_contended_event {
209 void *addr;
210 const char *name;
211};
212
213struct trace_release_event {
214 void *addr;
215 const char *name;
216};
217
218struct trace_lock_handler {
219 void (*acquire_event)(struct trace_acquire_event *,
220 struct event *,
221 int cpu,
222 u64 timestamp,
223 struct thread *thread);
224
225 void (*acquired_event)(struct trace_acquired_event *,
226 struct event *,
227 int cpu,
228 u64 timestamp,
229 struct thread *thread);
230
231 void (*contended_event)(struct trace_contended_event *,
232 struct event *,
233 int cpu,
234 u64 timestamp,
235 struct thread *thread);
236
237 void (*release_event)(struct trace_release_event *,
238 struct event *,
239 int cpu,
240 u64 timestamp,
241 struct thread *thread);
242};
243
244static void
245report_lock_acquire_event(struct trace_acquire_event *acquire_event,
246 struct event *__event __used,
247 int cpu __used,
248 u64 timestamp,
249 struct thread *thread __used)
250{
251 struct lock_stat *st;
252
253 st = lock_stat_findnew(acquire_event->addr, acquire_event->name);
254
255 switch (st->state) {
256 case LOCK_STATE_UNLOCKED:
257 break;
258 case LOCK_STATE_LOCKED:
259 break;
260 default:
261 BUG_ON(1);
262 break;
263 }
264
265 st->prev_event_time = timestamp;
266}
267
268static void
269report_lock_acquired_event(struct trace_acquired_event *acquired_event,
270 struct event *__event __used,
271 int cpu __used,
272 u64 timestamp,
273 struct thread *thread __used)
274{
275 struct lock_stat *st;
276
277 st = lock_stat_findnew(acquired_event->addr, acquired_event->name);
278
279 switch (st->state) {
280 case LOCK_STATE_UNLOCKED:
281 st->state = LOCK_STATE_LOCKED;
282 st->nr_acquired++;
283 break;
284 case LOCK_STATE_LOCKED:
285 break;
286 default:
287 BUG_ON(1);
288 break;
289 }
290
291 st->prev_event_time = timestamp;
292}
293
294static void
295report_lock_contended_event(struct trace_contended_event *contended_event,
296 struct event *__event __used,
297 int cpu __used,
298 u64 timestamp,
299 struct thread *thread __used)
300{
301 struct lock_stat *st;
302
303 st = lock_stat_findnew(contended_event->addr, contended_event->name);
304
305 switch (st->state) {
306 case LOCK_STATE_UNLOCKED:
307 break;
308 case LOCK_STATE_LOCKED:
309 st->nr_contended++;
310 break;
311 default:
312 BUG_ON(1);
313 break;
314 }
315
316 st->prev_event_time = timestamp;
317}
318
319static void
320report_lock_release_event(struct trace_release_event *release_event,
321 struct event *__event __used,
322 int cpu __used,
323 u64 timestamp,
324 struct thread *thread __used)
325{
326 struct lock_stat *st;
327 u64 hold_time;
328
329 st = lock_stat_findnew(release_event->addr, release_event->name);
330
331 switch (st->state) {
332 case LOCK_STATE_UNLOCKED:
333 break;
334 case LOCK_STATE_LOCKED:
335 st->state = LOCK_STATE_UNLOCKED;
336 hold_time = timestamp - st->prev_event_time;
337
338 if (timestamp < st->prev_event_time) {
339 /* terribly, this can happen... */
340 goto end;
341 }
342
343 if (st->wait_time_min > hold_time)
344 st->wait_time_min = hold_time;
345 if (st->wait_time_max < hold_time)
346 st->wait_time_max = hold_time;
347 st->wait_time_total += hold_time;
348
349 st->nr_release++;
350 break;
351 default:
352 BUG_ON(1);
353 break;
354 }
355
356end:
357 st->prev_event_time = timestamp;
358}
359
360/* lock oriented handlers */
361/* TODO: handlers for CPU oriented, thread oriented */
362static struct trace_lock_handler report_lock_ops = {
363 .acquire_event = report_lock_acquire_event,
364 .acquired_event = report_lock_acquired_event,
365 .contended_event = report_lock_contended_event,
366 .release_event = report_lock_release_event,
367};
368
369static struct trace_lock_handler *trace_handler;
370
371static void
372process_lock_acquire_event(void *data,
373 struct event *event __used,
374 int cpu __used,
375 u64 timestamp __used,
376 struct thread *thread __used)
377{
378 struct trace_acquire_event acquire_event;
379 u64 tmp; /* this is required for casting... */
380
381 tmp = raw_field_value(event, "lockdep_addr", data);
382 memcpy(&acquire_event.addr, &tmp, sizeof(void *));
383 acquire_event.name = (char *)raw_field_ptr(event, "name", data);
384
385 if (trace_handler->acquire_event)
386 trace_handler->acquire_event(&acquire_event, event, cpu, timestamp, thread);
387}
388
389static void
390process_lock_acquired_event(void *data,
391 struct event *event __used,
392 int cpu __used,
393 u64 timestamp __used,
394 struct thread *thread __used)
395{
396 struct trace_acquired_event acquired_event;
397 u64 tmp; /* this is required for casting... */
398
399 tmp = raw_field_value(event, "lockdep_addr", data);
400 memcpy(&acquired_event.addr, &tmp, sizeof(void *));
401 acquired_event.name = (char *)raw_field_ptr(event, "name", data);
402
403 if (trace_handler->acquire_event)
404 trace_handler->acquired_event(&acquired_event, event, cpu, timestamp, thread);
405}
406
407static void
408process_lock_contended_event(void *data,
409 struct event *event __used,
410 int cpu __used,
411 u64 timestamp __used,
412 struct thread *thread __used)
413{
414 struct trace_contended_event contended_event;
415 u64 tmp; /* this is required for casting... */
416
417 tmp = raw_field_value(event, "lockdep_addr", data);
418 memcpy(&contended_event.addr, &tmp, sizeof(void *));
419 contended_event.name = (char *)raw_field_ptr(event, "name", data);
420
421 if (trace_handler->acquire_event)
422 trace_handler->contended_event(&contended_event, event, cpu, timestamp, thread);
423}
424
425static void
426process_lock_release_event(void *data,
427 struct event *event __used,
428 int cpu __used,
429 u64 timestamp __used,
430 struct thread *thread __used)
431{
432 struct trace_release_event release_event;
433 u64 tmp; /* this is required for casting... */
434
435 tmp = raw_field_value(event, "lockdep_addr", data);
436 memcpy(&release_event.addr, &tmp, sizeof(void *));
437 release_event.name = (char *)raw_field_ptr(event, "name", data);
438
439 if (trace_handler->acquire_event)
440 trace_handler->release_event(&release_event, event, cpu, timestamp, thread);
441}
442
443static void
444process_raw_event(void *data, int cpu,
445 u64 timestamp, struct thread *thread)
446{
447 struct event *event;
448 int type;
449
450 type = trace_parse_common_type(data);
451 event = trace_find_event(type);
452
453 if (!strcmp(event->name, "lock_acquire"))
454 process_lock_acquire_event(data, event, cpu, timestamp, thread);
455 if (!strcmp(event->name, "lock_acquired"))
456 process_lock_acquired_event(data, event, cpu, timestamp, thread);
457 if (!strcmp(event->name, "lock_contended"))
458 process_lock_contended_event(data, event, cpu, timestamp, thread);
459 if (!strcmp(event->name, "lock_release"))
460 process_lock_release_event(data, event, cpu, timestamp, thread);
461}
462
463struct raw_event_queue {
464 u64 timestamp;
465 int cpu;
466 void *data;
467 struct thread *thread;
468 struct list_head list;
469};
470
471static LIST_HEAD(raw_event_head);
472
473#define FLUSH_PERIOD (5 * NSEC_PER_SEC)
474
475static u64 flush_limit = ULLONG_MAX;
476static u64 last_flush = 0;
477struct raw_event_queue *last_inserted;
478
479static void flush_raw_event_queue(u64 limit)
480{
481 struct raw_event_queue *tmp, *iter;
482
483 list_for_each_entry_safe(iter, tmp, &raw_event_head, list) {
484 if (iter->timestamp > limit)
485 return;
486
487 if (iter == last_inserted)
488 last_inserted = NULL;
489
490 process_raw_event(iter->data, iter->cpu, iter->timestamp,
491 iter->thread);
492
493 last_flush = iter->timestamp;
494 list_del(&iter->list);
495 free(iter->data);
496 free(iter);
497 }
498}
499
500static void __queue_raw_event_end(struct raw_event_queue *new)
501{
502 struct raw_event_queue *iter;
503
504 list_for_each_entry_reverse(iter, &raw_event_head, list) {
505 if (iter->timestamp < new->timestamp) {
506 list_add(&new->list, &iter->list);
507 return;
508 }
509 }
510
511 list_add(&new->list, &raw_event_head);
512}
513
514static void __queue_raw_event_before(struct raw_event_queue *new,
515 struct raw_event_queue *iter)
516{
517 list_for_each_entry_continue_reverse(iter, &raw_event_head, list) {
518 if (iter->timestamp < new->timestamp) {
519 list_add(&new->list, &iter->list);
520 return;
521 }
522 }
523
524 list_add(&new->list, &raw_event_head);
525}
526
527static void __queue_raw_event_after(struct raw_event_queue *new,
528 struct raw_event_queue *iter)
529{
530 list_for_each_entry_continue(iter, &raw_event_head, list) {
531 if (iter->timestamp > new->timestamp) {
532 list_add_tail(&new->list, &iter->list);
533 return;
534 }
535 }
536 list_add_tail(&new->list, &raw_event_head);
537}
538
539/* The queue is ordered by time */
540static void __queue_raw_event(struct raw_event_queue *new)
541{
542 if (!last_inserted) {
543 __queue_raw_event_end(new);
544 return;
545 }
546
547 /*
548 * Most of the time the current event has a timestamp
549 * very close to the last event inserted, unless we just switched
550 * to another event buffer. Having a sorting based on a list and
551 * on the last inserted event that is close to the current one is
552 * probably more efficient than an rbtree based sorting.
553 */
554 if (last_inserted->timestamp >= new->timestamp)
555 __queue_raw_event_before(new, last_inserted);
556 else
557 __queue_raw_event_after(new, last_inserted);
558}
559
560static void queue_raw_event(void *data, int raw_size, int cpu,
561 u64 timestamp, struct thread *thread)
562{
563 struct raw_event_queue *new;
564
565 if (flush_limit == ULLONG_MAX)
566 flush_limit = timestamp + FLUSH_PERIOD;
567
568 if (timestamp < last_flush) {
569 printf("Warning: Timestamp below last timeslice flush\n");
570 return;
571 }
572
573 new = malloc(sizeof(*new));
574 if (!new)
575 die("Not enough memory\n");
576
577 new->timestamp = timestamp;
578 new->cpu = cpu;
579 new->thread = thread;
580
581 new->data = malloc(raw_size);
582 if (!new->data)
583 die("Not enough memory\n");
584
585 memcpy(new->data, data, raw_size);
586
587 __queue_raw_event(new);
588 last_inserted = new;
589
590 /*
591 * We want to have a slice of events covering 2 * FLUSH_PERIOD
592 * If FLUSH_PERIOD is big enough, it ensures every events that occured
593 * in the first half of the timeslice have all been buffered and there
594 * are none remaining (we need that because of the weakly ordered
595 * event recording we have). Then once we reach the 2 * FLUSH_PERIOD
596 * timeslice, we flush the first half to be gentle with the memory
597 * (the second half can still get new events in the middle, so wait
598 * another period to flush it)
599 */
600 if (new->timestamp > flush_limit &&
601 new->timestamp - flush_limit > FLUSH_PERIOD) {
602 flush_limit += FLUSH_PERIOD;
603 flush_raw_event_queue(flush_limit);
604 }
605}
606
607static int process_sample_event(event_t *event, struct perf_session *session)
608{
609 struct thread *thread;
610 struct sample_data data;
611
612 bzero(&data, sizeof(struct sample_data));
613 event__parse_sample(event, session->sample_type, &data);
614 thread = perf_session__findnew(session, data.pid);
615
616 if (thread == NULL) {
617 pr_debug("problem processing %d event, skipping it.\n",
618 event->header.type);
619 return -1;
620 }
621
622 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
623
624 if (profile_cpu != -1 && profile_cpu != (int) data.cpu)
625 return 0;
626
627 queue_raw_event(data.raw_data, data.raw_size, data.cpu, data.time, thread);
628
629 return 0;
630}
631
632/* TODO: various way to print, coloring, nano or milli sec */
633static void print_result(void)
634{
635 struct lock_stat *st;
636 char cut_name[20];
637
638 printf("%18s ", "ID");
639 printf("%20s ", "Name");
640 printf("%10s ", "acquired");
641 printf("%10s ", "contended");
642
643 printf("%15s ", "total wait (ns)");
644 printf("%15s ", "max wait (ns)");
645 printf("%15s ", "min wait (ns)");
646
647 printf("\n\n");
648
649 while ((st = pop_from_result())) {
650 bzero(cut_name, 20);
651
652 printf("%p ", st->addr);
653
654 if (strlen(st->name) < 16) {
655 /* output raw name */
656 printf("%20s ", st->name);
657 } else {
658 strncpy(cut_name, st->name, 16);
659 cut_name[16] = '.';
660 cut_name[17] = '.';
661 cut_name[18] = '.';
662 cut_name[19] = '\0';
663 /* cut off name for saving output style */
664 printf("%20s ", cut_name);
665 }
666
667 printf("%10u ", st->nr_acquired);
668 printf("%10u ", st->nr_contended);
669
670 printf("%15llu ", st->wait_time_total);
671 printf("%15llu ", st->wait_time_max);
672 printf("%15llu ", st->wait_time_min == ULLONG_MAX ?
673 0 : st->wait_time_min);
674 printf("\n");
675 }
676}
677
678static void dump_map(void)
679{
680 unsigned int i;
681 struct lock_stat *st;
682
683 for (i = 0; i < LOCKHASH_SIZE; i++) {
684 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
685 printf("%p: %s\n", st->addr, st->name);
686 }
687 }
688}
689
690static struct perf_event_ops eops = {
691 .sample = process_sample_event,
692 .comm = event__process_comm,
693};
694
695static struct perf_session *session;
696
697static int read_events(void)
698{
699 session = perf_session__new(input_name, O_RDONLY, 0);
700 if (!session)
701 die("Initializing perf session failed\n");
702
703 return perf_session__process_events(session, &eops);
704}
705
706static void sort_result(void)
707{
708 unsigned int i;
709 struct lock_stat *st;
710
711 for (i = 0; i < LOCKHASH_SIZE; i++) {
712 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
713 insert_to_result(st, compare);
714 }
715 }
716}
717
718static void __cmd_report(void)
719{
720 setup_pager();
721 select_key();
722 read_events();
723 flush_raw_event_queue(ULLONG_MAX);
724 sort_result();
725 print_result();
726}
727
728static const char * const report_usage[] = {
729 "perf lock report [<options>]",
730 NULL
731};
732
733static const struct option report_options[] = {
734 OPT_STRING('k', "key", &sort_key, "acquired",
735 "key for sorting"),
736 /* TODO: type */
737 OPT_END()
738};
739
740static const char * const lock_usage[] = {
741 "perf lock [<options>] {record|trace|report}",
742 NULL
743};
744
745static const struct option lock_options[] = {
746 OPT_STRING('i', "input", &input_name, "file", "input file name"),
747 OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
748 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
749 OPT_END()
750};
751
752static const char *record_args[] = {
753 "record",
754 "-a",
755 "-R",
756 "-f",
757 "-m", "1024",
758 "-c", "1",
759 "-e", "lock:lock_acquire:r",
760 "-e", "lock:lock_acquired:r",
761 "-e", "lock:lock_contended:r",
762 "-e", "lock:lock_release:r",
763};
764
765static int __cmd_record(int argc, const char **argv)
766{
767 unsigned int rec_argc, i, j;
768 const char **rec_argv;
769
770 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
771 rec_argv = calloc(rec_argc + 1, sizeof(char *));
772
773 for (i = 0; i < ARRAY_SIZE(record_args); i++)
774 rec_argv[i] = strdup(record_args[i]);
775
776 for (j = 1; j < (unsigned int)argc; j++, i++)
777 rec_argv[i] = argv[j];
778
779 BUG_ON(i != rec_argc);
780
781 return cmd_record(i, rec_argv, NULL);
782}
783
784int cmd_lock(int argc, const char **argv, const char *prefix __used)
785{
786 unsigned int i;
787
788 symbol__init();
789 for (i = 0; i < LOCKHASH_SIZE; i++)
790 INIT_LIST_HEAD(lockhash_table + i);
791
792 argc = parse_options(argc, argv, lock_options, lock_usage,
793 PARSE_OPT_STOP_AT_NON_OPTION);
794 if (!argc)
795 usage_with_options(lock_usage, lock_options);
796
797 if (!strncmp(argv[0], "rec", 3)) {
798 return __cmd_record(argc, argv);
799 } else if (!strncmp(argv[0], "report", 6)) {
800 trace_handler = &report_lock_ops;
801 if (argc) {
802 argc = parse_options(argc, argv,
803 report_options, report_usage, 0);
804 if (argc)
805 usage_with_options(report_usage, report_options);
806 }
807 __cmd_report();
808 } else if (!strcmp(argv[0], "trace")) {
809 /* Aliased to 'perf trace' */
810 return cmd_trace(argc, argv, prefix);
811 } else if (!strcmp(argv[0], "map")) {
812 /* recycling report_lock_ops */
813 trace_handler = &report_lock_ops;
814 setup_pager();
815 read_events();
816 dump_map();
817 } else {
818 usage_with_options(lock_usage, lock_options);
819 }
820
821 return 0;
822}
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index c1e6774fd3ed..c30a33592340 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -41,7 +41,6 @@
41#include "util/debugfs.h" 41#include "util/debugfs.h"
42#include "util/symbol.h" 42#include "util/symbol.h"
43#include "util/thread.h" 43#include "util/thread.h"
44#include "util/session.h"
45#include "util/parse-options.h" 44#include "util/parse-options.h"
46#include "util/parse-events.h" /* For debugfs_path */ 45#include "util/parse-events.h" /* For debugfs_path */
47#include "util/probe-finder.h" 46#include "util/probe-finder.h"
@@ -55,11 +54,13 @@ static struct {
55 bool need_dwarf; 54 bool need_dwarf;
56 bool list_events; 55 bool list_events;
57 bool force_add; 56 bool force_add;
57 bool show_lines;
58 int nr_probe; 58 int nr_probe;
59 struct probe_point probes[MAX_PROBES]; 59 struct probe_point probes[MAX_PROBES];
60 struct strlist *dellist; 60 struct strlist *dellist;
61 struct perf_session *psession; 61 struct map_groups kmap_groups;
62 struct map *kmap; 62 struct map *kmaps[MAP__NR_TYPES];
63 struct line_range line_range;
63} session; 64} session;
64 65
65 66
@@ -120,22 +121,33 @@ static int opt_del_probe_event(const struct option *opt __used,
120static void evaluate_probe_point(struct probe_point *pp) 121static void evaluate_probe_point(struct probe_point *pp)
121{ 122{
122 struct symbol *sym; 123 struct symbol *sym;
123 sym = map__find_symbol_by_name(session.kmap, pp->function, 124 sym = map__find_symbol_by_name(session.kmaps[MAP__FUNCTION],
124 session.psession, NULL); 125 pp->function, NULL);
125 if (!sym) 126 if (!sym)
126 die("Kernel symbol \'%s\' not found - probe not added.", 127 die("Kernel symbol \'%s\' not found - probe not added.",
127 pp->function); 128 pp->function);
128} 129}
129 130
130#ifndef NO_LIBDWARF 131#ifndef NO_DWARF_SUPPORT
131static int open_vmlinux(void) 132static int open_vmlinux(void)
132{ 133{
133 if (map__load(session.kmap, session.psession, NULL) < 0) { 134 if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) {
134 pr_debug("Failed to load kernel map.\n"); 135 pr_debug("Failed to load kernel map.\n");
135 return -EINVAL; 136 return -EINVAL;
136 } 137 }
137 pr_debug("Try to open %s\n", session.kmap->dso->long_name); 138 pr_debug("Try to open %s\n",
138 return open(session.kmap->dso->long_name, O_RDONLY); 139 session.kmaps[MAP__FUNCTION]->dso->long_name);
140 return open(session.kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
141}
142
143static int opt_show_lines(const struct option *opt __used,
144 const char *str, int unset __used)
145{
146 if (str)
147 parse_line_range_desc(str, &session.line_range);
148 INIT_LIST_HEAD(&session.line_range.line_list);
149 session.show_lines = true;
150 return 0;
139} 151}
140#endif 152#endif
141 153
@@ -144,13 +156,16 @@ static const char * const probe_usage[] = {
144 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 156 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
145 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 157 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
146 "perf probe --list", 158 "perf probe --list",
159#ifndef NO_DWARF_SUPPORT
160 "perf probe --line 'LINEDESC'",
161#endif
147 NULL 162 NULL
148}; 163};
149 164
150static const struct option options[] = { 165static const struct option options[] = {
151 OPT_BOOLEAN('v', "verbose", &verbose, 166 OPT_BOOLEAN('v', "verbose", &verbose,
152 "be more verbose (show parsed arguments, etc)"), 167 "be more verbose (show parsed arguments, etc)"),
153#ifndef NO_LIBDWARF 168#ifndef NO_DWARF_SUPPORT
154 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 169 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
155 "file", "vmlinux pathname"), 170 "file", "vmlinux pathname"),
156#endif 171#endif
@@ -159,36 +174,60 @@ static const struct option options[] = {
159 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 174 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
160 opt_del_probe_event), 175 opt_del_probe_event),
161 OPT_CALLBACK('a', "add", NULL, 176 OPT_CALLBACK('a', "add", NULL,
162#ifdef NO_LIBDWARF 177#ifdef NO_DWARF_SUPPORT
163 "[EVENT=]FUNC[+OFFS|%return] [ARG ...]", 178 "[EVENT=]FUNC[+OFF|%return] [ARG ...]",
164#else 179#else
165 "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", 180 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
181 " [ARG ...]",
166#endif 182#endif
167 "probe point definition, where\n" 183 "probe point definition, where\n"
168 "\t\tGROUP:\tGroup name (optional)\n" 184 "\t\tGROUP:\tGroup name (optional)\n"
169 "\t\tEVENT:\tEvent name\n" 185 "\t\tEVENT:\tEvent name\n"
170 "\t\tFUNC:\tFunction name\n" 186 "\t\tFUNC:\tFunction name\n"
171 "\t\tOFFS:\tOffset from function entry (in byte)\n" 187 "\t\tOFF:\tOffset from function entry (in byte)\n"
172 "\t\t%return:\tPut the probe at function return\n" 188 "\t\t%return:\tPut the probe at function return\n"
173#ifdef NO_LIBDWARF 189#ifdef NO_DWARF_SUPPORT
174 "\t\tARG:\tProbe argument (only \n" 190 "\t\tARG:\tProbe argument (only \n"
175#else 191#else
176 "\t\tSRC:\tSource code path\n" 192 "\t\tSRC:\tSource code path\n"
177 "\t\tRLN:\tRelative line number from function entry.\n" 193 "\t\tRL:\tRelative line number from function entry.\n"
178 "\t\tALN:\tAbsolute line number in file.\n" 194 "\t\tAL:\tAbsolute line number in file.\n"
195 "\t\tPT:\tLazy expression of line code.\n"
179 "\t\tARG:\tProbe argument (local variable name or\n" 196 "\t\tARG:\tProbe argument (local variable name or\n"
180#endif 197#endif
181 "\t\t\tkprobe-tracer argument format.)\n", 198 "\t\t\tkprobe-tracer argument format.)\n",
182 opt_add_probe_event), 199 opt_add_probe_event),
183 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events" 200 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events"
184 " with existing name"), 201 " with existing name"),
202#ifndef NO_DWARF_SUPPORT
203 OPT_CALLBACK('L', "line", NULL,
204 "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]",
205 "Show source code lines.", opt_show_lines),
206#endif
185 OPT_END() 207 OPT_END()
186}; 208};
187 209
210/* Initialize symbol maps for vmlinux */
211static void init_vmlinux(void)
212{
213 symbol_conf.sort_by_name = true;
214 if (symbol_conf.vmlinux_name == NULL)
215 symbol_conf.try_vmlinux_path = true;
216 else
217 pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
218 if (symbol__init() < 0)
219 die("Failed to init symbol map.");
220
221 map_groups__init(&session.kmap_groups);
222 if (map_groups__create_kernel_maps(&session.kmap_groups,
223 session.kmaps) < 0)
224 die("Failed to create kernel maps.");
225}
226
188int cmd_probe(int argc, const char **argv, const char *prefix __used) 227int cmd_probe(int argc, const char **argv, const char *prefix __used)
189{ 228{
190 int i, ret; 229 int i, ret;
191#ifndef NO_LIBDWARF 230#ifndef NO_DWARF_SUPPORT
192 int fd; 231 int fd;
193#endif 232#endif
194 struct probe_point *pp; 233 struct probe_point *pp;
@@ -203,7 +242,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
203 parse_probe_event_argv(argc, argv); 242 parse_probe_event_argv(argc, argv);
204 } 243 }
205 244
206 if ((!session.nr_probe && !session.dellist && !session.list_events)) 245 if ((!session.nr_probe && !session.dellist && !session.list_events &&
246 !session.show_lines))
207 usage_with_options(probe_usage, options); 247 usage_with_options(probe_usage, options);
208 248
209 if (debugfs_valid_mountpoint(debugfs_path) < 0) 249 if (debugfs_valid_mountpoint(debugfs_path) < 0)
@@ -215,10 +255,34 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
215 " --add/--del.\n"); 255 " --add/--del.\n");
216 usage_with_options(probe_usage, options); 256 usage_with_options(probe_usage, options);
217 } 257 }
258 if (session.show_lines) {
259 pr_warning(" Error: Don't use --list with --line.\n");
260 usage_with_options(probe_usage, options);
261 }
218 show_perf_probe_events(); 262 show_perf_probe_events();
219 return 0; 263 return 0;
220 } 264 }
221 265
266#ifndef NO_DWARF_SUPPORT
267 if (session.show_lines) {
268 if (session.nr_probe != 0 || session.dellist) {
269 pr_warning(" Error: Don't use --line with"
270 " --add/--del.\n");
271 usage_with_options(probe_usage, options);
272 }
273 init_vmlinux();
274 fd = open_vmlinux();
275 if (fd < 0)
276 die("Could not open debuginfo file.");
277 ret = find_line_range(fd, &session.line_range);
278 if (ret <= 0)
279 die("Source line is not found.\n");
280 close(fd);
281 show_line_range(&session.line_range);
282 return 0;
283 }
284#endif
285
222 if (session.dellist) { 286 if (session.dellist) {
223 del_trace_kprobe_events(session.dellist); 287 del_trace_kprobe_events(session.dellist);
224 strlist__delete(session.dellist); 288 strlist__delete(session.dellist);
@@ -226,25 +290,13 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
226 return 0; 290 return 0;
227 } 291 }
228 292
229 /* Initialize symbol maps for vmlinux */ 293 /* Add probes */
230 symbol_conf.sort_by_name = true; 294 init_vmlinux();
231 if (symbol_conf.vmlinux_name == NULL)
232 symbol_conf.try_vmlinux_path = true;
233 if (symbol__init() < 0)
234 die("Failed to init symbol map.");
235 session.psession = perf_session__new(NULL, O_WRONLY, false);
236 if (session.psession == NULL)
237 die("Failed to init perf_session.");
238 session.kmap = map_groups__find_by_name(&session.psession->kmaps,
239 MAP__FUNCTION,
240 "[kernel.kallsyms]");
241 if (!session.kmap)
242 die("Could not find kernel map.\n");
243 295
244 if (session.need_dwarf) 296 if (session.need_dwarf)
245#ifdef NO_LIBDWARF 297#ifdef NO_DWARF_SUPPORT
246 die("Debuginfo-analysis is not supported"); 298 die("Debuginfo-analysis is not supported");
247#else /* !NO_LIBDWARF */ 299#else /* !NO_DWARF_SUPPORT */
248 pr_debug("Some probes require debuginfo.\n"); 300 pr_debug("Some probes require debuginfo.\n");
249 301
250 fd = open_vmlinux(); 302 fd = open_vmlinux();
@@ -264,7 +316,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
264 continue; 316 continue;
265 317
266 lseek(fd, SEEK_SET, 0); 318 lseek(fd, SEEK_SET, 0);
267 ret = find_probepoint(fd, pp); 319 ret = find_probe_point(fd, pp);
268 if (ret > 0) 320 if (ret > 0)
269 continue; 321 continue;
270 if (ret == 0) { /* No error but failed to find probe point. */ 322 if (ret == 0) { /* No error but failed to find probe point. */
@@ -285,7 +337,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
285 close(fd); 337 close(fd);
286 338
287end_dwarf: 339end_dwarf:
288#endif /* !NO_LIBDWARF */ 340#endif /* !NO_DWARF_SUPPORT */
289 341
290 /* Synthesize probes without dwarf */ 342 /* Synthesize probes without dwarf */
291 for (i = 0; i < session.nr_probe; i++) { 343 for (i = 0; i < session.nr_probe; i++) {
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 265425322734..771533ced6a8 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -5,10 +5,13 @@
5 * (or a CPU, or a PID) into the perf.data output file - for 5 * (or a CPU, or a PID) into the perf.data output file - for
6 * later analysis via perf report. 6 * later analysis via perf report.
7 */ 7 */
8#define _FILE_OFFSET_BITS 64
9
8#include "builtin.h" 10#include "builtin.h"
9 11
10#include "perf.h" 12#include "perf.h"
11 13
14#include "util/build-id.h"
12#include "util/util.h" 15#include "util/util.h"
13#include "util/parse-options.h" 16#include "util/parse-options.h"
14#include "util/parse-events.h" 17#include "util/parse-events.h"
@@ -62,6 +65,7 @@ static int nr_poll = 0;
62static int nr_cpu = 0; 65static int nr_cpu = 0;
63 66
64static int file_new = 1; 67static int file_new = 1;
68static off_t post_processing_offset;
65 69
66static struct perf_session *session; 70static struct perf_session *session;
67 71
@@ -111,22 +115,10 @@ static void write_output(void *buf, size_t size)
111 } 115 }
112} 116}
113 117
114static void write_event(event_t *buf, size_t size)
115{
116 /*
117 * Add it to the list of DSOs, so that when we finish this
118 * record session we can pick the available build-ids.
119 */
120 if (buf->header.type == PERF_RECORD_MMAP)
121 dsos__findnew(buf->mmap.filename);
122
123 write_output(buf, size);
124}
125
126static int process_synthesized_event(event_t *event, 118static int process_synthesized_event(event_t *event,
127 struct perf_session *self __used) 119 struct perf_session *self __used)
128{ 120{
129 write_event(event, event->header.size); 121 write_output(event, event->header.size);
130 return 0; 122 return 0;
131} 123}
132 124
@@ -178,14 +170,14 @@ static void mmap_read(struct mmap_data *md)
178 size = md->mask + 1 - (old & md->mask); 170 size = md->mask + 1 - (old & md->mask);
179 old += size; 171 old += size;
180 172
181 write_event(buf, size); 173 write_output(buf, size);
182 } 174 }
183 175
184 buf = &data[old & md->mask]; 176 buf = &data[old & md->mask];
185 size = head - old; 177 size = head - old;
186 old += size; 178 old += size;
187 179
188 write_event(buf, size); 180 write_output(buf, size);
189 181
190 md->prev = old; 182 md->prev = old;
191 mmap_write_tail(md, old); 183 mmap_write_tail(md, old);
@@ -395,10 +387,21 @@ static void open_counters(int cpu, pid_t pid)
395 nr_cpu++; 387 nr_cpu++;
396} 388}
397 389
390static int process_buildids(void)
391{
392 u64 size = lseek(output, 0, SEEK_CUR);
393
394 session->fd = output;
395 return __perf_session__process_events(session, post_processing_offset,
396 size - post_processing_offset,
397 size, &build_id__mark_dso_hit_ops);
398}
399
398static void atexit_header(void) 400static void atexit_header(void)
399{ 401{
400 session->header.data_size += bytes_written; 402 session->header.data_size += bytes_written;
401 403
404 process_buildids();
402 perf_header__write(&session->header, output, true); 405 perf_header__write(&session->header, output, true);
403} 406}
404 407
@@ -551,8 +554,23 @@ static int __cmd_record(int argc, const char **argv)
551 return err; 554 return err;
552 } 555 }
553 556
557 post_processing_offset = lseek(output, 0, SEEK_CUR);
558
559 err = event__synthesize_kernel_mmap(process_synthesized_event,
560 session, "_text");
561 if (err < 0) {
562 pr_err("Couldn't record kernel reference relocation symbol.\n");
563 return err;
564 }
565
566 err = event__synthesize_modules(process_synthesized_event, session);
567 if (err < 0) {
568 pr_err("Couldn't record kernel reference relocation symbol.\n");
569 return err;
570 }
571
554 if (!system_wide && profile_cpu == -1) 572 if (!system_wide && profile_cpu == -1)
555 event__synthesize_thread(pid, process_synthesized_event, 573 event__synthesize_thread(target_pid, process_synthesized_event,
556 session); 574 session);
557 else 575 else
558 event__synthesize_threads(process_synthesized_event, session); 576 event__synthesize_threads(process_synthesized_event, session);
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index db10c0e8ecae..cfc655d40bb7 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -34,6 +34,8 @@
34static char const *input_name = "perf.data"; 34static char const *input_name = "perf.data";
35 35
36static int force; 36static int force;
37static bool hide_unresolved;
38static bool dont_use_callchains;
37 39
38static int show_threads; 40static int show_threads;
39static struct perf_read_values show_threads_values; 41static struct perf_read_values show_threads_values;
@@ -91,11 +93,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
91 93
92 event__parse_sample(event, session->sample_type, &data); 94 event__parse_sample(event, session->sample_type, &data);
93 95
94 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 96 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
95 event->header.misc, 97 data.pid, data.tid, data.ip, data.period);
96 data.pid, data.tid,
97 (void *)(long)data.ip,
98 (long long)data.period);
99 98
100 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) { 99 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
101 unsigned int i; 100 unsigned int i;
@@ -121,7 +120,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
121 return -1; 120 return -1;
122 } 121 }
123 122
124 if (al.filtered) 123 if (al.filtered || (hide_unresolved && al.sym == NULL))
125 return 0; 124 return 0;
126 125
127 if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { 126 if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) {
@@ -156,14 +155,14 @@ static int process_read_event(event_t *event, struct perf_session *session __use
156 return 0; 155 return 0;
157} 156}
158 157
159static int sample_type_check(struct perf_session *session) 158static int perf_session__setup_sample_type(struct perf_session *self)
160{ 159{
161 if (!(session->sample_type & PERF_SAMPLE_CALLCHAIN)) { 160 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
162 if (sort__has_parent) { 161 if (sort__has_parent) {
163 fprintf(stderr, "selected --sort parent, but no" 162 fprintf(stderr, "selected --sort parent, but no"
164 " callchain data. Did you call" 163 " callchain data. Did you call"
165 " perf record without -g?\n"); 164 " perf record without -g?\n");
166 return -1; 165 return -EINVAL;
167 } 166 }
168 if (symbol_conf.use_callchain) { 167 if (symbol_conf.use_callchain) {
169 fprintf(stderr, "selected -g but no callchain data." 168 fprintf(stderr, "selected -g but no callchain data."
@@ -171,12 +170,13 @@ static int sample_type_check(struct perf_session *session)
171 " -g?\n"); 170 " -g?\n");
172 return -1; 171 return -1;
173 } 172 }
174 } else if (callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) { 173 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
174 !symbol_conf.use_callchain) {
175 symbol_conf.use_callchain = true; 175 symbol_conf.use_callchain = true;
176 if (register_callchain_param(&callchain_param) < 0) { 176 if (register_callchain_param(&callchain_param) < 0) {
177 fprintf(stderr, "Can't register callchain" 177 fprintf(stderr, "Can't register callchain"
178 " params\n"); 178 " params\n");
179 return -1; 179 return -EINVAL;
180 } 180 }
181 } 181 }
182 182
@@ -184,20 +184,18 @@ static int sample_type_check(struct perf_session *session)
184} 184}
185 185
186static struct perf_event_ops event_ops = { 186static struct perf_event_ops event_ops = {
187 .process_sample_event = process_sample_event, 187 .sample = process_sample_event,
188 .process_mmap_event = event__process_mmap, 188 .mmap = event__process_mmap,
189 .process_comm_event = event__process_comm, 189 .comm = event__process_comm,
190 .process_exit_event = event__process_task, 190 .exit = event__process_task,
191 .process_fork_event = event__process_task, 191 .fork = event__process_task,
192 .process_lost_event = event__process_lost, 192 .lost = event__process_lost,
193 .process_read_event = process_read_event, 193 .read = process_read_event,
194 .sample_type_check = sample_type_check,
195}; 194};
196 195
197
198static int __cmd_report(void) 196static int __cmd_report(void)
199{ 197{
200 int ret; 198 int ret = -EINVAL;
201 struct perf_session *session; 199 struct perf_session *session;
202 200
203 session = perf_session__new(input_name, O_RDONLY, force); 201 session = perf_session__new(input_name, O_RDONLY, force);
@@ -207,6 +205,10 @@ static int __cmd_report(void)
207 if (show_threads) 205 if (show_threads)
208 perf_read_values_init(&show_threads_values); 206 perf_read_values_init(&show_threads_values);
209 207
208 ret = perf_session__setup_sample_type(session);
209 if (ret)
210 goto out_delete;
211
210 ret = perf_session__process_events(session, &event_ops); 212 ret = perf_session__process_events(session, &event_ops);
211 if (ret) 213 if (ret)
212 goto out_delete; 214 goto out_delete;
@@ -243,11 +245,19 @@ out_delete:
243 245
244static int 246static int
245parse_callchain_opt(const struct option *opt __used, const char *arg, 247parse_callchain_opt(const struct option *opt __used, const char *arg,
246 int unset __used) 248 int unset)
247{ 249{
248 char *tok; 250 char *tok;
249 char *endptr; 251 char *endptr;
250 252
253 /*
254 * --no-call-graph
255 */
256 if (unset) {
257 dont_use_callchains = true;
258 return 0;
259 }
260
251 symbol_conf.use_callchain = true; 261 symbol_conf.use_callchain = true;
252 262
253 if (!arg) 263 if (!arg)
@@ -269,7 +279,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
269 279
270 else if (!strncmp(tok, "none", strlen(arg))) { 280 else if (!strncmp(tok, "none", strlen(arg))) {
271 callchain_param.mode = CHAIN_NONE; 281 callchain_param.mode = CHAIN_NONE;
272 symbol_conf.use_callchain = true; 282 symbol_conf.use_callchain = false;
273 283
274 return 0; 284 return 0;
275 } 285 }
@@ -319,7 +329,7 @@ static const struct option options[] = {
319 "pretty printing style key: normal raw"), 329 "pretty printing style key: normal raw"),
320 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 330 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
321 "sort by key(s): pid, comm, dso, symbol, parent"), 331 "sort by key(s): pid, comm, dso, symbol, parent"),
322 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, 332 OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
323 "Don't shorten the pathnames taking into account the cwd"), 333 "Don't shorten the pathnames taking into account the cwd"),
324 OPT_STRING('p', "parent", &parent_pattern, "regex", 334 OPT_STRING('p', "parent", &parent_pattern, "regex",
325 "regex filter to identify parent, see: '--sort parent'"), 335 "regex filter to identify parent, see: '--sort parent'"),
@@ -340,6 +350,8 @@ static const struct option options[] = {
340 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", 350 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
341 "separator for columns, no spaces will be added between " 351 "separator for columns, no spaces will be added between "
342 "columns '.' is reserved."), 352 "columns '.' is reserved."),
353 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
354 "Only display entries resolved to a symbol"),
343 OPT_END() 355 OPT_END()
344}; 356};
345 357
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 80209df6cfe8..4f5a03e43444 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1621,11 +1621,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
1621 1621
1622 event__parse_sample(event, session->sample_type, &data); 1622 event__parse_sample(event, session->sample_type, &data);
1623 1623
1624 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 1624 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
1625 event->header.misc, 1625 data.pid, data.tid, data.ip, data.period);
1626 data.pid, data.tid,
1627 (void *)(long)data.ip,
1628 (long long)data.period);
1629 1626
1630 thread = perf_session__findnew(session, data.pid); 1627 thread = perf_session__findnew(session, data.pid);
1631 if (thread == NULL) { 1628 if (thread == NULL) {
@@ -1653,33 +1650,22 @@ static int process_lost_event(event_t *event __used,
1653 return 0; 1650 return 0;
1654} 1651}
1655 1652
1656static int sample_type_check(struct perf_session *session __used)
1657{
1658 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1659 fprintf(stderr,
1660 "No trace sample to read. Did you call perf record "
1661 "without -R?");
1662 return -1;
1663 }
1664
1665 return 0;
1666}
1667
1668static struct perf_event_ops event_ops = { 1653static struct perf_event_ops event_ops = {
1669 .process_sample_event = process_sample_event, 1654 .sample = process_sample_event,
1670 .process_comm_event = event__process_comm, 1655 .comm = event__process_comm,
1671 .process_lost_event = process_lost_event, 1656 .lost = process_lost_event,
1672 .sample_type_check = sample_type_check,
1673}; 1657};
1674 1658
1675static int read_events(void) 1659static int read_events(void)
1676{ 1660{
1677 int err; 1661 int err = -EINVAL;
1678 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 1662 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1679 if (session == NULL) 1663 if (session == NULL)
1680 return -ENOMEM; 1664 return -ENOMEM;
1681 1665
1682 err = perf_session__process_events(session, &event_ops); 1666 if (perf_session__has_traces(session, "record -R"))
1667 err = perf_session__process_events(session, &event_ops);
1668
1683 perf_session__delete(session); 1669 perf_session__delete(session);
1684 return err; 1670 return err;
1685} 1671}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c70d72003557..e8c85d5aec41 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -44,6 +44,7 @@
44#include "util/parse-events.h" 44#include "util/parse-events.h"
45#include "util/event.h" 45#include "util/event.h"
46#include "util/debug.h" 46#include "util/debug.h"
47#include "util/header.h"
47 48
48#include <sys/prctl.h> 49#include <sys/prctl.h>
49#include <math.h> 50#include <math.h>
@@ -79,6 +80,8 @@ static int fd[MAX_NR_CPUS][MAX_COUNTERS];
79 80
80static int event_scaled[MAX_COUNTERS]; 81static int event_scaled[MAX_COUNTERS];
81 82
83static volatile int done = 0;
84
82struct stats 85struct stats
83{ 86{
84 double n, mean, M2; 87 double n, mean, M2;
@@ -247,61 +250,64 @@ static int run_perf_stat(int argc __used, const char **argv)
247 unsigned long long t0, t1; 250 unsigned long long t0, t1;
248 int status = 0; 251 int status = 0;
249 int counter; 252 int counter;
250 int pid; 253 int pid = target_pid;
251 int child_ready_pipe[2], go_pipe[2]; 254 int child_ready_pipe[2], go_pipe[2];
255 const bool forks = (target_pid == -1 && argc > 0);
252 char buf; 256 char buf;
253 257
254 if (!system_wide) 258 if (!system_wide)
255 nr_cpus = 1; 259 nr_cpus = 1;
256 260
257 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) { 261 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
258 perror("failed to create pipes"); 262 perror("failed to create pipes");
259 exit(1); 263 exit(1);
260 } 264 }
261 265
262 if ((pid = fork()) < 0) 266 if (forks) {
263 perror("failed to fork"); 267 if ((pid = fork()) < 0)
268 perror("failed to fork");
269
270 if (!pid) {
271 close(child_ready_pipe[0]);
272 close(go_pipe[1]);
273 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
274
275 /*
276 * Do a dummy execvp to get the PLT entry resolved,
277 * so we avoid the resolver overhead on the real
278 * execvp call.
279 */
280 execvp("", (char **)argv);
281
282 /*
283 * Tell the parent we're ready to go
284 */
285 close(child_ready_pipe[1]);
286
287 /*
288 * Wait until the parent tells us to go.
289 */
290 if (read(go_pipe[0], &buf, 1) == -1)
291 perror("unable to read pipe");
292
293 execvp(argv[0], (char **)argv);
294
295 perror(argv[0]);
296 exit(-1);
297 }
264 298
265 if (!pid) { 299 child_pid = pid;
266 close(child_ready_pipe[0]);
267 close(go_pipe[1]);
268 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
269 300
270 /* 301 /*
271 * Do a dummy execvp to get the PLT entry resolved, 302 * Wait for the child to be ready to exec.
272 * so we avoid the resolver overhead on the real
273 * execvp call.
274 */
275 execvp("", (char **)argv);
276
277 /*
278 * Tell the parent we're ready to go
279 */ 303 */
280 close(child_ready_pipe[1]); 304 close(child_ready_pipe[1]);
281 305 close(go_pipe[0]);
282 /* 306 if (read(child_ready_pipe[0], &buf, 1) == -1)
283 * Wait until the parent tells us to go.
284 */
285 if (read(go_pipe[0], &buf, 1) == -1)
286 perror("unable to read pipe"); 307 perror("unable to read pipe");
287 308 close(child_ready_pipe[0]);
288 execvp(argv[0], (char **)argv);
289
290 perror(argv[0]);
291 exit(-1);
292 } 309 }
293 310
294 child_pid = pid;
295
296 /*
297 * Wait for the child to be ready to exec.
298 */
299 close(child_ready_pipe[1]);
300 close(go_pipe[0]);
301 if (read(child_ready_pipe[0], &buf, 1) == -1)
302 perror("unable to read pipe");
303 close(child_ready_pipe[0]);
304
305 for (counter = 0; counter < nr_counters; counter++) 311 for (counter = 0; counter < nr_counters; counter++)
306 create_perf_stat_counter(counter, pid); 312 create_perf_stat_counter(counter, pid);
307 313
@@ -310,8 +316,12 @@ static int run_perf_stat(int argc __used, const char **argv)
310 */ 316 */
311 t0 = rdclock(); 317 t0 = rdclock();
312 318
313 close(go_pipe[1]); 319 if (forks) {
314 wait(&status); 320 close(go_pipe[1]);
321 wait(&status);
322 } else {
323 while(!done);
324 }
315 325
316 t1 = rdclock(); 326 t1 = rdclock();
317 327
@@ -417,10 +427,13 @@ static void print_stat(int argc, const char **argv)
417 fflush(stdout); 427 fflush(stdout);
418 428
419 fprintf(stderr, "\n"); 429 fprintf(stderr, "\n");
420 fprintf(stderr, " Performance counter stats for \'%s", argv[0]); 430 fprintf(stderr, " Performance counter stats for ");
421 431 if(target_pid == -1) {
422 for (i = 1; i < argc; i++) 432 fprintf(stderr, "\'%s", argv[0]);
423 fprintf(stderr, " %s", argv[i]); 433 for (i = 1; i < argc; i++)
434 fprintf(stderr, " %s", argv[i]);
435 }else
436 fprintf(stderr, "task pid \'%d", target_pid);
424 437
425 fprintf(stderr, "\'"); 438 fprintf(stderr, "\'");
426 if (run_count > 1) 439 if (run_count > 1)
@@ -445,6 +458,9 @@ static volatile int signr = -1;
445 458
446static void skip_signal(int signo) 459static void skip_signal(int signo)
447{ 460{
461 if(target_pid != -1)
462 done = 1;
463
448 signr = signo; 464 signr = signo;
449} 465}
450 466
@@ -461,7 +477,7 @@ static void sig_atexit(void)
461} 477}
462 478
463static const char * const stat_usage[] = { 479static const char * const stat_usage[] = {
464 "perf stat [<options>] <command>", 480 "perf stat [<options>] [<command>]",
465 NULL 481 NULL
466}; 482};
467 483
@@ -492,7 +508,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
492 508
493 argc = parse_options(argc, argv, options, stat_usage, 509 argc = parse_options(argc, argv, options, stat_usage,
494 PARSE_OPT_STOP_AT_NON_OPTION); 510 PARSE_OPT_STOP_AT_NON_OPTION);
495 if (!argc) 511 if (!argc && target_pid == -1)
496 usage_with_options(stat_usage, options); 512 usage_with_options(stat_usage, options);
497 if (run_count <= 0) 513 if (run_count <= 0)
498 usage_with_options(stat_usage, options); 514 usage_with_options(stat_usage, options);
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index a589a43112d6..0d4d8ff7914b 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -280,7 +280,7 @@ static u64 cpus_pstate_state[MAX_CPUS];
280 280
281static int process_comm_event(event_t *event, struct perf_session *session __used) 281static int process_comm_event(event_t *event, struct perf_session *session __used)
282{ 282{
283 pid_set_comm(event->comm.pid, event->comm.comm); 283 pid_set_comm(event->comm.tid, event->comm.comm);
284 return 0; 284 return 0;
285} 285}
286 286
@@ -1029,33 +1029,24 @@ static void process_samples(struct perf_session *session)
1029 } 1029 }
1030} 1030}
1031 1031
1032static int sample_type_check(struct perf_session *session)
1033{
1034 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1035 fprintf(stderr, "No trace samples found in the file.\n"
1036 "Have you used 'perf timechart record' to record it?\n");
1037 return -1;
1038 }
1039
1040 return 0;
1041}
1042
1043static struct perf_event_ops event_ops = { 1032static struct perf_event_ops event_ops = {
1044 .process_comm_event = process_comm_event, 1033 .comm = process_comm_event,
1045 .process_fork_event = process_fork_event, 1034 .fork = process_fork_event,
1046 .process_exit_event = process_exit_event, 1035 .exit = process_exit_event,
1047 .process_sample_event = queue_sample_event, 1036 .sample = queue_sample_event,
1048 .sample_type_check = sample_type_check,
1049}; 1037};
1050 1038
1051static int __cmd_timechart(void) 1039static int __cmd_timechart(void)
1052{ 1040{
1053 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 1041 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1054 int ret; 1042 int ret = -EINVAL;
1055 1043
1056 if (session == NULL) 1044 if (session == NULL)
1057 return -ENOMEM; 1045 return -ENOMEM;
1058 1046
1047 if (!perf_session__has_traces(session, "timechart record"))
1048 goto out_delete;
1049
1059 ret = perf_session__process_events(session, &event_ops); 1050 ret = perf_session__process_events(session, &event_ops);
1060 if (ret) 1051 if (ret)
1061 goto out_delete; 1052 goto out_delete;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ddc584b64871..31f2e597800c 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -94,6 +94,7 @@ struct source_line {
94 94
95static char *sym_filter = NULL; 95static char *sym_filter = NULL;
96struct sym_entry *sym_filter_entry = NULL; 96struct sym_entry *sym_filter_entry = NULL;
97struct sym_entry *sym_filter_entry_sched = NULL;
97static int sym_pcnt_filter = 5; 98static int sym_pcnt_filter = 5;
98static int sym_counter = 0; 99static int sym_counter = 0;
99static int display_weighted = -1; 100static int display_weighted = -1;
@@ -201,10 +202,9 @@ static void parse_source(struct sym_entry *syme)
201 len = sym->end - sym->start; 202 len = sym->end - sym->start;
202 203
203 sprintf(command, 204 sprintf(command,
204 "objdump --start-address=0x%016Lx " 205 "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s",
205 "--stop-address=0x%016Lx -dS %s", 206 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
206 map->unmap_ip(map, sym->start), 207 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
207 map->unmap_ip(map, sym->end), path);
208 208
209 file = popen(command, "r"); 209 file = popen(command, "r");
210 if (!file) 210 if (!file)
@@ -215,7 +215,7 @@ static void parse_source(struct sym_entry *syme)
215 while (!feof(file)) { 215 while (!feof(file)) {
216 struct source_line *src; 216 struct source_line *src;
217 size_t dummy = 0; 217 size_t dummy = 0;
218 char *c; 218 char *c, *sep;
219 219
220 src = malloc(sizeof(struct source_line)); 220 src = malloc(sizeof(struct source_line));
221 assert(src != NULL); 221 assert(src != NULL);
@@ -234,14 +234,11 @@ static void parse_source(struct sym_entry *syme)
234 *source->lines_tail = src; 234 *source->lines_tail = src;
235 source->lines_tail = &src->next; 235 source->lines_tail = &src->next;
236 236
237 if (strlen(src->line)>8 && src->line[8] == ':') { 237 src->eip = strtoull(src->line, &sep, 16);
238 src->eip = strtoull(src->line, NULL, 16); 238 if (*sep == ':')
239 src->eip = map->unmap_ip(map, src->eip); 239 src->eip = map__objdump_2ip(map, src->eip);
240 } 240 else /* this line has no ip info (e.g. source line) */
241 if (strlen(src->line)>8 && src->line[16] == ':') { 241 src->eip = 0;
242 src->eip = strtoull(src->line, NULL, 16);
243 src->eip = map->unmap_ip(map, src->eip);
244 }
245 } 242 }
246 pclose(file); 243 pclose(file);
247out_assign: 244out_assign:
@@ -276,6 +273,9 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
276 goto out_unlock; 273 goto out_unlock;
277 274
278 for (line = syme->src->lines; line; line = line->next) { 275 for (line = syme->src->lines; line; line = line->next) {
276 /* skip lines without IP info */
277 if (line->eip == 0)
278 continue;
279 if (line->eip == ip) { 279 if (line->eip == ip) {
280 line->count[counter]++; 280 line->count[counter]++;
281 break; 281 break;
@@ -287,17 +287,20 @@ out_unlock:
287 pthread_mutex_unlock(&syme->src->lock); 287 pthread_mutex_unlock(&syme->src->lock);
288} 288}
289 289
290#define PATTERN_LEN (BITS_PER_LONG / 4 + 2)
291
290static void lookup_sym_source(struct sym_entry *syme) 292static void lookup_sym_source(struct sym_entry *syme)
291{ 293{
292 struct symbol *symbol = sym_entry__symbol(syme); 294 struct symbol *symbol = sym_entry__symbol(syme);
293 struct source_line *line; 295 struct source_line *line;
294 char pattern[PATH_MAX]; 296 char pattern[PATTERN_LEN + 1];
295 297
296 sprintf(pattern, "<%s>:", symbol->name); 298 sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4,
299 map__rip_2objdump(syme->map, symbol->start));
297 300
298 pthread_mutex_lock(&syme->src->lock); 301 pthread_mutex_lock(&syme->src->lock);
299 for (line = syme->src->lines; line; line = line->next) { 302 for (line = syme->src->lines; line; line = line->next) {
300 if (strstr(line->line, pattern)) { 303 if (memcmp(line->line, pattern, PATTERN_LEN) == 0) {
301 syme->src->source = line; 304 syme->src->source = line;
302 break; 305 break;
303 } 306 }
@@ -667,7 +670,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
667 } 670 }
668 671
669 if (!found) { 672 if (!found) {
670 fprintf(stderr, "Sorry, %s is not active.\n", sym_filter); 673 fprintf(stderr, "Sorry, %s is not active.\n", buf);
671 sleep(1); 674 sleep(1);
672 return; 675 return;
673 } else 676 } else
@@ -695,17 +698,15 @@ static void print_mapped_keys(void)
695 698
696 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 699 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
697 700
698 if (symbol_conf.vmlinux_name) { 701 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
699 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); 702 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
700 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 703 fprintf(stdout, "\t[S] stop annotation.\n");
701 fprintf(stdout, "\t[S] stop annotation.\n");
702 }
703 704
704 if (nr_counters > 1) 705 if (nr_counters > 1)
705 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 706 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
706 707
707 fprintf(stdout, 708 fprintf(stdout,
708 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 709 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
709 hide_kernel_symbols ? "yes" : "no"); 710 hide_kernel_symbols ? "yes" : "no");
710 fprintf(stdout, 711 fprintf(stdout,
711 "\t[U] hide user symbols. \t(%s)\n", 712 "\t[U] hide user symbols. \t(%s)\n",
@@ -725,14 +726,13 @@ static int key_mapped(int c)
725 case 'Q': 726 case 'Q':
726 case 'K': 727 case 'K':
727 case 'U': 728 case 'U':
729 case 'F':
730 case 's':
731 case 'S':
728 return 1; 732 return 1;
729 case 'E': 733 case 'E':
730 case 'w': 734 case 'w':
731 return nr_counters > 1 ? 1 : 0; 735 return nr_counters > 1 ? 1 : 0;
732 case 'F':
733 case 's':
734 case 'S':
735 return symbol_conf.vmlinux_name ? 1 : 0;
736 default: 736 default:
737 break; 737 break;
738 } 738 }
@@ -910,8 +910,12 @@ static int symbol_filter(struct map *map, struct symbol *sym)
910 syme = symbol__priv(sym); 910 syme = symbol__priv(sym);
911 syme->map = map; 911 syme->map = map;
912 syme->src = NULL; 912 syme->src = NULL;
913 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) 913
914 sym_filter_entry = syme; 914 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
915 /* schedule initial sym_filter_entry setup */
916 sym_filter_entry_sched = syme;
917 sym_filter = NULL;
918 }
915 919
916 for (i = 0; skip_symbols[i]; i++) { 920 for (i = 0; skip_symbols[i]; i++) {
917 if (!strcmp(skip_symbols[i], name)) { 921 if (!strcmp(skip_symbols[i], name)) {
@@ -934,8 +938,11 @@ static void event__process_sample(const event_t *self,
934 struct addr_location al; 938 struct addr_location al;
935 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 939 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
936 940
941 ++samples;
942
937 switch (origin) { 943 switch (origin) {
938 case PERF_RECORD_MISC_USER: 944 case PERF_RECORD_MISC_USER:
945 ++userspace_samples;
939 if (hide_user_symbols) 946 if (hide_user_symbols)
940 return; 947 return;
941 break; 948 break;
@@ -948,9 +955,38 @@ static void event__process_sample(const event_t *self,
948 } 955 }
949 956
950 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || 957 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
951 al.sym == NULL || al.filtered) 958 al.filtered)
952 return; 959 return;
953 960
961 if (al.sym == NULL) {
962 /*
963 * As we do lazy loading of symtabs we only will know if the
964 * specified vmlinux file is invalid when we actually have a
965 * hit in kernel space and then try to load it. So if we get
966 * here and there are _no_ symbols in the DSO backing the
967 * kernel map, bail out.
968 *
969 * We may never get here, for instance, if we use -K/
970 * --hide-kernel-symbols, even if the user specifies an
971 * invalid --vmlinux ;-)
972 */
973 if (al.map == session->vmlinux_maps[MAP__FUNCTION] &&
974 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
975 pr_err("The %s file can't be used\n",
976 symbol_conf.vmlinux_name);
977 exit(1);
978 }
979
980 return;
981 }
982
983 /* let's see, whether we need to install initial sym_filter_entry */
984 if (sym_filter_entry_sched) {
985 sym_filter_entry = sym_filter_entry_sched;
986 sym_filter_entry_sched = NULL;
987 parse_source(sym_filter_entry);
988 }
989
954 syme = symbol__priv(al.sym); 990 syme = symbol__priv(al.sym);
955 if (!syme->skip) { 991 if (!syme->skip) {
956 syme->count[counter]++; 992 syme->count[counter]++;
@@ -960,9 +996,6 @@ static void event__process_sample(const event_t *self,
960 if (list_empty(&syme->node) || !syme->node.next) 996 if (list_empty(&syme->node) || !syme->node.next)
961 __list_insert_active_sym(syme); 997 __list_insert_active_sym(syme);
962 pthread_mutex_unlock(&active_symbols_lock); 998 pthread_mutex_unlock(&active_symbols_lock);
963 if (origin == PERF_RECORD_MISC_USER)
964 ++userspace_samples;
965 ++samples;
966 } 999 }
967} 1000}
968 1001
@@ -975,6 +1008,10 @@ static int event__process(event_t *event, struct perf_session *session)
975 case PERF_RECORD_MMAP: 1008 case PERF_RECORD_MMAP:
976 event__process_mmap(event, session); 1009 event__process_mmap(event, session);
977 break; 1010 break;
1011 case PERF_RECORD_FORK:
1012 case PERF_RECORD_EXIT:
1013 event__process_task(event, session);
1014 break;
978 default: 1015 default:
979 break; 1016 break;
980 } 1017 }
@@ -1244,7 +1281,7 @@ static const struct option options[] = {
1244 OPT_BOOLEAN('i', "inherit", &inherit, 1281 OPT_BOOLEAN('i', "inherit", &inherit,
1245 "child tasks inherit counters"), 1282 "child tasks inherit counters"),
1246 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1283 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1247 "symbol to annotate - requires -k option"), 1284 "symbol to annotate"),
1248 OPT_BOOLEAN('z', "zero", &zero, 1285 OPT_BOOLEAN('z', "zero", &zero,
1249 "zero history across updates"), 1286 "zero history across updates"),
1250 OPT_INTEGER('F', "freq", &freq, 1287 OPT_INTEGER('F', "freq", &freq,
@@ -1280,16 +1317,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1280 1317
1281 symbol_conf.priv_size = (sizeof(struct sym_entry) + 1318 symbol_conf.priv_size = (sizeof(struct sym_entry) +
1282 (nr_counters + 1) * sizeof(unsigned long)); 1319 (nr_counters + 1) * sizeof(unsigned long));
1283 if (symbol_conf.vmlinux_name == NULL) 1320
1284 symbol_conf.try_vmlinux_path = true; 1321 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1285 if (symbol__init() < 0) 1322 if (symbol__init() < 0)
1286 return -1; 1323 return -1;
1287 1324
1288 if (delay_secs < 1) 1325 if (delay_secs < 1)
1289 delay_secs = 1; 1326 delay_secs = 1;
1290 1327
1291 parse_source(sym_filter_entry);
1292
1293 /* 1328 /*
1294 * User specified count overrides default frequency. 1329 * User specified count overrides default frequency.
1295 */ 1330 */
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 574a215e800b..407041d20de0 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -44,6 +44,7 @@ static void setup_scripting(void)
44 perf_set_argv_exec_path(perf_exec_path()); 44 perf_set_argv_exec_path(perf_exec_path());
45 45
46 setup_perl_scripting(); 46 setup_perl_scripting();
47 setup_python_scripting();
47 48
48 scripting_ops = &default_scripting_ops; 49 scripting_ops = &default_scripting_ops;
49} 50}
@@ -75,11 +76,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
75 76
76 event__parse_sample(event, session->sample_type, &data); 77 event__parse_sample(event, session->sample_type, &data);
77 78
78 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 79 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
79 event->header.misc, 80 data.pid, data.tid, data.ip, data.period);
80 data.pid, data.tid,
81 (void *)(long)data.ip,
82 (long long)data.period);
83 81
84 thread = perf_session__findnew(session, event->ip.pid); 82 thread = perf_session__findnew(session, event->ip.pid);
85 if (thread == NULL) { 83 if (thread == NULL) {
@@ -103,22 +101,9 @@ static int process_sample_event(event_t *event, struct perf_session *session)
103 return 0; 101 return 0;
104} 102}
105 103
106static int sample_type_check(struct perf_session *session)
107{
108 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
109 fprintf(stderr,
110 "No trace sample to read. Did you call perf record "
111 "without -R?");
112 return -1;
113 }
114
115 return 0;
116}
117
118static struct perf_event_ops event_ops = { 104static struct perf_event_ops event_ops = {
119 .process_sample_event = process_sample_event, 105 .sample = process_sample_event,
120 .process_comm_event = event__process_comm, 106 .comm = event__process_comm,
121 .sample_type_check = sample_type_check,
122}; 107};
123 108
124static int __cmd_trace(struct perf_session *session) 109static int __cmd_trace(struct perf_session *session)
@@ -235,9 +220,9 @@ static int parse_scriptname(const struct option *opt __used,
235 const char *script, *ext; 220 const char *script, *ext;
236 int len; 221 int len;
237 222
238 if (strcmp(str, "list") == 0) { 223 if (strcmp(str, "lang") == 0) {
239 list_available_languages(); 224 list_available_languages();
240 return 0; 225 exit(0);
241 } 226 }
242 227
243 script = strchr(str, ':'); 228 script = strchr(str, ':');
@@ -531,6 +516,8 @@ static const struct option options[] = {
531 parse_scriptname), 516 parse_scriptname),
532 OPT_STRING('g', "gen-script", &generate_script_lang, "lang", 517 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
533 "generate perf-trace.xx script in specified language"), 518 "generate perf-trace.xx script in specified language"),
519 OPT_STRING('i', "input", &input_name, "file",
520 "input file name"),
534 521
535 OPT_END() 522 OPT_END()
536}; 523};
@@ -586,12 +573,16 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
586 573
587 if (symbol__init() < 0) 574 if (symbol__init() < 0)
588 return -1; 575 return -1;
589 setup_pager(); 576 if (!script_name)
577 setup_pager();
590 578
591 session = perf_session__new(input_name, O_RDONLY, 0); 579 session = perf_session__new(input_name, O_RDONLY, 0);
592 if (session == NULL) 580 if (session == NULL)
593 return -ENOMEM; 581 return -ENOMEM;
594 582
583 if (!perf_session__has_traces(session, "record -R"))
584 return -EINVAL;
585
595 if (generate_script_lang) { 586 if (generate_script_lang) {
596 struct stat perf_stat; 587 struct stat perf_stat;
597 588
@@ -618,7 +609,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
618 return -1; 609 return -1;
619 } 610 }
620 611
621 perf_header__read(&session->header, input);
622 err = scripting_ops->generate_script("perf-trace"); 612 err = scripting_ops->generate_script("perf-trace");
623 goto out; 613 goto out;
624 } 614 }
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 18035b1f16c7..10fe49e7048a 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -16,6 +16,7 @@ extern int check_pager_config(const char *cmd);
16 16
17extern int cmd_annotate(int argc, const char **argv, const char *prefix); 17extern int cmd_annotate(int argc, const char **argv, const char *prefix);
18extern int cmd_bench(int argc, const char **argv, const char *prefix); 18extern int cmd_bench(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); 20extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
20extern int cmd_diff(int argc, const char **argv, const char *prefix); 21extern int cmd_diff(int argc, const char **argv, const char *prefix);
21extern int cmd_help(int argc, const char **argv, const char *prefix); 22extern int cmd_help(int argc, const char **argv, const char *prefix);
@@ -30,5 +31,6 @@ extern int cmd_trace(int argc, const char **argv, const char *prefix);
30extern int cmd_version(int argc, const char **argv, const char *prefix); 31extern int cmd_version(int argc, const char **argv, const char *prefix);
31extern int cmd_probe(int argc, const char **argv, const char *prefix); 32extern int cmd_probe(int argc, const char **argv, const char *prefix);
32extern int cmd_kmem(int argc, const char **argv, const char *prefix); 33extern int cmd_kmem(int argc, const char **argv, const char *prefix);
34extern int cmd_lock(int argc, const char **argv, const char *prefix);
33 35
34#endif 36#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 71dc7c3fe7b2..db6ee94d4a8e 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -3,7 +3,9 @@
3# command name category [deprecated] [common] 3# command name category [deprecated] [common]
4# 4#
5perf-annotate mainporcelain common 5perf-annotate mainporcelain common
6perf-archive mainporcelain common
6perf-bench mainporcelain common 7perf-bench mainporcelain common
8perf-buildid-cache mainporcelain common
7perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
8perf-diff mainporcelain common 10perf-diff mainporcelain common
9perf-list mainporcelain common 11perf-list mainporcelain common
@@ -16,3 +18,4 @@ perf-top mainporcelain common
16perf-trace mainporcelain common 18perf-trace mainporcelain common
17perf-probe mainporcelain common 19perf-probe mainporcelain common
18perf-kmem mainporcelain common 20perf-kmem mainporcelain common
21perf-lock mainporcelain common
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index 8d0de5130db3..bd0bb1b1279b 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -101,10 +101,10 @@ enum hw_event_ids {
101 */ 101 */
102 PERF_COUNT_HW_CPU_CYCLES = 0, 102 PERF_COUNT_HW_CPU_CYCLES = 0,
103 PERF_COUNT_HW_INSTRUCTIONS = 1, 103 PERF_COUNT_HW_INSTRUCTIONS = 1,
104 PERF_COUNT_HW_CACHE_REFERENCES = 2, 104 PERF_COUNT_HW_CACHE_REFERENCES = 2,
105 PERF_COUNT_HW_CACHE_MISSES = 3, 105 PERF_COUNT_HW_CACHE_MISSES = 3,
106 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, 106 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
107 PERF_COUNT_HW_BRANCH_MISSES = 5, 107 PERF_COUNT_HW_BRANCH_MISSES = 5,
108 PERF_COUNT_HW_BUS_CYCLES = 6, 108 PERF_COUNT_HW_BUS_CYCLES = 6,
109}; 109};
110 110
@@ -131,8 +131,8 @@ software events, selected by 'event_id':
131 */ 131 */
132enum sw_event_ids { 132enum sw_event_ids {
133 PERF_COUNT_SW_CPU_CLOCK = 0, 133 PERF_COUNT_SW_CPU_CLOCK = 0,
134 PERF_COUNT_SW_TASK_CLOCK = 1, 134 PERF_COUNT_SW_TASK_CLOCK = 1,
135 PERF_COUNT_SW_PAGE_FAULTS = 2, 135 PERF_COUNT_SW_PAGE_FAULTS = 2,
136 PERF_COUNT_SW_CONTEXT_SWITCHES = 3, 136 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
137 PERF_COUNT_SW_CPU_MIGRATIONS = 4, 137 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, 138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh
new file mode 100644
index 000000000000..910468e6e01c
--- /dev/null
+++ b/tools/perf/perf-archive.sh
@@ -0,0 +1,33 @@
1#!/bin/bash
2# perf archive
3# Arnaldo Carvalho de Melo <acme@redhat.com>
4
5PERF_DATA=perf.data
6if [ $# -ne 0 ] ; then
7 PERF_DATA=$1
8fi
9
10DEBUGDIR=~/.debug/
11BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX)
12NOBUILDID=0000000000000000000000000000000000000000
13
14perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS
15if [ ! -s $BUILDIDS ] ; then
16 echo "perf archive: no build-ids found"
17 rm -f $BUILDIDS
18 exit 1
19fi
20
21MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX)
22
23cut -d ' ' -f 1 $BUILDIDS | \
24while read build_id ; do
25 linkname=$DEBUGDIR.build-id/${build_id:0:2}/${build_id:2}
26 filename=$(readlink -f $linkname)
27 echo ${linkname#$DEBUGDIR} >> $MANIFEST
28 echo ${filename#$DEBUGDIR} >> $MANIFEST
29done
30
31tar cfj $PERF_DATA.tar.bz2 -C $DEBUGDIR -T $MANIFEST
32rm -f $MANIFEST $BUILDIDS
33exit 0
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 873e55fab375..cd32c200cdb3 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -48,7 +48,8 @@ int check_pager_config(const char *cmd)
48 return c.val; 48 return c.val;
49} 49}
50 50
51static void commit_pager_choice(void) { 51static void commit_pager_choice(void)
52{
52 switch (use_pager) { 53 switch (use_pager) {
53 case 0: 54 case 0:
54 setenv("PERF_PAGER", "cat", 1); 55 setenv("PERF_PAGER", "cat", 1);
@@ -70,7 +71,7 @@ static void set_debugfs_path(void)
70 "tracing/events"); 71 "tracing/events");
71} 72}
72 73
73static int handle_options(const char*** argv, int* argc, int* envchanged) 74static int handle_options(const char ***argv, int *argc, int *envchanged)
74{ 75{
75 int handled = 0; 76 int handled = 0;
76 77
@@ -109,7 +110,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
109 *envchanged = 1; 110 *envchanged = 1;
110 } else if (!strcmp(cmd, "--perf-dir")) { 111 } else if (!strcmp(cmd, "--perf-dir")) {
111 if (*argc < 2) { 112 if (*argc < 2) {
112 fprintf(stderr, "No directory given for --perf-dir.\n" ); 113 fprintf(stderr, "No directory given for --perf-dir.\n");
113 usage(perf_usage_string); 114 usage(perf_usage_string);
114 } 115 }
115 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1); 116 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1);
@@ -124,7 +125,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
124 *envchanged = 1; 125 *envchanged = 1;
125 } else if (!strcmp(cmd, "--work-tree")) { 126 } else if (!strcmp(cmd, "--work-tree")) {
126 if (*argc < 2) { 127 if (*argc < 2) {
127 fprintf(stderr, "No directory given for --work-tree.\n" ); 128 fprintf(stderr, "No directory given for --work-tree.\n");
128 usage(perf_usage_string); 129 usage(perf_usage_string);
129 } 130 }
130 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1); 131 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
@@ -168,7 +169,7 @@ static int handle_alias(int *argcp, const char ***argv)
168{ 169{
169 int envchanged = 0, ret = 0, saved_errno = errno; 170 int envchanged = 0, ret = 0, saved_errno = errno;
170 int count, option_count; 171 int count, option_count;
171 const char** new_argv; 172 const char **new_argv;
172 const char *alias_command; 173 const char *alias_command;
173 char *alias_string; 174 char *alias_string;
174 175
@@ -210,11 +211,11 @@ static int handle_alias(int *argcp, const char ***argv)
210 if (!strcmp(alias_command, new_argv[0])) 211 if (!strcmp(alias_command, new_argv[0]))
211 die("recursive alias: %s", alias_command); 212 die("recursive alias: %s", alias_command);
212 213
213 new_argv = realloc(new_argv, sizeof(char*) * 214 new_argv = realloc(new_argv, sizeof(char *) *
214 (count + *argcp + 1)); 215 (count + *argcp + 1));
215 /* insert after command name */ 216 /* insert after command name */
216 memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp); 217 memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
217 new_argv[count+*argcp] = NULL; 218 new_argv[count + *argcp] = NULL;
218 219
219 *argv = new_argv; 220 *argv = new_argv;
220 *argcp += count - 1; 221 *argcp += count - 1;
@@ -285,6 +286,7 @@ static void handle_internal_command(int argc, const char **argv)
285{ 286{
286 const char *cmd = argv[0]; 287 const char *cmd = argv[0];
287 static struct cmd_struct commands[] = { 288 static struct cmd_struct commands[] = {
289 { "buildid-cache", cmd_buildid_cache, 0 },
288 { "buildid-list", cmd_buildid_list, 0 }, 290 { "buildid-list", cmd_buildid_list, 0 },
289 { "diff", cmd_diff, 0 }, 291 { "diff", cmd_diff, 0 },
290 { "help", cmd_help, 0 }, 292 { "help", cmd_help, 0 },
@@ -301,6 +303,7 @@ static void handle_internal_command(int argc, const char **argv)
301 { "sched", cmd_sched, 0 }, 303 { "sched", cmd_sched, 0 },
302 { "probe", cmd_probe, 0 }, 304 { "probe", cmd_probe, 0 },
303 { "kmem", cmd_kmem, 0 }, 305 { "kmem", cmd_kmem, 0 },
306 { "lock", cmd_lock, 0 },
304 }; 307 };
305 unsigned int i; 308 unsigned int i;
306 static const char ext[] = STRIP_EXTENSION; 309 static const char ext[] = STRIP_EXTENSION;
@@ -388,7 +391,7 @@ static int run_argv(int *argcp, const char ***argv)
388/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ 391/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
389static void get_debugfs_mntpt(void) 392static void get_debugfs_mntpt(void)
390{ 393{
391 const char *path = debugfs_find_mountpoint(); 394 const char *path = debugfs_mount(NULL);
392 395
393 if (path) 396 if (path)
394 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt)); 397 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
@@ -442,15 +445,15 @@ int main(int argc, const char **argv)
442 445
443 /* 446 /*
444 * We use PATH to find perf commands, but we prepend some higher 447 * We use PATH to find perf commands, but we prepend some higher
445 * precidence paths: the "--exec-path" option, the PERF_EXEC_PATH 448 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
446 * environment, and the $(perfexecdir) from the Makefile at build 449 * environment, and the $(perfexecdir) from the Makefile at build
447 * time. 450 * time.
448 */ 451 */
449 setup_path(); 452 setup_path();
450 453
451 while (1) { 454 while (1) {
452 static int done_help = 0; 455 static int done_help;
453 static int was_alias = 0; 456 static int was_alias;
454 457
455 was_alias = run_argv(&argc, &argv); 458 was_alias = run_argv(&argc, &argv);
456 if (errno != ENOENT) 459 if (errno != ENOENT)
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 75f941bfba9e..6fb379bc1d1f 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -65,9 +65,7 @@
65 * Use the __kuser_memory_barrier helper in the CPU helper page. See 65 * Use the __kuser_memory_barrier helper in the CPU helper page. See
66 * arch/arm/kernel/entry-armv.S in the kernel source for details. 66 * arch/arm/kernel/entry-armv.S in the kernel source for details.
67 */ 67 */
68#define rmb() asm volatile("mov r0, #0xffff0fff; mov lr, pc;" \ 68#define rmb() ((void(*)(void))0xffff0fa0)()
69 "sub pc, r0, #95" ::: "r0", "lr", "cc", \
70 "memory")
71#define cpu_relax() asm volatile("":::"memory") 69#define cpu_relax() asm volatile("":::"memory")
72#endif 70#endif
73 71
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
index af78d9a52a7d..01a64ad693f2 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
@@ -31,13 +31,14 @@
31#include "EXTERN.h" 31#include "EXTERN.h"
32#include "perl.h" 32#include "perl.h"
33#include "XSUB.h" 33#include "XSUB.h"
34#include "../../../util/trace-event-perl.h" 34#include "../../../perf.h"
35#include "../../../util/trace-event.h"
35 36
36#ifndef PERL_UNUSED_VAR 37#ifndef PERL_UNUSED_VAR
37# define PERL_UNUSED_VAR(var) if (0) var = var 38# define PERL_UNUSED_VAR(var) if (0) var = var
38#endif 39#endif
39 40
40#line 41 "Context.c" 41#line 42 "Context.c"
41 42
42XS(XS_Perf__Trace__Context_common_pc); /* prototype to pass -Wmissing-prototypes */ 43XS(XS_Perf__Trace__Context_common_pc); /* prototype to pass -Wmissing-prototypes */
43XS(XS_Perf__Trace__Context_common_pc) 44XS(XS_Perf__Trace__Context_common_pc)
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
index fb78006c165e..549cf0467d30 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
@@ -22,7 +22,8 @@
22#include "EXTERN.h" 22#include "EXTERN.h"
23#include "perl.h" 23#include "perl.h"
24#include "XSUB.h" 24#include "XSUB.h"
25#include "../../../util/trace-event-perl.h" 25#include "../../../perf.h"
26#include "../../../util/trace-event.h"
26 27
27MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context 28MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context
28PROTOTYPES: ENABLE 29PROTOTYPES: ENABLE
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
index 052f132ced24..f869c48dc9b0 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
@@ -44,7 +44,7 @@ sub nsecs_secs {
44sub nsecs_nsecs { 44sub nsecs_nsecs {
45 my ($nsecs) = @_; 45 my ($nsecs) = @_;
46 46
47 return $nsecs - nsecs_secs($nsecs); 47 return $nsecs % $NSECS_PER_SEC;
48} 48}
49 49
50sub nsecs_str { 50sub nsecs_str {
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-record b/tools/perf/scripts/perl/bin/check-perf-trace-record
index c7ec5de2f535..e6cb1474f8e8 100644
--- a/tools/perf/scripts/perl/bin/check-perf-trace-record
+++ b/tools/perf/scripts/perl/bin/check-perf-trace-record
@@ -1,7 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -c 1 -f -a -M -R -e kmem:kmalloc -e irq:softirq_entry 2perf record -c 1 -f -a -M -R -e kmem:kmalloc -e irq:softirq_entry -e kmem:kfree
3
4
5
6
7
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-report b/tools/perf/scripts/perl/bin/check-perf-trace-report
deleted file mode 100644
index 7fc4a033dd49..000000000000
--- a/tools/perf/scripts/perl/bin/check-perf-trace-report
+++ /dev/null
@@ -1,6 +0,0 @@
1#!/bin/bash
2# description: useless but exhaustive test script
3perf trace -s ~/libexec/perf-core/scripts/perl/check-perf-trace.pl
4
5
6
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record
new file mode 100644
index 000000000000..f8885d389e6f
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -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
new file mode 100644
index 000000000000..8bfc660e5056
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: system-wide failed syscalls
3# args: [comm]
4perf trace -s ~/libexec/perf-core/scripts/perl/failed-syscalls.pl $1
diff --git a/tools/perf/scripts/perl/failed-syscalls.pl b/tools/perf/scripts/perl/failed-syscalls.pl
new file mode 100644
index 000000000000..c18e7e27a84b
--- /dev/null
+++ b/tools/perf/scripts/perl/failed-syscalls.pl
@@ -0,0 +1,38 @@
1# failed system call counts
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Displays system-wide failed system call totals
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7
8use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
9use lib "./Perf-Trace-Util/lib";
10use Perf::Trace::Core;
11use Perf::Trace::Context;
12use Perf::Trace::Util;
13
14my %failed_syscalls;
15
16sub raw_syscalls::sys_exit
17{
18 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
19 $common_pid, $common_comm,
20 $id, $ret) = @_;
21
22 if ($ret < 0) {
23 $failed_syscalls{$common_comm}++;
24 }
25}
26
27sub trace_end
28{
29 printf("\nfailed syscalls by comm:\n\n");
30
31 printf("%-20s %10s\n", "comm", "# errors");
32 printf("%-20s %6s %10s\n", "--------------------", "----------");
33
34 foreach my $comm (sort {$failed_syscalls{$b} <=> $failed_syscalls{$a}}
35 keys %failed_syscalls) {
36 printf("%-20s %10s\n", $comm, $failed_syscalls{$comm});
37 }
38}
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c
new file mode 100644
index 000000000000..957085dd5d8d
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c
@@ -0,0 +1,88 @@
1/*
2 * Context.c. Python interfaces for perf trace.
3 *
4 * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <Python.h>
23#include "../../../perf.h"
24#include "../../../util/trace-event.h"
25
26PyMODINIT_FUNC initperf_trace_context(void);
27
28static PyObject *perf_trace_context_common_pc(PyObject *self, PyObject *args)
29{
30 static struct scripting_context *scripting_context;
31 PyObject *context;
32 int retval;
33
34 if (!PyArg_ParseTuple(args, "O", &context))
35 return NULL;
36
37 scripting_context = PyCObject_AsVoidPtr(context);
38 retval = common_pc(scripting_context);
39
40 return Py_BuildValue("i", retval);
41}
42
43static PyObject *perf_trace_context_common_flags(PyObject *self,
44 PyObject *args)
45{
46 static struct scripting_context *scripting_context;
47 PyObject *context;
48 int retval;
49
50 if (!PyArg_ParseTuple(args, "O", &context))
51 return NULL;
52
53 scripting_context = PyCObject_AsVoidPtr(context);
54 retval = common_flags(scripting_context);
55
56 return Py_BuildValue("i", retval);
57}
58
59static PyObject *perf_trace_context_common_lock_depth(PyObject *self,
60 PyObject *args)
61{
62 static struct scripting_context *scripting_context;
63 PyObject *context;
64 int retval;
65
66 if (!PyArg_ParseTuple(args, "O", &context))
67 return NULL;
68
69 scripting_context = PyCObject_AsVoidPtr(context);
70 retval = common_lock_depth(scripting_context);
71
72 return Py_BuildValue("i", retval);
73}
74
75static PyMethodDef ContextMethods[] = {
76 { "common_pc", perf_trace_context_common_pc, METH_VARARGS,
77 "Get the common preempt count event field value."},
78 { "common_flags", perf_trace_context_common_flags, METH_VARARGS,
79 "Get the common flags event field value."},
80 { "common_lock_depth", perf_trace_context_common_lock_depth,
81 METH_VARARGS, "Get the common lock depth event field value."},
82 { NULL, NULL, 0, NULL}
83};
84
85PyMODINIT_FUNC initperf_trace_context(void)
86{
87 (void) Py_InitModule("perf_trace_context", ContextMethods);
88}
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
new file mode 100644
index 000000000000..1dc464ee2ca8
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
@@ -0,0 +1,91 @@
1# Core.py - Python extension for perf trace, core functions
2#
3# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com>
4#
5# This software may be distributed under the terms of the GNU General
6# Public License ("GPL") version 2 as published by the Free Software
7# Foundation.
8
9from collections import defaultdict
10
11def autodict():
12 return defaultdict(autodict)
13
14flag_fields = autodict()
15symbolic_fields = autodict()
16
17def define_flag_field(event_name, field_name, delim):
18 flag_fields[event_name][field_name]['delim'] = delim
19
20def define_flag_value(event_name, field_name, value, field_str):
21 flag_fields[event_name][field_name]['values'][value] = field_str
22
23def define_symbolic_field(event_name, field_name):
24 # nothing to do, really
25 pass
26
27def define_symbolic_value(event_name, field_name, value, field_str):
28 symbolic_fields[event_name][field_name]['values'][value] = field_str
29
30def flag_str(event_name, field_name, value):
31 string = ""
32
33 if flag_fields[event_name][field_name]:
34 print_delim = 0
35 keys = flag_fields[event_name][field_name]['values'].keys()
36 keys.sort()
37 for idx in keys:
38 if not value and not idx:
39 string += flag_fields[event_name][field_name]['values'][idx]
40 break
41 if idx and (value & idx) == idx:
42 if print_delim and flag_fields[event_name][field_name]['delim']:
43 string += " " + flag_fields[event_name][field_name]['delim'] + " "
44 string += flag_fields[event_name][field_name]['values'][idx]
45 print_delim = 1
46 value &= ~idx
47
48 return string
49
50def symbol_str(event_name, field_name, value):
51 string = ""
52
53 if symbolic_fields[event_name][field_name]:
54 keys = symbolic_fields[event_name][field_name]['values'].keys()
55 keys.sort()
56 for idx in keys:
57 if not value and not idx:
58 string = symbolic_fields[event_name][field_name]['values'][idx]
59 break
60 if (value == idx):
61 string = symbolic_fields[event_name][field_name]['values'][idx]
62 break
63
64 return string
65
66trace_flags = { 0x00: "NONE", \
67 0x01: "IRQS_OFF", \
68 0x02: "IRQS_NOSUPPORT", \
69 0x04: "NEED_RESCHED", \
70 0x08: "HARDIRQ", \
71 0x10: "SOFTIRQ" }
72
73def trace_flag_str(value):
74 string = ""
75 print_delim = 0
76
77 keys = trace_flags.keys()
78
79 for idx in keys:
80 if not value and not idx:
81 string += "NONE"
82 break
83
84 if idx and (value & idx) == idx:
85 if print_delim:
86 string += " | ";
87 string += trace_flags[idx]
88 print_delim = 1
89 value &= ~idx
90
91 return string
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
new file mode 100644
index 000000000000..83e91435ed09
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
@@ -0,0 +1,25 @@
1# Util.py - Python extension for perf trace, miscellaneous utility code
2#
3# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com>
4#
5# This software may be distributed under the terms of the GNU General
6# Public License ("GPL") version 2 as published by the Free Software
7# Foundation.
8
9NSECS_PER_SEC = 1000000000
10
11def avg(total, n):
12 return total / n
13
14def nsecs(secs, nsecs):
15 return secs * NSECS_PER_SEC + nsecs
16
17def nsecs_secs(nsecs):
18 return nsecs / NSECS_PER_SEC
19
20def nsecs_nsecs(nsecs):
21 return nsecs % NSECS_PER_SEC
22
23def nsecs_str(nsecs):
24 str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)),
25 return str
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
new file mode 100644
index 000000000000..f8885d389e6f
--- /dev/null
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -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
new file mode 100644
index 000000000000..1e0c0a860c87
--- /dev/null
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: system-wide failed syscalls, by pid
3# args: [comm]
4perf trace -s ~/libexec/perf-core/scripts/python/failed-syscalls-by-pid.py $1
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
new file mode 100644
index 000000000000..45a8c50359da
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -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
new file mode 100644
index 000000000000..f8044d192271
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: system-wide syscall counts, by pid
3# args: [comm]
4perf trace -s ~/libexec/perf-core/scripts/python/syscall-counts-by-pid.py $1
diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record
new file mode 100644
index 000000000000..45a8c50359da
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -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
new file mode 100644
index 000000000000..a366aa61612f
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: system-wide syscall counts
3# args: [comm]
4perf trace -s ~/libexec/perf-core/scripts/python/syscall-counts.py $1
diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py
new file mode 100644
index 000000000000..964d934395ff
--- /dev/null
+++ b/tools/perf/scripts/python/check-perf-trace.py
@@ -0,0 +1,83 @@
1# perf trace event handlers, generated by perf trace -g python
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# This script tests basic functionality such as flag and symbol
6# strings, common_xxx() calls back into perf, begin, end, unhandled
7# events, etc. Basically, if this script runs successfully and
8# displays expected results, Python scripting support should be ok.
9
10import os
11import sys
12
13sys.path.append(os.environ['PERF_EXEC_PATH'] + \
14 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
15
16from Core import *
17from perf_trace_context import *
18
19unhandled = autodict()
20
21def trace_begin():
22 print "trace_begin"
23 pass
24
25def trace_end():
26 print_unhandled()
27
28def irq__softirq_entry(event_name, context, common_cpu,
29 common_secs, common_nsecs, common_pid, common_comm,
30 vec):
31 print_header(event_name, common_cpu, common_secs, common_nsecs,
32 common_pid, common_comm)
33
34 print_uncommon(context)
35
36 print "vec=%s\n" % \
37 (symbol_str("irq__softirq_entry", "vec", vec)),
38
39def kmem__kmalloc(event_name, context, common_cpu,
40 common_secs, common_nsecs, common_pid, common_comm,
41 call_site, ptr, bytes_req, bytes_alloc,
42 gfp_flags):
43 print_header(event_name, common_cpu, common_secs, common_nsecs,
44 common_pid, common_comm)
45
46 print_uncommon(context)
47
48 print "call_site=%u, ptr=%u, bytes_req=%u, " \
49 "bytes_alloc=%u, gfp_flags=%s\n" % \
50 (call_site, ptr, bytes_req, bytes_alloc,
51
52 flag_str("kmem__kmalloc", "gfp_flags", gfp_flags)),
53
54def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
55 common_pid, common_comm):
56 try:
57 unhandled[event_name] += 1
58 except TypeError:
59 unhandled[event_name] = 1
60
61def print_header(event_name, cpu, secs, nsecs, pid, comm):
62 print "%-20s %5u %05u.%09u %8u %-20s " % \
63 (event_name, cpu, secs, nsecs, pid, comm),
64
65# print trace fields not included in handler args
66def print_uncommon(context):
67 print "common_preempt_count=%d, common_flags=%s, common_lock_depth=%d, " \
68 % (common_pc(context), trace_flag_str(common_flags(context)), \
69 common_lock_depth(context))
70
71def print_unhandled():
72 keys = unhandled.keys()
73 if not keys:
74 return
75
76 print "\nunhandled events:\n\n",
77
78 print "%-40s %10s\n" % ("event", "count"),
79 print "%-40s %10s\n" % ("----------------------------------------", \
80 "-----------"),
81
82 for event_name in keys:
83 print "%-40s %10d\n" % (event_name, unhandled[event_name])
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py
new file mode 100644
index 000000000000..0ca02278fe69
--- /dev/null
+++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py
@@ -0,0 +1,68 @@
1# failed system call counts, by pid
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Displays system-wide failed system call totals, broken down by pid.
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7
8import os
9import sys
10
11sys.path.append(os.environ['PERF_EXEC_PATH'] + \
12 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
13
14from perf_trace_context import *
15from Core import *
16
17usage = "perf trace -s syscall-counts-by-pid.py [comm]\n";
18
19for_comm = None
20
21if len(sys.argv) > 2:
22 sys.exit(usage)
23
24if len(sys.argv) > 1:
25 for_comm = sys.argv[1]
26
27syscalls = autodict()
28
29def trace_begin():
30 pass
31
32def trace_end():
33 print_error_totals()
34
35def raw_syscalls__sys_exit(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm,
37 id, ret):
38 if for_comm is not None:
39 if common_comm != for_comm:
40 return
41
42 if ret < 0:
43 try:
44 syscalls[common_comm][common_pid][id][ret] += 1
45 except TypeError:
46 syscalls[common_comm][common_pid][id][ret] = 1
47
48def print_error_totals():
49 if for_comm is not None:
50 print "\nsyscall errors for %s:\n\n" % (for_comm),
51 else:
52 print "\nsyscall errors:\n\n",
53
54 print "%-30s %10s\n" % ("comm [pid]", "count"),
55 print "%-30s %10s\n" % ("------------------------------", \
56 "----------"),
57
58 comm_keys = syscalls.keys()
59 for comm in comm_keys:
60 pid_keys = syscalls[comm].keys()
61 for pid in pid_keys:
62 print "\n%s [%d]\n" % (comm, pid),
63 id_keys = syscalls[comm][pid].keys()
64 for id in id_keys:
65 print " syscall: %-16d\n" % (id),
66 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):
68 print " err = %-20d %10d\n" % (ret, val),
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py
new file mode 100644
index 000000000000..af722d6a4b3f
--- /dev/null
+++ b/tools/perf/scripts/python/syscall-counts-by-pid.py
@@ -0,0 +1,64 @@
1# system call counts, by pid
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
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.
7
8import os
9import sys
10
11sys.path.append(os.environ['PERF_EXEC_PATH'] + \
12 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
13
14from perf_trace_context import *
15from Core import *
16
17usage = "perf trace -s syscall-counts-by-pid.py [comm]\n";
18
19for_comm = None
20
21if len(sys.argv) > 2:
22 sys.exit(usage)
23
24if len(sys.argv) > 1:
25 for_comm = sys.argv[1]
26
27syscalls = autodict()
28
29def trace_begin():
30 pass
31
32def trace_end():
33 print_syscall_totals()
34
35def raw_syscalls__sys_enter(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm,
37 id, args):
38 if for_comm is not None:
39 if common_comm != for_comm:
40 return
41 try:
42 syscalls[common_comm][common_pid][id] += 1
43 except TypeError:
44 syscalls[common_comm][common_pid][id] = 1
45
46def print_syscall_totals():
47 if for_comm is not None:
48 print "\nsyscall events for %s:\n\n" % (for_comm),
49 else:
50 print "\nsyscall events by comm/pid:\n\n",
51
52 print "%-40s %10s\n" % ("comm [pid]/syscalls", "count"),
53 print "%-40s %10s\n" % ("----------------------------------------", \
54 "----------"),
55
56 comm_keys = syscalls.keys()
57 for comm in comm_keys:
58 pid_keys = syscalls[comm].keys()
59 for pid in pid_keys:
60 print "\n%s [%d]\n" % (comm, pid),
61 id_keys = syscalls[comm][pid].keys()
62 for id, val in sorted(syscalls[comm][pid].iteritems(), \
63 key = lambda(k, v): (v, k), reverse = True):
64 print " %-38d %10d\n" % (id, val),
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py
new file mode 100644
index 000000000000..f977e85ff049
--- /dev/null
+++ b/tools/perf/scripts/python/syscall-counts.py
@@ -0,0 +1,58 @@
1# system call counts
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
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.
7
8import os
9import sys
10
11sys.path.append(os.environ['PERF_EXEC_PATH'] + \
12 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
13
14from perf_trace_context import *
15from Core import *
16
17usage = "perf trace -s syscall-counts.py [comm]\n";
18
19for_comm = None
20
21if len(sys.argv) > 2:
22 sys.exit(usage)
23
24if len(sys.argv) > 1:
25 for_comm = sys.argv[1]
26
27syscalls = autodict()
28
29def trace_begin():
30 pass
31
32def trace_end():
33 print_syscall_totals()
34
35def raw_syscalls__sys_enter(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm,
37 id, args):
38 if for_comm is not None:
39 if common_comm != for_comm:
40 return
41 try:
42 syscalls[id] += 1
43 except TypeError:
44 syscalls[id] = 1
45
46def print_syscall_totals():
47 if for_comm is not None:
48 print "\nsyscall events for %s:\n\n" % (for_comm),
49 else:
50 print "\nsyscall events:\n\n",
51
52 print "%-40s %10s\n" % ("event", "count"),
53 print "%-40s %10s\n" % ("----------------------------------------", \
54 "-----------"),
55
56 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
57 reverse = True):
58 print "%-40d %10d\n" % (id, val),
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
new file mode 100644
index 000000000000..04904b35ba81
--- /dev/null
+++ b/tools/perf/util/build-id.c
@@ -0,0 +1,39 @@
1/*
2 * build-id.c
3 *
4 * build-id support
5 *
6 * Copyright (C) 2009, 2010 Red Hat Inc.
7 * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "build-id.h"
10#include "event.h"
11#include "symbol.h"
12#include <linux/kernel.h>
13
14static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
15{
16 struct addr_location al;
17 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
18 struct thread *thread = perf_session__findnew(session, event->ip.pid);
19
20 if (thread == NULL) {
21 pr_err("problem processing %d event, skipping it.\n",
22 event->header.type);
23 return -1;
24 }
25
26 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
27 event->ip.ip, &al);
28
29 if (al.map != NULL)
30 al.map->dso->hit = 1;
31
32 return 0;
33}
34
35struct perf_event_ops build_id__mark_dso_hit_ops = {
36 .sample = build_id__mark_dso_hit,
37 .mmap = event__process_mmap,
38 .fork = event__process_task,
39};
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
new file mode 100644
index 000000000000..1d981d63cf9a
--- /dev/null
+++ b/tools/perf/util/build-id.h
@@ -0,0 +1,8 @@
1#ifndef PERF_BUILD_ID_H_
2#define PERF_BUILD_ID_H_ 1
3
4#include "session.h"
5
6extern struct perf_event_ops build_id__mark_dso_hit_ops;
7
8#endif
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
deleted file mode 100644
index b557b836de3d..000000000000
--- a/tools/perf/util/data_map.c
+++ /dev/null
@@ -1,252 +0,0 @@
1#include "symbol.h"
2#include "util.h"
3#include "debug.h"
4#include "thread.h"
5#include "session.h"
6
7static int process_event_stub(event_t *event __used,
8 struct perf_session *session __used)
9{
10 dump_printf(": unhandled!\n");
11 return 0;
12}
13
14static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
15{
16 if (!handler->process_sample_event)
17 handler->process_sample_event = process_event_stub;
18 if (!handler->process_mmap_event)
19 handler->process_mmap_event = process_event_stub;
20 if (!handler->process_comm_event)
21 handler->process_comm_event = process_event_stub;
22 if (!handler->process_fork_event)
23 handler->process_fork_event = process_event_stub;
24 if (!handler->process_exit_event)
25 handler->process_exit_event = process_event_stub;
26 if (!handler->process_lost_event)
27 handler->process_lost_event = process_event_stub;
28 if (!handler->process_read_event)
29 handler->process_read_event = process_event_stub;
30 if (!handler->process_throttle_event)
31 handler->process_throttle_event = process_event_stub;
32 if (!handler->process_unthrottle_event)
33 handler->process_unthrottle_event = process_event_stub;
34}
35
36static const char *event__name[] = {
37 [0] = "TOTAL",
38 [PERF_RECORD_MMAP] = "MMAP",
39 [PERF_RECORD_LOST] = "LOST",
40 [PERF_RECORD_COMM] = "COMM",
41 [PERF_RECORD_EXIT] = "EXIT",
42 [PERF_RECORD_THROTTLE] = "THROTTLE",
43 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
44 [PERF_RECORD_FORK] = "FORK",
45 [PERF_RECORD_READ] = "READ",
46 [PERF_RECORD_SAMPLE] = "SAMPLE",
47};
48
49unsigned long event__total[PERF_RECORD_MAX];
50
51void event__print_totals(void)
52{
53 int i;
54 for (i = 0; i < PERF_RECORD_MAX; ++i)
55 pr_info("%10s events: %10ld\n",
56 event__name[i], event__total[i]);
57}
58
59static int process_event(event_t *event, struct perf_session *session,
60 struct perf_event_ops *ops,
61 unsigned long offset, unsigned long head)
62{
63 trace_event(event);
64
65 if (event->header.type < PERF_RECORD_MAX) {
66 dump_printf("%p [%p]: PERF_RECORD_%s",
67 (void *)(offset + head),
68 (void *)(long)(event->header.size),
69 event__name[event->header.type]);
70 ++event__total[0];
71 ++event__total[event->header.type];
72 }
73
74 switch (event->header.type) {
75 case PERF_RECORD_SAMPLE:
76 return ops->process_sample_event(event, session);
77 case PERF_RECORD_MMAP:
78 return ops->process_mmap_event(event, session);
79 case PERF_RECORD_COMM:
80 return ops->process_comm_event(event, session);
81 case PERF_RECORD_FORK:
82 return ops->process_fork_event(event, session);
83 case PERF_RECORD_EXIT:
84 return ops->process_exit_event(event, session);
85 case PERF_RECORD_LOST:
86 return ops->process_lost_event(event, session);
87 case PERF_RECORD_READ:
88 return ops->process_read_event(event, session);
89 case PERF_RECORD_THROTTLE:
90 return ops->process_throttle_event(event, session);
91 case PERF_RECORD_UNTHROTTLE:
92 return ops->process_unthrottle_event(event, session);
93 default:
94 ops->total_unknown++;
95 return -1;
96 }
97}
98
99int perf_header__read_build_ids(int input, u64 offset, u64 size)
100{
101 struct build_id_event bev;
102 char filename[PATH_MAX];
103 u64 limit = offset + size;
104 int err = -1;
105
106 while (offset < limit) {
107 struct dso *dso;
108 ssize_t len;
109
110 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
111 goto out;
112
113 len = bev.header.size - sizeof(bev);
114 if (read(input, filename, len) != len)
115 goto out;
116
117 dso = dsos__findnew(filename);
118 if (dso != NULL)
119 dso__set_build_id(dso, &bev.build_id);
120
121 offset += bev.header.size;
122 }
123 err = 0;
124out:
125 return err;
126}
127
128static struct thread *perf_session__register_idle_thread(struct perf_session *self)
129{
130 struct thread *thread = perf_session__findnew(self, 0);
131
132 if (!thread || thread__set_comm(thread, "swapper")) {
133 pr_err("problem inserting idle task.\n");
134 thread = NULL;
135 }
136
137 return thread;
138}
139
140int perf_session__process_events(struct perf_session *self,
141 struct perf_event_ops *ops)
142{
143 int err;
144 unsigned long head, shift;
145 unsigned long offset = 0;
146 size_t page_size;
147 event_t *event;
148 uint32_t size;
149 char *buf;
150
151 if (perf_session__register_idle_thread(self) == NULL)
152 return -ENOMEM;
153
154 perf_event_ops__fill_defaults(ops);
155
156 page_size = getpagesize();
157
158 head = self->header.data_offset;
159 self->sample_type = perf_header__sample_type(&self->header);
160
161 err = -EINVAL;
162 if (ops->sample_type_check && ops->sample_type_check(self) < 0)
163 goto out_err;
164
165 if (!ops->full_paths) {
166 char bf[PATH_MAX];
167
168 if (getcwd(bf, sizeof(bf)) == NULL) {
169 err = -errno;
170out_getcwd_err:
171 pr_err("failed to get the current directory\n");
172 goto out_err;
173 }
174 self->cwd = strdup(bf);
175 if (self->cwd == NULL) {
176 err = -ENOMEM;
177 goto out_getcwd_err;
178 }
179 self->cwdlen = strlen(self->cwd);
180 }
181
182 shift = page_size * (head / page_size);
183 offset += shift;
184 head -= shift;
185
186remap:
187 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
188 MAP_SHARED, self->fd, offset);
189 if (buf == MAP_FAILED) {
190 pr_err("failed to mmap file\n");
191 err = -errno;
192 goto out_err;
193 }
194
195more:
196 event = (event_t *)(buf + head);
197
198 size = event->header.size;
199 if (!size)
200 size = 8;
201
202 if (head + event->header.size >= page_size * self->mmap_window) {
203 int munmap_ret;
204
205 shift = page_size * (head / page_size);
206
207 munmap_ret = munmap(buf, page_size * self->mmap_window);
208 assert(munmap_ret == 0);
209
210 offset += shift;
211 head -= shift;
212 goto remap;
213 }
214
215 size = event->header.size;
216
217 dump_printf("\n%p [%p]: event: %d\n",
218 (void *)(offset + head),
219 (void *)(long)event->header.size,
220 event->header.type);
221
222 if (!size || process_event(event, self, ops, offset, head) < 0) {
223
224 dump_printf("%p [%p]: skipping unknown header type: %d\n",
225 (void *)(offset + head),
226 (void *)(long)(event->header.size),
227 event->header.type);
228
229 /*
230 * assume we lost track of the stream, check alignment, and
231 * increment a single u64 in the hope to catch on again 'soon'.
232 */
233
234 if (unlikely(head & 7))
235 head &= ~7ULL;
236
237 size = 8;
238 }
239
240 head += size;
241
242 if (offset + head >= self->header.data_offset + self->header.data_size)
243 goto done;
244
245 if (offset + head < self->size)
246 goto more;
247
248done:
249 err = 0;
250out_err:
251 return err;
252}
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 28d520d5a1fb..0905600c3851 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -9,6 +9,7 @@
9#include "color.h" 9#include "color.h"
10#include "event.h" 10#include "event.h"
11#include "debug.h" 11#include "debug.h"
12#include "util.h"
12 13
13int verbose = 0; 14int verbose = 0;
14int dump_trace = 0; 15int dump_trace = 0;
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index 06b73ee02c49..a88fefc0cc0a 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -106,16 +106,14 @@ int debugfs_valid_entry(const char *path)
106 return 0; 106 return 0;
107} 107}
108 108
109/* mount the debugfs somewhere */ 109/* mount the debugfs somewhere if it's not mounted */
110 110
111int debugfs_mount(const char *mountpoint) 111char *debugfs_mount(const char *mountpoint)
112{ 112{
113 char mountcmd[128];
114
115 /* see if it's already mounted */ 113 /* see if it's already mounted */
116 if (debugfs_find_mountpoint()) { 114 if (debugfs_find_mountpoint()) {
117 debugfs_premounted = 1; 115 debugfs_premounted = 1;
118 return 0; 116 return debugfs_mountpoint;
119 } 117 }
120 118
121 /* if not mounted and no argument */ 119 /* if not mounted and no argument */
@@ -127,13 +125,14 @@ int debugfs_mount(const char *mountpoint)
127 mountpoint = "/sys/kernel/debug"; 125 mountpoint = "/sys/kernel/debug";
128 } 126 }
129 127
128 if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
129 return NULL;
130
130 /* save the mountpoint */ 131 /* save the mountpoint */
131 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); 132 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
133 debugfs_found = 1;
132 134
133 /* mount it */ 135 return debugfs_mountpoint;
134 snprintf(mountcmd, sizeof(mountcmd),
135 "/bin/mount -t debugfs debugfs %s", mountpoint);
136 return system(mountcmd);
137} 136}
138 137
139/* umount the debugfs */ 138/* umount the debugfs */
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 3cd14f9ae784..83a02879745f 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -15,7 +15,7 @@
15extern const char *debugfs_find_mountpoint(void); 15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs); 16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path); 17extern int debugfs_valid_entry(const char *path);
18extern int debugfs_mount(const char *mountpoint); 18extern char *debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void); 19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value); 20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size); 21extern int debugfs_read(const char *entry, char *buffer, size_t size);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index bb0fd6da2d56..705ec63548b4 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -8,8 +8,7 @@
8#include "thread.h" 8#include "thread.h"
9 9
10static pid_t event__synthesize_comm(pid_t pid, int full, 10static pid_t event__synthesize_comm(pid_t pid, int full,
11 int (*process)(event_t *event, 11 event__handler_t process,
12 struct perf_session *session),
13 struct perf_session *session) 12 struct perf_session *session)
14{ 13{
15 event_t ev; 14 event_t ev;
@@ -91,8 +90,7 @@ out_failure:
91} 90}
92 91
93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 92static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
94 int (*process)(event_t *event, 93 event__handler_t process,
95 struct perf_session *session),
96 struct perf_session *session) 94 struct perf_session *session)
97{ 95{
98 char filename[PATH_MAX]; 96 char filename[PATH_MAX];
@@ -112,7 +110,10 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
112 while (1) { 110 while (1) {
113 char bf[BUFSIZ], *pbf = bf; 111 char bf[BUFSIZ], *pbf = bf;
114 event_t ev = { 112 event_t ev = {
115 .header = { .type = PERF_RECORD_MMAP }, 113 .header = {
114 .type = PERF_RECORD_MMAP,
115 .misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */
116 },
116 }; 117 };
117 int n; 118 int n;
118 size_t size; 119 size_t size;
@@ -156,9 +157,38 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
156 return 0; 157 return 0;
157} 158}
158 159
159int event__synthesize_thread(pid_t pid, 160int event__synthesize_modules(event__handler_t process,
160 int (*process)(event_t *event, 161 struct perf_session *session)
161 struct perf_session *session), 162{
163 struct rb_node *nd;
164
165 for (nd = rb_first(&session->kmaps.maps[MAP__FUNCTION]);
166 nd; nd = rb_next(nd)) {
167 event_t ev;
168 size_t size;
169 struct map *pos = rb_entry(nd, struct map, rb_node);
170
171 if (pos->dso->kernel)
172 continue;
173
174 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
175 memset(&ev, 0, sizeof(ev));
176 ev.mmap.header.misc = 1; /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
177 ev.mmap.header.type = PERF_RECORD_MMAP;
178 ev.mmap.header.size = (sizeof(ev.mmap) -
179 (sizeof(ev.mmap.filename) - size));
180 ev.mmap.start = pos->start;
181 ev.mmap.len = pos->end - pos->start;
182
183 memcpy(ev.mmap.filename, pos->dso->long_name,
184 pos->dso->long_name_len + 1);
185 process(&ev, session);
186 }
187
188 return 0;
189}
190
191int event__synthesize_thread(pid_t pid, event__handler_t process,
162 struct perf_session *session) 192 struct perf_session *session)
163{ 193{
164 pid_t tgid = event__synthesize_comm(pid, 1, process, session); 194 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
@@ -167,8 +197,7 @@ int event__synthesize_thread(pid_t pid,
167 return event__synthesize_mmap_events(pid, tgid, process, session); 197 return event__synthesize_mmap_events(pid, tgid, process, session);
168} 198}
169 199
170void event__synthesize_threads(int (*process)(event_t *event, 200void event__synthesize_threads(event__handler_t process,
171 struct perf_session *session),
172 struct perf_session *session) 201 struct perf_session *session)
173{ 202{
174 DIR *proc; 203 DIR *proc;
@@ -189,6 +218,59 @@ void event__synthesize_threads(int (*process)(event_t *event,
189 closedir(proc); 218 closedir(proc);
190} 219}
191 220
221struct process_symbol_args {
222 const char *name;
223 u64 start;
224};
225
226static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
227{
228 struct process_symbol_args *args = arg;
229
230 /*
231 * Must be a function or at least an alias, as in PARISC64, where "_text" is
232 * an 'A' to the same address as "_stext".
233 */
234 if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
235 type == 'A') || strcmp(name, args->name))
236 return 0;
237
238 args->start = start;
239 return 1;
240}
241
242int event__synthesize_kernel_mmap(event__handler_t process,
243 struct perf_session *session,
244 const char *symbol_name)
245{
246 size_t size;
247 event_t ev = {
248 .header = {
249 .type = PERF_RECORD_MMAP,
250 .misc = 1, /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
251 },
252 };
253 /*
254 * We should get this from /sys/kernel/sections/.text, but till that is
255 * available use this, and after it is use this as a fallback for older
256 * kernels.
257 */
258 struct process_symbol_args args = { .name = symbol_name, };
259
260 if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0)
261 return -ENOENT;
262
263 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
264 "[kernel.kallsyms.%s]", symbol_name) + 1;
265 size = ALIGN(size, sizeof(u64));
266 ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size));
267 ev.mmap.pgoff = args.start;
268 ev.mmap.start = session->vmlinux_maps[MAP__FUNCTION]->start;
269 ev.mmap.len = session->vmlinux_maps[MAP__FUNCTION]->end - ev.mmap.start ;
270
271 return process(&ev, session);
272}
273
192static void thread__comm_adjust(struct thread *self) 274static void thread__comm_adjust(struct thread *self)
193{ 275{
194 char *comm = self->comm; 276 char *comm = self->comm;
@@ -240,22 +322,88 @@ int event__process_lost(event_t *self, struct perf_session *session)
240 322
241int event__process_mmap(event_t *self, struct perf_session *session) 323int event__process_mmap(event_t *self, struct perf_session *session)
242{ 324{
243 struct thread *thread = perf_session__findnew(session, self->mmap.pid); 325 struct thread *thread;
244 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 326 struct map *map;
245 session->cwd, session->cwdlen); 327
328 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
329 self->mmap.pid, self->mmap.tid, self->mmap.start,
330 self->mmap.len, self->mmap.pgoff, self->mmap.filename);
331
332 if (self->mmap.pid == 0) {
333 static const char kmmap_prefix[] = "[kernel.kallsyms.";
334
335 if (self->mmap.filename[0] == '/') {
336 char short_module_name[1024];
337 char *name = strrchr(self->mmap.filename, '/'), *dot;
338
339 if (name == NULL)
340 goto out_problem;
341
342 ++name; /* skip / */
343 dot = strrchr(name, '.');
344 if (dot == NULL)
345 goto out_problem;
346
347 snprintf(short_module_name, sizeof(short_module_name),
348 "[%.*s]", (int)(dot - name), name);
349 strxfrchar(short_module_name, '-', '_');
350
351 map = perf_session__new_module_map(session,
352 self->mmap.start,
353 self->mmap.filename);
354 if (map == NULL)
355 goto out_problem;
356
357 name = strdup(short_module_name);
358 if (name == NULL)
359 goto out_problem;
360
361 map->dso->short_name = name;
362 map->end = map->start + self->mmap.len;
363 } else if (memcmp(self->mmap.filename, kmmap_prefix,
364 sizeof(kmmap_prefix) - 1) == 0) {
365 const char *symbol_name = (self->mmap.filename +
366 sizeof(kmmap_prefix) - 1);
367 /*
368 * Should be there already, from the build-id table in
369 * the header.
370 */
371 struct dso *kernel = __dsos__findnew(&dsos__kernel,
372 "[kernel.kallsyms]");
373 if (kernel == NULL)
374 goto out_problem;
375
376 kernel->kernel = 1;
377 if (__perf_session__create_kernel_maps(session, kernel) < 0)
378 goto out_problem;
379
380 session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start;
381 session->vmlinux_maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
382 /*
383 * Be a bit paranoid here, some perf.data file came with
384 * a zero sized synthesized MMAP event for the kernel.
385 */
386 if (session->vmlinux_maps[MAP__FUNCTION]->end == 0)
387 session->vmlinux_maps[MAP__FUNCTION]->end = ~0UL;
388
389 perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name,
390 self->mmap.pgoff);
391 }
392 return 0;
393 }
246 394
247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 395 thread = perf_session__findnew(session, self->mmap.pid);
248 self->mmap.pid, self->mmap.tid, 396 map = map__new(&self->mmap, MAP__FUNCTION,
249 (void *)(long)self->mmap.start, 397 session->cwd, session->cwdlen);
250 (void *)(long)self->mmap.len,
251 (void *)(long)self->mmap.pgoff,
252 self->mmap.filename);
253 398
254 if (thread == NULL || map == NULL) 399 if (thread == NULL || map == NULL)
255 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); 400 goto out_problem;
256 else
257 thread__insert_map(thread, map);
258 401
402 thread__insert_map(thread, map);
403 return 0;
404
405out_problem:
406 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
259 return 0; 407 return 0;
260} 408}
261 409
@@ -284,26 +432,24 @@ int event__process_task(event_t *self, struct perf_session *session)
284 return 0; 432 return 0;
285} 433}
286 434
287void thread__find_addr_location(struct thread *self, 435void thread__find_addr_map(struct thread *self,
288 struct perf_session *session, u8 cpumode, 436 struct perf_session *session, u8 cpumode,
289 enum map_type type, u64 addr, 437 enum map_type type, u64 addr,
290 struct addr_location *al, 438 struct addr_location *al)
291 symbol_filter_t filter)
292{ 439{
293 struct map_groups *mg = &self->mg; 440 struct map_groups *mg = &self->mg;
294 441
295 al->thread = self; 442 al->thread = self;
296 al->addr = addr; 443 al->addr = addr;
297 444
298 if (cpumode & PERF_RECORD_MISC_KERNEL) { 445 if (cpumode == PERF_RECORD_MISC_KERNEL) {
299 al->level = 'k'; 446 al->level = 'k';
300 mg = &session->kmaps; 447 mg = &session->kmaps;
301 } else if (cpumode & PERF_RECORD_MISC_USER) 448 } else if (cpumode == PERF_RECORD_MISC_USER)
302 al->level = '.'; 449 al->level = '.';
303 else { 450 else {
304 al->level = 'H'; 451 al->level = 'H';
305 al->map = NULL; 452 al->map = NULL;
306 al->sym = NULL;
307 return; 453 return;
308 } 454 }
309try_again: 455try_again:
@@ -322,11 +468,21 @@ try_again:
322 mg = &session->kmaps; 468 mg = &session->kmaps;
323 goto try_again; 469 goto try_again;
324 } 470 }
325 al->sym = NULL; 471 } else
326 } else {
327 al->addr = al->map->map_ip(al->map, al->addr); 472 al->addr = al->map->map_ip(al->map, al->addr);
328 al->sym = map__find_symbol(al->map, session, al->addr, filter); 473}
329 } 474
475void thread__find_addr_location(struct thread *self,
476 struct perf_session *session, u8 cpumode,
477 enum map_type type, u64 addr,
478 struct addr_location *al,
479 symbol_filter_t filter)
480{
481 thread__find_addr_map(self, session, cpumode, type, addr, al);
482 if (al->map != NULL)
483 al->sym = map__find_symbol(al->map, al->addr, filter);
484 else
485 al->sym = NULL;
330} 486}
331 487
332static void dso__calc_col_width(struct dso *self) 488static void dso__calc_col_width(struct dso *self)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 690a96d0467c..50a7132887f5 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,10 +1,10 @@
1#ifndef __PERF_RECORD_H 1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3 3
4#include <limits.h>
5
4#include "../perf.h" 6#include "../perf.h"
5#include "util.h" 7#include "map.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8 8
9/* 9/*
10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -101,74 +101,19 @@ struct events_stats {
101 101
102void event__print_totals(void); 102void event__print_totals(void);
103 103
104enum map_type {
105 MAP__FUNCTION = 0,
106 MAP__VARIABLE,
107};
108
109#define MAP__NR_TYPES (MAP__VARIABLE + 1)
110
111struct map {
112 union {
113 struct rb_node rb_node;
114 struct list_head node;
115 };
116 u64 start;
117 u64 end;
118 enum map_type type;
119 u64 pgoff;
120 u64 (*map_ip)(struct map *, u64);
121 u64 (*unmap_ip)(struct map *, u64);
122 struct dso *dso;
123};
124
125static inline u64 map__map_ip(struct map *map, u64 ip)
126{
127 return ip - map->start + map->pgoff;
128}
129
130static inline u64 map__unmap_ip(struct map *map, u64 ip)
131{
132 return ip + map->start - map->pgoff;
133}
134
135static inline u64 identity__map_ip(struct map *map __used, u64 ip)
136{
137 return ip;
138}
139
140struct symbol;
141
142typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
143
144void map__init(struct map *self, enum map_type type,
145 u64 start, u64 end, u64 pgoff, struct dso *dso);
146struct map *map__new(struct mmap_event *event, enum map_type,
147 char *cwd, int cwdlen);
148void map__delete(struct map *self);
149struct map *map__clone(struct map *self);
150int map__overlap(struct map *l, struct map *r);
151size_t map__fprintf(struct map *self, FILE *fp);
152
153struct perf_session; 104struct perf_session;
154 105
155int map__load(struct map *self, struct perf_session *session, 106typedef int (*event__handler_t)(event_t *event, struct perf_session *session);
156 symbol_filter_t filter); 107
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session, 108int event__synthesize_thread(pid_t pid, event__handler_t process,
158 u64 addr, symbol_filter_t filter);
159struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
160 struct perf_session *session,
161 symbol_filter_t filter);
162void map__fixup_start(struct map *self);
163void map__fixup_end(struct map *self);
164
165int event__synthesize_thread(pid_t pid,
166 int (*process)(event_t *event,
167 struct perf_session *session),
168 struct perf_session *session); 109 struct perf_session *session);
169void event__synthesize_threads(int (*process)(event_t *event, 110void event__synthesize_threads(event__handler_t process,
170 struct perf_session *session),
171 struct perf_session *session); 111 struct perf_session *session);
112int event__synthesize_kernel_mmap(event__handler_t process,
113 struct perf_session *session,
114 const char *symbol_name);
115int event__synthesize_modules(event__handler_t process,
116 struct perf_session *session);
172 117
173int event__process_comm(event_t *self, struct perf_session *session); 118int event__process_comm(event_t *self, struct perf_session *session);
174int event__process_lost(event_t *self, struct perf_session *session); 119int event__process_lost(event_t *self, struct perf_session *session);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 8a0bca55106f..6c9aa16ee51f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,8 +1,12 @@
1#define _FILE_OFFSET_BITS 64
2
1#include <sys/types.h> 3#include <sys/types.h>
4#include <byteswap.h>
2#include <unistd.h> 5#include <unistd.h>
3#include <stdio.h> 6#include <stdio.h>
4#include <stdlib.h> 7#include <stdlib.h>
5#include <linux/list.h> 8#include <linux/list.h>
9#include <linux/kernel.h>
6 10
7#include "util.h" 11#include "util.h"
8#include "header.h" 12#include "header.h"
@@ -105,24 +109,28 @@ struct perf_trace_event_type {
105static int event_count; 109static int event_count;
106static struct perf_trace_event_type *events; 110static struct perf_trace_event_type *events;
107 111
108void perf_header__push_event(u64 id, const char *name) 112int perf_header__push_event(u64 id, const char *name)
109{ 113{
110 if (strlen(name) > MAX_EVENT_NAME) 114 if (strlen(name) > MAX_EVENT_NAME)
111 pr_warning("Event %s will be truncated\n", name); 115 pr_warning("Event %s will be truncated\n", name);
112 116
113 if (!events) { 117 if (!events) {
114 events = malloc(sizeof(struct perf_trace_event_type)); 118 events = malloc(sizeof(struct perf_trace_event_type));
115 if (!events) 119 if (events == NULL)
116 die("nomem"); 120 return -ENOMEM;
117 } else { 121 } else {
118 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); 122 struct perf_trace_event_type *nevents;
119 if (!events) 123
120 die("nomem"); 124 nevents = realloc(events, (event_count + 1) * sizeof(*events));
125 if (nevents == NULL)
126 return -ENOMEM;
127 events = nevents;
121 } 128 }
122 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 129 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
123 events[event_count].event_id = id; 130 events[event_count].event_id = id;
124 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 131 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
125 event_count++; 132 event_count++;
133 return 0;
126} 134}
127 135
128char *perf_header__find_event(u64 id) 136char *perf_header__find_event(u64 id)
@@ -169,31 +177,48 @@ static int do_write(int fd, const void *buf, size_t size)
169 return 0; 177 return 0;
170} 178}
171 179
172static int __dsos__write_buildid_table(struct list_head *head, int fd) 180#define NAME_ALIGN 64
181
182static int write_padded(int fd, const void *bf, size_t count,
183 size_t count_aligned)
173{ 184{
174#define NAME_ALIGN 64
175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN]; 185 static const char zero_buf[NAME_ALIGN];
186 int err = do_write(fd, bf, count);
187
188 if (!err)
189 err = do_write(fd, zero_buf, count_aligned - count);
190
191 return err;
192}
177 193
178 list_for_each_entry(pos, head, node) { 194#define dsos__for_each_with_build_id(pos, head) \
195 list_for_each_entry(pos, head, node) \
196 if (!pos->has_build_id) \
197 continue; \
198 else
199
200static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
201{
202 struct dso *pos;
203
204 dsos__for_each_with_build_id(pos, head) {
179 int err; 205 int err;
180 struct build_id_event b; 206 struct build_id_event b;
181 size_t len; 207 size_t len;
182 208
183 if (!pos->has_build_id) 209 if (!pos->hit)
184 continue; 210 continue;
185 len = pos->long_name_len + 1; 211 len = pos->long_name_len + 1;
186 len = ALIGN(len, NAME_ALIGN); 212 len = ALIGN(len, NAME_ALIGN);
187 memset(&b, 0, sizeof(b)); 213 memset(&b, 0, sizeof(b));
188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 214 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
215 b.header.misc = misc;
189 b.header.size = sizeof(b) + len; 216 b.header.size = sizeof(b) + len;
190 err = do_write(fd, &b, sizeof(b)); 217 err = do_write(fd, &b, sizeof(b));
191 if (err < 0) 218 if (err < 0)
192 return err; 219 return err;
193 err = do_write(fd, pos->long_name, pos->long_name_len + 1); 220 err = write_padded(fd, pos->long_name,
194 if (err < 0) 221 pos->long_name_len + 1, len);
195 return err;
196 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
197 if (err < 0) 222 if (err < 0)
198 return err; 223 return err;
199 } 224 }
@@ -203,12 +228,143 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)
203 228
204static int dsos__write_buildid_table(int fd) 229static int dsos__write_buildid_table(int fd)
205{ 230{
206 int err = __dsos__write_buildid_table(&dsos__kernel, fd); 231 int err = __dsos__write_buildid_table(&dsos__kernel,
232 PERF_RECORD_MISC_KERNEL, fd);
207 if (err == 0) 233 if (err == 0)
208 err = __dsos__write_buildid_table(&dsos__user, fd); 234 err = __dsos__write_buildid_table(&dsos__user,
235 PERF_RECORD_MISC_USER, fd);
209 return err; 236 return err;
210} 237}
211 238
239int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
240 const char *name, bool is_kallsyms)
241{
242 const size_t size = PATH_MAX;
243 char *filename = malloc(size),
244 *linkname = malloc(size), *targetname;
245 int len, err = -1;
246
247 if (filename == NULL || linkname == NULL)
248 goto out_free;
249
250 len = snprintf(filename, size, "%s%s%s",
251 debugdir, is_kallsyms ? "/" : "", name);
252 if (mkdir_p(filename, 0755))
253 goto out_free;
254
255 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
256
257 if (access(filename, F_OK)) {
258 if (is_kallsyms) {
259 if (copyfile("/proc/kallsyms", filename))
260 goto out_free;
261 } else if (link(name, filename) && copyfile(name, filename))
262 goto out_free;
263 }
264
265 len = snprintf(linkname, size, "%s/.build-id/%.2s",
266 debugdir, sbuild_id);
267
268 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
269 goto out_free;
270
271 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
272 targetname = filename + strlen(debugdir) - 5;
273 memcpy(targetname, "../..", 5);
274
275 if (symlink(targetname, linkname) == 0)
276 err = 0;
277out_free:
278 free(filename);
279 free(linkname);
280 return err;
281}
282
283static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
284 const char *name, const char *debugdir,
285 bool is_kallsyms)
286{
287 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
288
289 build_id__sprintf(build_id, build_id_size, sbuild_id);
290
291 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
292}
293
294int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
295{
296 const size_t size = PATH_MAX;
297 char *filename = malloc(size),
298 *linkname = malloc(size);
299 int err = -1;
300
301 if (filename == NULL || linkname == NULL)
302 goto out_free;
303
304 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
305 debugdir, sbuild_id, sbuild_id + 2);
306
307 if (access(linkname, F_OK))
308 goto out_free;
309
310 if (readlink(linkname, filename, size) < 0)
311 goto out_free;
312
313 if (unlink(linkname))
314 goto out_free;
315
316 /*
317 * Since the link is relative, we must make it absolute:
318 */
319 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
320 debugdir, sbuild_id, filename);
321
322 if (unlink(linkname))
323 goto out_free;
324
325 err = 0;
326out_free:
327 free(filename);
328 free(linkname);
329 return err;
330}
331
332static int dso__cache_build_id(struct dso *self, const char *debugdir)
333{
334 bool is_kallsyms = self->kernel && self->long_name[0] != '/';
335
336 return build_id_cache__add_b(self->build_id, sizeof(self->build_id),
337 self->long_name, debugdir, is_kallsyms);
338}
339
340static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
341{
342 struct dso *pos;
343 int err = 0;
344
345 dsos__for_each_with_build_id(pos, head)
346 if (dso__cache_build_id(pos, debugdir))
347 err = -1;
348
349 return err;
350}
351
352static int dsos__cache_build_ids(void)
353{
354 int err_kernel, err_user;
355 char debugdir[PATH_MAX];
356
357 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
358 DEBUG_CACHE_DIR);
359
360 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
361 return -1;
362
363 err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir);
364 err_user = __dsos__cache_build_ids(&dsos__user, debugdir);
365 return err_kernel || err_user ? -1 : 0;
366}
367
212static int perf_header__adds_write(struct perf_header *self, int fd) 368static int perf_header__adds_write(struct perf_header *self, int fd)
213{ 369{
214 int nr_sections; 370 int nr_sections;
@@ -217,7 +373,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
217 u64 sec_start; 373 u64 sec_start;
218 int idx = 0, err; 374 int idx = 0, err;
219 375
220 if (dsos__read_build_ids()) 376 if (dsos__read_build_ids(true))
221 perf_header__set_feat(self, HEADER_BUILD_ID); 377 perf_header__set_feat(self, HEADER_BUILD_ID);
222 378
223 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 379 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
@@ -257,7 +413,9 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
257 pr_debug("failed to write buildid table\n"); 413 pr_debug("failed to write buildid table\n");
258 goto out_free; 414 goto out_free;
259 } 415 }
260 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; 416 buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
417 buildid_sec->offset;
418 dsos__cache_build_ids();
261 } 419 }
262 420
263 lseek(fd, sec_start, SEEK_SET); 421 lseek(fd, sec_start, SEEK_SET);
@@ -360,30 +518,43 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
360 return 0; 518 return 0;
361} 519}
362 520
363static void do_read(int fd, void *buf, size_t size) 521static int do_read(int fd, void *buf, size_t size)
364{ 522{
365 while (size) { 523 while (size) {
366 int ret = read(fd, buf, size); 524 int ret = read(fd, buf, size);
367 525
368 if (ret < 0) 526 if (ret <= 0)
369 die("failed to read"); 527 return -1;
370 if (ret == 0)
371 die("failed to read: missing data");
372 528
373 size -= ret; 529 size -= ret;
374 buf += ret; 530 buf += ret;
375 } 531 }
532
533 return 0;
534}
535
536static int perf_header__getbuffer64(struct perf_header *self,
537 int fd, void *buf, size_t size)
538{
539 if (do_read(fd, buf, size))
540 return -1;
541
542 if (self->needs_swap)
543 mem_bswap_64(buf, size);
544
545 return 0;
376} 546}
377 547
378int perf_header__process_sections(struct perf_header *self, int fd, 548int perf_header__process_sections(struct perf_header *self, int fd,
379 int (*process)(struct perf_file_section *self, 549 int (*process)(struct perf_file_section *self,
550 struct perf_header *ph,
380 int feat, int fd)) 551 int feat, int fd))
381{ 552{
382 struct perf_file_section *feat_sec; 553 struct perf_file_section *feat_sec;
383 int nr_sections; 554 int nr_sections;
384 int sec_size; 555 int sec_size;
385 int idx = 0; 556 int idx = 0;
386 int err = 0, feat = 1; 557 int err = -1, feat = 1;
387 558
388 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 559 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
389 if (!nr_sections) 560 if (!nr_sections)
@@ -397,33 +568,45 @@ int perf_header__process_sections(struct perf_header *self, int fd,
397 568
398 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 569 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
399 570
400 do_read(fd, feat_sec, sec_size); 571 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
572 goto out_free;
401 573
574 err = 0;
402 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 575 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
403 if (perf_header__has_feat(self, feat)) { 576 if (perf_header__has_feat(self, feat)) {
404 struct perf_file_section *sec = &feat_sec[idx++]; 577 struct perf_file_section *sec = &feat_sec[idx++];
405 578
406 err = process(sec, feat, fd); 579 err = process(sec, self, feat, fd);
407 if (err < 0) 580 if (err < 0)
408 break; 581 break;
409 } 582 }
410 ++feat; 583 ++feat;
411 } 584 }
412 585out_free:
413 free(feat_sec); 586 free(feat_sec);
414 return err; 587 return err;
415}; 588}
416 589
417int perf_file_header__read(struct perf_file_header *self, 590int perf_file_header__read(struct perf_file_header *self,
418 struct perf_header *ph, int fd) 591 struct perf_header *ph, int fd)
419{ 592{
420 lseek(fd, 0, SEEK_SET); 593 lseek(fd, 0, SEEK_SET);
421 do_read(fd, self, sizeof(*self));
422 594
423 if (self->magic != PERF_MAGIC || 595 if (do_read(fd, self, sizeof(*self)) ||
424 self->attr_size != sizeof(struct perf_file_attr)) 596 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
425 return -1; 597 return -1;
426 598
599 if (self->attr_size != sizeof(struct perf_file_attr)) {
600 u64 attr_size = bswap_64(self->attr_size);
601
602 if (attr_size != sizeof(struct perf_file_attr))
603 return -1;
604
605 mem_bswap_64(self, offsetof(struct perf_file_header,
606 adds_features));
607 ph->needs_swap = true;
608 }
609
427 if (self->size != sizeof(*self)) { 610 if (self->size != sizeof(*self)) {
428 /* Support the previous format */ 611 /* Support the previous format */
429 if (self->size == offsetof(typeof(*self), adds_features)) 612 if (self->size == offsetof(typeof(*self), adds_features))
@@ -433,19 +616,31 @@ int perf_file_header__read(struct perf_file_header *self,
433 } 616 }
434 617
435 memcpy(&ph->adds_features, &self->adds_features, 618 memcpy(&ph->adds_features, &self->adds_features,
436 sizeof(self->adds_features)); 619 sizeof(ph->adds_features));
620 /*
621 * FIXME: hack that assumes that if we need swap the perf.data file
622 * may be coming from an arch with a different word-size, ergo different
623 * DEFINE_BITMAP format, investigate more later, but for now its mostly
624 * safe to assume that we have a build-id section. Trace files probably
625 * have several other issues in this realm anyway...
626 */
627 if (ph->needs_swap) {
628 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
629 perf_header__set_feat(ph, HEADER_BUILD_ID);
630 }
437 631
438 ph->event_offset = self->event_types.offset; 632 ph->event_offset = self->event_types.offset;
439 ph->event_size = self->event_types.size; 633 ph->event_size = self->event_types.size;
440 ph->data_offset = self->data.offset; 634 ph->data_offset = self->data.offset;
441 ph->data_size = self->data.size; 635 ph->data_size = self->data.size;
442 return 0; 636 return 0;
443} 637}
444 638
445static int perf_file_section__process(struct perf_file_section *self, 639static int perf_file_section__process(struct perf_file_section *self,
640 struct perf_header *ph,
446 int feat, int fd) 641 int feat, int fd)
447{ 642{
448 if (lseek(fd, self->offset, SEEK_SET) < 0) { 643 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) {
449 pr_debug("Failed to lseek to %Ld offset for feature %d, " 644 pr_debug("Failed to lseek to %Ld offset for feature %d, "
450 "continuing...\n", self->offset, feat); 645 "continuing...\n", self->offset, feat);
451 return 0; 646 return 0;
@@ -457,7 +652,7 @@ static int perf_file_section__process(struct perf_file_section *self,
457 break; 652 break;
458 653
459 case HEADER_BUILD_ID: 654 case HEADER_BUILD_ID:
460 if (perf_header__read_build_ids(fd, self->offset, self->size)) 655 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
461 pr_debug("Failed to read buildids, continuing...\n"); 656 pr_debug("Failed to read buildids, continuing...\n");
462 break; 657 break;
463 default: 658 default:
@@ -469,7 +664,7 @@ static int perf_file_section__process(struct perf_file_section *self,
469 664
470int perf_header__read(struct perf_header *self, int fd) 665int perf_header__read(struct perf_header *self, int fd)
471{ 666{
472 struct perf_file_header f_header; 667 struct perf_file_header f_header;
473 struct perf_file_attr f_attr; 668 struct perf_file_attr f_attr;
474 u64 f_id; 669 u64 f_id;
475 int nr_attrs, nr_ids, i, j; 670 int nr_attrs, nr_ids, i, j;
@@ -486,7 +681,9 @@ int perf_header__read(struct perf_header *self, int fd)
486 struct perf_header_attr *attr; 681 struct perf_header_attr *attr;
487 off_t tmp; 682 off_t tmp;
488 683
489 do_read(fd, &f_attr, sizeof(f_attr)); 684 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
685 goto out_errno;
686
490 tmp = lseek(fd, 0, SEEK_CUR); 687 tmp = lseek(fd, 0, SEEK_CUR);
491 688
492 attr = perf_header_attr__new(&f_attr.attr); 689 attr = perf_header_attr__new(&f_attr.attr);
@@ -497,7 +694,8 @@ int perf_header__read(struct perf_header *self, int fd)
497 lseek(fd, f_attr.ids.offset, SEEK_SET); 694 lseek(fd, f_attr.ids.offset, SEEK_SET);
498 695
499 for (j = 0; j < nr_ids; j++) { 696 for (j = 0; j < nr_ids; j++) {
500 do_read(fd, &f_id, sizeof(f_id)); 697 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
698 goto out_errno;
501 699
502 if (perf_header_attr__add_id(attr, f_id) < 0) { 700 if (perf_header_attr__add_id(attr, f_id) < 0) {
503 perf_header_attr__delete(attr); 701 perf_header_attr__delete(attr);
@@ -517,7 +715,9 @@ int perf_header__read(struct perf_header *self, int fd)
517 events = malloc(f_header.event_types.size); 715 events = malloc(f_header.event_types.size);
518 if (events == NULL) 716 if (events == NULL)
519 return -ENOMEM; 717 return -ENOMEM;
520 do_read(fd, events, f_header.event_types.size); 718 if (perf_header__getbuffer64(self, fd, events,
719 f_header.event_types.size))
720 goto out_errno;
521 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 721 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
522 } 722 }
523 723
@@ -527,6 +727,8 @@ int perf_header__read(struct perf_header *self, int fd)
527 727
528 self->frozen = 1; 728 self->frozen = 1;
529 return 0; 729 return 0;
730out_errno:
731 return -errno;
530} 732}
531 733
532u64 perf_header__sample_type(struct perf_header *header) 734u64 perf_header__sample_type(struct perf_header *header)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d118d05d3abe..82a6af72d4cc 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -5,6 +5,7 @@
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include "types.h"
8#include "event.h"
8 9
9#include <linux/bitmap.h> 10#include <linux/bitmap.h>
10 11
@@ -52,6 +53,7 @@ struct perf_header {
52 u64 data_size; 53 u64 data_size;
53 u64 event_offset; 54 u64 event_offset;
54 u64 event_size; 55 u64 event_size;
56 bool needs_swap;
55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 57 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
56}; 58};
57 59
@@ -64,7 +66,7 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit);
64int perf_header__add_attr(struct perf_header *self, 66int perf_header__add_attr(struct perf_header *self,
65 struct perf_header_attr *attr); 67 struct perf_header_attr *attr);
66 68
67void perf_header__push_event(u64 id, const char *name); 69int perf_header__push_event(u64 id, const char *name);
68char *perf_header__find_event(u64 id); 70char *perf_header__find_event(u64 id);
69 71
70struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr); 72struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
@@ -80,6 +82,11 @@ bool perf_header__has_feat(const struct perf_header *self, int feat);
80 82
81int perf_header__process_sections(struct perf_header *self, int fd, 83int perf_header__process_sections(struct perf_header *self, int fd,
82 int (*process)(struct perf_file_section *self, 84 int (*process)(struct perf_file_section *self,
85 struct perf_header *ph,
83 int feat, int fd)); 86 int feat, int fd));
84 87
88int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
89 const char *name, bool is_kallsyms);
90int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
91
85#endif /* __PERF_HEADER_H */ 92#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index e8daf5ca6fd2..44408c2621cf 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -321,7 +321,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
321 new_depth_mask &= ~(1 << (depth - 1)); 321 new_depth_mask &= ~(1 << (depth - 1));
322 322
323 /* 323 /*
324 * But we keep the older depth mask for the line seperator 324 * But we keep the older depth mask for the line separator
325 * to keep the level link until we reach the last child 325 * to keep the level link until we reach the last child
326 */ 326 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, 327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
diff --git a/tools/perf/util/include/linux/hash.h b/tools/perf/util/include/linux/hash.h
new file mode 100644
index 000000000000..201f57397997
--- /dev/null
+++ b/tools/perf/util/include/linux/hash.h
@@ -0,0 +1,5 @@
1#include "../../../../include/linux/hash.h"
2
3#ifndef PERF_HASH_H
4#define PERF_HASH_H
5#endif
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index 21c0274c02fa..f2611655ab51 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -101,5 +101,6 @@ simple_strtoul(const char *nptr, char **endptr, int base)
101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) 101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
102#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) 102#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
103#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) 103#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
104#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
104 105
105#endif 106#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index c4d55a0da2ea..e509cd59c67d 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -5,6 +5,11 @@
5#include <stdio.h> 5#include <stdio.h>
6#include "debug.h" 6#include "debug.h"
7 7
8const char *map_type__name[MAP__NR_TYPES] = {
9 [MAP__FUNCTION] = "Functions",
10 [MAP__VARIABLE] = "Variables",
11};
12
8static inline int is_anon_memory(const char *filename) 13static inline int is_anon_memory(const char *filename)
9{ 14{
10 return strcmp(filename, "//anon") == 0; 15 return strcmp(filename, "//anon") == 0;
@@ -68,8 +73,13 @@ struct map *map__new(struct mmap_event *event, enum map_type type,
68 map__init(self, type, event->start, event->start + event->len, 73 map__init(self, type, event->start, event->start + event->len,
69 event->pgoff, dso); 74 event->pgoff, dso);
70 75
71 if (self->dso == vdso || anon) 76 if (anon) {
77set_identity:
72 self->map_ip = self->unmap_ip = identity__map_ip; 78 self->map_ip = self->unmap_ip = identity__map_ip;
79 } else if (strcmp(filename, "[vdso]") == 0) {
80 dso__set_loaded(dso, self->type);
81 goto set_identity;
82 }
73 } 83 }
74 return self; 84 return self;
75out_delete: 85out_delete:
@@ -104,8 +114,7 @@ void map__fixup_end(struct map *self)
104 114
105#define DSO__DELETED "(deleted)" 115#define DSO__DELETED "(deleted)"
106 116
107int map__load(struct map *self, struct perf_session *session, 117int map__load(struct map *self, symbol_filter_t filter)
108 symbol_filter_t filter)
109{ 118{
110 const char *name = self->dso->long_name; 119 const char *name = self->dso->long_name;
111 int nr; 120 int nr;
@@ -113,7 +122,7 @@ int map__load(struct map *self, struct perf_session *session,
113 if (dso__loaded(self->dso, self->type)) 122 if (dso__loaded(self->dso, self->type))
114 return 0; 123 return 0;
115 124
116 nr = dso__load(self->dso, self, session, filter); 125 nr = dso__load(self->dso, self, filter);
117 if (nr < 0) { 126 if (nr < 0) {
118 if (self->dso->has_build_id) { 127 if (self->dso->has_build_id) {
119 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 128 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -144,24 +153,29 @@ int map__load(struct map *self, struct perf_session *session,
144 153
145 return -1; 154 return -1;
146 } 155 }
156 /*
157 * Only applies to the kernel, as its symtabs aren't relative like the
158 * module ones.
159 */
160 if (self->dso->kernel)
161 map__reloc_vmlinux(self);
147 162
148 return 0; 163 return 0;
149} 164}
150 165
151struct symbol *map__find_symbol(struct map *self, struct perf_session *session, 166struct symbol *map__find_symbol(struct map *self, u64 addr,
152 u64 addr, symbol_filter_t filter) 167 symbol_filter_t filter)
153{ 168{
154 if (map__load(self, session, filter) < 0) 169 if (map__load(self, filter) < 0)
155 return NULL; 170 return NULL;
156 171
157 return dso__find_symbol(self->dso, self->type, addr); 172 return dso__find_symbol(self->dso, self->type, addr);
158} 173}
159 174
160struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 175struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
161 struct perf_session *session,
162 symbol_filter_t filter) 176 symbol_filter_t filter)
163{ 177{
164 if (map__load(self, session, filter) < 0) 178 if (map__load(self, filter) < 0)
165 return NULL; 179 return NULL;
166 180
167 if (!dso__sorted_by_name(self->dso, self->type)) 181 if (!dso__sorted_by_name(self->dso, self->type))
@@ -201,3 +215,23 @@ size_t map__fprintf(struct map *self, FILE *fp)
201 return fprintf(fp, " %Lx-%Lx %Lx %s\n", 215 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
202 self->start, self->end, self->pgoff, self->dso->name); 216 self->start, self->end, self->pgoff, self->dso->name);
203} 217}
218
219/*
220 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
221 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
222 */
223u64 map__rip_2objdump(struct map *map, u64 rip)
224{
225 u64 addr = map->dso->adjust_symbols ?
226 map->unmap_ip(map, rip) : /* RIP -> IP */
227 rip;
228 return addr;
229}
230
231u64 map__objdump_2ip(struct map *map, u64 addr)
232{
233 u64 ip = map->dso->adjust_symbols ?
234 addr :
235 map->unmap_ip(map, addr); /* RIP -> IP */
236 return ip;
237}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
new file mode 100644
index 000000000000..b756368076c6
--- /dev/null
+++ b/tools/perf/util/map.h
@@ -0,0 +1,94 @@
1#ifndef __PERF_MAP_H
2#define __PERF_MAP_H
3
4#include <linux/compiler.h>
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include <linux/types.h>
8
9enum map_type {
10 MAP__FUNCTION = 0,
11 MAP__VARIABLE,
12};
13
14#define MAP__NR_TYPES (MAP__VARIABLE + 1)
15
16extern const char *map_type__name[MAP__NR_TYPES];
17
18struct dso;
19struct ref_reloc_sym;
20struct map_groups;
21
22struct map {
23 union {
24 struct rb_node rb_node;
25 struct list_head node;
26 };
27 u64 start;
28 u64 end;
29 enum map_type type;
30 u64 pgoff;
31
32 /* ip -> dso rip */
33 u64 (*map_ip)(struct map *, u64);
34 /* dso rip -> ip */
35 u64 (*unmap_ip)(struct map *, u64);
36
37 struct dso *dso;
38};
39
40struct kmap {
41 struct ref_reloc_sym *ref_reloc_sym;
42 struct map_groups *kmaps;
43};
44
45static inline struct kmap *map__kmap(struct map *self)
46{
47 return (struct kmap *)(self + 1);
48}
49
50static inline u64 map__map_ip(struct map *map, u64 ip)
51{
52 return ip - map->start + map->pgoff;
53}
54
55static inline u64 map__unmap_ip(struct map *map, u64 ip)
56{
57 return ip + map->start - map->pgoff;
58}
59
60static inline u64 identity__map_ip(struct map *map __used, u64 ip)
61{
62 return ip;
63}
64
65
66/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
67u64 map__rip_2objdump(struct map *map, u64 rip);
68u64 map__objdump_2ip(struct map *map, u64 addr);
69
70struct symbol;
71struct mmap_event;
72
73typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
74
75void map__init(struct map *self, enum map_type type,
76 u64 start, u64 end, u64 pgoff, struct dso *dso);
77struct map *map__new(struct mmap_event *event, enum map_type,
78 char *cwd, int cwdlen);
79void map__delete(struct map *self);
80struct map *map__clone(struct map *self);
81int map__overlap(struct map *l, struct map *r);
82size_t map__fprintf(struct map *self, FILE *fp);
83
84int map__load(struct map *self, symbol_filter_t filter);
85struct symbol *map__find_symbol(struct map *self,
86 u64 addr, symbol_filter_t filter);
87struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
88 symbol_filter_t filter);
89void map__fixup_start(struct map *self);
90void map__fixup_end(struct map *self);
91
92void map__reloc_vmlinux(struct map *self);
93
94#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index e5bc0fb016b2..05d0c5c2030c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -450,7 +450,8 @@ parse_single_tracepoint_event(char *sys_name,
450/* sys + ':' + event + ':' + flags*/ 450/* sys + ':' + event + ':' + flags*/
451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
452static enum event_result 452static enum event_result
453parse_subsystem_tracepoint_event(char *sys_name, char *flags) 453parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
454 char *flags)
454{ 455{
455 char evt_path[MAXPATHLEN]; 456 char evt_path[MAXPATHLEN];
456 struct dirent *evt_ent; 457 struct dirent *evt_ent;
@@ -474,6 +475,9 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
474 || !strcmp(evt_ent->d_name, "filter")) 475 || !strcmp(evt_ent->d_name, "filter"))
475 continue; 476 continue;
476 477
478 if (!strglobmatch(evt_ent->d_name, evt_exp))
479 continue;
480
477 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, 481 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
478 evt_ent->d_name, flags ? ":" : "", 482 evt_ent->d_name, flags ? ":" : "",
479 flags ?: ""); 483 flags ?: "");
@@ -522,9 +526,10 @@ static enum event_result parse_tracepoint_event(const char **strp,
522 if (evt_length >= MAX_EVENT_LENGTH) 526 if (evt_length >= MAX_EVENT_LENGTH)
523 return EVT_FAILED; 527 return EVT_FAILED;
524 528
525 if (!strcmp(evt_name, "*")) { 529 if (strpbrk(evt_name, "*?")) {
526 *strp = evt_name + evt_length; 530 *strp = evt_name + evt_length;
527 return parse_subsystem_tracepoint_event(sys_name, flags); 531 return parse_multiple_tracepoint_event(sys_name, evt_name,
532 flags);
528 } else 533 } else
529 return parse_single_tracepoint_event(sys_name, evt_name, 534 return parse_single_tracepoint_event(sys_name, evt_name,
530 evt_length, flags, 535 evt_length, flags,
@@ -753,11 +758,11 @@ modifier:
753 return ret; 758 return ret;
754} 759}
755 760
756static void store_event_type(const char *orgname) 761static int store_event_type(const char *orgname)
757{ 762{
758 char filename[PATH_MAX], *c; 763 char filename[PATH_MAX], *c;
759 FILE *file; 764 FILE *file;
760 int id; 765 int id, n;
761 766
762 sprintf(filename, "%s/", debugfs_path); 767 sprintf(filename, "%s/", debugfs_path);
763 strncat(filename, orgname, strlen(orgname)); 768 strncat(filename, orgname, strlen(orgname));
@@ -769,11 +774,14 @@ static void store_event_type(const char *orgname)
769 774
770 file = fopen(filename, "r"); 775 file = fopen(filename, "r");
771 if (!file) 776 if (!file)
772 return; 777 return 0;
773 if (fscanf(file, "%i", &id) < 1) 778 n = fscanf(file, "%i", &id);
774 die("cannot store event ID");
775 fclose(file); 779 fclose(file);
776 perf_header__push_event(id, orgname); 780 if (n < 1) {
781 pr_err("cannot store event ID\n");
782 return -EINVAL;
783 }
784 return perf_header__push_event(id, orgname);
777} 785}
778 786
779int parse_events(const struct option *opt __used, const char *str, int unset __used) 787int parse_events(const struct option *opt __used, const char *str, int unset __used)
@@ -782,7 +790,8 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
782 enum event_result ret; 790 enum event_result ret;
783 791
784 if (strchr(str, ':')) 792 if (strchr(str, ':'))
785 store_event_type(str); 793 if (store_event_type(str) < 0)
794 return -1;
786 795
787 for (;;) { 796 for (;;) {
788 if (nr_counters == MAX_COUNTERS) 797 if (nr_counters == MAX_COUNTERS)
@@ -835,11 +844,12 @@ int parse_filter(const struct option *opt __used, const char *str,
835} 844}
836 845
837static const char * const event_type_descriptors[] = { 846static const char * const event_type_descriptors[] = {
838 "",
839 "Hardware event", 847 "Hardware event",
840 "Software event", 848 "Software event",
841 "Tracepoint event", 849 "Tracepoint event",
842 "Hardware cache event", 850 "Hardware cache event",
851 "Raw hardware event descriptor",
852 "Hardware breakpoint",
843}; 853};
844 854
845/* 855/*
@@ -872,7 +882,7 @@ static void print_tracepoint_events(void)
872 snprintf(evt_path, MAXPATHLEN, "%s:%s", 882 snprintf(evt_path, MAXPATHLEN, "%s:%s",
873 sys_dirent.d_name, evt_dirent.d_name); 883 sys_dirent.d_name, evt_dirent.d_name);
874 printf(" %-42s [%s]\n", evt_path, 884 printf(" %-42s [%s]\n", evt_path,
875 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 885 event_type_descriptors[PERF_TYPE_TRACEPOINT]);
876 } 886 }
877 closedir(evt_dir); 887 closedir(evt_dir);
878 } 888 }
@@ -892,9 +902,7 @@ void print_events(void)
892 printf("List of pre-defined events (to be used in -e):\n"); 902 printf("List of pre-defined events (to be used in -e):\n");
893 903
894 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 904 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
895 type = syms->type + 1; 905 type = syms->type;
896 if (type >= ARRAY_SIZE(event_type_descriptors))
897 type = 0;
898 906
899 if (type != prev_type) 907 if (type != prev_type)
900 printf("\n"); 908 printf("\n");
@@ -919,17 +927,19 @@ void print_events(void)
919 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 927 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
920 printf(" %-42s [%s]\n", 928 printf(" %-42s [%s]\n",
921 event_cache_name(type, op, i), 929 event_cache_name(type, op, i),
922 event_type_descriptors[4]); 930 event_type_descriptors[PERF_TYPE_HW_CACHE]);
923 } 931 }
924 } 932 }
925 } 933 }
926 934
927 printf("\n"); 935 printf("\n");
928 printf(" %-42s [raw hardware event descriptor]\n", 936 printf(" %-42s [%s]\n",
929 "rNNN"); 937 "rNNN", event_type_descriptors[PERF_TYPE_RAW]);
930 printf("\n"); 938 printf("\n");
931 939
932 printf(" %-42s [hardware breakpoint]\n", "mem:<addr>[:access]"); 940 printf(" %-42s [%s]\n",
941 "mem:<addr>[:access]",
942 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
933 printf("\n"); 943 printf("\n");
934 944
935 print_tracepoint_events(); 945 print_tracepoint_events();
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 29465d440043..53181dbfe4a8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -37,6 +37,8 @@
37#include "string.h" 37#include "string.h"
38#include "strlist.h" 38#include "strlist.h"
39#include "debug.h" 39#include "debug.h"
40#include "cache.h"
41#include "color.h"
40#include "parse-events.h" /* For debugfs_path */ 42#include "parse-events.h" /* For debugfs_path */
41#include "probe-event.h" 43#include "probe-event.h"
42 44
@@ -62,6 +64,42 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
62 return ret; 64 return ret;
63} 65}
64 66
67void parse_line_range_desc(const char *arg, struct line_range *lr)
68{
69 const char *ptr;
70 char *tmp;
71 /*
72 * <Syntax>
73 * SRC:SLN[+NUM|-ELN]
74 * FUNC[:SLN[+NUM|-ELN]]
75 */
76 ptr = strchr(arg, ':');
77 if (ptr) {
78 lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0);
79 if (*tmp == '+')
80 lr->end = lr->start + (unsigned int)strtoul(tmp + 1,
81 &tmp, 0);
82 else if (*tmp == '-')
83 lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0);
84 else
85 lr->end = 0;
86 pr_debug("Line range is %u to %u\n", lr->start, lr->end);
87 if (lr->end && lr->start > lr->end)
88 semantic_error("Start line must be smaller"
89 " than end line.");
90 if (*tmp != '\0')
91 semantic_error("Tailing with invalid character '%d'.",
92 *tmp);
93 tmp = strndup(arg, (ptr - arg));
94 } else
95 tmp = strdup(arg);
96
97 if (strchr(tmp, '.'))
98 lr->file = tmp;
99 else
100 lr->function = tmp;
101}
102
65/* Check the name is good for event/group */ 103/* Check the name is good for event/group */
66static bool check_event_name(const char *name) 104static bool check_event_name(const char *name)
67{ 105{
@@ -81,14 +119,14 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
81 char c, nc = 0; 119 char c, nc = 0;
82 /* 120 /*
83 * <Syntax> 121 * <Syntax>
84 * perf probe [EVENT=]SRC:LN 122 * perf probe [EVENT=]SRC[:LN|;PTN]
85 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC] 123 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
86 * 124 *
87 * TODO:Group name support 125 * TODO:Group name support
88 */ 126 */
89 127
90 ptr = strchr(arg, '='); 128 ptr = strpbrk(arg, ";=@+%");
91 if (ptr) { /* Event name */ 129 if (ptr && *ptr == '=') { /* Event name */
92 *ptr = '\0'; 130 *ptr = '\0';
93 tmp = ptr + 1; 131 tmp = ptr + 1;
94 ptr = strchr(arg, ':'); 132 ptr = strchr(arg, ':');
@@ -101,7 +139,7 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
101 arg = tmp; 139 arg = tmp;
102 } 140 }
103 141
104 ptr = strpbrk(arg, ":+@%"); 142 ptr = strpbrk(arg, ";:+@%");
105 if (ptr) { 143 if (ptr) {
106 nc = *ptr; 144 nc = *ptr;
107 *ptr++ = '\0'; 145 *ptr++ = '\0';
@@ -118,7 +156,11 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
118 while (ptr) { 156 while (ptr) {
119 arg = ptr; 157 arg = ptr;
120 c = nc; 158 c = nc;
121 ptr = strpbrk(arg, ":+@%"); 159 if (c == ';') { /* Lazy pattern must be the last part */
160 pp->lazy_line = strdup(arg);
161 break;
162 }
163 ptr = strpbrk(arg, ";:+@%");
122 if (ptr) { 164 if (ptr) {
123 nc = *ptr; 165 nc = *ptr;
124 *ptr++ = '\0'; 166 *ptr++ = '\0';
@@ -127,13 +169,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
127 case ':': /* Line number */ 169 case ':': /* Line number */
128 pp->line = strtoul(arg, &tmp, 0); 170 pp->line = strtoul(arg, &tmp, 0);
129 if (*tmp != '\0') 171 if (*tmp != '\0')
130 semantic_error("There is non-digit charactor" 172 semantic_error("There is non-digit char"
131 " in line number."); 173 " in line number.");
132 break; 174 break;
133 case '+': /* Byte offset from a symbol */ 175 case '+': /* Byte offset from a symbol */
134 pp->offset = strtoul(arg, &tmp, 0); 176 pp->offset = strtoul(arg, &tmp, 0);
135 if (*tmp != '\0') 177 if (*tmp != '\0')
136 semantic_error("There is non-digit charactor" 178 semantic_error("There is non-digit character"
137 " in offset."); 179 " in offset.");
138 break; 180 break;
139 case '@': /* File name */ 181 case '@': /* File name */
@@ -141,9 +183,6 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
141 semantic_error("SRC@SRC is not allowed."); 183 semantic_error("SRC@SRC is not allowed.");
142 pp->file = strdup(arg); 184 pp->file = strdup(arg);
143 DIE_IF(pp->file == NULL); 185 DIE_IF(pp->file == NULL);
144 if (ptr)
145 semantic_error("@SRC must be the last "
146 "option.");
147 break; 186 break;
148 case '%': /* Probe places */ 187 case '%': /* Probe places */
149 if (strcmp(arg, "return") == 0) { 188 if (strcmp(arg, "return") == 0) {
@@ -158,11 +197,18 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
158 } 197 }
159 198
160 /* Exclusion check */ 199 /* Exclusion check */
200 if (pp->lazy_line && pp->line)
201 semantic_error("Lazy pattern can't be used with line number.");
202
203 if (pp->lazy_line && pp->offset)
204 semantic_error("Lazy pattern can't be used with offset.");
205
161 if (pp->line && pp->offset) 206 if (pp->line && pp->offset)
162 semantic_error("Offset can't be used with line number."); 207 semantic_error("Offset can't be used with line number.");
163 208
164 if (!pp->line && pp->file && !pp->function) 209 if (!pp->line && !pp->lazy_line && pp->file && !pp->function)
165 semantic_error("File always requires line number."); 210 semantic_error("File always requires line number or "
211 "lazy pattern.");
166 212
167 if (pp->offset && !pp->function) 213 if (pp->offset && !pp->function)
168 semantic_error("Offset requires an entry function."); 214 semantic_error("Offset requires an entry function.");
@@ -170,11 +216,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
170 if (pp->retprobe && !pp->function) 216 if (pp->retprobe && !pp->function)
171 semantic_error("Return probe requires an entry function."); 217 semantic_error("Return probe requires an entry function.");
172 218
173 if ((pp->offset || pp->line) && pp->retprobe) 219 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe)
174 semantic_error("Offset/Line can't be used with return probe."); 220 semantic_error("Offset/Line/Lazy pattern can't be used with "
221 "return probe.");
175 222
176 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n", 223 pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n",
177 pp->function, pp->file, pp->line, pp->offset, pp->retprobe); 224 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
225 pp->lazy_line);
178} 226}
179 227
180/* Parse perf-probe event definition */ 228/* Parse perf-probe event definition */
@@ -272,6 +320,7 @@ int synthesize_perf_probe_point(struct probe_point *pp)
272 int ret; 320 int ret;
273 321
274 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 322 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
323 pp->found = 1;
275 if (!buf) 324 if (!buf)
276 die("Failed to allocate memory by zalloc."); 325 die("Failed to allocate memory by zalloc.");
277 if (pp->offset) { 326 if (pp->offset) {
@@ -294,6 +343,7 @@ int synthesize_perf_probe_point(struct probe_point *pp)
294error: 343error:
295 free(pp->probes[0]); 344 free(pp->probes[0]);
296 pp->probes[0] = NULL; 345 pp->probes[0] = NULL;
346 pp->found = 0;
297 } 347 }
298 return ret; 348 return ret;
299} 349}
@@ -368,7 +418,7 @@ static int open_kprobe_events(int flags, int mode)
368 if (ret < 0) { 418 if (ret < 0) {
369 if (errno == ENOENT) 419 if (errno == ENOENT)
370 die("kprobe_events file does not exist -" 420 die("kprobe_events file does not exist -"
371 " please rebuild with CONFIG_KPROBE_TRACER."); 421 " please rebuild with CONFIG_KPROBE_EVENT.");
372 else 422 else
373 die("Could not open kprobe_events file: %s", 423 die("Could not open kprobe_events file: %s",
374 strerror(errno)); 424 strerror(errno));
@@ -418,6 +468,8 @@ static void clear_probe_point(struct probe_point *pp)
418 free(pp->function); 468 free(pp->function);
419 if (pp->file) 469 if (pp->file)
420 free(pp->file); 470 free(pp->file);
471 if (pp->lazy_line)
472 free(pp->lazy_line);
421 for (i = 0; i < pp->nr_args; i++) 473 for (i = 0; i < pp->nr_args; i++)
422 free(pp->args[i]); 474 free(pp->args[i]);
423 if (pp->args) 475 if (pp->args)
@@ -455,6 +507,9 @@ void show_perf_probe_events(void)
455 struct strlist *rawlist; 507 struct strlist *rawlist;
456 struct str_node *ent; 508 struct str_node *ent;
457 509
510 setup_pager();
511 memset(&pp, 0, sizeof(pp));
512
458 fd = open_kprobe_events(O_RDONLY, 0); 513 fd = open_kprobe_events(O_RDONLY, 0);
459 rawlist = get_trace_kprobe_event_rawlist(fd); 514 rawlist = get_trace_kprobe_event_rawlist(fd);
460 close(fd); 515 close(fd);
@@ -675,3 +730,73 @@ void del_trace_kprobe_events(struct strlist *dellist)
675 close(fd); 730 close(fd);
676} 731}
677 732
733#define LINEBUF_SIZE 256
734#define NR_ADDITIONAL_LINES 2
735
736static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
737{
738 char buf[LINEBUF_SIZE];
739 const char *color = PERF_COLOR_BLUE;
740
741 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
742 goto error;
743 if (!skip) {
744 if (show_num)
745 fprintf(stdout, "%7u %s", l, buf);
746 else
747 color_fprintf(stdout, color, " %s", buf);
748 }
749
750 while (strlen(buf) == LINEBUF_SIZE - 1 &&
751 buf[LINEBUF_SIZE - 2] != '\n') {
752 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
753 goto error;
754 if (!skip) {
755 if (show_num)
756 fprintf(stdout, "%s", buf);
757 else
758 color_fprintf(stdout, color, "%s", buf);
759 }
760 }
761 return;
762error:
763 if (feof(fp))
764 die("Source file is shorter than expected.");
765 else
766 die("File read error: %s", strerror(errno));
767}
768
769void show_line_range(struct line_range *lr)
770{
771 unsigned int l = 1;
772 struct line_node *ln;
773 FILE *fp;
774
775 setup_pager();
776
777 if (lr->function)
778 fprintf(stdout, "<%s:%d>\n", lr->function,
779 lr->start - lr->offset);
780 else
781 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
782
783 fp = fopen(lr->path, "r");
784 if (fp == NULL)
785 die("Failed to open %s: %s", lr->path, strerror(errno));
786 /* Skip to starting line number */
787 while (l < lr->start)
788 show_one_line(fp, l++, true, false);
789
790 list_for_each_entry(ln, &lr->line_list, list) {
791 while (ln->line > l)
792 show_one_line(fp, (l++) - lr->offset, false, false);
793 show_one_line(fp, (l++) - lr->offset, false, true);
794 }
795
796 if (lr->end == INT_MAX)
797 lr->end = l + NR_ADDITIONAL_LINES;
798 while (l < lr->end && !feof(fp))
799 show_one_line(fp, (l++) - lr->offset, false, false);
800
801 fclose(fp);
802}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 7f1d499118c0..711287d4baea 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -5,6 +5,7 @@
5#include "probe-finder.h" 5#include "probe-finder.h"
6#include "strlist.h" 6#include "strlist.h"
7 7
8extern void parse_line_range_desc(const char *arg, struct line_range *lr);
8extern void parse_perf_probe_event(const char *str, struct probe_point *pp, 9extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
9 bool *need_dwarf); 10 bool *need_dwarf);
10extern int synthesize_perf_probe_point(struct probe_point *pp); 11extern int synthesize_perf_probe_point(struct probe_point *pp);
@@ -15,6 +16,7 @@ extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
15 bool force_add); 16 bool force_add);
16extern void del_trace_kprobe_events(struct strlist *dellist); 17extern void del_trace_kprobe_events(struct strlist *dellist);
17extern void show_perf_probe_events(void); 18extern void show_perf_probe_events(void);
19extern void show_line_range(struct line_range *lr);
18 20
19/* Maximum index number of event-name postfix */ 21/* Maximum index number of event-name postfix */
20#define MAX_EVENT_INDEX 1024 22#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4b852c0d16a5..e77dc886760e 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -32,21 +32,13 @@
32#include <stdarg.h> 32#include <stdarg.h>
33#include <ctype.h> 33#include <ctype.h>
34 34
35#include "string.h"
35#include "event.h" 36#include "event.h"
36#include "debug.h" 37#include "debug.h"
37#include "util.h" 38#include "util.h"
38#include "probe-finder.h" 39#include "probe-finder.h"
39 40
40 41
41/* Dwarf_Die Linkage to parent Die */
42struct die_link {
43 struct die_link *parent; /* Parent die */
44 Dwarf_Die die; /* Current die */
45};
46
47static Dwarf_Debug __dw_debug;
48static Dwarf_Error __dw_error;
49
50/* 42/*
51 * Generic dwarf analysis helpers 43 * Generic dwarf analysis helpers
52 */ 44 */
@@ -113,256 +105,190 @@ static int strtailcmp(const char *s1, const char *s2)
113 return 0; 105 return 0;
114} 106}
115 107
116/* Find the fileno of the target file. */ 108/* Line number list operations */
117static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
118{
119 Dwarf_Signed cnt, i;
120 Dwarf_Unsigned found = 0;
121 char **srcs;
122 int ret;
123
124 if (!fname)
125 return 0;
126 109
127 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 110/* Add a line to line number list */
128 if (ret == DW_DLV_OK) { 111static void line_list__add_line(struct list_head *head, unsigned int line)
129 for (i = 0; i < cnt && !found; i++) { 112{
130 if (strtailcmp(srcs[i], fname) == 0) 113 struct line_node *ln;
131 found = i + 1; 114 struct list_head *p;
132 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 115
133 } 116 /* Reverse search, because new line will be the last one */
134 for (; i < cnt; i++) 117 list_for_each_entry_reverse(ln, head, list) {
135 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 118 if (ln->line < line) {
136 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST); 119 p = &ln->list;
120 goto found;
121 } else if (ln->line == line) /* Already exist */
122 return ;
137 } 123 }
138 if (found) 124 /* List is empty, or the smallest entry */
139 pr_debug("found fno: %d\n", (int)found); 125 p = head;
140 return found; 126found:
127 pr_debug("line list: add a line %u\n", line);
128 ln = zalloc(sizeof(struct line_node));
129 DIE_IF(ln == NULL);
130 ln->line = line;
131 INIT_LIST_HEAD(&ln->list);
132 list_add(&ln->list, p);
141} 133}
142 134
143/* Compare diename and tname */ 135/* Check if the line in line number list */
144static int die_compare_name(Dwarf_Die dw_die, const char *tname) 136static int line_list__has_line(struct list_head *head, unsigned int line)
145{ 137{
146 char *name; 138 struct line_node *ln;
147 int ret;
148 ret = dwarf_diename(dw_die, &name, &__dw_error);
149 DIE_IF(ret == DW_DLV_ERROR);
150 if (ret == DW_DLV_OK) {
151 ret = strcmp(tname, name);
152 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
153 } else
154 ret = -1;
155 return ret;
156}
157 139
158/* Check the address is in the subprogram(function). */ 140 /* Reverse search, because new line will be the last one */
159static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr, 141 list_for_each_entry(ln, head, list)
160 Dwarf_Signed *offs) 142 if (ln->line == line)
161{ 143 return 1;
162 Dwarf_Addr lopc, hipc;
163 int ret;
164 144
165 /* TODO: check ranges */ 145 return 0;
166 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error);
167 DIE_IF(ret == DW_DLV_ERROR);
168 if (ret == DW_DLV_NO_ENTRY)
169 return 0;
170 ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
171 DIE_IF(ret != DW_DLV_OK);
172 if (lopc <= addr && addr < hipc) {
173 *offs = addr - lopc;
174 return 1;
175 } else
176 return 0;
177} 146}
178 147
179/* Check the die is inlined function */ 148/* Init line number list */
180static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die) 149static void line_list__init(struct list_head *head)
181{ 150{
182 /* TODO: check strictly */ 151 INIT_LIST_HEAD(head);
183 Dwarf_Bool inl; 152}
184 int ret;
185 153
186 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error); 154/* Free line number list */
187 DIE_IF(ret == DW_DLV_ERROR); 155static void line_list__free(struct list_head *head)
188 return inl; 156{
157 struct line_node *ln;
158 while (!list_empty(head)) {
159 ln = list_first_entry(head, struct line_node, list);
160 list_del(&ln->list);
161 free(ln);
162 }
189} 163}
190 164
191/* Get the offset of abstruct_origin */ 165/* Dwarf wrappers */
192static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die) 166
167/* Find the realpath of the target file. */
168static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
193{ 169{
194 Dwarf_Attribute attr; 170 Dwarf_Files *files;
195 Dwarf_Off cu_offs; 171 size_t nfiles, i;
172 const char *src;
196 int ret; 173 int ret;
197 174
198 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error); 175 if (!fname)
199 DIE_IF(ret != DW_DLV_OK); 176 return NULL;
200 ret = dwarf_formref(attr, &cu_offs, &__dw_error); 177
201 DIE_IF(ret != DW_DLV_OK); 178 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
202 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 179 if (ret != 0)
203 return cu_offs; 180 return NULL;
181
182 for (i = 0; i < nfiles; i++) {
183 src = dwarf_filesrc(files, i, NULL, NULL);
184 if (strtailcmp(src, fname) == 0)
185 break;
186 }
187 return src;
204} 188}
205 189
206/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 190struct __addr_die_search_param {
207static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die) 191 Dwarf_Addr addr;
192 Dwarf_Die *die_mem;
193};
194
195static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
208{ 196{
209 Dwarf_Attribute attr; 197 struct __addr_die_search_param *ad = data;
210 Dwarf_Addr addr;
211 Dwarf_Off offs;
212 Dwarf_Ranges *ranges;
213 Dwarf_Signed cnt;
214 int ret;
215 198
216 /* Try to get entry pc */ 199 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
217 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error); 200 dwarf_haspc(fn_die, ad->addr)) {
218 DIE_IF(ret == DW_DLV_ERROR); 201 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
219 if (ret == DW_DLV_OK) { 202 return DWARF_CB_ABORT;
220 ret = dwarf_formaddr(attr, &addr, &__dw_error);
221 DIE_IF(ret != DW_DLV_OK);
222 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
223 return addr;
224 } 203 }
204 return DWARF_CB_OK;
205}
225 206
226 /* Try to get low pc */ 207/* Search a real subprogram including this line, */
227 ret = dwarf_lowpc(dw_die, &addr, &__dw_error); 208static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
228 DIE_IF(ret == DW_DLV_ERROR); 209 Dwarf_Die *die_mem)
229 if (ret == DW_DLV_OK) 210{
230 return addr; 211 struct __addr_die_search_param ad;
231 212 ad.addr = addr;
232 /* Try to get ranges */ 213 ad.die_mem = die_mem;
233 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error); 214 /* dwarf_getscopes can't find subprogram. */
234 DIE_IF(ret != DW_DLV_OK); 215 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
235 ret = dwarf_formref(attr, &offs, &__dw_error); 216 return NULL;
236 DIE_IF(ret != DW_DLV_OK); 217 else
237 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL, 218 return die_mem;
238 &__dw_error);
239 DIE_IF(ret != DW_DLV_OK);
240 addr = ranges[0].dwr_addr1;
241 dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
242 return addr;
243} 219}
244 220
245/* 221/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
246 * Search a Die from Die tree. 222static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
247 * Note: cur_link->die should be deallocated in this function. 223 Dwarf_Die *die_mem)
248 */
249static int __search_die_tree(struct die_link *cur_link,
250 int (*die_cb)(struct die_link *, void *),
251 void *data)
252{ 224{
253 Dwarf_Die new_die; 225 Dwarf_Die child_die;
254 struct die_link new_link;
255 int ret; 226 int ret;
256 227
257 if (!die_cb) 228 ret = dwarf_child(sp_die, die_mem);
258 return 0; 229 if (ret != 0)
259 230 return NULL;
260 /* Check current die */
261 while (!(ret = die_cb(cur_link, data))) {
262 /* Check child die */
263 ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
264 DIE_IF(ret == DW_DLV_ERROR);
265 if (ret == DW_DLV_OK) {
266 new_link.parent = cur_link;
267 new_link.die = new_die;
268 ret = __search_die_tree(&new_link, die_cb, data);
269 if (ret)
270 break;
271 }
272 231
273 /* Move to next sibling */ 232 do {
274 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die, 233 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
275 &__dw_error); 234 dwarf_haspc(die_mem, addr))
276 DIE_IF(ret == DW_DLV_ERROR); 235 return die_mem;
277 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
278 cur_link->die = new_die;
279 if (ret == DW_DLV_NO_ENTRY)
280 return 0;
281 }
282 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
283 return ret;
284}
285 236
286/* Search a die in its children's die tree */ 237 if (die_get_inlinefunc(die_mem, addr, &child_die)) {
287static int search_die_from_children(Dwarf_Die parent_die, 238 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
288 int (*die_cb)(struct die_link *, void *), 239 return die_mem;
289 void *data) 240 }
290{ 241 } while (dwarf_siblingof(die_mem, die_mem) == 0);
291 struct die_link new_link;
292 int ret;
293 242
294 new_link.parent = NULL; 243 return NULL;
295 ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
296 DIE_IF(ret == DW_DLV_ERROR);
297 if (ret == DW_DLV_OK)
298 return __search_die_tree(&new_link, die_cb, data);
299 else
300 return 0;
301} 244}
302 245
303/* Find a locdesc corresponding to the address */ 246/* Compare diename and tname */
304static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc, 247static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
305 Dwarf_Addr addr)
306{ 248{
307 Dwarf_Signed lcnt; 249 const char *name;
308 Dwarf_Locdesc **llbuf; 250 name = dwarf_diename(dw_die);
309 int ret, i; 251 DIE_IF(name == NULL);
310 252 return strcmp(tname, name);
311 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
312 DIE_IF(ret != DW_DLV_OK);
313 ret = DW_DLV_NO_ENTRY;
314 for (i = 0; i < lcnt; ++i) {
315 if (llbuf[i]->ld_lopc <= addr &&
316 llbuf[i]->ld_hipc > addr) {
317 memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
318 desc->ld_s =
319 malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
320 DIE_IF(desc->ld_s == NULL);
321 memcpy(desc->ld_s, llbuf[i]->ld_s,
322 sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
323 ret = DW_DLV_OK;
324 break;
325 }
326 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
327 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
328 }
329 /* Releasing loop */
330 for (; i < lcnt; ++i) {
331 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
332 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
333 }
334 dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
335 return ret;
336} 253}
337 254
338/* Get decl_file attribute value (file number) */ 255/* Get entry pc(or low pc, 1st entry of ranges) of the die */
339static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die) 256static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
340{ 257{
341 Dwarf_Attribute attr; 258 Dwarf_Addr epc;
342 Dwarf_Unsigned fno;
343 int ret; 259 int ret;
344 260
345 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error); 261 ret = dwarf_entrypc(dw_die, &epc);
346 DIE_IF(ret != DW_DLV_OK); 262 DIE_IF(ret == -1);
347 dwarf_formudata(attr, &fno, &__dw_error); 263 return epc;
348 DIE_IF(ret != DW_DLV_OK);
349 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
350 return fno;
351} 264}
352 265
353/* Get decl_line attribute value (line number) */ 266/* Get a variable die */
354static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die) 267static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
268 Dwarf_Die *die_mem)
355{ 269{
356 Dwarf_Attribute attr; 270 Dwarf_Die child_die;
357 Dwarf_Unsigned lno; 271 int tag;
358 int ret; 272 int ret;
359 273
360 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error); 274 ret = dwarf_child(sp_die, die_mem);
361 DIE_IF(ret != DW_DLV_OK); 275 if (ret != 0)
362 dwarf_formudata(attr, &lno, &__dw_error); 276 return NULL;
363 DIE_IF(ret != DW_DLV_OK); 277
364 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 278 do {
365 return lno; 279 tag = dwarf_tag(die_mem);
280 if ((tag == DW_TAG_formal_parameter ||
281 tag == DW_TAG_variable) &&
282 (die_compare_name(die_mem, name) == 0))
283 return die_mem;
284
285 if (die_find_variable(die_mem, name, &child_die)) {
286 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
287 return die_mem;
288 }
289 } while (dwarf_siblingof(die_mem, die_mem) == 0);
290
291 return NULL;
366} 292}
367 293
368/* 294/*
@@ -370,47 +296,45 @@ static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
370 */ 296 */
371 297
372/* Show a location */ 298/* Show a location */
373static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) 299static void show_location(Dwarf_Op *op, struct probe_finder *pf)
374{ 300{
375 Dwarf_Small op; 301 unsigned int regn;
376 Dwarf_Unsigned regn; 302 Dwarf_Word offs = 0;
377 Dwarf_Signed offs;
378 int deref = 0, ret; 303 int deref = 0, ret;
379 const char *regs; 304 const char *regs;
380 305
381 op = loc->lr_atom; 306 /* TODO: support CFA */
382
383 /* If this is based on frame buffer, set the offset */ 307 /* If this is based on frame buffer, set the offset */
384 if (op == DW_OP_fbreg) { 308 if (op->atom == DW_OP_fbreg) {
309 if (pf->fb_ops == NULL)
310 die("The attribute of frame base is not supported.\n");
385 deref = 1; 311 deref = 1;
386 offs = (Dwarf_Signed)loc->lr_number; 312 offs = op->number;
387 op = pf->fbloc.ld_s[0].lr_atom; 313 op = &pf->fb_ops[0];
388 loc = &pf->fbloc.ld_s[0]; 314 }
389 } else
390 offs = 0;
391 315
392 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) { 316 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
393 regn = op - DW_OP_breg0; 317 regn = op->atom - DW_OP_breg0;
394 offs += (Dwarf_Signed)loc->lr_number; 318 offs += op->number;
395 deref = 1; 319 deref = 1;
396 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { 320 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
397 regn = op - DW_OP_reg0; 321 regn = op->atom - DW_OP_reg0;
398 } else if (op == DW_OP_bregx) { 322 } else if (op->atom == DW_OP_bregx) {
399 regn = loc->lr_number; 323 regn = op->number;
400 offs += (Dwarf_Signed)loc->lr_number2; 324 offs += op->number2;
401 deref = 1; 325 deref = 1;
402 } else if (op == DW_OP_regx) { 326 } else if (op->atom == DW_OP_regx) {
403 regn = loc->lr_number; 327 regn = op->number;
404 } else 328 } else
405 die("Dwarf_OP %d is not supported.\n", op); 329 die("DW_OP %d is not supported.", op->atom);
406 330
407 regs = get_arch_regstr(regn); 331 regs = get_arch_regstr(regn);
408 if (!regs) 332 if (!regs)
409 die("%lld exceeds max register number.\n", regn); 333 die("%u exceeds max register number.", regn);
410 334
411 if (deref) 335 if (deref)
412 ret = snprintf(pf->buf, pf->len, 336 ret = snprintf(pf->buf, pf->len, " %s=+%ju(%s)",
413 " %s=%+lld(%s)", pf->var, offs, regs); 337 pf->var, (uintmax_t)offs, regs);
414 else 338 else
415 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 339 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
416 DIE_IF(ret < 0); 340 DIE_IF(ret < 0);
@@ -418,52 +342,37 @@ static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
418} 342}
419 343
420/* Show a variables in kprobe event format */ 344/* Show a variables in kprobe event format */
421static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) 345static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
422{ 346{
423 Dwarf_Attribute attr; 347 Dwarf_Attribute attr;
424 Dwarf_Locdesc ld; 348 Dwarf_Op *expr;
349 size_t nexpr;
425 int ret; 350 int ret;
426 351
427 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error); 352 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
428 if (ret != DW_DLV_OK)
429 goto error; 353 goto error;
430 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base)); 354 /* TODO: handle more than 1 exprs */
431 if (ret != DW_DLV_OK) 355 ret = dwarf_getlocation_addr(&attr, (pf->addr - pf->cu_base),
356 &expr, &nexpr, 1);
357 if (ret <= 0 || nexpr == 0)
432 goto error; 358 goto error;
433 /* TODO? */ 359
434 DIE_IF(ld.ld_cents != 1); 360 show_location(expr, pf);
435 show_location(&ld.ld_s[0], pf); 361 /* *expr will be cached in libdw. Don't free it. */
436 free(ld.ld_s);
437 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
438 return ; 362 return ;
439error: 363error:
364 /* TODO: Support const_value */
440 die("Failed to find the location of %s at this address.\n" 365 die("Failed to find the location of %s at this address.\n"
441 " Perhaps, it has been optimized out.\n", pf->var); 366 " Perhaps, it has been optimized out.", pf->var);
442}
443
444static int variable_callback(struct die_link *dlink, void *data)
445{
446 struct probe_finder *pf = (struct probe_finder *)data;
447 Dwarf_Half tag;
448 int ret;
449
450 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
451 DIE_IF(ret == DW_DLV_ERROR);
452 if ((tag == DW_TAG_formal_parameter ||
453 tag == DW_TAG_variable) &&
454 (die_compare_name(dlink->die, pf->var) == 0)) {
455 show_variable(dlink->die, pf);
456 return 1;
457 }
458 /* TODO: Support struct members and arrays */
459 return 0;
460} 367}
461 368
462/* Find a variable in a subprogram die */ 369/* Find a variable in a subprogram die */
463static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) 370static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
464{ 371{
465 int ret; 372 int ret;
373 Dwarf_Die vr_die;
466 374
375 /* TODO: Support struct members and arrays */
467 if (!is_c_varname(pf->var)) { 376 if (!is_c_varname(pf->var)) {
468 /* Output raw parameters */ 377 /* Output raw parameters */
469 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 378 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
@@ -474,58 +383,51 @@ static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
474 383
475 pr_debug("Searching '%s' variable in context.\n", pf->var); 384 pr_debug("Searching '%s' variable in context.\n", pf->var);
476 /* Search child die for local variables and parameters. */ 385 /* Search child die for local variables and parameters. */
477 ret = search_die_from_children(sp_die, variable_callback, pf); 386 if (!die_find_variable(sp_die, pf->var, &vr_die))
478 if (!ret) 387 die("Failed to find '%s' in this function.", pf->var);
479 die("Failed to find '%s' in this function.\n", pf->var);
480}
481 388
482/* Get a frame base on the address */ 389 show_variable(&vr_die, pf);
483static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
484{
485 Dwarf_Attribute attr;
486 int ret;
487
488 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
489 DIE_IF(ret != DW_DLV_OK);
490 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
491 DIE_IF(ret != DW_DLV_OK);
492 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
493}
494
495static void free_current_frame_base(struct probe_finder *pf)
496{
497 free(pf->fbloc.ld_s);
498 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
499} 390}
500 391
501/* Show a probe point to output buffer */ 392/* Show a probe point to output buffer */
502static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs, 393static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
503 struct probe_finder *pf)
504{ 394{
505 struct probe_point *pp = pf->pp; 395 struct probe_point *pp = pf->pp;
506 char *name; 396 Dwarf_Addr eaddr;
397 Dwarf_Die die_mem;
398 const char *name;
507 char tmp[MAX_PROBE_BUFFER]; 399 char tmp[MAX_PROBE_BUFFER];
508 int ret, i, len; 400 int ret, i, len;
401 Dwarf_Attribute fb_attr;
402 size_t nops;
403
404 /* If no real subprogram, find a real one */
405 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
406 sp_die = die_get_real_subprogram(&pf->cu_die,
407 pf->addr, &die_mem);
408 if (!sp_die)
409 die("Probe point is not found in subprograms.");
410 }
509 411
510 /* Output name of probe point */ 412 /* Output name of probe point */
511 ret = dwarf_diename(sp_die, &name, &__dw_error); 413 name = dwarf_diename(sp_die);
512 DIE_IF(ret == DW_DLV_ERROR); 414 if (name) {
513 if (ret == DW_DLV_OK) { 415 dwarf_entrypc(sp_die, &eaddr);
514 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, 416 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
515 (unsigned int)offs); 417 (unsigned long)(pf->addr - eaddr));
516 /* Copy the function name if possible */ 418 /* Copy the function name if possible */
517 if (!pp->function) { 419 if (!pp->function) {
518 pp->function = strdup(name); 420 pp->function = strdup(name);
519 pp->offset = offs; 421 pp->offset = (size_t)(pf->addr - eaddr);
520 } 422 }
521 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
522 } else { 423 } else {
523 /* This function has no name. */ 424 /* This function has no name. */
524 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr); 425 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx",
426 (uintmax_t)pf->addr);
525 if (!pp->function) { 427 if (!pp->function) {
526 /* TODO: Use _stext */ 428 /* TODO: Use _stext */
527 pp->function = strdup(""); 429 pp->function = strdup("");
528 pp->offset = (int)pf->addr; 430 pp->offset = (size_t)pf->addr;
529 } 431 }
530 } 432 }
531 DIE_IF(ret < 0); 433 DIE_IF(ret < 0);
@@ -533,8 +435,15 @@ static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
533 len = ret; 435 len = ret;
534 pr_debug("Probe point found: %s\n", tmp); 436 pr_debug("Probe point found: %s\n", tmp);
535 437
438 /* Get the frame base attribute/ops */
439 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
440 ret = dwarf_getlocation_addr(&fb_attr, (pf->addr - pf->cu_base),
441 &pf->fb_ops, &nops, 1);
442 if (ret <= 0 || nops == 0)
443 pf->fb_ops = NULL;
444
536 /* Find each argument */ 445 /* Find each argument */
537 get_current_frame_base(sp_die, pf); 446 /* TODO: use dwarf_cfi_addrframe */
538 for (i = 0; i < pp->nr_args; i++) { 447 for (i = 0; i < pp->nr_args; i++) {
539 pf->var = pp->args[i]; 448 pf->var = pp->args[i];
540 pf->buf = &tmp[len]; 449 pf->buf = &tmp[len];
@@ -542,189 +451,383 @@ static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
542 find_variable(sp_die, pf); 451 find_variable(sp_die, pf);
543 len += strlen(pf->buf); 452 len += strlen(pf->buf);
544 } 453 }
545 free_current_frame_base(pf); 454
455 /* *pf->fb_ops will be cached in libdw. Don't free it. */
456 pf->fb_ops = NULL;
546 457
547 pp->probes[pp->found] = strdup(tmp); 458 pp->probes[pp->found] = strdup(tmp);
548 pp->found++; 459 pp->found++;
549} 460}
550 461
551static int probeaddr_callback(struct die_link *dlink, void *data) 462/* Find probe point from its line number */
463static void find_probe_point_by_line(struct probe_finder *pf)
552{ 464{
553 struct probe_finder *pf = (struct probe_finder *)data; 465 Dwarf_Lines *lines;
554 Dwarf_Half tag; 466 Dwarf_Line *line;
555 Dwarf_Signed offs; 467 size_t nlines, i;
468 Dwarf_Addr addr;
469 int lineno;
556 int ret; 470 int ret;
557 471
558 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 472 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
559 DIE_IF(ret == DW_DLV_ERROR); 473 DIE_IF(ret != 0);
560 /* Check the address is in this subprogram */ 474
561 if (tag == DW_TAG_subprogram && 475 for (i = 0; i < nlines; i++) {
562 die_within_subprogram(dlink->die, pf->addr, &offs)) { 476 line = dwarf_onesrcline(lines, i);
563 show_probepoint(dlink->die, offs, pf); 477 dwarf_lineno(line, &lineno);
564 return 1; 478 if (lineno != pf->lno)
479 continue;
480
481 /* TODO: Get fileno from line, but how? */
482 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
483 continue;
484
485 ret = dwarf_lineaddr(line, &addr);
486 DIE_IF(ret != 0);
487 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
488 (int)i, lineno, (uintmax_t)addr);
489 pf->addr = addr;
490
491 show_probe_point(NULL, pf);
492 /* Continuing, because target line might be inlined. */
565 } 493 }
566 return 0;
567} 494}
568 495
569/* Find probe point from its line number */ 496/* Find lines which match lazy pattern */
570static void find_by_line(struct probe_finder *pf) 497static int find_lazy_match_lines(struct list_head *head,
498 const char *fname, const char *pat)
499{
500 char *fbuf, *p1, *p2;
501 int fd, line, nlines = 0;
502 struct stat st;
503
504 fd = open(fname, O_RDONLY);
505 if (fd < 0)
506 die("failed to open %s", fname);
507 DIE_IF(fstat(fd, &st) < 0);
508 fbuf = malloc(st.st_size + 2);
509 DIE_IF(fbuf == NULL);
510 DIE_IF(read(fd, fbuf, st.st_size) < 0);
511 close(fd);
512 fbuf[st.st_size] = '\n'; /* Dummy line */
513 fbuf[st.st_size + 1] = '\0';
514 p1 = fbuf;
515 line = 1;
516 while ((p2 = strchr(p1, '\n')) != NULL) {
517 *p2 = '\0';
518 if (strlazymatch(p1, pat)) {
519 line_list__add_line(head, line);
520 nlines++;
521 }
522 line++;
523 p1 = p2 + 1;
524 }
525 free(fbuf);
526 return nlines;
527}
528
529/* Find probe points from lazy pattern */
530static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
571{ 531{
572 Dwarf_Signed cnt, i, clm; 532 Dwarf_Lines *lines;
573 Dwarf_Line *lines; 533 Dwarf_Line *line;
574 Dwarf_Unsigned lineno = 0; 534 size_t nlines, i;
575 Dwarf_Addr addr; 535 Dwarf_Addr addr;
576 Dwarf_Unsigned fno; 536 Dwarf_Die die_mem;
537 int lineno;
577 int ret; 538 int ret;
578 539
579 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error); 540 if (list_empty(&pf->lcache)) {
580 DIE_IF(ret != DW_DLV_OK); 541 /* Matching lazy line pattern */
542 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
543 pf->pp->lazy_line);
544 if (ret <= 0)
545 die("No matched lines found in %s.", pf->fname);
546 }
547
548 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
549 DIE_IF(ret != 0);
550 for (i = 0; i < nlines; i++) {
551 line = dwarf_onesrcline(lines, i);
581 552
582 for (i = 0; i < cnt; i++) { 553 dwarf_lineno(line, &lineno);
583 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); 554 if (!line_list__has_line(&pf->lcache, lineno))
584 DIE_IF(ret != DW_DLV_OK);
585 if (fno != pf->fno)
586 continue; 555 continue;
587 556
588 ret = dwarf_lineno(lines[i], &lineno, &__dw_error); 557 /* TODO: Get fileno from line, but how? */
589 DIE_IF(ret != DW_DLV_OK); 558 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
590 if (lineno != pf->lno)
591 continue; 559 continue;
592 560
593 ret = dwarf_lineoff(lines[i], &clm, &__dw_error); 561 ret = dwarf_lineaddr(line, &addr);
594 DIE_IF(ret != DW_DLV_OK); 562 DIE_IF(ret != 0);
563 if (sp_die) {
564 /* Address filtering 1: does sp_die include addr? */
565 if (!dwarf_haspc(sp_die, addr))
566 continue;
567 /* Address filtering 2: No child include addr? */
568 if (die_get_inlinefunc(sp_die, addr, &die_mem))
569 continue;
570 }
595 571
596 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 572 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
597 DIE_IF(ret != DW_DLV_OK); 573 (int)i, lineno, (unsigned long long)addr);
598 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
599 (int)i, (unsigned)lineno, (int)clm, addr);
600 pf->addr = addr; 574 pf->addr = addr;
601 /* Search a real subprogram including this line, */ 575
602 ret = search_die_from_children(pf->cu_die, 576 show_probe_point(sp_die, pf);
603 probeaddr_callback, pf);
604 if (ret == 0)
605 die("Probe point is not found in subprograms.\n");
606 /* Continuing, because target line might be inlined. */ 577 /* Continuing, because target line might be inlined. */
607 } 578 }
608 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 579 /* TODO: deallocate lines, but how? */
580}
581
582static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
583{
584 struct probe_finder *pf = (struct probe_finder *)data;
585 struct probe_point *pp = pf->pp;
586
587 if (pp->lazy_line)
588 find_probe_point_lazy(in_die, pf);
589 else {
590 /* Get probe address */
591 pf->addr = die_get_entrypc(in_die);
592 pf->addr += pp->offset;
593 pr_debug("found inline addr: 0x%jx\n",
594 (uintmax_t)pf->addr);
595
596 show_probe_point(in_die, pf);
597 }
598
599 return DWARF_CB_OK;
609} 600}
610 601
611/* Search function from function name */ 602/* Search function from function name */
612static int probefunc_callback(struct die_link *dlink, void *data) 603static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
613{ 604{
614 struct probe_finder *pf = (struct probe_finder *)data; 605 struct probe_finder *pf = (struct probe_finder *)data;
615 struct probe_point *pp = pf->pp; 606 struct probe_point *pp = pf->pp;
616 struct die_link *lk;
617 Dwarf_Signed offs;
618 Dwarf_Half tag;
619 int ret;
620 607
621 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 608 /* Check tag and diename */
622 DIE_IF(ret == DW_DLV_ERROR); 609 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
623 if (tag == DW_TAG_subprogram) { 610 die_compare_name(sp_die, pp->function) != 0)
624 if (die_compare_name(dlink->die, pp->function) == 0) { 611 return 0;
625 if (pp->line) { /* Function relative line */ 612
626 pf->fno = die_get_decl_file(dlink->die); 613 pf->fname = dwarf_decl_file(sp_die);
627 pf->lno = die_get_decl_line(dlink->die) 614 if (pp->line) { /* Function relative line */
628 + pp->line; 615 dwarf_decl_line(sp_die, &pf->lno);
629 find_by_line(pf); 616 pf->lno += pp->line;
630 return 1; 617 find_probe_point_by_line(pf);
631 } 618 } else if (!dwarf_func_inline(sp_die)) {
632 if (die_inlined_subprogram(dlink->die)) { 619 /* Real function */
633 /* Inlined function, save it. */ 620 if (pp->lazy_line)
634 ret = dwarf_die_CU_offset(dlink->die, 621 find_probe_point_lazy(sp_die, pf);
635 &pf->inl_offs, 622 else {
636 &__dw_error); 623 pf->addr = die_get_entrypc(sp_die);
637 DIE_IF(ret != DW_DLV_OK);
638 pr_debug("inline definition offset %lld\n",
639 pf->inl_offs);
640 return 0; /* Continue to search */
641 }
642 /* Get probe address */
643 pf->addr = die_get_entrypc(dlink->die);
644 pf->addr += pp->offset; 624 pf->addr += pp->offset;
645 /* TODO: Check the address in this function */ 625 /* TODO: Check the address in this function */
646 show_probepoint(dlink->die, pp->offset, pf); 626 show_probe_point(sp_die, pf);
647 return 1; /* Exit; no same symbol in this CU. */
648 }
649 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
650 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
651 /* Get probe address */
652 pf->addr = die_get_entrypc(dlink->die);
653 pf->addr += pp->offset;
654 pr_debug("found inline addr: 0x%llx\n", pf->addr);
655 /* Inlined function. Get a real subprogram */
656 for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
657 tag = 0;
658 dwarf_tag(lk->die, &tag, &__dw_error);
659 DIE_IF(ret == DW_DLV_ERROR);
660 if (tag == DW_TAG_subprogram &&
661 !die_inlined_subprogram(lk->die))
662 goto found;
663 }
664 die("Failed to find real subprogram.\n");
665found:
666 /* Get offset from subprogram */
667 ret = die_within_subprogram(lk->die, pf->addr, &offs);
668 DIE_IF(!ret);
669 show_probepoint(lk->die, offs, pf);
670 /* Continue to search */
671 } 627 }
672 } 628 } else
673 return 0; 629 /* Inlined function: search instances */
630 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
631
632 return 1; /* Exit; no same symbol in this CU. */
674} 633}
675 634
676static void find_by_func(struct probe_finder *pf) 635static void find_probe_point_by_func(struct probe_finder *pf)
677{ 636{
678 search_die_from_children(pf->cu_die, probefunc_callback, pf); 637 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
679} 638}
680 639
681/* Find a probe point */ 640/* Find a probe point */
682int find_probepoint(int fd, struct probe_point *pp) 641int find_probe_point(int fd, struct probe_point *pp)
683{ 642{
684 Dwarf_Half addr_size = 0;
685 Dwarf_Unsigned next_cuh = 0;
686 int cu_number = 0, ret;
687 struct probe_finder pf = {.pp = pp}; 643 struct probe_finder pf = {.pp = pp};
644 int ret;
645 Dwarf_Off off, noff;
646 size_t cuhl;
647 Dwarf_Die *diep;
648 Dwarf *dbg;
688 649
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 650 dbg = dwarf_begin(fd, DWARF_C_READ);
690 if (ret != DW_DLV_OK) 651 if (!dbg)
691 return -ENOENT; 652 return -ENOENT;
692 653
693 pp->found = 0; 654 pp->found = 0;
694 while (++cu_number) { 655 off = 0;
695 /* Search CU (Compilation Unit) */ 656 line_list__init(&pf.lcache);
696 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 657 /* Loop on CUs (Compilation Unit) */
697 &addr_size, &next_cuh, &__dw_error); 658 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
698 DIE_IF(ret == DW_DLV_ERROR);
699 if (ret == DW_DLV_NO_ENTRY)
700 break;
701
702 /* Get the DIE(Debugging Information Entry) of this CU */ 659 /* Get the DIE(Debugging Information Entry) of this CU */
703 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error); 660 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
704 DIE_IF(ret != DW_DLV_OK); 661 if (!diep)
662 continue;
705 663
706 /* Check if target file is included. */ 664 /* Check if target file is included. */
707 if (pp->file) 665 if (pp->file)
708 pf.fno = cu_find_fileno(pf.cu_die, pp->file); 666 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
667 else
668 pf.fname = NULL;
709 669
710 if (!pp->file || pf.fno) { 670 if (!pp->file || pf.fname) {
711 /* Save CU base address (for frame_base) */ 671 /* Save CU base address (for frame_base) */
712 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error); 672 ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base);
713 DIE_IF(ret == DW_DLV_ERROR); 673 if (ret != 0)
714 if (ret == DW_DLV_NO_ENTRY)
715 pf.cu_base = 0; 674 pf.cu_base = 0;
716 if (pp->function) 675 if (pp->function)
717 find_by_func(&pf); 676 find_probe_point_by_func(&pf);
677 else if (pp->lazy_line)
678 find_probe_point_lazy(NULL, &pf);
718 else { 679 else {
719 pf.lno = pp->line; 680 pf.lno = pp->line;
720 find_by_line(&pf); 681 find_probe_point_by_line(&pf);
721 } 682 }
722 } 683 }
723 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); 684 off = noff;
724 } 685 }
725 ret = dwarf_finish(__dw_debug, &__dw_error); 686 line_list__free(&pf.lcache);
726 DIE_IF(ret != DW_DLV_OK); 687 dwarf_end(dbg);
727 688
728 return pp->found; 689 return pp->found;
729} 690}
730 691
692/* Find line range from its line number */
693static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
694{
695 Dwarf_Lines *lines;
696 Dwarf_Line *line;
697 size_t nlines, i;
698 Dwarf_Addr addr;
699 int lineno;
700 int ret;
701 const char *src;
702 Dwarf_Die die_mem;
703
704 line_list__init(&lf->lr->line_list);
705 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
706 DIE_IF(ret != 0);
707
708 for (i = 0; i < nlines; i++) {
709 line = dwarf_onesrcline(lines, i);
710 ret = dwarf_lineno(line, &lineno);
711 DIE_IF(ret != 0);
712 if (lf->lno_s > lineno || lf->lno_e < lineno)
713 continue;
714
715 if (sp_die) {
716 /* Address filtering 1: does sp_die include addr? */
717 ret = dwarf_lineaddr(line, &addr);
718 DIE_IF(ret != 0);
719 if (!dwarf_haspc(sp_die, addr))
720 continue;
721
722 /* Address filtering 2: No child include addr? */
723 if (die_get_inlinefunc(sp_die, addr, &die_mem))
724 continue;
725 }
726
727 /* TODO: Get fileno from line, but how? */
728 src = dwarf_linesrc(line, NULL, NULL);
729 if (strtailcmp(src, lf->fname) != 0)
730 continue;
731
732 /* Copy real path */
733 if (!lf->lr->path)
734 lf->lr->path = strdup(src);
735 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
736 }
737 /* Update status */
738 if (!list_empty(&lf->lr->line_list))
739 lf->found = 1;
740 else {
741 free(lf->lr->path);
742 lf->lr->path = NULL;
743 }
744}
745
746static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
747{
748 find_line_range_by_line(in_die, (struct line_finder *)data);
749 return DWARF_CB_ABORT; /* No need to find other instances */
750}
751
752/* Search function from function name */
753static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
754{
755 struct line_finder *lf = (struct line_finder *)data;
756 struct line_range *lr = lf->lr;
757
758 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
759 die_compare_name(sp_die, lr->function) == 0) {
760 lf->fname = dwarf_decl_file(sp_die);
761 dwarf_decl_line(sp_die, &lr->offset);
762 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
763 lf->lno_s = lr->offset + lr->start;
764 if (!lr->end)
765 lf->lno_e = INT_MAX;
766 else
767 lf->lno_e = lr->offset + lr->end;
768 lr->start = lf->lno_s;
769 lr->end = lf->lno_e;
770 if (dwarf_func_inline(sp_die))
771 dwarf_func_inline_instances(sp_die,
772 line_range_inline_cb, lf);
773 else
774 find_line_range_by_line(sp_die, lf);
775 return 1;
776 }
777 return 0;
778}
779
780static void find_line_range_by_func(struct line_finder *lf)
781{
782 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
783}
784
785int find_line_range(int fd, struct line_range *lr)
786{
787 struct line_finder lf = {.lr = lr, .found = 0};
788 int ret;
789 Dwarf_Off off = 0, noff;
790 size_t cuhl;
791 Dwarf_Die *diep;
792 Dwarf *dbg;
793
794 dbg = dwarf_begin(fd, DWARF_C_READ);
795 if (!dbg)
796 return -ENOENT;
797
798 /* Loop on CUs (Compilation Unit) */
799 while (!lf.found) {
800 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL);
801 if (ret != 0)
802 break;
803
804 /* Get the DIE(Debugging Information Entry) of this CU */
805 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
806 if (!diep)
807 continue;
808
809 /* Check if target file is included. */
810 if (lr->file)
811 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
812 else
813 lf.fname = 0;
814
815 if (!lr->file || lf.fname) {
816 if (lr->function)
817 find_line_range_by_func(&lf);
818 else {
819 lf.lno_s = lr->start;
820 if (!lr->end)
821 lf.lno_e = INT_MAX;
822 else
823 lf.lno_e = lr->end;
824 find_line_range_by_line(NULL, &lf);
825 }
826 }
827 off = noff;
828 }
829 pr_debug("path: %lx\n", (unsigned long)lr->path);
830 dwarf_end(dbg);
831 return lf.found;
832}
833
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index a4086aaddb73..d1a651793ba6 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -1,6 +1,9 @@
1#ifndef _PROBE_FINDER_H 1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H 2#define _PROBE_FINDER_H
3 3
4#include <stdbool.h>
5#include "util.h"
6
4#define MAX_PATH_LEN 256 7#define MAX_PATH_LEN 256
5#define MAX_PROBE_BUFFER 1024 8#define MAX_PROBE_BUFFER 1024
6#define MAX_PROBES 128 9#define MAX_PROBES 128
@@ -18,6 +21,7 @@ struct probe_point {
18 /* Inputs */ 21 /* Inputs */
19 char *file; /* File name */ 22 char *file; /* File name */
20 int line; /* Line number */ 23 int line; /* Line number */
24 char *lazy_line; /* Lazy line pattern */
21 25
22 char *function; /* Function name */ 26 char *function; /* Function name */
23 int offset; /* Offset bytes */ 27 int offset; /* Offset bytes */
@@ -32,34 +36,58 @@ struct probe_point {
32 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ 36 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
33}; 37};
34 38
35#ifndef NO_LIBDWARF 39/* Line number container */
36extern int find_probepoint(int fd, struct probe_point *pp); 40struct line_node {
41 struct list_head list;
42 unsigned int line;
43};
44
45/* Line range */
46struct line_range {
47 char *file; /* File name */
48 char *function; /* Function name */
49 unsigned int start; /* Start line number */
50 unsigned int end; /* End line number */
51 int offset; /* Start line offset */
52 char *path; /* Real path name */
53 struct list_head line_list; /* Visible lines */
54};
37 55
38/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */ 56#ifndef NO_DWARF_SUPPORT
39#ifndef _MIPS_SZLONG 57extern int find_probe_point(int fd, struct probe_point *pp);
40# define _MIPS_SZLONG 0 58extern int find_line_range(int fd, struct line_range *lr);
41#endif
42 59
43#include <dwarf.h> 60#include <dwarf.h>
44#include <libdwarf.h> 61#include <libdw.h>
45 62
46struct probe_finder { 63struct probe_finder {
47 struct probe_point *pp; /* Target probe point */ 64 struct probe_point *pp; /* Target probe point */
48 65
49 /* For function searching */ 66 /* For function searching */
50 Dwarf_Addr addr; /* Address */ 67 Dwarf_Addr addr; /* Address */
51 Dwarf_Unsigned fno; /* File number */ 68 const char *fname; /* File name */
52 Dwarf_Unsigned lno; /* Line number */ 69 int lno; /* Line number */
53 Dwarf_Off inl_offs; /* Inline offset */ 70 Dwarf_Die cu_die; /* Current CU */
54 Dwarf_Die cu_die; /* Current CU */
55 71
56 /* For variable searching */ 72 /* For variable searching */
57 Dwarf_Addr cu_base; /* Current CU base address */ 73 Dwarf_Op *fb_ops; /* Frame base attribute */
58 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ 74 Dwarf_Addr cu_base; /* Current CU base address */
59 const char *var; /* Current variable name */ 75 const char *var; /* Current variable name */
60 char *buf; /* Current output buffer */ 76 char *buf; /* Current output buffer */
61 int len; /* Length of output buffer */ 77 int len; /* Length of output buffer */
78 struct list_head lcache; /* Line cache for lazy match */
62}; 79};
63#endif /* NO_LIBDWARF */ 80
81struct line_finder {
82 struct line_range *lr; /* Target line range */
83
84 const char *fname; /* File name */
85 int lno_s; /* Start line number */
86 int lno_e; /* End line number */
87 Dwarf_Die cu_die; /* Current CU */
88 int found;
89};
90
91#endif /* NO_DWARF_SUPPORT */
64 92
65#endif /*_PROBE_FINDER_H */ 93#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 6d6d76b8a21e..5376378e0cfc 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -25,10 +25,16 @@
25#include <ctype.h> 25#include <ctype.h>
26#include <errno.h> 26#include <errno.h>
27 27
28#include "../perf.h" 28#include "../../perf.h"
29#include "util.h" 29#include "../util.h"
30#include "trace-event.h" 30#include "../trace-event.h"
31#include "trace-event-perl.h" 31
32#include <EXTERN.h>
33#include <perl.h>
34
35void boot_Perf__Trace__Context(pTHX_ CV *cv);
36void boot_DynaLoader(pTHX_ CV *cv);
37typedef PerlInterpreter * INTERP;
32 38
33void xs_init(pTHX); 39void xs_init(pTHX);
34 40
@@ -49,7 +55,7 @@ INTERP my_perl;
49 55
50struct event *events[FTRACE_MAX_EVENT]; 56struct event *events[FTRACE_MAX_EVENT];
51 57
52static struct scripting_context *scripting_context; 58extern struct scripting_context *scripting_context;
53 59
54static char *cur_field_name; 60static char *cur_field_name;
55static int zero_flag_atom; 61static int zero_flag_atom;
@@ -239,33 +245,6 @@ static inline struct event *find_cache_event(int type)
239 return event; 245 return event;
240} 246}
241 247
242int common_pc(struct scripting_context *context)
243{
244 int pc;
245
246 pc = parse_common_pc(context->event_data);
247
248 return pc;
249}
250
251int common_flags(struct scripting_context *context)
252{
253 int flags;
254
255 flags = parse_common_flags(context->event_data);
256
257 return flags;
258}
259
260int common_lock_depth(struct scripting_context *context)
261{
262 int lock_depth;
263
264 lock_depth = parse_common_lock_depth(context->event_data);
265
266 return lock_depth;
267}
268
269static void perl_process_event(int cpu, void *data, 248static void perl_process_event(int cpu, void *data,
270 int size __unused, 249 int size __unused,
271 unsigned long long nsecs, char *comm) 250 unsigned long long nsecs, char *comm)
@@ -587,75 +566,3 @@ struct scripting_ops perl_scripting_ops = {
587 .process_event = perl_process_event, 566 .process_event = perl_process_event,
588 .generate_script = perl_generate_script, 567 .generate_script = perl_generate_script,
589}; 568};
590
591static void print_unsupported_msg(void)
592{
593 fprintf(stderr, "Perl scripting not supported."
594 " Install libperl and rebuild perf to enable it.\n"
595 "For example:\n # apt-get install libperl-dev (ubuntu)"
596 "\n # yum install perl-ExtUtils-Embed (Fedora)"
597 "\n etc.\n");
598}
599
600static int perl_start_script_unsupported(const char *script __unused,
601 int argc __unused,
602 const char **argv __unused)
603{
604 print_unsupported_msg();
605
606 return -1;
607}
608
609static int perl_stop_script_unsupported(void)
610{
611 return 0;
612}
613
614static void perl_process_event_unsupported(int cpu __unused,
615 void *data __unused,
616 int size __unused,
617 unsigned long long nsecs __unused,
618 char *comm __unused)
619{
620}
621
622static int perl_generate_script_unsupported(const char *outfile __unused)
623{
624 print_unsupported_msg();
625
626 return -1;
627}
628
629struct scripting_ops perl_scripting_unsupported_ops = {
630 .name = "Perl",
631 .start_script = perl_start_script_unsupported,
632 .stop_script = perl_stop_script_unsupported,
633 .process_event = perl_process_event_unsupported,
634 .generate_script = perl_generate_script_unsupported,
635};
636
637static void register_perl_scripting(struct scripting_ops *scripting_ops)
638{
639 int err;
640 err = script_spec_register("Perl", scripting_ops);
641 if (err)
642 die("error registering Perl script extension");
643
644 err = script_spec_register("pl", scripting_ops);
645 if (err)
646 die("error registering pl script extension");
647
648 scripting_context = malloc(sizeof(struct scripting_context));
649}
650
651#ifdef NO_LIBPERL
652void setup_perl_scripting(void)
653{
654 register_perl_scripting(&perl_scripting_unsupported_ops);
655}
656#else
657void setup_perl_scripting(void)
658{
659 register_perl_scripting(&perl_scripting_ops);
660}
661#endif
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
new file mode 100644
index 000000000000..33a414bbba3e
--- /dev/null
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -0,0 +1,573 @@
1/*
2 * trace-event-python. Feed trace events to an embedded Python interpreter.
3 *
4 * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <Python.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28#include <errno.h>
29
30#include "../../perf.h"
31#include "../util.h"
32#include "../trace-event.h"
33
34PyMODINIT_FUNC initperf_trace_context(void);
35
36#define FTRACE_MAX_EVENT \
37 ((1 << (sizeof(unsigned short) * 8)) - 1)
38
39struct event *events[FTRACE_MAX_EVENT];
40
41#define MAX_FIELDS 64
42#define N_COMMON_FIELDS 7
43
44extern struct scripting_context *scripting_context;
45
46static char *cur_field_name;
47static int zero_flag_atom;
48
49static PyObject *main_module, *main_dict;
50
51static void handler_call_die(const char *handler_name)
52{
53 PyErr_Print();
54 Py_FatalError("problem in Python trace event handler");
55}
56
57static void define_value(enum print_arg_type field_type,
58 const char *ev_name,
59 const char *field_name,
60 const char *field_value,
61 const char *field_str)
62{
63 const char *handler_name = "define_flag_value";
64 PyObject *handler, *t, *retval;
65 unsigned long long value;
66 unsigned n = 0;
67
68 if (field_type == PRINT_SYMBOL)
69 handler_name = "define_symbolic_value";
70
71 t = PyTuple_New(4);
72 if (!t)
73 Py_FatalError("couldn't create Python tuple");
74
75 value = eval_flag(field_value);
76
77 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
78 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
79 PyTuple_SetItem(t, n++, PyInt_FromLong(value));
80 PyTuple_SetItem(t, n++, PyString_FromString(field_str));
81
82 handler = PyDict_GetItemString(main_dict, handler_name);
83 if (handler && PyCallable_Check(handler)) {
84 retval = PyObject_CallObject(handler, t);
85 if (retval == NULL)
86 handler_call_die(handler_name);
87 }
88
89 Py_DECREF(t);
90}
91
92static void define_values(enum print_arg_type field_type,
93 struct print_flag_sym *field,
94 const char *ev_name,
95 const char *field_name)
96{
97 define_value(field_type, ev_name, field_name, field->value,
98 field->str);
99
100 if (field->next)
101 define_values(field_type, field->next, ev_name, field_name);
102}
103
104static void define_field(enum print_arg_type field_type,
105 const char *ev_name,
106 const char *field_name,
107 const char *delim)
108{
109 const char *handler_name = "define_flag_field";
110 PyObject *handler, *t, *retval;
111 unsigned n = 0;
112
113 if (field_type == PRINT_SYMBOL)
114 handler_name = "define_symbolic_field";
115
116 if (field_type == PRINT_FLAGS)
117 t = PyTuple_New(3);
118 else
119 t = PyTuple_New(2);
120 if (!t)
121 Py_FatalError("couldn't create Python tuple");
122
123 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
124 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
125 if (field_type == PRINT_FLAGS)
126 PyTuple_SetItem(t, n++, PyString_FromString(delim));
127
128 handler = PyDict_GetItemString(main_dict, handler_name);
129 if (handler && PyCallable_Check(handler)) {
130 retval = PyObject_CallObject(handler, t);
131 if (retval == NULL)
132 handler_call_die(handler_name);
133 }
134
135 Py_DECREF(t);
136}
137
138static void define_event_symbols(struct event *event,
139 const char *ev_name,
140 struct print_arg *args)
141{
142 switch (args->type) {
143 case PRINT_NULL:
144 break;
145 case PRINT_ATOM:
146 define_value(PRINT_FLAGS, ev_name, cur_field_name, "0",
147 args->atom.atom);
148 zero_flag_atom = 0;
149 break;
150 case PRINT_FIELD:
151 if (cur_field_name)
152 free(cur_field_name);
153 cur_field_name = strdup(args->field.name);
154 break;
155 case PRINT_FLAGS:
156 define_event_symbols(event, ev_name, args->flags.field);
157 define_field(PRINT_FLAGS, ev_name, cur_field_name,
158 args->flags.delim);
159 define_values(PRINT_FLAGS, args->flags.flags, ev_name,
160 cur_field_name);
161 break;
162 case PRINT_SYMBOL:
163 define_event_symbols(event, ev_name, args->symbol.field);
164 define_field(PRINT_SYMBOL, ev_name, cur_field_name, NULL);
165 define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name,
166 cur_field_name);
167 break;
168 case PRINT_STRING:
169 break;
170 case PRINT_TYPE:
171 define_event_symbols(event, ev_name, args->typecast.item);
172 break;
173 case PRINT_OP:
174 if (strcmp(args->op.op, ":") == 0)
175 zero_flag_atom = 1;
176 define_event_symbols(event, ev_name, args->op.left);
177 define_event_symbols(event, ev_name, args->op.right);
178 break;
179 default:
180 /* we should warn... */
181 return;
182 }
183
184 if (args->next)
185 define_event_symbols(event, ev_name, args->next);
186}
187
188static inline struct event *find_cache_event(int type)
189{
190 static char ev_name[256];
191 struct event *event;
192
193 if (events[type])
194 return events[type];
195
196 events[type] = event = trace_find_event(type);
197 if (!event)
198 return NULL;
199
200 sprintf(ev_name, "%s__%s", event->system, event->name);
201
202 define_event_symbols(event, ev_name, event->print_fmt.args);
203
204 return event;
205}
206
207static void python_process_event(int cpu, void *data,
208 int size __unused,
209 unsigned long long nsecs, char *comm)
210{
211 PyObject *handler, *retval, *context, *t;
212 static char handler_name[256];
213 struct format_field *field;
214 unsigned long long val;
215 unsigned long s, ns;
216 struct event *event;
217 unsigned n = 0;
218 int type;
219 int pid;
220
221 t = PyTuple_New(MAX_FIELDS);
222 if (!t)
223 Py_FatalError("couldn't create Python tuple");
224
225 type = trace_parse_common_type(data);
226
227 event = find_cache_event(type);
228 if (!event)
229 die("ug! no event found for type %d", type);
230
231 pid = trace_parse_common_pid(data);
232
233 sprintf(handler_name, "%s__%s", event->system, event->name);
234
235 s = nsecs / NSECS_PER_SEC;
236 ns = nsecs - s * NSECS_PER_SEC;
237
238 scripting_context->event_data = data;
239
240 context = PyCObject_FromVoidPtr(scripting_context, NULL);
241
242 PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
243 PyTuple_SetItem(t, n++,
244 PyCObject_FromVoidPtr(scripting_context, NULL));
245 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
246 PyTuple_SetItem(t, n++, PyInt_FromLong(s));
247 PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
248 PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
249 PyTuple_SetItem(t, n++, PyString_FromString(comm));
250
251 for (field = event->format.fields; field; field = field->next) {
252 if (field->flags & FIELD_IS_STRING) {
253 int offset;
254 if (field->flags & FIELD_IS_DYNAMIC) {
255 offset = *(int *)(data + field->offset);
256 offset &= 0xffff;
257 } else
258 offset = field->offset;
259 PyTuple_SetItem(t, n++,
260 PyString_FromString((char *)data + offset));
261 } else { /* FIELD_IS_NUMERIC */
262 val = read_size(data + field->offset, field->size);
263 if (field->flags & FIELD_IS_SIGNED) {
264 PyTuple_SetItem(t, n++, PyInt_FromLong(val));
265 } else {
266 PyTuple_SetItem(t, n++, PyInt_FromLong(val));
267 }
268 }
269 }
270
271 if (_PyTuple_Resize(&t, n) == -1)
272 Py_FatalError("error resizing Python tuple");
273
274 handler = PyDict_GetItemString(main_dict, handler_name);
275 if (handler && PyCallable_Check(handler)) {
276 retval = PyObject_CallObject(handler, t);
277 if (retval == NULL)
278 handler_call_die(handler_name);
279 } else {
280 handler = PyDict_GetItemString(main_dict, "trace_unhandled");
281 if (handler && PyCallable_Check(handler)) {
282 if (_PyTuple_Resize(&t, N_COMMON_FIELDS) == -1)
283 Py_FatalError("error resizing Python tuple");
284
285 retval = PyObject_CallObject(handler, t);
286 if (retval == NULL)
287 handler_call_die("trace_unhandled");
288 }
289 }
290
291 Py_DECREF(t);
292}
293
294static int run_start_sub(void)
295{
296 PyObject *handler, *retval;
297 int err = 0;
298
299 main_module = PyImport_AddModule("__main__");
300 if (main_module == NULL)
301 return -1;
302 Py_INCREF(main_module);
303
304 main_dict = PyModule_GetDict(main_module);
305 if (main_dict == NULL) {
306 err = -1;
307 goto error;
308 }
309 Py_INCREF(main_dict);
310
311 handler = PyDict_GetItemString(main_dict, "trace_begin");
312 if (handler == NULL || !PyCallable_Check(handler))
313 goto out;
314
315 retval = PyObject_CallObject(handler, NULL);
316 if (retval == NULL)
317 handler_call_die("trace_begin");
318
319 Py_DECREF(retval);
320 return err;
321error:
322 Py_XDECREF(main_dict);
323 Py_XDECREF(main_module);
324out:
325 return err;
326}
327
328/*
329 * Start trace script
330 */
331static int python_start_script(const char *script, int argc, const char **argv)
332{
333 const char **command_line;
334 char buf[PATH_MAX];
335 int i, err = 0;
336 FILE *fp;
337
338 command_line = malloc((argc + 1) * sizeof(const char *));
339 command_line[0] = script;
340 for (i = 1; i < argc + 1; i++)
341 command_line[i] = argv[i - 1];
342
343 Py_Initialize();
344
345 initperf_trace_context();
346
347 PySys_SetArgv(argc + 1, (char **)command_line);
348
349 fp = fopen(script, "r");
350 if (!fp) {
351 sprintf(buf, "Can't open python script \"%s\"", script);
352 perror(buf);
353 err = -1;
354 goto error;
355 }
356
357 err = PyRun_SimpleFile(fp, script);
358 if (err) {
359 fprintf(stderr, "Error running python script %s\n", script);
360 goto error;
361 }
362
363 err = run_start_sub();
364 if (err) {
365 fprintf(stderr, "Error starting python script %s\n", script);
366 goto error;
367 }
368
369 free(command_line);
370 fprintf(stderr, "perf trace started with Python script %s\n\n",
371 script);
372
373 return err;
374error:
375 Py_Finalize();
376 free(command_line);
377
378 return err;
379}
380
381/*
382 * Stop trace script
383 */
384static int python_stop_script(void)
385{
386 PyObject *handler, *retval;
387 int err = 0;
388
389 handler = PyDict_GetItemString(main_dict, "trace_end");
390 if (handler == NULL || !PyCallable_Check(handler))
391 goto out;
392
393 retval = PyObject_CallObject(handler, NULL);
394 if (retval == NULL)
395 handler_call_die("trace_end");
396 else
397 Py_DECREF(retval);
398out:
399 Py_XDECREF(main_dict);
400 Py_XDECREF(main_module);
401 Py_Finalize();
402
403 fprintf(stderr, "\nperf trace Python script stopped\n");
404
405 return err;
406}
407
408static int python_generate_script(const char *outfile)
409{
410 struct event *event = NULL;
411 struct format_field *f;
412 char fname[PATH_MAX];
413 int not_first, count;
414 FILE *ofp;
415
416 sprintf(fname, "%s.py", outfile);
417 ofp = fopen(fname, "w");
418 if (ofp == NULL) {
419 fprintf(stderr, "couldn't open %s\n", fname);
420 return -1;
421 }
422 fprintf(ofp, "# perf trace event handlers, "
423 "generated by perf trace -g python\n");
424
425 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
426 " License version 2\n\n");
427
428 fprintf(ofp, "# The common_* event handler fields are the most useful "
429 "fields common to\n");
430
431 fprintf(ofp, "# all events. They don't necessarily correspond to "
432 "the 'common_*' fields\n");
433
434 fprintf(ofp, "# in the format files. Those fields not available as "
435 "handler params can\n");
436
437 fprintf(ofp, "# be retrieved using Python functions of the form "
438 "common_*(context).\n");
439
440 fprintf(ofp, "# See the perf-trace-python Documentation for the list "
441 "of available functions.\n\n");
442
443 fprintf(ofp, "import os\n");
444 fprintf(ofp, "import sys\n\n");
445
446 fprintf(ofp, "sys.path.append(os.environ['PERF_EXEC_PATH'] + \\\n");
447 fprintf(ofp, "\t'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')\n");
448 fprintf(ofp, "\nfrom perf_trace_context import *\n");
449 fprintf(ofp, "from Core import *\n\n\n");
450
451 fprintf(ofp, "def trace_begin():\n");
452 fprintf(ofp, "\tprint \"in trace_begin\"\n\n");
453
454 fprintf(ofp, "def trace_end():\n");
455 fprintf(ofp, "\tprint \"in trace_end\"\n\n");
456
457 while ((event = trace_find_next_event(event))) {
458 fprintf(ofp, "def %s__%s(", event->system, event->name);
459 fprintf(ofp, "event_name, ");
460 fprintf(ofp, "context, ");
461 fprintf(ofp, "common_cpu,\n");
462 fprintf(ofp, "\tcommon_secs, ");
463 fprintf(ofp, "common_nsecs, ");
464 fprintf(ofp, "common_pid, ");
465 fprintf(ofp, "common_comm,\n\t");
466
467 not_first = 0;
468 count = 0;
469
470 for (f = event->format.fields; f; f = f->next) {
471 if (not_first++)
472 fprintf(ofp, ", ");
473 if (++count % 5 == 0)
474 fprintf(ofp, "\n\t");
475
476 fprintf(ofp, "%s", f->name);
477 }
478 fprintf(ofp, "):\n");
479
480 fprintf(ofp, "\t\tprint_header(event_name, common_cpu, "
481 "common_secs, common_nsecs,\n\t\t\t"
482 "common_pid, common_comm)\n\n");
483
484 fprintf(ofp, "\t\tprint \"");
485
486 not_first = 0;
487 count = 0;
488
489 for (f = event->format.fields; f; f = f->next) {
490 if (not_first++)
491 fprintf(ofp, ", ");
492 if (count && count % 3 == 0) {
493 fprintf(ofp, "\" \\\n\t\t\"");
494 }
495 count++;
496
497 fprintf(ofp, "%s=", f->name);
498 if (f->flags & FIELD_IS_STRING ||
499 f->flags & FIELD_IS_FLAG ||
500 f->flags & FIELD_IS_SYMBOLIC)
501 fprintf(ofp, "%%s");
502 else if (f->flags & FIELD_IS_SIGNED)
503 fprintf(ofp, "%%d");
504 else
505 fprintf(ofp, "%%u");
506 }
507
508 fprintf(ofp, "\\n\" %% \\\n\t\t(");
509
510 not_first = 0;
511 count = 0;
512
513 for (f = event->format.fields; f; f = f->next) {
514 if (not_first++)
515 fprintf(ofp, ", ");
516
517 if (++count % 5 == 0)
518 fprintf(ofp, "\n\t\t");
519
520 if (f->flags & FIELD_IS_FLAG) {
521 if ((count - 1) % 5 != 0) {
522 fprintf(ofp, "\n\t\t");
523 count = 4;
524 }
525 fprintf(ofp, "flag_str(\"");
526 fprintf(ofp, "%s__%s\", ", event->system,
527 event->name);
528 fprintf(ofp, "\"%s\", %s)", f->name,
529 f->name);
530 } else if (f->flags & FIELD_IS_SYMBOLIC) {
531 if ((count - 1) % 5 != 0) {
532 fprintf(ofp, "\n\t\t");
533 count = 4;
534 }
535 fprintf(ofp, "symbol_str(\"");
536 fprintf(ofp, "%s__%s\", ", event->system,
537 event->name);
538 fprintf(ofp, "\"%s\", %s)", f->name,
539 f->name);
540 } else
541 fprintf(ofp, "%s", f->name);
542 }
543
544 fprintf(ofp, "),\n\n");
545 }
546
547 fprintf(ofp, "def trace_unhandled(event_name, context, "
548 "common_cpu, common_secs, common_nsecs,\n\t\t"
549 "common_pid, common_comm):\n");
550
551 fprintf(ofp, "\t\tprint_header(event_name, common_cpu, "
552 "common_secs, common_nsecs,\n\t\tcommon_pid, "
553 "common_comm)\n\n");
554
555 fprintf(ofp, "def print_header("
556 "event_name, cpu, secs, nsecs, pid, comm):\n"
557 "\tprint \"%%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\\n\t"
558 "(event_name, cpu, secs, nsecs, pid, comm),\n");
559
560 fclose(ofp);
561
562 fprintf(stderr, "generated Python script: %s\n", fname);
563
564 return 0;
565}
566
567struct scripting_ops python_scripting_ops = {
568 .name = "Python",
569 .start_script = python_start_script,
570 .stop_script = python_stop_script,
571 .process_event = python_process_event,
572 .generate_script = python_generate_script,
573};
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ce3a6c8abe76..0de7258e70a5 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,5 +1,8 @@
1#define _FILE_OFFSET_BITS 64
2
1#include <linux/kernel.h> 3#include <linux/kernel.h>
2 4
5#include <byteswap.h>
3#include <unistd.h> 6#include <unistd.h>
4#include <sys/types.h> 7#include <sys/types.h>
5 8
@@ -49,6 +52,11 @@ out_close:
49 return -1; 52 return -1;
50} 53}
51 54
55static inline int perf_session__create_kernel_maps(struct perf_session *self)
56{
57 return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps);
58}
59
52struct perf_session *perf_session__new(const char *filename, int mode, bool force) 60struct perf_session *perf_session__new(const char *filename, int mode, bool force)
53{ 61{
54 size_t len = filename ? strlen(filename) + 1 : 0; 62 size_t len = filename ? strlen(filename) + 1 : 0;
@@ -66,13 +74,22 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
66 self->mmap_window = 32; 74 self->mmap_window = 32;
67 self->cwd = NULL; 75 self->cwd = NULL;
68 self->cwdlen = 0; 76 self->cwdlen = 0;
77 self->unknown_events = 0;
69 map_groups__init(&self->kmaps); 78 map_groups__init(&self->kmaps);
70 79
71 if (perf_session__create_kernel_maps(self) < 0) 80 if (mode == O_RDONLY) {
72 goto out_delete; 81 if (perf_session__open(self, force) < 0)
82 goto out_delete;
83 } else if (mode == O_WRONLY) {
84 /*
85 * In O_RDONLY mode this will be performed when reading the
86 * kernel MMAP event, in event__process_mmap().
87 */
88 if (perf_session__create_kernel_maps(self) < 0)
89 goto out_delete;
90 }
73 91
74 if (mode == O_RDONLY && perf_session__open(self, force) < 0) 92 self->sample_type = perf_header__sample_type(&self->header);
75 goto out_delete;
76out: 93out:
77 return self; 94 return self;
78out_free: 95out_free:
@@ -148,3 +165,409 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
148 165
149 return syms; 166 return syms;
150} 167}
168
169static int process_event_stub(event_t *event __used,
170 struct perf_session *session __used)
171{
172 dump_printf(": unhandled!\n");
173 return 0;
174}
175
176static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
177{
178 if (handler->sample == NULL)
179 handler->sample = process_event_stub;
180 if (handler->mmap == NULL)
181 handler->mmap = process_event_stub;
182 if (handler->comm == NULL)
183 handler->comm = process_event_stub;
184 if (handler->fork == NULL)
185 handler->fork = process_event_stub;
186 if (handler->exit == NULL)
187 handler->exit = process_event_stub;
188 if (handler->lost == NULL)
189 handler->lost = process_event_stub;
190 if (handler->read == NULL)
191 handler->read = process_event_stub;
192 if (handler->throttle == NULL)
193 handler->throttle = process_event_stub;
194 if (handler->unthrottle == NULL)
195 handler->unthrottle = process_event_stub;
196}
197
198static const char *event__name[] = {
199 [0] = "TOTAL",
200 [PERF_RECORD_MMAP] = "MMAP",
201 [PERF_RECORD_LOST] = "LOST",
202 [PERF_RECORD_COMM] = "COMM",
203 [PERF_RECORD_EXIT] = "EXIT",
204 [PERF_RECORD_THROTTLE] = "THROTTLE",
205 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
206 [PERF_RECORD_FORK] = "FORK",
207 [PERF_RECORD_READ] = "READ",
208 [PERF_RECORD_SAMPLE] = "SAMPLE",
209};
210
211unsigned long event__total[PERF_RECORD_MAX];
212
213void event__print_totals(void)
214{
215 int i;
216 for (i = 0; i < PERF_RECORD_MAX; ++i)
217 pr_info("%10s events: %10ld\n",
218 event__name[i], event__total[i]);
219}
220
221void mem_bswap_64(void *src, int byte_size)
222{
223 u64 *m = src;
224
225 while (byte_size > 0) {
226 *m = bswap_64(*m);
227 byte_size -= sizeof(u64);
228 ++m;
229 }
230}
231
232static void event__all64_swap(event_t *self)
233{
234 struct perf_event_header *hdr = &self->header;
235 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
236}
237
238static void event__comm_swap(event_t *self)
239{
240 self->comm.pid = bswap_32(self->comm.pid);
241 self->comm.tid = bswap_32(self->comm.tid);
242}
243
244static void event__mmap_swap(event_t *self)
245{
246 self->mmap.pid = bswap_32(self->mmap.pid);
247 self->mmap.tid = bswap_32(self->mmap.tid);
248 self->mmap.start = bswap_64(self->mmap.start);
249 self->mmap.len = bswap_64(self->mmap.len);
250 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
251}
252
253static void event__task_swap(event_t *self)
254{
255 self->fork.pid = bswap_32(self->fork.pid);
256 self->fork.tid = bswap_32(self->fork.tid);
257 self->fork.ppid = bswap_32(self->fork.ppid);
258 self->fork.ptid = bswap_32(self->fork.ptid);
259 self->fork.time = bswap_64(self->fork.time);
260}
261
262static void event__read_swap(event_t *self)
263{
264 self->read.pid = bswap_32(self->read.pid);
265 self->read.tid = bswap_32(self->read.tid);
266 self->read.value = bswap_64(self->read.value);
267 self->read.time_enabled = bswap_64(self->read.time_enabled);
268 self->read.time_running = bswap_64(self->read.time_running);
269 self->read.id = bswap_64(self->read.id);
270}
271
272typedef void (*event__swap_op)(event_t *self);
273
274static event__swap_op event__swap_ops[] = {
275 [PERF_RECORD_MMAP] = event__mmap_swap,
276 [PERF_RECORD_COMM] = event__comm_swap,
277 [PERF_RECORD_FORK] = event__task_swap,
278 [PERF_RECORD_EXIT] = event__task_swap,
279 [PERF_RECORD_LOST] = event__all64_swap,
280 [PERF_RECORD_READ] = event__read_swap,
281 [PERF_RECORD_SAMPLE] = event__all64_swap,
282 [PERF_RECORD_MAX] = NULL,
283};
284
285static int perf_session__process_event(struct perf_session *self,
286 event_t *event,
287 struct perf_event_ops *ops,
288 u64 offset, u64 head)
289{
290 trace_event(event);
291
292 if (event->header.type < PERF_RECORD_MAX) {
293 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
294 offset + head, event->header.size,
295 event__name[event->header.type]);
296 ++event__total[0];
297 ++event__total[event->header.type];
298 }
299
300 if (self->header.needs_swap && event__swap_ops[event->header.type])
301 event__swap_ops[event->header.type](event);
302
303 switch (event->header.type) {
304 case PERF_RECORD_SAMPLE:
305 return ops->sample(event, self);
306 case PERF_RECORD_MMAP:
307 return ops->mmap(event, self);
308 case PERF_RECORD_COMM:
309 return ops->comm(event, self);
310 case PERF_RECORD_FORK:
311 return ops->fork(event, self);
312 case PERF_RECORD_EXIT:
313 return ops->exit(event, self);
314 case PERF_RECORD_LOST:
315 return ops->lost(event, self);
316 case PERF_RECORD_READ:
317 return ops->read(event, self);
318 case PERF_RECORD_THROTTLE:
319 return ops->throttle(event, self);
320 case PERF_RECORD_UNTHROTTLE:
321 return ops->unthrottle(event, self);
322 default:
323 self->unknown_events++;
324 return -1;
325 }
326}
327
328void perf_event_header__bswap(struct perf_event_header *self)
329{
330 self->type = bswap_32(self->type);
331 self->misc = bswap_16(self->misc);
332 self->size = bswap_16(self->size);
333}
334
335int perf_header__read_build_ids(struct perf_header *self,
336 int input, u64 offset, u64 size)
337{
338 struct build_id_event bev;
339 char filename[PATH_MAX];
340 u64 limit = offset + size;
341 int err = -1;
342
343 while (offset < limit) {
344 struct dso *dso;
345 ssize_t len;
346 struct list_head *head = &dsos__user;
347
348 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
349 goto out;
350
351 if (self->needs_swap)
352 perf_event_header__bswap(&bev.header);
353
354 len = bev.header.size - sizeof(bev);
355 if (read(input, filename, len) != len)
356 goto out;
357
358 if (bev.header.misc & PERF_RECORD_MISC_KERNEL)
359 head = &dsos__kernel;
360
361 dso = __dsos__findnew(head, filename);
362 if (dso != NULL) {
363 dso__set_build_id(dso, &bev.build_id);
364 if (head == &dsos__kernel && filename[0] == '[')
365 dso->kernel = 1;
366 }
367
368 offset += bev.header.size;
369 }
370 err = 0;
371out:
372 return err;
373}
374
375static struct thread *perf_session__register_idle_thread(struct perf_session *self)
376{
377 struct thread *thread = perf_session__findnew(self, 0);
378
379 if (thread == NULL || thread__set_comm(thread, "swapper")) {
380 pr_err("problem inserting idle task.\n");
381 thread = NULL;
382 }
383
384 return thread;
385}
386
387int __perf_session__process_events(struct perf_session *self,
388 u64 data_offset, u64 data_size,
389 u64 file_size, struct perf_event_ops *ops)
390{
391 int err, mmap_prot, mmap_flags;
392 u64 head, shift;
393 u64 offset = 0;
394 size_t page_size;
395 event_t *event;
396 uint32_t size;
397 char *buf;
398
399 perf_event_ops__fill_defaults(ops);
400
401 page_size = sysconf(_SC_PAGESIZE);
402
403 head = data_offset;
404 shift = page_size * (head / page_size);
405 offset += shift;
406 head -= shift;
407
408 mmap_prot = PROT_READ;
409 mmap_flags = MAP_SHARED;
410
411 if (self->header.needs_swap) {
412 mmap_prot |= PROT_WRITE;
413 mmap_flags = MAP_PRIVATE;
414 }
415remap:
416 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
417 mmap_flags, self->fd, offset);
418 if (buf == MAP_FAILED) {
419 pr_err("failed to mmap file\n");
420 err = -errno;
421 goto out_err;
422 }
423
424more:
425 event = (event_t *)(buf + head);
426
427 if (self->header.needs_swap)
428 perf_event_header__bswap(&event->header);
429 size = event->header.size;
430 if (size == 0)
431 size = 8;
432
433 if (head + event->header.size >= page_size * self->mmap_window) {
434 int munmap_ret;
435
436 shift = page_size * (head / page_size);
437
438 munmap_ret = munmap(buf, page_size * self->mmap_window);
439 assert(munmap_ret == 0);
440
441 offset += shift;
442 head -= shift;
443 goto remap;
444 }
445
446 size = event->header.size;
447
448 dump_printf("\n%#Lx [%#x]: event: %d\n",
449 offset + head, event->header.size, event->header.type);
450
451 if (size == 0 ||
452 perf_session__process_event(self, event, ops, offset, head) < 0) {
453 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
454 offset + head, event->header.size,
455 event->header.type);
456 /*
457 * assume we lost track of the stream, check alignment, and
458 * increment a single u64 in the hope to catch on again 'soon'.
459 */
460 if (unlikely(head & 7))
461 head &= ~7ULL;
462
463 size = 8;
464 }
465
466 head += size;
467
468 if (offset + head >= data_offset + data_size)
469 goto done;
470
471 if (offset + head < file_size)
472 goto more;
473done:
474 err = 0;
475out_err:
476 return err;
477}
478
479int perf_session__process_events(struct perf_session *self,
480 struct perf_event_ops *ops)
481{
482 int err;
483
484 if (perf_session__register_idle_thread(self) == NULL)
485 return -ENOMEM;
486
487 if (!symbol_conf.full_paths) {
488 char bf[PATH_MAX];
489
490 if (getcwd(bf, sizeof(bf)) == NULL) {
491 err = -errno;
492out_getcwd_err:
493 pr_err("failed to get the current directory\n");
494 goto out_err;
495 }
496 self->cwd = strdup(bf);
497 if (self->cwd == NULL) {
498 err = -ENOMEM;
499 goto out_getcwd_err;
500 }
501 self->cwdlen = strlen(self->cwd);
502 }
503
504 err = __perf_session__process_events(self, self->header.data_offset,
505 self->header.data_size,
506 self->size, ops);
507out_err:
508 return err;
509}
510
511bool perf_session__has_traces(struct perf_session *self, const char *msg)
512{
513 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
514 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
515 return false;
516 }
517
518 return true;
519}
520
521int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
522 const char *symbol_name,
523 u64 addr)
524{
525 char *bracket;
526 enum map_type i;
527
528 self->ref_reloc_sym.name = strdup(symbol_name);
529 if (self->ref_reloc_sym.name == NULL)
530 return -ENOMEM;
531
532 bracket = strchr(self->ref_reloc_sym.name, ']');
533 if (bracket)
534 *bracket = '\0';
535
536 self->ref_reloc_sym.addr = addr;
537
538 for (i = 0; i < MAP__NR_TYPES; ++i) {
539 struct kmap *kmap = map__kmap(self->vmlinux_maps[i]);
540 kmap->ref_reloc_sym = &self->ref_reloc_sym;
541 }
542
543 return 0;
544}
545
546static u64 map__reloc_map_ip(struct map *map, u64 ip)
547{
548 return ip + (s64)map->pgoff;
549}
550
551static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
552{
553 return ip - (s64)map->pgoff;
554}
555
556void map__reloc_vmlinux(struct map *self)
557{
558 struct kmap *kmap = map__kmap(self);
559 s64 reloc;
560
561 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
562 return;
563
564 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
565 kmap->ref_reloc_sym->addr);
566
567 if (!reloc)
568 return;
569
570 self->map_ip = map__reloc_map_ip;
571 self->unmap_ip = map__reloc_unmap_ip;
572 self->pgoff = reloc;
573}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 32eaa1bada06..31950fcd8a4d 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -3,13 +3,13 @@
3 3
4#include "event.h" 4#include "event.h"
5#include "header.h" 5#include "header.h"
6#include "symbol.h"
6#include "thread.h" 7#include "thread.h"
7#include <linux/rbtree.h> 8#include <linux/rbtree.h>
8#include "../../../include/linux/perf_event.h" 9#include "../../../include/linux/perf_event.h"
9 10
10struct ip_callchain; 11struct ip_callchain;
11struct thread; 12struct thread;
12struct symbol;
13 13
14struct perf_session { 14struct perf_session {
15 struct perf_header header; 15 struct perf_header header;
@@ -18,10 +18,13 @@ struct perf_session {
18 struct map_groups kmaps; 18 struct map_groups kmaps;
19 struct rb_root threads; 19 struct rb_root threads;
20 struct thread *last_match; 20 struct thread *last_match;
21 struct map *vmlinux_maps[MAP__NR_TYPES];
21 struct events_stats events_stats; 22 struct events_stats events_stats;
22 unsigned long event_total[PERF_RECORD_MAX]; 23 unsigned long event_total[PERF_RECORD_MAX];
24 unsigned long unknown_events;
23 struct rb_root hists; 25 struct rb_root hists;
24 u64 sample_type; 26 u64 sample_type;
27 struct ref_reloc_sym ref_reloc_sym;
25 int fd; 28 int fd;
26 int cwdlen; 29 int cwdlen;
27 char *cwd; 30 char *cwd;
@@ -31,23 +34,25 @@ struct perf_session {
31typedef int (*event_op)(event_t *self, struct perf_session *session); 34typedef int (*event_op)(event_t *self, struct perf_session *session);
32 35
33struct perf_event_ops { 36struct perf_event_ops {
34 event_op process_sample_event; 37 event_op sample,
35 event_op process_mmap_event; 38 mmap,
36 event_op process_comm_event; 39 comm,
37 event_op process_fork_event; 40 fork,
38 event_op process_exit_event; 41 exit,
39 event_op process_lost_event; 42 lost,
40 event_op process_read_event; 43 read,
41 event_op process_throttle_event; 44 throttle,
42 event_op process_unthrottle_event; 45 unthrottle;
43 int (*sample_type_check)(struct perf_session *session);
44 unsigned long total_unknown;
45 bool full_paths;
46}; 46};
47 47
48struct perf_session *perf_session__new(const char *filename, int mode, bool force); 48struct perf_session *perf_session__new(const char *filename, int mode, bool force);
49void perf_session__delete(struct perf_session *self); 49void perf_session__delete(struct perf_session *self);
50 50
51void perf_event_header__bswap(struct perf_event_header *self);
52
53int __perf_session__process_events(struct perf_session *self,
54 u64 data_offset, u64 data_size, u64 size,
55 struct perf_event_ops *ops);
51int perf_session__process_events(struct perf_session *self, 56int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops); 57 struct perf_event_ops *event_ops);
53 58
@@ -56,6 +61,28 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
56 struct ip_callchain *chain, 61 struct ip_callchain *chain,
57 struct symbol **parent); 62 struct symbol **parent);
58 63
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size); 64bool perf_session__has_traces(struct perf_session *self, const char *msg);
65
66int perf_header__read_build_ids(struct perf_header *self, int input,
67 u64 offset, u64 file_size);
68
69int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
70 const char *symbol_name,
71 u64 addr);
72
73void mem_bswap_64(void *src, int byte_size);
74
75static inline int __perf_session__create_kernel_maps(struct perf_session *self,
76 struct dso *kernel)
77{
78 return __map_groups__create_kernel_maps(&self->kmaps,
79 self->vmlinux_maps, kernel);
80}
60 81
82static inline struct map *
83 perf_session__new_module_map(struct perf_session *self,
84 u64 start, const char *filename)
85{
86 return map_groups__new_module(&self->kmaps, start, filename);
87}
61#endif /* __PERF_SESSION_H */ 88#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 5352d7dccc61..a175949ed216 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -227,16 +227,73 @@ fail:
227 return NULL; 227 return NULL;
228} 228}
229 229
230/* Glob expression pattern matching */ 230/* Character class matching */
231bool strglobmatch(const char *str, const char *pat) 231static bool __match_charclass(const char *pat, char c, const char **npat)
232{
233 bool complement = false, ret = true;
234
235 if (*pat == '!') {
236 complement = true;
237 pat++;
238 }
239 if (*pat++ == c) /* First character is special */
240 goto end;
241
242 while (*pat && *pat != ']') { /* Matching */
243 if (*pat == '-' && *(pat + 1) != ']') { /* Range */
244 if (*(pat - 1) <= c && c <= *(pat + 1))
245 goto end;
246 if (*(pat - 1) > *(pat + 1))
247 goto error;
248 pat += 2;
249 } else if (*pat++ == c)
250 goto end;
251 }
252 if (!*pat)
253 goto error;
254 ret = false;
255
256end:
257 while (*pat && *pat != ']') /* Searching closing */
258 pat++;
259 if (!*pat)
260 goto error;
261 *npat = pat + 1;
262 return complement ? !ret : ret;
263
264error:
265 return false;
266}
267
268/* Glob/lazy pattern matching */
269static bool __match_glob(const char *str, const char *pat, bool ignore_space)
232{ 270{
233 while (*str && *pat && *pat != '*') { 271 while (*str && *pat && *pat != '*') {
234 if (*pat == '?') { 272 if (ignore_space) {
273 /* Ignore spaces for lazy matching */
274 if (isspace(*str)) {
275 str++;
276 continue;
277 }
278 if (isspace(*pat)) {
279 pat++;
280 continue;
281 }
282 }
283 if (*pat == '?') { /* Matches any single character */
235 str++; 284 str++;
236 pat++; 285 pat++;
237 } else 286 continue;
238 if (*str++ != *pat++) 287 } else if (*pat == '[') /* Character classes/Ranges */
288 if (__match_charclass(pat + 1, *str, &pat)) {
289 str++;
290 continue;
291 } else
239 return false; 292 return false;
293 else if (*pat == '\\') /* Escaped char match as normal char */
294 pat++;
295 if (*str++ != *pat++)
296 return false;
240 } 297 }
241 /* Check wild card */ 298 /* Check wild card */
242 if (*pat == '*') { 299 if (*pat == '*') {
@@ -251,3 +308,32 @@ bool strglobmatch(const char *str, const char *pat)
251 return !*str && !*pat; 308 return !*str && !*pat;
252} 309}
253 310
311/**
312 * strglobmatch - glob expression pattern matching
313 * @str: the target string to match
314 * @pat: the pattern string to match
315 *
316 * This returns true if the @str matches @pat. @pat can includes wildcards
317 * ('*','?') and character classes ([CHARS], complementation and ranges are
318 * also supported). Also, this supports escape character ('\') to use special
319 * characters as normal character.
320 *
321 * Note: if @pat syntax is broken, this always returns false.
322 */
323bool strglobmatch(const char *str, const char *pat)
324{
325 return __match_glob(str, pat, false);
326}
327
328/**
329 * strlazymatch - matching pattern strings lazily with glob pattern
330 * @str: the target string to match
331 * @pat: the pattern string to match
332 *
333 * This is similar to strglobmatch, except this ignores spaces in
334 * the target string.
335 */
336bool strlazymatch(const char *str, const char *pat)
337{
338 return __match_glob(str, pat, true);
339}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 02ede58c54b4..542e44de3719 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -10,6 +10,7 @@ s64 perf_atoll(const char *str);
10char **argv_split(const char *str, int *argcp); 10char **argv_split(const char *str, int *argcp);
11void argv_free(char **argv); 11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat); 12bool strglobmatch(const char *str, const char *pat);
13bool strlazymatch(const char *str, const char *pat);
13 14
14#define _STR(x) #x 15#define _STR(x) #x
15#define STR(x) _STR(x) 16#define STR(x) _STR(x)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ab92763edb03..323c0aea0a91 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,6 +1,5 @@
1#include "util.h" 1#include "util.h"
2#include "../perf.h" 2#include "../perf.h"
3#include "session.h"
4#include "sort.h" 3#include "sort.h"
5#include "string.h" 4#include "string.h"
6#include "symbol.h" 5#include "symbol.h"
@@ -22,6 +21,7 @@
22enum dso_origin { 21enum dso_origin {
23 DSO__ORIG_KERNEL = 0, 22 DSO__ORIG_KERNEL = 0,
24 DSO__ORIG_JAVA_JIT, 23 DSO__ORIG_JAVA_JIT,
24 DSO__ORIG_BUILD_ID_CACHE,
25 DSO__ORIG_FEDORA, 25 DSO__ORIG_FEDORA,
26 DSO__ORIG_UBUNTU, 26 DSO__ORIG_UBUNTU,
27 DSO__ORIG_BUILDID, 27 DSO__ORIG_BUILDID,
@@ -33,7 +33,7 @@ enum dso_origin {
33static void dsos__add(struct list_head *head, struct dso *dso); 33static void dsos__add(struct list_head *head, struct dso *dso);
34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
35static int dso__load_kernel_sym(struct dso *self, struct map *map, 35static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 struct perf_session *session, symbol_filter_t filter); 36 symbol_filter_t filter);
37static int vmlinux_path__nr_entries; 37static int vmlinux_path__nr_entries;
38static char **vmlinux_path; 38static char **vmlinux_path;
39 39
@@ -53,17 +53,12 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type)
53 return self->sorted_by_name & (1 << type); 53 return self->sorted_by_name & (1 << type);
54} 54}
55 55
56static void dso__set_loaded(struct dso *self, enum map_type type)
57{
58 self->loaded |= (1 << type);
59}
60
61static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 56static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
62{ 57{
63 self->sorted_by_name |= (1 << type); 58 self->sorted_by_name |= (1 << type);
64} 59}
65 60
66static bool symbol_type__is_a(char symbol_type, enum map_type map_type) 61bool symbol_type__is_a(char symbol_type, enum map_type map_type)
67{ 62{
68 switch (map_type) { 63 switch (map_type) {
69 case MAP__FUNCTION: 64 case MAP__FUNCTION:
@@ -142,14 +137,14 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name)
142 self->start = start; 137 self->start = start;
143 self->end = len ? start + len - 1 : start; 138 self->end = len ? start + len - 1 : start;
144 139
145 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 140 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
146 141
147 memcpy(self->name, name, namelen); 142 memcpy(self->name, name, namelen);
148 143
149 return self; 144 return self;
150} 145}
151 146
152static void symbol__delete(struct symbol *self) 147void symbol__delete(struct symbol *self)
153{ 148{
154 free(((void *)self) - symbol_conf.priv_size); 149 free(((void *)self) - symbol_conf.priv_size);
155} 150}
@@ -160,7 +155,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp)
160 self->start, self->end, self->name); 155 self->start, self->end, self->name);
161} 156}
162 157
163static void dso__set_long_name(struct dso *self, char *name) 158void dso__set_long_name(struct dso *self, char *name)
164{ 159{
165 if (name == NULL) 160 if (name == NULL)
166 return; 161 return;
@@ -175,7 +170,7 @@ static void dso__set_basename(struct dso *self)
175 170
176struct dso *dso__new(const char *name) 171struct dso *dso__new(const char *name)
177{ 172{
178 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 173 struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1);
179 174
180 if (self != NULL) { 175 if (self != NULL) {
181 int i; 176 int i;
@@ -344,10 +339,10 @@ void dso__sort_by_name(struct dso *self, enum map_type type)
344 &self->symbols[type]); 339 &self->symbols[type]);
345} 340}
346 341
347int build_id__sprintf(u8 *self, int len, char *bf) 342int build_id__sprintf(const u8 *self, int len, char *bf)
348{ 343{
349 char *bid = bf; 344 char *bid = bf;
350 u8 *raw = self; 345 const u8 *raw = self;
351 int i; 346 int i;
352 347
353 for (i = 0; i < len; ++i) { 348 for (i = 0; i < len; ++i) {
@@ -372,6 +367,10 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
372 struct rb_node *nd; 367 struct rb_node *nd;
373 size_t ret = fprintf(fp, "dso: %s (", self->short_name); 368 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
374 369
370 if (self->short_name != self->long_name)
371 ret += fprintf(fp, "%s, ", self->long_name);
372 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
373 self->loaded ? "" : "NOT ");
375 ret += dso__fprintf_buildid(self, fp); 374 ret += dso__fprintf_buildid(self, fp);
376 ret += fprintf(fp, ")\n"); 375 ret += fprintf(fp, ")\n");
377 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 376 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
@@ -382,24 +381,20 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
382 return ret; 381 return ret;
383} 382}
384 383
385/* 384int kallsyms__parse(const char *filename, void *arg,
386 * Loads the function entries in /proc/kallsyms into kernel_map->dso, 385 int (*process_symbol)(void *arg, const char *name,
387 * so that we can in the next step set the symbol ->end address and then 386 char type, u64 start))
388 * call kernel_maps__split_kallsyms.
389 */
390static int dso__load_all_kallsyms(struct dso *self, struct map *map)
391{ 387{
392 char *line = NULL; 388 char *line = NULL;
393 size_t n; 389 size_t n;
394 struct rb_root *root = &self->symbols[map->type]; 390 int err = 0;
395 FILE *file = fopen("/proc/kallsyms", "r"); 391 FILE *file = fopen(filename, "r");
396 392
397 if (file == NULL) 393 if (file == NULL)
398 goto out_failure; 394 goto out_failure;
399 395
400 while (!feof(file)) { 396 while (!feof(file)) {
401 u64 start; 397 u64 start;
402 struct symbol *sym;
403 int line_len, len; 398 int line_len, len;
404 char symbol_type; 399 char symbol_type;
405 char *symbol_name; 400 char *symbol_name;
@@ -420,43 +415,72 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
420 continue; 415 continue;
421 416
422 symbol_type = toupper(line[len]); 417 symbol_type = toupper(line[len]);
423 if (!symbol_type__is_a(symbol_type, map->type))
424 continue;
425
426 symbol_name = line + len + 2; 418 symbol_name = line + len + 2;
427 /*
428 * Will fix up the end later, when we have all symbols sorted.
429 */
430 sym = symbol__new(start, 0, symbol_name);
431 419
432 if (sym == NULL) 420 err = process_symbol(arg, symbol_name, symbol_type, start);
433 goto out_delete_line; 421 if (err)
434 /* 422 break;
435 * We will pass the symbols to the filter later, in
436 * map__split_kallsyms, when we have split the maps per module
437 */
438 symbols__insert(root, sym);
439 } 423 }
440 424
441 free(line); 425 free(line);
442 fclose(file); 426 fclose(file);
427 return err;
443 428
444 return 0;
445
446out_delete_line:
447 free(line);
448out_failure: 429out_failure:
449 return -1; 430 return -1;
450} 431}
451 432
433struct process_kallsyms_args {
434 struct map *map;
435 struct dso *dso;
436};
437
438static int map__process_kallsym_symbol(void *arg, const char *name,
439 char type, u64 start)
440{
441 struct symbol *sym;
442 struct process_kallsyms_args *a = arg;
443 struct rb_root *root = &a->dso->symbols[a->map->type];
444
445 if (!symbol_type__is_a(type, a->map->type))
446 return 0;
447
448 /*
449 * Will fix up the end later, when we have all symbols sorted.
450 */
451 sym = symbol__new(start, 0, name);
452
453 if (sym == NULL)
454 return -ENOMEM;
455 /*
456 * We will pass the symbols to the filter later, in
457 * map__split_kallsyms, when we have split the maps per module
458 */
459 symbols__insert(root, sym);
460 return 0;
461}
462
463/*
464 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
465 * so that we can in the next step set the symbol ->end address and then
466 * call kernel_maps__split_kallsyms.
467 */
468static int dso__load_all_kallsyms(struct dso *self, const char *filename,
469 struct map *map)
470{
471 struct process_kallsyms_args args = { .map = map, .dso = self, };
472 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
473}
474
452/* 475/*
453 * Split the symbols into maps, making sure there are no overlaps, i.e. the 476 * Split the symbols into maps, making sure there are no overlaps, i.e. the
454 * kernel range is broken in several maps, named [kernel].N, as we don't have 477 * kernel range is broken in several maps, named [kernel].N, as we don't have
455 * the original ELF section names vmlinux have. 478 * the original ELF section names vmlinux have.
456 */ 479 */
457static int dso__split_kallsyms(struct dso *self, struct map *map, 480static int dso__split_kallsyms(struct dso *self, struct map *map,
458 struct perf_session *session, symbol_filter_t filter) 481 symbol_filter_t filter)
459{ 482{
483 struct map_groups *kmaps = map__kmap(map)->kmaps;
460 struct map *curr_map = map; 484 struct map *curr_map = map;
461 struct symbol *pos; 485 struct symbol *pos;
462 int count = 0; 486 int count = 0;
@@ -477,13 +501,17 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
477 501
478 *module++ = '\0'; 502 *module++ = '\0';
479 503
480 if (strcmp(self->name, module)) { 504 if (strcmp(curr_map->dso->short_name, module)) {
481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); 505 curr_map = map_groups__find_by_name(kmaps, map->type, module);
482 if (curr_map == NULL) { 506 if (curr_map == NULL) {
483 pr_debug("/proc/{kallsyms,modules} " 507 pr_debug("/proc/{kallsyms,modules} "
484 "inconsistency!\n"); 508 "inconsistency while looking "
509 "for \"%s\" module!\n", module);
485 return -1; 510 return -1;
486 } 511 }
512
513 if (curr_map->dso->loaded)
514 goto discard_symbol;
487 } 515 }
488 /* 516 /*
489 * So that we look just like we get from .ko files, 517 * So that we look just like we get from .ko files,
@@ -503,13 +531,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
503 return -1; 531 return -1;
504 532
505 curr_map = map__new2(pos->start, dso, map->type); 533 curr_map = map__new2(pos->start, dso, map->type);
506 if (map == NULL) { 534 if (curr_map == NULL) {
507 dso__delete(dso); 535 dso__delete(dso);
508 return -1; 536 return -1;
509 } 537 }
510 538
511 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 539 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
512 map_groups__insert(&session->kmaps, curr_map); 540 map_groups__insert(kmaps, curr_map);
513 ++kernel_range; 541 ++kernel_range;
514 } 542 }
515 543
@@ -528,17 +556,16 @@ discard_symbol: rb_erase(&pos->rb_node, root);
528 return count; 556 return count;
529} 557}
530 558
531 559int dso__load_kallsyms(struct dso *self, const char *filename,
532static int dso__load_kallsyms(struct dso *self, struct map *map, 560 struct map *map, symbol_filter_t filter)
533 struct perf_session *session, symbol_filter_t filter)
534{ 561{
535 if (dso__load_all_kallsyms(self, map) < 0) 562 if (dso__load_all_kallsyms(self, filename, map) < 0)
536 return -1; 563 return -1;
537 564
538 symbols__fixup_end(&self->symbols[map->type]); 565 symbols__fixup_end(&self->symbols[map->type]);
539 self->origin = DSO__ORIG_KERNEL; 566 self->origin = DSO__ORIG_KERNEL;
540 567
541 return dso__split_kallsyms(self, map, session, filter); 568 return dso__split_kallsyms(self, map, filter);
542} 569}
543 570
544static int dso__load_perf_map(struct dso *self, struct map *map, 571static int dso__load_perf_map(struct dso *self, struct map *map,
@@ -864,10 +891,10 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
864 } 891 }
865} 892}
866 893
867static int dso__load_sym(struct dso *self, struct map *map, 894static int dso__load_sym(struct dso *self, struct map *map, const char *name,
868 struct perf_session *session, const char *name, int fd, 895 int fd, symbol_filter_t filter, int kmodule)
869 symbol_filter_t filter, int kernel, int kmodule)
870{ 896{
897 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
871 struct map *curr_map = map; 898 struct map *curr_map = map;
872 struct dso *curr_dso = self; 899 struct dso *curr_dso = self;
873 size_t dso_name_len = strlen(self->short_name); 900 size_t dso_name_len = strlen(self->short_name);
@@ -924,7 +951,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
924 nr_syms = shdr.sh_size / shdr.sh_entsize; 951 nr_syms = shdr.sh_size / shdr.sh_entsize;
925 952
926 memset(&sym, 0, sizeof(sym)); 953 memset(&sym, 0, sizeof(sym));
927 if (!kernel) { 954 if (!self->kernel) {
928 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 955 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
929 elf_section_by_name(elf, &ehdr, &shdr, 956 elf_section_by_name(elf, &ehdr, &shdr,
930 ".gnu.prelink_undo", 957 ".gnu.prelink_undo",
@@ -933,11 +960,15 @@ static int dso__load_sym(struct dso *self, struct map *map,
933 960
934 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 961 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
935 struct symbol *f; 962 struct symbol *f;
936 const char *elf_name; 963 const char *elf_name = elf_sym__name(&sym, symstrs);
937 char *demangled = NULL; 964 char *demangled = NULL;
938 int is_label = elf_sym__is_label(&sym); 965 int is_label = elf_sym__is_label(&sym);
939 const char *section_name; 966 const char *section_name;
940 967
968 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
969 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
970 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
971
941 if (!is_label && !elf_sym__is_a(&sym, map->type)) 972 if (!is_label && !elf_sym__is_a(&sym, map->type))
942 continue; 973 continue;
943 974
@@ -950,10 +981,9 @@ static int dso__load_sym(struct dso *self, struct map *map,
950 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 981 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
951 continue; 982 continue;
952 983
953 elf_name = elf_sym__name(&sym, symstrs);
954 section_name = elf_sec__name(&shdr, secstrs); 984 section_name = elf_sec__name(&shdr, secstrs);
955 985
956 if (kernel || kmodule) { 986 if (self->kernel || kmodule) {
957 char dso_name[PATH_MAX]; 987 char dso_name[PATH_MAX];
958 988
959 if (strcmp(section_name, 989 if (strcmp(section_name,
@@ -969,7 +999,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
969 snprintf(dso_name, sizeof(dso_name), 999 snprintf(dso_name, sizeof(dso_name),
970 "%s%s", self->short_name, section_name); 1000 "%s%s", self->short_name, section_name);
971 1001
972 curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name); 1002 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
973 if (curr_map == NULL) { 1003 if (curr_map == NULL) {
974 u64 start = sym.st_value; 1004 u64 start = sym.st_value;
975 1005
@@ -980,7 +1010,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
980 if (curr_dso == NULL) 1010 if (curr_dso == NULL)
981 goto out_elf_end; 1011 goto out_elf_end;
982 curr_map = map__new2(start, curr_dso, 1012 curr_map = map__new2(start, curr_dso,
983 MAP__FUNCTION); 1013 map->type);
984 if (curr_map == NULL) { 1014 if (curr_map == NULL) {
985 dso__delete(curr_dso); 1015 dso__delete(curr_dso);
986 goto out_elf_end; 1016 goto out_elf_end;
@@ -988,8 +1018,9 @@ static int dso__load_sym(struct dso *self, struct map *map,
988 curr_map->map_ip = identity__map_ip; 1018 curr_map->map_ip = identity__map_ip;
989 curr_map->unmap_ip = identity__map_ip; 1019 curr_map->unmap_ip = identity__map_ip;
990 curr_dso->origin = DSO__ORIG_KERNEL; 1020 curr_dso->origin = DSO__ORIG_KERNEL;
991 map_groups__insert(&session->kmaps, curr_map); 1021 map_groups__insert(kmap->kmaps, curr_map);
992 dsos__add(&dsos__kernel, curr_dso); 1022 dsos__add(&dsos__kernel, curr_dso);
1023 dso__set_loaded(curr_dso, map->type);
993 } else 1024 } else
994 curr_dso = curr_map->dso; 1025 curr_dso = curr_map->dso;
995 1026
@@ -997,9 +1028,10 @@ static int dso__load_sym(struct dso *self, struct map *map,
997 } 1028 }
998 1029
999 if (curr_dso->adjust_symbols) { 1030 if (curr_dso->adjust_symbols) {
1000 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 1031 pr_debug4("%s: adjusting symbol: st_value: %#Lx "
1001 "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 1032 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
1002 (u64)shdr.sh_addr, (u64)shdr.sh_offset); 1033 (u64)sym.st_value, (u64)shdr.sh_addr,
1034 (u64)shdr.sh_offset);
1003 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1035 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1004 } 1036 }
1005 /* 1037 /*
@@ -1027,8 +1059,16 @@ new_symbol:
1027 /* 1059 /*
1028 * For misannotated, zeroed, ASM function sizes. 1060 * For misannotated, zeroed, ASM function sizes.
1029 */ 1061 */
1030 if (nr > 0) 1062 if (nr > 0) {
1031 symbols__fixup_end(&self->symbols[map->type]); 1063 symbols__fixup_end(&self->symbols[map->type]);
1064 if (kmap) {
1065 /*
1066 * We need to fixup this here too because we create new
1067 * maps here, for things like vsyscall sections.
1068 */
1069 __map_groups__fixup_end(kmap->kmaps, map->type);
1070 }
1071 }
1032 err = nr; 1072 err = nr;
1033out_elf_end: 1073out_elf_end:
1034 elf_end(elf); 1074 elf_end(elf);
@@ -1041,25 +1081,28 @@ static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1041 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 1081 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1042} 1082}
1043 1083
1044static bool __dsos__read_build_ids(struct list_head *head) 1084static bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
1045{ 1085{
1046 bool have_build_id = false; 1086 bool have_build_id = false;
1047 struct dso *pos; 1087 struct dso *pos;
1048 1088
1049 list_for_each_entry(pos, head, node) 1089 list_for_each_entry(pos, head, node) {
1090 if (with_hits && !pos->hit)
1091 continue;
1050 if (filename__read_build_id(pos->long_name, pos->build_id, 1092 if (filename__read_build_id(pos->long_name, pos->build_id,
1051 sizeof(pos->build_id)) > 0) { 1093 sizeof(pos->build_id)) > 0) {
1052 have_build_id = true; 1094 have_build_id = true;
1053 pos->has_build_id = true; 1095 pos->has_build_id = true;
1054 } 1096 }
1097 }
1055 1098
1056 return have_build_id; 1099 return have_build_id;
1057} 1100}
1058 1101
1059bool dsos__read_build_ids(void) 1102bool dsos__read_build_ids(bool with_hits)
1060{ 1103{
1061 bool kbuildids = __dsos__read_build_ids(&dsos__kernel), 1104 bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits),
1062 ubuildids = __dsos__read_build_ids(&dsos__user); 1105 ubuildids = __dsos__read_build_ids(&dsos__user, with_hits);
1063 return kbuildids || ubuildids; 1106 return kbuildids || ubuildids;
1064} 1107}
1065 1108
@@ -1191,6 +1234,7 @@ char dso__symtab_origin(const struct dso *self)
1191 static const char origin[] = { 1234 static const char origin[] = {
1192 [DSO__ORIG_KERNEL] = 'k', 1235 [DSO__ORIG_KERNEL] = 'k',
1193 [DSO__ORIG_JAVA_JIT] = 'j', 1236 [DSO__ORIG_JAVA_JIT] = 'j',
1237 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
1194 [DSO__ORIG_FEDORA] = 'f', 1238 [DSO__ORIG_FEDORA] = 'f',
1195 [DSO__ORIG_UBUNTU] = 'u', 1239 [DSO__ORIG_UBUNTU] = 'u',
1196 [DSO__ORIG_BUILDID] = 'b', 1240 [DSO__ORIG_BUILDID] = 'b',
@@ -1203,19 +1247,19 @@ char dso__symtab_origin(const struct dso *self)
1203 return origin[self->origin]; 1247 return origin[self->origin];
1204} 1248}
1205 1249
1206int dso__load(struct dso *self, struct map *map, struct perf_session *session, 1250int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1207 symbol_filter_t filter)
1208{ 1251{
1209 int size = PATH_MAX; 1252 int size = PATH_MAX;
1210 char *name; 1253 char *name;
1211 u8 build_id[BUILD_ID_SIZE]; 1254 u8 build_id[BUILD_ID_SIZE];
1255 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1212 int ret = -1; 1256 int ret = -1;
1213 int fd; 1257 int fd;
1214 1258
1215 dso__set_loaded(self, map->type); 1259 dso__set_loaded(self, map->type);
1216 1260
1217 if (self->kernel) 1261 if (self->kernel)
1218 return dso__load_kernel_sym(self, map, session, filter); 1262 return dso__load_kernel_sym(self, map, filter);
1219 1263
1220 name = malloc(size); 1264 name = malloc(size);
1221 if (!name) 1265 if (!name)
@@ -1230,8 +1274,16 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1230 return ret; 1274 return ret;
1231 } 1275 }
1232 1276
1233 self->origin = DSO__ORIG_FEDORA - 1; 1277 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1234 1278
1279 if (self->has_build_id) {
1280 build_id__sprintf(self->build_id, sizeof(self->build_id),
1281 build_id_hex);
1282 snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
1283 getenv("HOME"), DEBUG_CACHE_DIR,
1284 build_id_hex, build_id_hex + 2);
1285 goto open_file;
1286 }
1235more: 1287more:
1236 do { 1288 do {
1237 self->origin++; 1289 self->origin++;
@@ -1247,8 +1299,6 @@ more:
1247 case DSO__ORIG_BUILDID: 1299 case DSO__ORIG_BUILDID:
1248 if (filename__read_build_id(self->long_name, build_id, 1300 if (filename__read_build_id(self->long_name, build_id,
1249 sizeof(build_id))) { 1301 sizeof(build_id))) {
1250 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1251
1252 build_id__sprintf(build_id, sizeof(build_id), 1302 build_id__sprintf(build_id, sizeof(build_id),
1253 build_id_hex); 1303 build_id_hex);
1254 snprintf(name, size, 1304 snprintf(name, size,
@@ -1276,11 +1326,11 @@ compare_build_id:
1276 if (!dso__build_id_equal(self, build_id)) 1326 if (!dso__build_id_equal(self, build_id))
1277 goto more; 1327 goto more;
1278 } 1328 }
1279 1329open_file:
1280 fd = open(name, O_RDONLY); 1330 fd = open(name, O_RDONLY);
1281 } while (fd < 0); 1331 } while (fd < 0);
1282 1332
1283 ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 1333 ret = dso__load_sym(self, map, name, fd, filter, 0);
1284 close(fd); 1334 close(fd);
1285 1335
1286 /* 1336 /*
@@ -1309,14 +1359,34 @@ struct map *map_groups__find_by_name(struct map_groups *self,
1309 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1359 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1310 struct map *map = rb_entry(nd, struct map, rb_node); 1360 struct map *map = rb_entry(nd, struct map, rb_node);
1311 1361
1312 if (map->dso && strcmp(map->dso->name, name) == 0) 1362 if (map->dso && strcmp(map->dso->short_name, name) == 0)
1313 return map; 1363 return map;
1314 } 1364 }
1315 1365
1316 return NULL; 1366 return NULL;
1317} 1367}
1318 1368
1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) 1369static int dso__kernel_module_get_build_id(struct dso *self)
1370{
1371 char filename[PATH_MAX];
1372 /*
1373 * kernel module short names are of the form "[module]" and
1374 * we need just "module" here.
1375 */
1376 const char *name = self->short_name + 1;
1377
1378 snprintf(filename, sizeof(filename),
1379 "/sys/module/%.*s/notes/.note.gnu.build-id",
1380 (int)strlen(name - 1), name);
1381
1382 if (sysfs__read_build_id(filename, self->build_id,
1383 sizeof(self->build_id)) == 0)
1384 self->has_build_id = true;
1385
1386 return 0;
1387}
1388
1389static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname)
1320{ 1390{
1321 struct dirent *dent; 1391 struct dirent *dent;
1322 DIR *dir = opendir(dirname); 1392 DIR *dir = opendir(dirname);
@@ -1336,7 +1406,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
1336 1406
1337 snprintf(path, sizeof(path), "%s/%s", 1407 snprintf(path, sizeof(path), "%s/%s",
1338 dirname, dent->d_name); 1408 dirname, dent->d_name);
1339 if (perf_session__set_modules_path_dir(self, path) < 0) 1409 if (map_groups__set_modules_path_dir(self, path) < 0)
1340 goto failure; 1410 goto failure;
1341 } else { 1411 } else {
1342 char *dot = strrchr(dent->d_name, '.'), 1412 char *dot = strrchr(dent->d_name, '.'),
@@ -1350,7 +1420,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
1350 (int)(dot - dent->d_name), dent->d_name); 1420 (int)(dot - dent->d_name), dent->d_name);
1351 1421
1352 strxfrchar(dso_name, '-', '_'); 1422 strxfrchar(dso_name, '-', '_');
1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name); 1423 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1354 if (map == NULL) 1424 if (map == NULL)
1355 continue; 1425 continue;
1356 1426
@@ -1361,6 +1431,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
1361 if (long_name == NULL) 1431 if (long_name == NULL)
1362 goto failure; 1432 goto failure;
1363 dso__set_long_name(map->dso, long_name); 1433 dso__set_long_name(map->dso, long_name);
1434 dso__kernel_module_get_build_id(map->dso);
1364 } 1435 }
1365 } 1436 }
1366 1437
@@ -1370,7 +1441,7 @@ failure:
1370 return -1; 1441 return -1;
1371} 1442}
1372 1443
1373static int perf_session__set_modules_path(struct perf_session *self) 1444static int map_groups__set_modules_path(struct map_groups *self)
1374{ 1445{
1375 struct utsname uts; 1446 struct utsname uts;
1376 char modules_path[PATH_MAX]; 1447 char modules_path[PATH_MAX];
@@ -1381,7 +1452,7 @@ static int perf_session__set_modules_path(struct perf_session *self)
1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1452 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1382 uts.release); 1453 uts.release);
1383 1454
1384 return perf_session__set_modules_path_dir(self, modules_path); 1455 return map_groups__set_modules_path_dir(self, modules_path);
1385} 1456}
1386 1457
1387/* 1458/*
@@ -1391,8 +1462,8 @@ static int perf_session__set_modules_path(struct perf_session *self)
1391 */ 1462 */
1392static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1463static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1393{ 1464{
1394 struct map *self = malloc(sizeof(*self)); 1465 struct map *self = zalloc(sizeof(*self) +
1395 1466 (dso->kernel ? sizeof(struct kmap) : 0));
1396 if (self != NULL) { 1467 if (self != NULL) {
1397 /* 1468 /*
1398 * ->end will be filled after we load all the symbols 1469 * ->end will be filled after we load all the symbols
@@ -1403,7 +1474,25 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1403 return self; 1474 return self;
1404} 1475}
1405 1476
1406static int perf_session__create_module_maps(struct perf_session *self) 1477struct map *map_groups__new_module(struct map_groups *self, u64 start,
1478 const char *filename)
1479{
1480 struct map *map;
1481 struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
1482
1483 if (dso == NULL)
1484 return NULL;
1485
1486 map = map__new2(start, dso, MAP__FUNCTION);
1487 if (map == NULL)
1488 return NULL;
1489
1490 dso->origin = DSO__ORIG_KMODULE;
1491 map_groups__insert(self, map);
1492 return map;
1493}
1494
1495static int map_groups__create_modules(struct map_groups *self)
1407{ 1496{
1408 char *line = NULL; 1497 char *line = NULL;
1409 size_t n; 1498 size_t n;
@@ -1416,7 +1505,6 @@ static int perf_session__create_module_maps(struct perf_session *self)
1416 while (!feof(file)) { 1505 while (!feof(file)) {
1417 char name[PATH_MAX]; 1506 char name[PATH_MAX];
1418 u64 start; 1507 u64 start;
1419 struct dso *dso;
1420 char *sep; 1508 char *sep;
1421 int line_len; 1509 int line_len;
1422 1510
@@ -1442,32 +1530,16 @@ static int perf_session__create_module_maps(struct perf_session *self)
1442 *sep = '\0'; 1530 *sep = '\0';
1443 1531
1444 snprintf(name, sizeof(name), "[%s]", line); 1532 snprintf(name, sizeof(name), "[%s]", line);
1445 dso = dso__new(name); 1533 map = map_groups__new_module(self, start, name);
1446 1534 if (map == NULL)
1447 if (dso == NULL)
1448 goto out_delete_line;
1449
1450 map = map__new2(start, dso, MAP__FUNCTION);
1451 if (map == NULL) {
1452 dso__delete(dso);
1453 goto out_delete_line; 1535 goto out_delete_line;
1454 } 1536 dso__kernel_module_get_build_id(map->dso);
1455
1456 snprintf(name, sizeof(name),
1457 "/sys/module/%s/notes/.note.gnu.build-id", line);
1458 if (sysfs__read_build_id(name, dso->build_id,
1459 sizeof(dso->build_id)) == 0)
1460 dso->has_build_id = true;
1461
1462 dso->origin = DSO__ORIG_KMODULE;
1463 map_groups__insert(&self->kmaps, map);
1464 dsos__add(&dsos__kernel, dso);
1465 } 1537 }
1466 1538
1467 free(line); 1539 free(line);
1468 fclose(file); 1540 fclose(file);
1469 1541
1470 return perf_session__set_modules_path(self); 1542 return map_groups__set_modules_path(self);
1471 1543
1472out_delete_line: 1544out_delete_line:
1473 free(line); 1545 free(line);
@@ -1476,7 +1548,6 @@ out_failure:
1476} 1548}
1477 1549
1478static int dso__load_vmlinux(struct dso *self, struct map *map, 1550static int dso__load_vmlinux(struct dso *self, struct map *map,
1479 struct perf_session *session,
1480 const char *vmlinux, symbol_filter_t filter) 1551 const char *vmlinux, symbol_filter_t filter)
1481{ 1552{
1482 int err = -1, fd; 1553 int err = -1, fd;
@@ -1510,51 +1581,124 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1510 return -1; 1581 return -1;
1511 1582
1512 dso__set_loaded(self, map->type); 1583 dso__set_loaded(self, map->type);
1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0); 1584 err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
1514 close(fd); 1585 close(fd);
1515 1586
1587 if (err > 0)
1588 pr_debug("Using %s for symbols\n", vmlinux);
1589
1590 return err;
1591}
1592
1593int dso__load_vmlinux_path(struct dso *self, struct map *map,
1594 symbol_filter_t filter)
1595{
1596 int i, err = 0;
1597
1598 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1599 vmlinux_path__nr_entries);
1600
1601 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1602 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1603 if (err > 0) {
1604 dso__set_long_name(self, strdup(vmlinux_path[i]));
1605 break;
1606 }
1607 }
1608
1516 return err; 1609 return err;
1517} 1610}
1518 1611
1519static int dso__load_kernel_sym(struct dso *self, struct map *map, 1612static int dso__load_kernel_sym(struct dso *self, struct map *map,
1520 struct perf_session *session, symbol_filter_t filter) 1613 symbol_filter_t filter)
1521{ 1614{
1522 int err; 1615 int err;
1523 bool is_kallsyms; 1616 const char *kallsyms_filename = NULL;
1617 char *kallsyms_allocated_filename = NULL;
1618 /*
1619 * Step 1: if the user specified a vmlinux filename, use it and only
1620 * it, reporting errors to the user if it cannot be used.
1621 *
1622 * For instance, try to analyse an ARM perf.data file _without_ a
1623 * build-id, or if the user specifies the wrong path to the right
1624 * vmlinux file, obviously we can't fallback to another vmlinux (a
1625 * x86_86 one, on the machine where analysis is being performed, say),
1626 * or worse, /proc/kallsyms.
1627 *
1628 * If the specified file _has_ a build-id and there is a build-id
1629 * section in the perf.data file, we will still do the expected
1630 * validation in dso__load_vmlinux and will bail out if they don't
1631 * match.
1632 */
1633 if (symbol_conf.vmlinux_name != NULL) {
1634 err = dso__load_vmlinux(self, map,
1635 symbol_conf.vmlinux_name, filter);
1636 goto out_try_fixup;
1637 }
1524 1638
1525 if (vmlinux_path != NULL) { 1639 if (vmlinux_path != NULL) {
1526 int i; 1640 err = dso__load_vmlinux_path(self, map, filter);
1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1641 if (err > 0)
1528 vmlinux_path__nr_entries); 1642 goto out_fixup;
1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1643 }
1530 err = dso__load_vmlinux(self, map, session, 1644
1531 vmlinux_path[i], filter); 1645 /*
1532 if (err > 0) { 1646 * Say the kernel DSO was created when processing the build-id header table,
1533 pr_debug("Using %s for symbols\n", 1647 * we have a build-id, so check if it is the same as the running kernel,
1534 vmlinux_path[i]); 1648 * using it if it is.
1535 dso__set_long_name(self, 1649 */
1536 strdup(vmlinux_path[i])); 1650 if (self->has_build_id) {
1537 goto out_fixup; 1651 u8 kallsyms_build_id[BUILD_ID_SIZE];
1652 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1653
1654 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1655 sizeof(kallsyms_build_id)) == 0) {
1656 if (dso__build_id_equal(self, kallsyms_build_id)) {
1657 kallsyms_filename = "/proc/kallsyms";
1658 goto do_kallsyms;
1538 } 1659 }
1539 } 1660 }
1540 } 1661 /*
1662 * Now look if we have it on the build-id cache in
1663 * $HOME/.debug/[kernel.kallsyms].
1664 */
1665 build_id__sprintf(self->build_id, sizeof(self->build_id),
1666 sbuild_id);
1541 1667
1542 is_kallsyms = self->long_name[0] == '['; 1668 if (asprintf(&kallsyms_allocated_filename,
1543 if (is_kallsyms) 1669 "%s/.debug/[kernel.kallsyms]/%s",
1544 goto do_kallsyms; 1670 getenv("HOME"), sbuild_id) == -1) {
1671 pr_err("Not enough memory for kallsyms file lookup\n");
1672 return -1;
1673 }
1545 1674
1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter); 1675 kallsyms_filename = kallsyms_allocated_filename;
1547 if (err <= 0) { 1676
1548 pr_info("The file %s cannot be used, " 1677 if (access(kallsyms_filename, F_OK)) {
1549 "trying to use /proc/kallsyms...", self->long_name); 1678 pr_err("No kallsyms or vmlinux with build-id %s "
1550do_kallsyms: 1679 "was found\n", sbuild_id);
1551 err = dso__load_kallsyms(self, map, session, filter); 1680 free(kallsyms_allocated_filename);
1552 if (err > 0 && !is_kallsyms) 1681 return -1;
1553 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1682 }
1683 } else {
1684 /*
1685 * Last resort, if we don't have a build-id and couldn't find
1686 * any vmlinux file, try the running kernel kallsyms table.
1687 */
1688 kallsyms_filename = "/proc/kallsyms";
1554 } 1689 }
1555 1690
1691do_kallsyms:
1692 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1693 if (err > 0)
1694 pr_debug("Using %s for symbols\n", kallsyms_filename);
1695 free(kallsyms_allocated_filename);
1696
1697out_try_fixup:
1556 if (err > 0) { 1698 if (err > 0) {
1557out_fixup: 1699out_fixup:
1700 if (kallsyms_filename != NULL)
1701 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1558 map__fixup_start(map); 1702 map__fixup_start(map);
1559 map__fixup_end(map); 1703 map__fixup_end(map);
1560 } 1704 }
@@ -1564,7 +1708,6 @@ out_fixup:
1564 1708
1565LIST_HEAD(dsos__user); 1709LIST_HEAD(dsos__user);
1566LIST_HEAD(dsos__kernel); 1710LIST_HEAD(dsos__kernel);
1567struct dso *vdso;
1568 1711
1569static void dsos__add(struct list_head *head, struct dso *dso) 1712static void dsos__add(struct list_head *head, struct dso *dso)
1570{ 1713{
@@ -1576,19 +1719,19 @@ static struct dso *dsos__find(struct list_head *head, const char *name)
1576 struct dso *pos; 1719 struct dso *pos;
1577 1720
1578 list_for_each_entry(pos, head, node) 1721 list_for_each_entry(pos, head, node)
1579 if (strcmp(pos->name, name) == 0) 1722 if (strcmp(pos->long_name, name) == 0)
1580 return pos; 1723 return pos;
1581 return NULL; 1724 return NULL;
1582} 1725}
1583 1726
1584struct dso *dsos__findnew(const char *name) 1727struct dso *__dsos__findnew(struct list_head *head, const char *name)
1585{ 1728{
1586 struct dso *dso = dsos__find(&dsos__user, name); 1729 struct dso *dso = dsos__find(head, name);
1587 1730
1588 if (!dso) { 1731 if (!dso) {
1589 dso = dso__new(name); 1732 dso = dso__new(name);
1590 if (dso != NULL) { 1733 if (dso != NULL) {
1591 dsos__add(&dsos__user, dso); 1734 dsos__add(head, dso);
1592 dso__set_basename(dso); 1735 dso__set_basename(dso);
1593 } 1736 }
1594 } 1737 }
@@ -1613,75 +1756,78 @@ void dsos__fprintf(FILE *fp)
1613 __dsos__fprintf(&dsos__user, fp); 1756 __dsos__fprintf(&dsos__user, fp);
1614} 1757}
1615 1758
1616static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 1759static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1760 bool with_hits)
1617{ 1761{
1618 struct dso *pos; 1762 struct dso *pos;
1619 size_t ret = 0; 1763 size_t ret = 0;
1620 1764
1621 list_for_each_entry(pos, head, node) { 1765 list_for_each_entry(pos, head, node) {
1766 if (with_hits && !pos->hit)
1767 continue;
1622 ret += dso__fprintf_buildid(pos, fp); 1768 ret += dso__fprintf_buildid(pos, fp);
1623 ret += fprintf(fp, " %s\n", pos->long_name); 1769 ret += fprintf(fp, " %s\n", pos->long_name);
1624 } 1770 }
1625 return ret; 1771 return ret;
1626} 1772}
1627 1773
1628size_t dsos__fprintf_buildid(FILE *fp) 1774size_t dsos__fprintf_buildid(FILE *fp, bool with_hits)
1629{ 1775{
1630 return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 1776 return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) +
1631 __dsos__fprintf_buildid(&dsos__user, fp)); 1777 __dsos__fprintf_buildid(&dsos__user, fp, with_hits));
1632} 1778}
1633 1779
1634static struct dso *dsos__create_kernel( const char *vmlinux) 1780struct dso *dso__new_kernel(const char *name)
1635{ 1781{
1636 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1782 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1637 1783
1638 if (kernel == NULL) 1784 if (self != NULL) {
1639 return NULL; 1785 self->short_name = "[kernel]";
1786 self->kernel = 1;
1787 }
1640 1788
1641 kernel->short_name = "[kernel]"; 1789 return self;
1642 kernel->kernel = 1; 1790}
1643 1791
1644 vdso = dso__new("[vdso]"); 1792void dso__read_running_kernel_build_id(struct dso *self)
1645 if (vdso == NULL) 1793{
1646 goto out_delete_kernel_dso; 1794 if (sysfs__read_build_id("/sys/kernel/notes", self->build_id,
1647 dso__set_loaded(vdso, MAP__FUNCTION); 1795 sizeof(self->build_id)) == 0)
1796 self->has_build_id = true;
1797}
1648 1798
1649 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 1799static struct dso *dsos__create_kernel(const char *vmlinux)
1650 sizeof(kernel->build_id)) == 0) 1800{
1651 kernel->has_build_id = true; 1801 struct dso *kernel = dso__new_kernel(vmlinux);
1652 1802
1653 dsos__add(&dsos__kernel, kernel); 1803 if (kernel != NULL) {
1654 dsos__add(&dsos__user, vdso); 1804 dso__read_running_kernel_build_id(kernel);
1805 dsos__add(&dsos__kernel, kernel);
1806 }
1655 1807
1656 return kernel; 1808 return kernel;
1657
1658out_delete_kernel_dso:
1659 dso__delete(kernel);
1660 return NULL;
1661} 1809}
1662 1810
1663static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux) 1811int __map_groups__create_kernel_maps(struct map_groups *self,
1812 struct map *vmlinux_maps[MAP__NR_TYPES],
1813 struct dso *kernel)
1664{ 1814{
1665 struct map *functions, *variables; 1815 enum map_type type;
1666 struct dso *kernel = dsos__create_kernel(vmlinux);
1667 1816
1668 if (kernel == NULL) 1817 for (type = 0; type < MAP__NR_TYPES; ++type) {
1669 return -1; 1818 struct kmap *kmap;
1670 1819
1671 functions = map__new2(0, kernel, MAP__FUNCTION); 1820 vmlinux_maps[type] = map__new2(0, kernel, type);
1672 if (functions == NULL) 1821 if (vmlinux_maps[type] == NULL)
1673 return -1; 1822 return -1;
1674 1823
1675 variables = map__new2(0, kernel, MAP__VARIABLE); 1824 vmlinux_maps[type]->map_ip =
1676 if (variables == NULL) { 1825 vmlinux_maps[type]->unmap_ip = identity__map_ip;
1677 map__delete(functions);
1678 return -1;
1679 }
1680 1826
1681 functions->map_ip = functions->unmap_ip = 1827 kmap = map__kmap(vmlinux_maps[type]);
1682 variables->map_ip = variables->unmap_ip = identity__map_ip; 1828 kmap->kmaps = self;
1683 map_groups__insert(self, functions); 1829 map_groups__insert(self, vmlinux_maps[type]);
1684 map_groups__insert(self, variables); 1830 }
1685 1831
1686 return 0; 1832 return 0;
1687} 1833}
@@ -1791,19 +1937,22 @@ out_free_comm_list:
1791 return -1; 1937 return -1;
1792} 1938}
1793 1939
1794int perf_session__create_kernel_maps(struct perf_session *self) 1940int map_groups__create_kernel_maps(struct map_groups *self,
1941 struct map *vmlinux_maps[MAP__NR_TYPES])
1795{ 1942{
1796 if (map_groups__create_kernel_maps(&self->kmaps, 1943 struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name);
1797 symbol_conf.vmlinux_name) < 0) 1944
1945 if (kernel == NULL)
1946 return -1;
1947
1948 if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0)
1798 return -1; 1949 return -1;
1799 1950
1800 if (symbol_conf.use_modules && 1951 if (symbol_conf.use_modules && map_groups__create_modules(self) < 0)
1801 perf_session__create_module_maps(self) < 0) 1952 pr_debug("Problems creating module maps, continuing anyway...\n");
1802 pr_debug("Failed to load list of modules for session %s, "
1803 "continuing...\n", self->filename);
1804 /* 1953 /*
1805 * Now that we have all the maps created, just set the ->end of them: 1954 * Now that we have all the maps created, just set the ->end of them:
1806 */ 1955 */
1807 map_groups__fixup_end(&self->kmaps); 1956 map_groups__fixup_end(self);
1808 return 0; 1957 return 0;
1809} 1958}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 8aded2356f79..280dadd32a08 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -8,6 +8,8 @@
8#include <linux/rbtree.h> 8#include <linux/rbtree.h>
9#include "event.h" 9#include "event.h"
10 10
11#define DEBUG_CACHE_DIR ".debug"
12
11#ifdef HAVE_CPLUS_DEMANGLE 13#ifdef HAVE_CPLUS_DEMANGLE
12extern char *cplus_demangle(const char *, int); 14extern char *cplus_demangle(const char *, int);
13 15
@@ -49,6 +51,8 @@ struct symbol {
49 char name[0]; 51 char name[0];
50}; 52};
51 53
54void symbol__delete(struct symbol *self);
55
52struct strlist; 56struct strlist;
53 57
54struct symbol_conf { 58struct symbol_conf {
@@ -58,7 +62,8 @@ struct symbol_conf {
58 sort_by_name, 62 sort_by_name,
59 show_nr_samples, 63 show_nr_samples,
60 use_callchain, 64 use_callchain,
61 exclude_other; 65 exclude_other,
66 full_paths;
62 const char *vmlinux_name, 67 const char *vmlinux_name,
63 *field_sep; 68 *field_sep;
64 char *dso_list_str, 69 char *dso_list_str,
@@ -77,6 +82,12 @@ static inline void *symbol__priv(struct symbol *self)
77 return ((void *)self) - symbol_conf.priv_size; 82 return ((void *)self) - symbol_conf.priv_size;
78} 83}
79 84
85struct ref_reloc_sym {
86 const char *name;
87 u64 addr;
88 u64 unrelocated_addr;
89};
90
80struct addr_location { 91struct addr_location {
81 struct thread *thread; 92 struct thread *thread;
82 struct map *map; 93 struct map *map;
@@ -94,6 +105,7 @@ struct dso {
94 u8 slen_calculated:1; 105 u8 slen_calculated:1;
95 u8 has_build_id:1; 106 u8 has_build_id:1;
96 u8 kernel:1; 107 u8 kernel:1;
108 u8 hit:1;
97 unsigned char origin; 109 unsigned char origin;
98 u8 sorted_by_name; 110 u8 sorted_by_name;
99 u8 loaded; 111 u8 loaded;
@@ -105,37 +117,55 @@ struct dso {
105}; 117};
106 118
107struct dso *dso__new(const char *name); 119struct dso *dso__new(const char *name);
120struct dso *dso__new_kernel(const char *name);
108void dso__delete(struct dso *self); 121void dso__delete(struct dso *self);
109 122
110bool dso__loaded(const struct dso *self, enum map_type type); 123bool dso__loaded(const struct dso *self, enum map_type type);
111bool dso__sorted_by_name(const struct dso *self, enum map_type type); 124bool dso__sorted_by_name(const struct dso *self, enum map_type type);
112 125
126static inline void dso__set_loaded(struct dso *self, enum map_type type)
127{
128 self->loaded |= (1 << type);
129}
130
113void dso__sort_by_name(struct dso *self, enum map_type type); 131void dso__sort_by_name(struct dso *self, enum map_type type);
114 132
115struct perf_session; 133extern struct list_head dsos__user, dsos__kernel;
134
135struct dso *__dsos__findnew(struct list_head *head, const char *name);
136
137static inline struct dso *dsos__findnew(const char *name)
138{
139 return __dsos__findnew(&dsos__user, name);
140}
116 141
117struct dso *dsos__findnew(const char *name); 142int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
118int dso__load(struct dso *self, struct map *map, struct perf_session *session, 143int dso__load_vmlinux_path(struct dso *self, struct map *map,
119 symbol_filter_t filter); 144 symbol_filter_t filter);
145int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
146 symbol_filter_t filter);
120void dsos__fprintf(FILE *fp); 147void dsos__fprintf(FILE *fp);
121size_t dsos__fprintf_buildid(FILE *fp); 148size_t dsos__fprintf_buildid(FILE *fp, bool with_hits);
122 149
123size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 150size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
124size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 151size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
125char dso__symtab_origin(const struct dso *self); 152char dso__symtab_origin(const struct dso *self);
153void dso__set_long_name(struct dso *self, char *name);
126void dso__set_build_id(struct dso *self, void *build_id); 154void dso__set_build_id(struct dso *self, void *build_id);
155void dso__read_running_kernel_build_id(struct dso *self);
127struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 156struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
128struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 157struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
129 const char *name); 158 const char *name);
130 159
131int filename__read_build_id(const char *filename, void *bf, size_t size); 160int filename__read_build_id(const char *filename, void *bf, size_t size);
132int sysfs__read_build_id(const char *filename, void *bf, size_t size); 161int sysfs__read_build_id(const char *filename, void *bf, size_t size);
133bool dsos__read_build_ids(void); 162bool dsos__read_build_ids(bool with_hits);
134int build_id__sprintf(u8 *self, int len, char *bf); 163int build_id__sprintf(const u8 *self, int len, char *bf);
164int kallsyms__parse(const char *filename, void *arg,
165 int (*process_symbol)(void *arg, const char *name,
166 char type, u64 start));
135 167
136int symbol__init(void); 168int symbol__init(void);
137int perf_session__create_kernel_maps(struct perf_session *self); 169bool symbol_type__is_a(char symbol_type, enum map_type map_type);
138 170
139extern struct list_head dsos__user, dsos__kernel;
140extern struct dso *vdso;
141#endif /* __PERF_SYMBOL */ 171#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 4a08dcf50b68..21b92162282b 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -31,12 +31,41 @@ static struct thread *thread__new(pid_t pid)
31 return self; 31 return self;
32} 32}
33 33
34static void map_groups__flush(struct map_groups *self)
35{
36 int type;
37
38 for (type = 0; type < MAP__NR_TYPES; type++) {
39 struct rb_root *root = &self->maps[type];
40 struct rb_node *next = rb_first(root);
41
42 while (next) {
43 struct map *pos = rb_entry(next, struct map, rb_node);
44 next = rb_next(&pos->rb_node);
45 rb_erase(&pos->rb_node, root);
46 /*
47 * We may have references to this map, for
48 * instance in some hist_entry instances, so
49 * just move them to a separate list.
50 */
51 list_add_tail(&pos->node, &self->removed_maps[pos->type]);
52 }
53 }
54}
55
34int thread__set_comm(struct thread *self, const char *comm) 56int thread__set_comm(struct thread *self, const char *comm)
35{ 57{
58 int err;
59
36 if (self->comm) 60 if (self->comm)
37 free(self->comm); 61 free(self->comm);
38 self->comm = strdup(comm); 62 self->comm = strdup(comm);
39 return self->comm ? 0 : -ENOMEM; 63 err = self->comm == NULL ? -ENOMEM : 0;
64 if (!err) {
65 self->comm_set = true;
66 map_groups__flush(&self->mg);
67 }
68 return err;
40} 69}
41 70
42int thread__comm_len(struct thread *self) 71int thread__comm_len(struct thread *self)
@@ -50,11 +79,6 @@ int thread__comm_len(struct thread *self)
50 return self->comm_len; 79 return self->comm_len;
51} 80}
52 81
53static const char *map_type__name[MAP__NR_TYPES] = {
54 [MAP__FUNCTION] = "Functions",
55 [MAP__VARIABLE] = "Variables",
56};
57
58static size_t __map_groups__fprintf_maps(struct map_groups *self, 82static size_t __map_groups__fprintf_maps(struct map_groups *self,
59 enum map_type type, FILE *fp) 83 enum map_type type, FILE *fp)
60{ 84{
@@ -255,11 +279,14 @@ int thread__fork(struct thread *self, struct thread *parent)
255{ 279{
256 int i; 280 int i;
257 281
258 if (self->comm) 282 if (parent->comm_set) {
259 free(self->comm); 283 if (self->comm)
260 self->comm = strdup(parent->comm); 284 free(self->comm);
261 if (!self->comm) 285 self->comm = strdup(parent->comm);
262 return -ENOMEM; 286 if (!self->comm)
287 return -ENOMEM;
288 self->comm_set = true;
289 }
263 290
264 for (i = 0; i < MAP__NR_TYPES; ++i) 291 for (i = 0; i < MAP__NR_TYPES; ++i)
265 if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 292 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
@@ -282,14 +309,13 @@ size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
282} 309}
283 310
284struct symbol *map_groups__find_symbol(struct map_groups *self, 311struct symbol *map_groups__find_symbol(struct map_groups *self,
285 struct perf_session *session,
286 enum map_type type, u64 addr, 312 enum map_type type, u64 addr,
287 symbol_filter_t filter) 313 symbol_filter_t filter)
288{ 314{
289 struct map *map = map_groups__find(self, type, addr); 315 struct map *map = map_groups__find(self, type, addr);
290 316
291 if (map != NULL) 317 if (map != NULL)
292 return map__find_symbol(map, session, map->map_ip(map, addr), filter); 318 return map__find_symbol(map, map->map_ip(map, addr), filter);
293 319
294 return NULL; 320 return NULL;
295} 321}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index c206f72c8881..0a28f39de545 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -15,6 +15,7 @@ struct thread {
15 struct map_groups mg; 15 struct map_groups mg;
16 pid_t pid; 16 pid_t pid;
17 char shortname[3]; 17 char shortname[3];
18 bool comm_set;
18 char *comm; 19 char *comm;
19 int comm_len; 20 int comm_len;
20}; 21};
@@ -48,23 +49,36 @@ static inline struct map *thread__find_map(struct thread *self,
48 return self ? map_groups__find(&self->mg, type, addr) : NULL; 49 return self ? map_groups__find(&self->mg, type, addr) : NULL;
49} 50}
50 51
52void thread__find_addr_map(struct thread *self,
53 struct perf_session *session, u8 cpumode,
54 enum map_type type, u64 addr,
55 struct addr_location *al);
56
51void thread__find_addr_location(struct thread *self, 57void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode, 58 struct perf_session *session, u8 cpumode,
53 enum map_type type, u64 addr, 59 enum map_type type, u64 addr,
54 struct addr_location *al, 60 struct addr_location *al,
55 symbol_filter_t filter); 61 symbol_filter_t filter);
56struct symbol *map_groups__find_symbol(struct map_groups *self, 62struct symbol *map_groups__find_symbol(struct map_groups *self,
57 struct perf_session *session,
58 enum map_type type, u64 addr, 63 enum map_type type, u64 addr,
59 symbol_filter_t filter); 64 symbol_filter_t filter);
60 65
61static inline struct symbol * 66static inline struct symbol *map_groups__find_function(struct map_groups *self,
62map_groups__find_function(struct map_groups *self, struct perf_session *session, 67 u64 addr,
63 u64 addr, symbol_filter_t filter) 68 symbol_filter_t filter)
64{ 69{
65 return map_groups__find_symbol(self, session, MAP__FUNCTION, addr, filter); 70 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
66} 71}
67 72
68struct map *map_groups__find_by_name(struct map_groups *self, 73struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name); 74 enum map_type type, const char *name);
75
76int __map_groups__create_kernel_maps(struct map_groups *self,
77 struct map *vmlinux_maps[MAP__NR_TYPES],
78 struct dso *kernel);
79int map_groups__create_kernel_maps(struct map_groups *self,
80 struct map *vmlinux_maps[MAP__NR_TYPES]);
81
82struct map *map_groups__new_module(struct map_groups *self, u64 start,
83 const char *filename);
70#endif /* __PERF_THREAD_H */ 84#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index cace35595530..5ea8973ad331 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -20,6 +20,7 @@
20 */ 20 */
21#define _GNU_SOURCE 21#define _GNU_SOURCE
22#include <dirent.h> 22#include <dirent.h>
23#include <mntent.h>
23#include <stdio.h> 24#include <stdio.h>
24#include <stdlib.h> 25#include <stdlib.h>
25#include <string.h> 26#include <string.h>
@@ -37,6 +38,7 @@
37 38
38#include "../perf.h" 39#include "../perf.h"
39#include "trace-event.h" 40#include "trace-event.h"
41#include "debugfs.h"
40 42
41#define VERSION "0.5" 43#define VERSION "0.5"
42 44
@@ -101,32 +103,12 @@ void *malloc_or_die(unsigned int size)
101 103
102static const char *find_debugfs(void) 104static const char *find_debugfs(void)
103{ 105{
104 static char debugfs[MAX_PATH+1]; 106 const char *path = debugfs_mount(NULL);
105 static int debugfs_found;
106 char type[100];
107 FILE *fp;
108
109 if (debugfs_found)
110 return debugfs;
111
112 if ((fp = fopen("/proc/mounts","r")) == NULL)
113 die("Can't open /proc/mounts for read");
114
115 while (fscanf(fp, "%*s %"
116 STR(MAX_PATH)
117 "s %99s %*s %*d %*d\n",
118 debugfs, type) == 2) {
119 if (strcmp(type, "debugfs") == 0)
120 break;
121 }
122 fclose(fp);
123
124 if (strcmp(type, "debugfs") != 0)
125 die("debugfs not mounted, please mount");
126 107
127 debugfs_found = 1; 108 if (!path)
109 die("Your kernel not support debugfs filesystem");
128 110
129 return debugfs; 111 return path;
130} 112}
131 113
132/* 114/*
@@ -271,6 +253,8 @@ static void read_header_files(void)
271 write_or_die("header_page", 12); 253 write_or_die("header_page", 12);
272 write_or_die(&size, 8); 254 write_or_die(&size, 8);
273 check_size = copy_file_fd(fd); 255 check_size = copy_file_fd(fd);
256 close(fd);
257
274 if (size != check_size) 258 if (size != check_size)
275 die("wrong size for '%s' size=%lld read=%lld", 259 die("wrong size for '%s' size=%lld read=%lld",
276 path, size, check_size); 260 path, size, check_size);
@@ -289,6 +273,7 @@ static void read_header_files(void)
289 if (size != check_size) 273 if (size != check_size)
290 die("wrong size for '%s'", path); 274 die("wrong size for '%s'", path);
291 put_tracing_file(path); 275 put_tracing_file(path);
276 close(fd);
292} 277}
293 278
294static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 279static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -317,7 +302,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
317 die("can't read directory '%s'", sys); 302 die("can't read directory '%s'", sys);
318 303
319 while ((dent = readdir(dir))) { 304 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 || 305 if (dent->d_type != DT_DIR ||
306 strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0 || 307 strcmp(dent->d_name, "..") == 0 ||
322 !name_in_tp_list(dent->d_name, tps)) 308 !name_in_tp_list(dent->d_name, tps))
323 continue; 309 continue;
@@ -334,7 +320,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
334 320
335 rewinddir(dir); 321 rewinddir(dir);
336 while ((dent = readdir(dir))) { 322 while ((dent = readdir(dir))) {
337 if (strcmp(dent->d_name, ".") == 0 || 323 if (dent->d_type != DT_DIR ||
324 strcmp(dent->d_name, ".") == 0 ||
338 strcmp(dent->d_name, "..") == 0 || 325 strcmp(dent->d_name, "..") == 0 ||
339 !name_in_tp_list(dent->d_name, tps)) 326 !name_in_tp_list(dent->d_name, tps))
340 continue; 327 continue;
@@ -353,6 +340,7 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
353 340
354 free(format); 341 free(format);
355 } 342 }
343 closedir(dir);
356} 344}
357 345
358static void read_ftrace_files(struct tracepoint_path *tps) 346static void read_ftrace_files(struct tracepoint_path *tps)
@@ -394,26 +382,21 @@ static void read_event_files(struct tracepoint_path *tps)
394 die("can't read directory '%s'", path); 382 die("can't read directory '%s'", path);
395 383
396 while ((dent = readdir(dir))) { 384 while ((dent = readdir(dir))) {
397 if (strcmp(dent->d_name, ".") == 0 || 385 if (dent->d_type != DT_DIR ||
386 strcmp(dent->d_name, ".") == 0 ||
398 strcmp(dent->d_name, "..") == 0 || 387 strcmp(dent->d_name, "..") == 0 ||
399 strcmp(dent->d_name, "ftrace") == 0 || 388 strcmp(dent->d_name, "ftrace") == 0 ||
400 !system_in_tp_list(dent->d_name, tps)) 389 !system_in_tp_list(dent->d_name, tps))
401 continue; 390 continue;
402 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 391 count++;
403 sprintf(sys, "%s/%s", path, dent->d_name);
404 ret = stat(sys, &st);
405 free(sys);
406 if (ret < 0)
407 continue;
408 if (S_ISDIR(st.st_mode))
409 count++;
410 } 392 }
411 393
412 write_or_die(&count, 4); 394 write_or_die(&count, 4);
413 395
414 rewinddir(dir); 396 rewinddir(dir);
415 while ((dent = readdir(dir))) { 397 while ((dent = readdir(dir))) {
416 if (strcmp(dent->d_name, ".") == 0 || 398 if (dent->d_type != DT_DIR ||
399 strcmp(dent->d_name, ".") == 0 ||
417 strcmp(dent->d_name, "..") == 0 || 400 strcmp(dent->d_name, "..") == 0 ||
418 strcmp(dent->d_name, "ftrace") == 0 || 401 strcmp(dent->d_name, "ftrace") == 0 ||
419 !system_in_tp_list(dent->d_name, tps)) 402 !system_in_tp_list(dent->d_name, tps))
@@ -422,14 +405,13 @@ static void read_event_files(struct tracepoint_path *tps)
422 sprintf(sys, "%s/%s", path, dent->d_name); 405 sprintf(sys, "%s/%s", path, dent->d_name);
423 ret = stat(sys, &st); 406 ret = stat(sys, &st);
424 if (ret >= 0) { 407 if (ret >= 0) {
425 if (S_ISDIR(st.st_mode)) { 408 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
426 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 409 copy_event_system(sys, tps);
427 copy_event_system(sys, tps);
428 }
429 } 410 }
430 free(sys); 411 free(sys);
431 } 412 }
432 413
414 closedir(dir);
433 put_tracing_file(path); 415 put_tracing_file(path);
434} 416}
435 417
@@ -533,7 +515,7 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
533 write_or_die(buf, 1); 515 write_or_die(buf, 1);
534 516
535 /* save page_size */ 517 /* save page_size */
536 page_size = getpagesize(); 518 page_size = sysconf(_SC_PAGESIZE);
537 write_or_die(&page_size, 4); 519 write_or_die(&page_size, 4);
538 520
539 read_header_files(); 521 read_header_files();
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index c5c32be040bf..9b3c20f42f98 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -1925,6 +1925,15 @@ void *raw_field_ptr(struct event *event, const char *name, void *data)
1925 if (!field) 1925 if (!field)
1926 return NULL; 1926 return NULL;
1927 1927
1928 if (field->flags & FIELD_IS_STRING) {
1929 int offset;
1930
1931 offset = *(int *)(data + field->offset);
1932 offset &= 0xffff;
1933
1934 return data + offset;
1935 }
1936
1928 return data + field->offset; 1937 return data + field->offset;
1929} 1938}
1930 1939
@@ -3277,3 +3286,18 @@ void parse_set_info(int nr_cpus, int long_sz)
3277 cpus = nr_cpus; 3286 cpus = nr_cpus;
3278 long_size = long_sz; 3287 long_size = long_sz;
3279} 3288}
3289
3290int common_pc(struct scripting_context *context)
3291{
3292 return parse_common_pc(context->event_data);
3293}
3294
3295int common_flags(struct scripting_context *context)
3296{
3297 return parse_common_flags(context->event_data);
3298}
3299
3300int common_lock_depth(struct scripting_context *context)
3301{
3302 return parse_common_lock_depth(context->event_data);
3303}
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h
deleted file mode 100644
index e88fb26137bb..000000000000
--- a/tools/perf/util/trace-event-perl.h
+++ /dev/null
@@ -1,55 +0,0 @@
1#ifndef __PERF_TRACE_EVENT_PERL_H
2#define __PERF_TRACE_EVENT_PERL_H
3#ifdef NO_LIBPERL
4typedef int INTERP;
5#define dSP
6#define ENTER
7#define SAVETMPS
8#define PUTBACK
9#define SPAGAIN
10#define FREETMPS
11#define LEAVE
12#define SP
13#define ERRSV
14#define G_SCALAR (0)
15#define G_DISCARD (0)
16#define G_NOARGS (0)
17#define PUSHMARK(a)
18#define SvTRUE(a) (0)
19#define XPUSHs(s)
20#define sv_2mortal(a)
21#define newSVpv(a,b)
22#define newSVuv(a)
23#define newSViv(a)
24#define get_cv(a,b) (0)
25#define call_pv(a,b) (0)
26#define perl_alloc() (0)
27#define perl_construct(a) (0)
28#define perl_parse(a,b,c,d,e) (0)
29#define perl_run(a) (0)
30#define perl_destruct(a) (0)
31#define perl_free(a) (0)
32#define pTHX void
33#define CV void
34#define dXSUB_SYS
35#define pTHX_
36static inline void newXS(const char *a, void *b, const char *c) {}
37static void boot_Perf__Trace__Context(pTHX_ CV *cv) {}
38static void boot_DynaLoader(pTHX_ CV *cv) {}
39#else
40#include <EXTERN.h>
41#include <perl.h>
42void boot_Perf__Trace__Context(pTHX_ CV *cv);
43void boot_DynaLoader(pTHX_ CV *cv);
44typedef PerlInterpreter * INTERP;
45#endif
46
47struct scripting_context {
48 void *event_data;
49};
50
51int common_pc(struct scripting_context *context);
52int common_flags(struct scripting_context *context);
53int common_lock_depth(struct scripting_context *context);
54
55#endif /* __PERF_TRACE_EVENT_PERL_H */
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1744422cafcb..7cd1193918c7 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -18,7 +18,7 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#define _LARGEFILE64_SOURCE 21#define _FILE_OFFSET_BITS 64
22 22
23#include <dirent.h> 23#include <dirent.h>
24#include <stdio.h> 24#include <stdio.h>
@@ -83,7 +83,7 @@ static char *read_string(void)
83 char *str = NULL; 83 char *str = NULL;
84 int size = 0; 84 int size = 0;
85 int i; 85 int i;
86 int r; 86 off_t r;
87 87
88 for (;;) { 88 for (;;) {
89 r = read(input_fd, buf, BUFSIZ); 89 r = read(input_fd, buf, BUFSIZ);
@@ -118,7 +118,7 @@ static char *read_string(void)
118 118
119 /* move the file descriptor to the end of the string */ 119 /* move the file descriptor to the end of the string */
120 r = lseek(input_fd, -(r - i), SEEK_CUR); 120 r = lseek(input_fd, -(r - i), SEEK_CUR);
121 if (r < 0) 121 if (r == (off_t)-1)
122 die("lseek"); 122 die("lseek");
123 123
124 if (str) { 124 if (str) {
@@ -282,8 +282,8 @@ static void update_cpu_data_index(int cpu)
282 282
283static void get_next_page(int cpu) 283static void get_next_page(int cpu)
284{ 284{
285 off64_t save_seek; 285 off_t save_seek;
286 off64_t ret; 286 off_t ret;
287 287
288 if (!cpu_data[cpu].page) 288 if (!cpu_data[cpu].page)
289 return; 289 return;
@@ -298,17 +298,17 @@ static void get_next_page(int cpu)
298 update_cpu_data_index(cpu); 298 update_cpu_data_index(cpu);
299 299
300 /* other parts of the code may expect the pointer to not move */ 300 /* other parts of the code may expect the pointer to not move */
301 save_seek = lseek64(input_fd, 0, SEEK_CUR); 301 save_seek = lseek(input_fd, 0, SEEK_CUR);
302 302
303 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET); 303 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
304 if (ret < 0) 304 if (ret == (off_t)-1)
305 die("failed to lseek"); 305 die("failed to lseek");
306 ret = read(input_fd, cpu_data[cpu].page, page_size); 306 ret = read(input_fd, cpu_data[cpu].page, page_size);
307 if (ret < 0) 307 if (ret < 0)
308 die("failed to read page"); 308 die("failed to read page");
309 309
310 /* reset the file pointer back */ 310 /* reset the file pointer back */
311 lseek64(input_fd, save_seek, SEEK_SET); 311 lseek(input_fd, save_seek, SEEK_SET);
312 312
313 return; 313 return;
314 } 314 }
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
new file mode 100644
index 000000000000..7ea983acfaea
--- /dev/null
+++ b/tools/perf/util/trace-event-scripting.c
@@ -0,0 +1,167 @@
1/*
2 * trace-event-scripting. Scripting engine common and initialization code.
3 *
4 * Copyright (C) 2009-2010 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include "../perf.h"
29#include "util.h"
30#include "trace-event.h"
31
32struct scripting_context *scripting_context;
33
34static int stop_script_unsupported(void)
35{
36 return 0;
37}
38
39static void process_event_unsupported(int cpu __unused,
40 void *data __unused,
41 int size __unused,
42 unsigned long long nsecs __unused,
43 char *comm __unused)
44{
45}
46
47static void print_python_unsupported_msg(void)
48{
49 fprintf(stderr, "Python scripting not supported."
50 " Install libpython and rebuild perf to enable it.\n"
51 "For example:\n # apt-get install python-dev (ubuntu)"
52 "\n # yum install python-devel (Fedora)"
53 "\n etc.\n");
54}
55
56static int python_start_script_unsupported(const char *script __unused,
57 int argc __unused,
58 const char **argv __unused)
59{
60 print_python_unsupported_msg();
61
62 return -1;
63}
64
65static int python_generate_script_unsupported(const char *outfile __unused)
66{
67 print_python_unsupported_msg();
68
69 return -1;
70}
71
72struct scripting_ops python_scripting_unsupported_ops = {
73 .name = "Python",
74 .start_script = python_start_script_unsupported,
75 .stop_script = stop_script_unsupported,
76 .process_event = process_event_unsupported,
77 .generate_script = python_generate_script_unsupported,
78};
79
80static void register_python_scripting(struct scripting_ops *scripting_ops)
81{
82 int err;
83 err = script_spec_register("Python", scripting_ops);
84 if (err)
85 die("error registering Python script extension");
86
87 err = script_spec_register("py", scripting_ops);
88 if (err)
89 die("error registering py script extension");
90
91 scripting_context = malloc(sizeof(struct scripting_context));
92}
93
94#ifdef NO_LIBPYTHON
95void setup_python_scripting(void)
96{
97 register_python_scripting(&python_scripting_unsupported_ops);
98}
99#else
100struct scripting_ops python_scripting_ops;
101
102void setup_python_scripting(void)
103{
104 register_python_scripting(&python_scripting_ops);
105}
106#endif
107
108static void print_perl_unsupported_msg(void)
109{
110 fprintf(stderr, "Perl scripting not supported."
111 " Install libperl and rebuild perf to enable it.\n"
112 "For example:\n # apt-get install libperl-dev (ubuntu)"
113 "\n # yum install 'perl(ExtUtils::Embed)' (Fedora)"
114 "\n etc.\n");
115}
116
117static int perl_start_script_unsupported(const char *script __unused,
118 int argc __unused,
119 const char **argv __unused)
120{
121 print_perl_unsupported_msg();
122
123 return -1;
124}
125
126static int perl_generate_script_unsupported(const char *outfile __unused)
127{
128 print_perl_unsupported_msg();
129
130 return -1;
131}
132
133struct scripting_ops perl_scripting_unsupported_ops = {
134 .name = "Perl",
135 .start_script = perl_start_script_unsupported,
136 .stop_script = stop_script_unsupported,
137 .process_event = process_event_unsupported,
138 .generate_script = perl_generate_script_unsupported,
139};
140
141static void register_perl_scripting(struct scripting_ops *scripting_ops)
142{
143 int err;
144 err = script_spec_register("Perl", scripting_ops);
145 if (err)
146 die("error registering Perl script extension");
147
148 err = script_spec_register("pl", scripting_ops);
149 if (err)
150 die("error registering pl script extension");
151
152 scripting_context = malloc(sizeof(struct scripting_context));
153}
154
155#ifdef NO_LIBPERL
156void setup_perl_scripting(void)
157{
158 register_perl_scripting(&perl_scripting_unsupported_ops);
159}
160#else
161struct scripting_ops perl_scripting_ops;
162
163void setup_perl_scripting(void)
164{
165 register_perl_scripting(&perl_scripting_ops);
166}
167#endif
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 6ad405620c9b..c3269b937db4 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -279,7 +279,15 @@ struct scripting_ops {
279 279
280int script_spec_register(const char *spec, struct scripting_ops *ops); 280int script_spec_register(const char *spec, struct scripting_ops *ops);
281 281
282extern struct scripting_ops perl_scripting_ops;
283void setup_perl_scripting(void); 282void setup_perl_scripting(void);
283void setup_python_scripting(void);
284
285struct scripting_context {
286 void *event_data;
287};
288
289int common_pc(struct scripting_context *context);
290int common_flags(struct scripting_context *context);
291int common_lock_depth(struct scripting_context *context);
284 292
285#endif /* __PERF_TRACE_EVENTS_H */ 293#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
new file mode 100644
index 000000000000..f9b890fde681
--- /dev/null
+++ b/tools/perf/util/util.c
@@ -0,0 +1,94 @@
1#include "util.h"
2#include <sys/mman.h>
3
4int mkdir_p(char *path, mode_t mode)
5{
6 struct stat st;
7 int err;
8 char *d = path;
9
10 if (*d != '/')
11 return -1;
12
13 if (stat(path, &st) == 0)
14 return 0;
15
16 while (*++d == '/');
17
18 while ((d = strchr(d, '/'))) {
19 *d = '\0';
20 err = stat(path, &st) && mkdir(path, mode);
21 *d++ = '/';
22 if (err)
23 return -1;
24 while (*d == '/')
25 ++d;
26 }
27 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
28}
29
30static int slow_copyfile(const char *from, const char *to)
31{
32 int err = 0;
33 char *line = NULL;
34 size_t n;
35 FILE *from_fp = fopen(from, "r"), *to_fp;
36
37 if (from_fp == NULL)
38 goto out;
39
40 to_fp = fopen(to, "w");
41 if (to_fp == NULL)
42 goto out_fclose_from;
43
44 while (getline(&line, &n, from_fp) > 0)
45 if (fputs(line, to_fp) == EOF)
46 goto out_fclose_to;
47 err = 0;
48out_fclose_to:
49 fclose(to_fp);
50 free(line);
51out_fclose_from:
52 fclose(from_fp);
53out:
54 return err;
55}
56
57int copyfile(const char *from, const char *to)
58{
59 int fromfd, tofd;
60 struct stat st;
61 void *addr;
62 int err = -1;
63
64 if (stat(from, &st))
65 goto out;
66
67 if (st.st_size == 0) /* /proc? do it slowly... */
68 return slow_copyfile(from, to);
69
70 fromfd = open(from, O_RDONLY);
71 if (fromfd < 0)
72 goto out;
73
74 tofd = creat(to, 0755);
75 if (tofd < 0)
76 goto out_close_from;
77
78 addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
79 if (addr == MAP_FAILED)
80 goto out_close_to;
81
82 if (write(tofd, addr, st.st_size) == st.st_size)
83 err = 0;
84
85 munmap(addr, st.st_size);
86out_close_to:
87 close(tofd);
88 if (err)
89 unlink(to);
90out_close_from:
91 close(fromfd);
92out:
93 return err;
94}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c673d8825883..0f5b2a6f1080 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -403,4 +403,7 @@ void git_qsort(void *base, size_t nmemb, size_t size,
403#endif 403#endif
404#endif 404#endif
405 405
406int mkdir_p(char *path, mode_t mode);
407int copyfile(const char *from, const char *to);
408
406#endif 409#endif
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 1c15e39f99e3..cfa55d686e3b 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -169,6 +169,7 @@ static void perf_read_values__display_pretty(FILE *fp,
169 counterwidth[j], values->value[i][j]); 169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n"); 170 fprintf(fp, "\n");
171 } 171 }
172 free(counterwidth);
172} 173}
173 174
174static void perf_read_values__display_raw(FILE *fp, 175static void perf_read_values__display_raw(FILE *fp,