aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/.gitignore2
-rw-r--r--tools/perf/Documentation/perf-probe.txt8
-rw-r--r--tools/perf/Documentation/perf-record.txt13
-rw-r--r--tools/perf/Documentation/perf-stat.txt7
-rw-r--r--tools/perf/Documentation/perf-top.txt8
-rw-r--r--tools/perf/MANIFEST12
-rw-r--r--tools/perf/Makefile141
-rw-r--r--tools/perf/arch/sh/Makefile4
-rw-r--r--tools/perf/arch/sh/util/dwarf-regs.c55
-rw-r--r--tools/perf/builtin-annotate.c6
-rw-r--r--tools/perf/builtin-buildid-cache.c3
-rw-r--r--tools/perf/builtin-diff.c7
-rw-r--r--tools/perf/builtin-probe.c2
-rw-r--r--tools/perf/builtin-record.c44
-rw-r--r--tools/perf/builtin-report.c25
-rw-r--r--tools/perf/builtin-stat.c14
-rw-r--r--tools/perf/builtin-top.c20
-rw-r--r--tools/perf/builtin-trace.c32
-rw-r--r--tools/perf/feature-tests.mak119
-rw-r--r--tools/perf/perf-archive.sh20
-rw-r--r--tools/perf/perf.c2
-rw-r--r--tools/perf/util/build-id.c10
-rw-r--r--tools/perf/util/cache.h1
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/config.c64
-rw-r--r--tools/perf/util/cpumap.c57
-rw-r--r--tools/perf/util/cpumap.h2
-rw-r--r--tools/perf/util/debug.c10
-rw-r--r--tools/perf/util/event.c37
-rw-r--r--tools/perf/util/event.h5
-rw-r--r--tools/perf/util/header.c13
-rw-r--r--tools/perf/util/hist.c39
-rw-r--r--tools/perf/util/newt.c199
-rw-r--r--tools/perf/util/parse-events.c11
-rw-r--r--tools/perf/util/probe-event.c140
-rw-r--r--tools/perf/util/probe-event.h2
-rw-r--r--tools/perf/util/probe-finder.c228
-rw-r--r--tools/perf/util/session.c6
-rw-r--r--tools/perf/util/sort.c27
-rw-r--r--tools/perf/util/sort.h6
-rw-r--r--tools/perf/util/symbol.c37
-rw-r--r--tools/perf/util/symbol.h6
-rw-r--r--tools/perf/util/util.h3
44 files changed, 1091 insertions, 360 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index e1d60d780784..cb43289e447f 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -18,3 +18,5 @@ perf-archive
18tags 18tags
19TAGS 19TAGS
20cscope* 20cscope*
21config.mak
22config.mak.autogen
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 94a258c96a44..27d52dae5a43 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -31,6 +31,10 @@ OPTIONS
31--vmlinux=PATH:: 31--vmlinux=PATH::
32 Specify vmlinux path which has debuginfo (Dwarf binary). 32 Specify vmlinux path which has debuginfo (Dwarf binary).
33 33
34-s::
35--source=PATH::
36 Specify path to kernel source.
37
34-v:: 38-v::
35--verbose:: 39--verbose::
36 Be more verbose (show parsed arguments, etc). 40 Be more verbose (show parsed arguments, etc).
@@ -90,8 +94,8 @@ Each probe argument follows below syntax.
90 94
91 [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE] 95 [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE]
92 96
93'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) 97'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
94'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. 98'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type.
95 99
96LINE SYNTAX 100LINE SYNTAX
97----------- 101-----------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 34e255fc3e2f..3ee27dccfde9 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -103,6 +103,19 @@ OPTIONS
103--raw-samples:: 103--raw-samples::
104Collect raw sample records from all opened counters (default for tracepoint counters). 104Collect raw sample records from all opened counters (default for tracepoint counters).
105 105
106-C::
107--cpu::
108Collect samples only on the list of cpus provided. Multiple CPUs can be provided as a
109comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
110In per-thread mode with inheritance mode on (default), samples are captured only when
111the thread executes on the designated CPUs. Default is to monitor all CPUs.
112
113-N::
114--no-buildid-cache::
115Do not update the builid cache. This saves some overhead in situations
116where the information in the perf.data file (which includes buildids)
117is sufficient.
118
106SEE ALSO 119SEE ALSO
107-------- 120--------
108linkperf:perf-stat[1], linkperf:perf-list[1] 121linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 909fa766fa1c..4b3a2d46b437 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -46,6 +46,13 @@ OPTIONS
46-B:: 46-B::
47 print large numbers with thousands' separators according to locale 47 print large numbers with thousands' separators according to locale
48 48
49-C::
50--cpu=::
51Count only on the list of cpus provided. Multiple CPUs can be provided as a
52comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
53In per-thread mode, this option is ignored. The -a option is still necessary
54to activate system-wide monitoring. Default is to count on all CPUs.
55
49EXAMPLES 56EXAMPLES
50-------- 57--------
51 58
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 785b9fc32a46..1f9687663f2a 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -25,9 +25,11 @@ OPTIONS
25--count=<count>:: 25--count=<count>::
26 Event period to sample. 26 Event period to sample.
27 27
28-C <cpu>:: 28-C <cpu-list>::
29--CPU=<cpu>:: 29--cpu=<cpu>::
30 CPU to profile. 30Monitor only on the list of cpus provided. Multiple CPUs can be provided as a
31comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
32Default is to monitor all CPUS.
31 33
32-d <seconds>:: 34-d <seconds>::
33--delay=<seconds>:: 35--delay=<seconds>::
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
new file mode 100644
index 000000000000..8c7fc0c8f0b8
--- /dev/null
+++ b/tools/perf/MANIFEST
@@ -0,0 +1,12 @@
1tools/perf
2include/linux/perf_event.h
3include/linux/rbtree.h
4include/linux/list.h
5include/linux/hash.h
6include/linux/stringify.h
7lib/rbtree.c
8include/linux/swab.h
9arch/*/include/asm/unistd*.h
10include/linux/poison.h
11include/linux/magic.h
12include/linux/hw_breakpoint.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 3d8f31ed771d..26f626d45a9e 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -285,14 +285,10 @@ else
285 QUIET_STDERR = ">/dev/null 2>&1" 285 QUIET_STDERR = ">/dev/null 2>&1"
286endif 286endif
287 287
288BITBUCKET = "/dev/null" 288-include feature-tests.mak
289 289
290ifneq ($(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) 290ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
291 BITBUCKET = .perf.dev.null 291 CFLAGS := $(CFLAGS) -fstack-protector-all
292endif
293
294ifeq ($(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)
295 CFLAGS := $(CFLAGS) -fstack-protector-all
296endif 292endif
297 293
298 294
@@ -508,7 +504,8 @@ PERFLIBS = $(LIB_FILE)
508-include config.mak 504-include config.mak
509 505
510ifndef NO_DWARF 506ifndef NO_DWARF
511ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo '\#include <version.h>'; echo '\#ifndef _ELFUTILS_PREREQ'; echo '\#error'; echo '\#endif'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 507FLAGS_DWARF=$(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
508ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y)
512 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); 509 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
513 NO_DWARF := 1 510 NO_DWARF := 1
514endif # Dwarf support 511endif # Dwarf support
@@ -536,16 +533,18 @@ ifneq ($(OUTPUT),)
536 BASIC_CFLAGS += -I$(OUTPUT) 533 BASIC_CFLAGS += -I$(OUTPUT)
537endif 534endif
538 535
539ifeq ($(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) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 536FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
540ifneq ($(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) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 537ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
541 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 538 FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
539 ifneq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y)
540 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
541 else
542 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
543 endif
542endif 544endif
543 545
544 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) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 546ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y)
545 BASIC_CFLAGS += -DLIBELF_NO_MMAP 547 BASIC_CFLAGS += -DLIBELF_NO_MMAP
546 endif
547else
548 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
549endif 548endif
550 549
551ifndef NO_DWARF 550ifndef NO_DWARF
@@ -561,69 +560,80 @@ endif # NO_DWARF
561ifdef NO_NEWT 560ifdef NO_NEWT
562 BASIC_CFLAGS += -DNO_NEWT_SUPPORT 561 BASIC_CFLAGS += -DNO_NEWT_SUPPORT
563else 562else
564ifneq ($(shell sh -c "(echo '\#include <newt.h>'; echo 'int main(void) { newtInit(); newtCls(); return newtFinished(); }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -lnewt -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 563 FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt
565 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); 564 ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y)
566 BASIC_CFLAGS += -DNO_NEWT_SUPPORT 565 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
567else 566 BASIC_CFLAGS += -DNO_NEWT_SUPPORT
568 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h 567 else
569 BASIC_CFLAGS += -I/usr/include/slang 568 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
570 EXTLIBS += -lnewt -lslang 569 BASIC_CFLAGS += -I/usr/include/slang
571 LIB_OBJS += $(OUTPUT)util/newt.o 570 EXTLIBS += -lnewt -lslang
572endif 571 LIB_OBJS += $(OUTPUT)util/newt.o
573endif # NO_NEWT 572 endif
574
575ifndef NO_LIBPERL
576PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
577PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
578endif 573endif
579 574
580ifneq ($(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) 575ifdef NO_LIBPERL
581 BASIC_CFLAGS += -DNO_LIBPERL 576 BASIC_CFLAGS += -DNO_LIBPERL
582else 577else
583 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS) 578 PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
584 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o 579 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
585 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o 580 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
586endif
587 581
588ifndef NO_LIBPYTHON 582 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y)
589PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null` 583 BASIC_CFLAGS += -DNO_LIBPERL
590PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` 584 else
585 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
586 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
587 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
588 endif
591endif 589endif
592 590
593ifneq ($(shell sh -c "(echo '\#include <Python.h>'; echo 'int main(void) { Py_Initialize(); return 0; }') | $(CC) -x c - $(PYTHON_EMBED_CCOPTS) -o $(BITBUCKET) $(PYTHON_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) 591ifdef NO_LIBPYTHON
594 BASIC_CFLAGS += -DNO_LIBPYTHON 592 BASIC_CFLAGS += -DNO_LIBPYTHON
595else 593else
596 ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS) 594 PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null`
597 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o 595 PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
598 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o 596 FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
597 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
598 BASIC_CFLAGS += -DNO_LIBPYTHON
599 else
600 ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS)
601 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
602 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
603 endif
599endif 604endif
600 605
601ifdef NO_DEMANGLE 606ifdef NO_DEMANGLE
602 BASIC_CFLAGS += -DNO_DEMANGLE 607 BASIC_CFLAGS += -DNO_DEMANGLE
603else ifdef HAVE_CPLUS_DEMANGLE
604 EXTLIBS += -liberty
605 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
606else 608else
607 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") 609 ifdef HAVE_CPLUS_DEMANGLE
608 610 EXTLIBS += -liberty
609 ifeq ($(has_bfd),y) 611 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
610 EXTLIBS += -lbfd 612 else
611 else 613 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd
612 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") 614 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD))
613 ifeq ($(has_bfd_iberty),y) 615 ifeq ($(has_bfd),y)
614 EXTLIBS += -lbfd -liberty 616 EXTLIBS += -lbfd
615 else 617 else
616 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") 618 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
617 ifeq ($(has_bfd_iberty_z),y) 619 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY))
618 EXTLIBS += -lbfd -liberty -lz 620 ifeq ($(has_bfd_iberty),y)
621 EXTLIBS += -lbfd -liberty
619 else 622 else
620 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") 623 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
621 ifeq ($(has_cplus_demangle),y) 624 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z))
622 EXTLIBS += -liberty 625 ifeq ($(has_bfd_iberty_z),y)
623 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 626 EXTLIBS += -lbfd -liberty -lz
624 else 627 else
625 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) 628 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
626 BASIC_CFLAGS += -DNO_DEMANGLE 629 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE))
630 ifeq ($(has_cplus_demangle),y)
631 EXTLIBS += -liberty
632 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
633 else
634 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
635 BASIC_CFLAGS += -DNO_DEMANGLE
636 endif
627 endif 637 endif
628 endif 638 endif
629 endif 639 endif
@@ -865,7 +875,7 @@ export TAR INSTALL DESTDIR SHELL_PATH
865 875
866SHELL = $(SHELL_PATH) 876SHELL = $(SHELL_PATH)
867 877
868all:: .perf.dev.null shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS 878all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS
869ifneq (,$X) 879ifneq (,$X)
870 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) 880 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
871endif 881endif
@@ -1195,11 +1205,6 @@ clean:
1195.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 1205.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
1196.PHONY: .FORCE-PERF-BUILD-OPTIONS 1206.PHONY: .FORCE-PERF-BUILD-OPTIONS
1197 1207
1198.perf.dev.null:
1199 touch .perf.dev.null
1200
1201.INTERMEDIATE: .perf.dev.null
1202
1203### Make sure built-ins do not have dups and listed in perf.c 1208### Make sure built-ins do not have dups and listed in perf.c
1204# 1209#
1205check-builtins:: 1210check-builtins::
diff --git a/tools/perf/arch/sh/Makefile b/tools/perf/arch/sh/Makefile
new file mode 100644
index 000000000000..15130b50dfe3
--- /dev/null
+++ b/tools/perf/arch/sh/Makefile
@@ -0,0 +1,4 @@
1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif
diff --git a/tools/perf/arch/sh/util/dwarf-regs.c b/tools/perf/arch/sh/util/dwarf-regs.c
new file mode 100644
index 000000000000..a11edb007a6c
--- /dev/null
+++ b/tools/perf/arch/sh/util/dwarf-regs.c
@@ -0,0 +1,55 @@
1/*
2 * Mapping of DWARF debug register numbers into register names.
3 *
4 * Copyright (C) 2010 Matt Fleming <matt@console-pimps.org>
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 <libio.h>
23#include <dwarf-regs.h>
24
25/*
26 * Generic dwarf analysis helpers
27 */
28
29#define SH_MAX_REGS 18
30const char *sh_regs_table[SH_MAX_REGS] = {
31 "r0",
32 "r1",
33 "r2",
34 "r3",
35 "r4",
36 "r5",
37 "r6",
38 "r7",
39 "r8",
40 "r9",
41 "r10",
42 "r11",
43 "r12",
44 "r13",
45 "r14",
46 "r15",
47 "pc",
48 "pr",
49};
50
51/* Return architecture dependent register string (for kprobe-tracer) */
52const char *get_arch_regstr(unsigned int n)
53{
54 return (n <= SH_MAX_REGS) ? sh_regs_table[n] : NULL;
55}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 96db5248e995..fd20670ce986 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -61,11 +61,9 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
61static int process_sample_event(event_t *event, struct perf_session *session) 61static int process_sample_event(event_t *event, struct perf_session *session)
62{ 62{
63 struct addr_location al; 63 struct addr_location al;
64 struct sample_data data;
64 65
65 dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc, 66 if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
66 event->ip.pid, event->ip.ip);
67
68 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
69 pr_warning("problem processing %d event, skipping it.\n", 67 pr_warning("problem processing %d event, skipping it.\n",
70 event->header.type); 68 event->header.type);
71 return -1; 69 return -1;
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index f8e3d1852029..29ad20e67919 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -78,8 +78,7 @@ static int __cmd_buildid_cache(void)
78 struct str_node *pos; 78 struct str_node *pos;
79 char debugdir[PATH_MAX]; 79 char debugdir[PATH_MAX];
80 80
81 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), 81 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
82 DEBUG_CACHE_DIR);
83 82
84 if (add_name_list_str) { 83 if (add_name_list_str) {
85 list = strlist__new(true, add_name_list_str); 84 list = strlist__new(true, add_name_list_str);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index a6e2fdc7a04e..39e6627ebb96 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -35,10 +35,7 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
35 struct addr_location al; 35 struct addr_location al;
36 struct sample_data data = { .period = 1, }; 36 struct sample_data data = { .period = 1, };
37 37
38 dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc, 38 if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
39 event->ip.pid, event->ip.ip);
40
41 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
42 pr_warning("problem processing %d event, skipping it.\n", 39 pr_warning("problem processing %d event, skipping it.\n",
43 event->header.type); 40 event->header.type);
44 return -1; 41 return -1;
@@ -47,8 +44,6 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
47 if (al.filtered || al.sym == NULL) 44 if (al.filtered || al.sym == NULL)
48 return 0; 45 return 0;
49 46
50 event__parse_sample(event, session->sample_type, &data);
51
52 if (hists__add_entry(&session->hists, &al, data.period)) { 47 if (hists__add_entry(&session->hists, &al, data.period)) {
53 pr_warning("problem incrementing symbol period, skipping event\n"); 48 pr_warning("problem incrementing symbol period, skipping event\n");
54 return -1; 49 return -1;
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index e4a4da32a568..54551867e7e0 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -182,6 +182,8 @@ static const struct option options[] = {
182 "Show source code lines.", opt_show_lines), 182 "Show source code lines.", opt_show_lines),
183 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 183 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
184 "file", "vmlinux pathname"), 184 "file", "vmlinux pathname"),
185 OPT_STRING('s', "source", &symbol_conf.source_prefix,
186 "directory", "path to kernel source"),
185#endif 187#endif
186 OPT__DRY_RUN(&probe_event_dry_run), 188 OPT__DRY_RUN(&probe_event_dry_run),
187 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 189 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 711745f56bba..b93879677cca 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -49,7 +49,6 @@ static int group = 0;
49static int realtime_prio = 0; 49static int realtime_prio = 0;
50static bool raw_samples = false; 50static bool raw_samples = false;
51static bool system_wide = false; 51static bool system_wide = false;
52static int profile_cpu = -1;
53static pid_t target_pid = -1; 52static pid_t target_pid = -1;
54static pid_t target_tid = -1; 53static pid_t target_tid = -1;
55static pid_t *all_tids = NULL; 54static pid_t *all_tids = NULL;
@@ -61,6 +60,7 @@ static bool call_graph = false;
61static bool inherit_stat = false; 60static bool inherit_stat = false;
62static bool no_samples = false; 61static bool no_samples = false;
63static bool sample_address = false; 62static bool sample_address = false;
63static bool no_buildid = false;
64 64
65static long samples = 0; 65static long samples = 0;
66static u64 bytes_written = 0; 66static u64 bytes_written = 0;
@@ -74,6 +74,7 @@ static int file_new = 1;
74static off_t post_processing_offset; 74static off_t post_processing_offset;
75 75
76static struct perf_session *session; 76static struct perf_session *session;
77static const char *cpu_list;
77 78
78struct mmap_data { 79struct mmap_data {
79 int counter; 80 int counter;
@@ -268,12 +269,17 @@ static void create_counter(int counter, int cpu)
268 if (inherit_stat) 269 if (inherit_stat)
269 attr->inherit_stat = 1; 270 attr->inherit_stat = 1;
270 271
271 if (sample_address) 272 if (sample_address) {
272 attr->sample_type |= PERF_SAMPLE_ADDR; 273 attr->sample_type |= PERF_SAMPLE_ADDR;
274 attr->mmap_data = track;
275 }
273 276
274 if (call_graph) 277 if (call_graph)
275 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 278 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
276 279
280 if (system_wide)
281 attr->sample_type |= PERF_SAMPLE_CPU;
282
277 if (raw_samples) { 283 if (raw_samples) {
278 attr->sample_type |= PERF_SAMPLE_TIME; 284 attr->sample_type |= PERF_SAMPLE_TIME;
279 attr->sample_type |= PERF_SAMPLE_RAW; 285 attr->sample_type |= PERF_SAMPLE_RAW;
@@ -300,7 +306,7 @@ try_again:
300 die("Permission error - are you root?\n" 306 die("Permission error - are you root?\n"
301 "\t Consider tweaking" 307 "\t Consider tweaking"
302 " /proc/sys/kernel/perf_event_paranoid.\n"); 308 " /proc/sys/kernel/perf_event_paranoid.\n");
303 else if (err == ENODEV && profile_cpu != -1) { 309 else if (err == ENODEV && cpu_list) {
304 die("No such device - did you specify" 310 die("No such device - did you specify"
305 " an out-of-range profile CPU?\n"); 311 " an out-of-range profile CPU?\n");
306 } 312 }
@@ -439,8 +445,6 @@ static void atexit_header(void)
439static void event__synthesize_guest_os(struct machine *machine, void *data) 445static void event__synthesize_guest_os(struct machine *machine, void *data)
440{ 446{
441 int err; 447 int err;
442 char *guest_kallsyms;
443 char path[PATH_MAX];
444 struct perf_session *psession = data; 448 struct perf_session *psession = data;
445 449
446 if (machine__is_host(machine)) 450 if (machine__is_host(machine))
@@ -460,13 +464,6 @@ static void event__synthesize_guest_os(struct machine *machine, void *data)
460 pr_err("Couldn't record guest kernel [%d]'s reference" 464 pr_err("Couldn't record guest kernel [%d]'s reference"
461 " relocation symbol.\n", machine->pid); 465 " relocation symbol.\n", machine->pid);
462 466
463 if (machine__is_default_guest(machine))
464 guest_kallsyms = (char *) symbol_conf.default_guest_kallsyms;
465 else {
466 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
467 guest_kallsyms = path;
468 }
469
470 /* 467 /*
471 * We use _stext for guest kernel because guest kernel's /proc/kallsyms 468 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
472 * have no _text sometimes. 469 * have no _text sometimes.
@@ -622,10 +619,15 @@ static int __cmd_record(int argc, const char **argv)
622 close(child_ready_pipe[0]); 619 close(child_ready_pipe[0]);
623 } 620 }
624 621
625 if ((!system_wide && no_inherit) || profile_cpu != -1) { 622 nr_cpus = read_cpu_map(cpu_list);
626 open_counters(profile_cpu); 623 if (nr_cpus < 1) {
624 perror("failed to collect number of CPUs\n");
625 return -1;
626 }
627
628 if (!system_wide && no_inherit && !cpu_list) {
629 open_counters(-1);
627 } else { 630 } else {
628 nr_cpus = read_cpu_map();
629 for (i = 0; i < nr_cpus; i++) 631 for (i = 0; i < nr_cpus; i++)
630 open_counters(cpumap[i]); 632 open_counters(cpumap[i]);
631 } 633 }
@@ -704,7 +706,7 @@ static int __cmd_record(int argc, const char **argv)
704 if (perf_guest) 706 if (perf_guest)
705 perf_session__process_machines(session, event__synthesize_guest_os); 707 perf_session__process_machines(session, event__synthesize_guest_os);
706 708
707 if (!system_wide && profile_cpu == -1) 709 if (!system_wide)
708 event__synthesize_thread(target_tid, process_synthesized_event, 710 event__synthesize_thread(target_tid, process_synthesized_event,
709 session); 711 session);
710 else 712 else
@@ -794,8 +796,8 @@ static const struct option options[] = {
794 "system-wide collection from all CPUs"), 796 "system-wide collection from all CPUs"),
795 OPT_BOOLEAN('A', "append", &append_file, 797 OPT_BOOLEAN('A', "append", &append_file,
796 "append to the output file to do incremental profiling"), 798 "append to the output file to do incremental profiling"),
797 OPT_INTEGER('C', "profile_cpu", &profile_cpu, 799 OPT_STRING('C', "cpu", &cpu_list, "cpu",
798 "CPU to profile on"), 800 "list of cpus to monitor"),
799 OPT_BOOLEAN('f', "force", &force, 801 OPT_BOOLEAN('f', "force", &force,
800 "overwrite existing data file (deprecated)"), 802 "overwrite existing data file (deprecated)"),
801 OPT_U64('c', "count", &user_interval, "event period to sample"), 803 OPT_U64('c', "count", &user_interval, "event period to sample"),
@@ -815,6 +817,8 @@ static const struct option options[] = {
815 "Sample addresses"), 817 "Sample addresses"),
816 OPT_BOOLEAN('n', "no-samples", &no_samples, 818 OPT_BOOLEAN('n', "no-samples", &no_samples,
817 "don't sample"), 819 "don't sample"),
820 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid,
821 "do not update the buildid cache"),
818 OPT_END() 822 OPT_END()
819}; 823};
820 824
@@ -825,7 +829,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
825 argc = parse_options(argc, argv, options, record_usage, 829 argc = parse_options(argc, argv, options, record_usage,
826 PARSE_OPT_STOP_AT_NON_OPTION); 830 PARSE_OPT_STOP_AT_NON_OPTION);
827 if (!argc && target_pid == -1 && target_tid == -1 && 831 if (!argc && target_pid == -1 && target_tid == -1 &&
828 !system_wide && profile_cpu == -1) 832 !system_wide && !cpu_list)
829 usage_with_options(record_usage, options); 833 usage_with_options(record_usage, options);
830 834
831 if (force && append_file) { 835 if (force && append_file) {
@@ -839,6 +843,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
839 } 843 }
840 844
841 symbol__init(); 845 symbol__init();
846 if (no_buildid)
847 disable_buildid_cache();
842 848
843 if (!nr_counters) { 849 if (!nr_counters) {
844 nr_counters = 1; 850 nr_counters = 1;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index fd7407c7205c..ce42bbaa252d 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -155,30 +155,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
155 struct addr_location al; 155 struct addr_location al;
156 struct perf_event_attr *attr; 156 struct perf_event_attr *attr;
157 157
158 event__parse_sample(event, session->sample_type, &data); 158 if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
159
160 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
161 data.pid, data.tid, data.ip, data.period);
162
163 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
164 unsigned int i;
165
166 dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
167
168 if (!ip_callchain__valid(data.callchain, event)) {
169 pr_debug("call-chain problem with event, "
170 "skipping it.\n");
171 return 0;
172 }
173
174 if (dump_trace) {
175 for (i = 0; i < data.callchain->nr; i++)
176 dump_printf("..... %2d: %016Lx\n",
177 i, data.callchain->ips[i]);
178 }
179 }
180
181 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
182 fprintf(stderr, "problem processing %d event, skipping it.\n", 159 fprintf(stderr, "problem processing %d event, skipping it.\n",
183 event->header.type); 160 event->header.type);
184 return -1; 161 return -1;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 9a39ca3c3ac4..a6b4d44f9502 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -69,7 +69,7 @@ static struct perf_event_attr default_attrs[] = {
69}; 69};
70 70
71static bool system_wide = false; 71static bool system_wide = false;
72static unsigned int nr_cpus = 0; 72static int nr_cpus = 0;
73static int run_idx = 0; 73static int run_idx = 0;
74 74
75static int run_count = 1; 75static int run_count = 1;
@@ -82,6 +82,7 @@ static int thread_num = 0;
82static pid_t child_pid = -1; 82static pid_t child_pid = -1;
83static bool null_run = false; 83static bool null_run = false;
84static bool big_num = false; 84static bool big_num = false;
85static const char *cpu_list;
85 86
86 87
87static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; 88static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
@@ -158,7 +159,7 @@ static int create_perf_stat_counter(int counter)
158 PERF_FORMAT_TOTAL_TIME_RUNNING; 159 PERF_FORMAT_TOTAL_TIME_RUNNING;
159 160
160 if (system_wide) { 161 if (system_wide) {
161 unsigned int cpu; 162 int cpu;
162 163
163 for (cpu = 0; cpu < nr_cpus; cpu++) { 164 for (cpu = 0; cpu < nr_cpus; cpu++) {
164 fd[cpu][counter][0] = sys_perf_event_open(attr, 165 fd[cpu][counter][0] = sys_perf_event_open(attr,
@@ -208,7 +209,7 @@ static inline int nsec_counter(int counter)
208static void read_counter(int counter) 209static void read_counter(int counter)
209{ 210{
210 u64 count[3], single_count[3]; 211 u64 count[3], single_count[3];
211 unsigned int cpu; 212 int cpu;
212 size_t res, nv; 213 size_t res, nv;
213 int scaled; 214 int scaled;
214 int i, thread; 215 int i, thread;
@@ -542,6 +543,8 @@ static const struct option options[] = {
542 "null run - dont start any counters"), 543 "null run - dont start any counters"),
543 OPT_BOOLEAN('B', "big-num", &big_num, 544 OPT_BOOLEAN('B', "big-num", &big_num,
544 "print large numbers with thousands\' separators"), 545 "print large numbers with thousands\' separators"),
546 OPT_STRING('C', "cpu", &cpu_list, "cpu",
547 "list of cpus to monitor in system-wide"),
545 OPT_END() 548 OPT_END()
546}; 549};
547 550
@@ -566,10 +569,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
566 } 569 }
567 570
568 if (system_wide) 571 if (system_wide)
569 nr_cpus = read_cpu_map(); 572 nr_cpus = read_cpu_map(cpu_list);
570 else 573 else
571 nr_cpus = 1; 574 nr_cpus = 1;
572 575
576 if (nr_cpus < 1)
577 usage_with_options(stat_usage, options);
578
573 if (target_pid != -1) { 579 if (target_pid != -1) {
574 target_tid = target_pid; 580 target_tid = target_pid;
575 thread_num = find_all_tid(target_pid, &all_tids); 581 thread_num = find_all_tid(target_pid, &all_tids);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index a66f4272b994..1e8e92e317b9 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -102,6 +102,7 @@ struct sym_entry *sym_filter_entry_sched = NULL;
102static int sym_pcnt_filter = 5; 102static int sym_pcnt_filter = 5;
103static int sym_counter = 0; 103static int sym_counter = 0;
104static int display_weighted = -1; 104static int display_weighted = -1;
105static const char *cpu_list;
105 106
106/* 107/*
107 * Symbols 108 * Symbols
@@ -982,6 +983,7 @@ static void event__process_sample(const event_t *self,
982 u64 ip = self->ip.ip; 983 u64 ip = self->ip.ip;
983 struct sym_entry *syme; 984 struct sym_entry *syme;
984 struct addr_location al; 985 struct addr_location al;
986 struct sample_data data;
985 struct machine *machine; 987 struct machine *machine;
986 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 988 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
987 989
@@ -1024,7 +1026,8 @@ static void event__process_sample(const event_t *self,
1024 if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) 1026 if (self->header.misc & PERF_RECORD_MISC_EXACT_IP)
1025 exact_samples++; 1027 exact_samples++;
1026 1028
1027 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || 1029 if (event__preprocess_sample(self, session, &al, &data,
1030 symbol_filter) < 0 ||
1028 al.filtered) 1031 al.filtered)
1029 return; 1032 return;
1030 1033
@@ -1351,8 +1354,8 @@ static const struct option options[] = {
1351 "profile events on existing thread id"), 1354 "profile events on existing thread id"),
1352 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1355 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1353 "system-wide collection from all CPUs"), 1356 "system-wide collection from all CPUs"),
1354 OPT_INTEGER('C', "CPU", &profile_cpu, 1357 OPT_STRING('C', "cpu", &cpu_list, "cpu",
1355 "CPU to profile on"), 1358 "list of cpus to monitor"),
1356 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1359 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1357 "file", "vmlinux pathname"), 1360 "file", "vmlinux pathname"),
1358 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, 1361 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
@@ -1428,10 +1431,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1428 return -ENOMEM; 1431 return -ENOMEM;
1429 1432
1430 /* CPU and PID are mutually exclusive */ 1433 /* CPU and PID are mutually exclusive */
1431 if (target_tid > 0 && profile_cpu != -1) { 1434 if (target_tid > 0 && cpu_list) {
1432 printf("WARNING: PID switch overriding CPU\n"); 1435 printf("WARNING: PID switch overriding CPU\n");
1433 sleep(1); 1436 sleep(1);
1434 profile_cpu = -1; 1437 cpu_list = NULL;
1435 } 1438 }
1436 1439
1437 if (!nr_counters) 1440 if (!nr_counters)
@@ -1469,10 +1472,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1469 attrs[counter].sample_period = default_interval; 1472 attrs[counter].sample_period = default_interval;
1470 } 1473 }
1471 1474
1472 if (target_tid != -1 || profile_cpu != -1) 1475 if (target_tid != -1)
1473 nr_cpus = 1; 1476 nr_cpus = 1;
1474 else 1477 else
1475 nr_cpus = read_cpu_map(); 1478 nr_cpus = read_cpu_map(cpu_list);
1479
1480 if (nr_cpus < 1)
1481 usage_with_options(top_usage, options);
1476 1482
1477 get_term_dimensions(&winsize); 1483 get_term_dimensions(&winsize);
1478 if (print_entries == 0) { 1484 if (print_entries == 0) {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index dddf3f01b5ab..294da725a57d 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -11,8 +11,9 @@
11 11
12static char const *script_name; 12static char const *script_name;
13static char const *generate_script_lang; 13static char const *generate_script_lang;
14static bool debug_ordering; 14static bool debug_mode;
15static u64 last_timestamp; 15static u64 last_timestamp;
16static u64 nr_unordered;
16 17
17static int default_start_script(const char *script __unused, 18static int default_start_script(const char *script __unused,
18 int argc __unused, 19 int argc __unused,
@@ -91,13 +92,15 @@ static int process_sample_event(event_t *event, struct perf_session *session)
91 } 92 }
92 93
93 if (session->sample_type & PERF_SAMPLE_RAW) { 94 if (session->sample_type & PERF_SAMPLE_RAW) {
94 if (debug_ordering) { 95 if (debug_mode) {
95 if (data.time < last_timestamp) { 96 if (data.time < last_timestamp) {
96 pr_err("Samples misordered, previous: %llu " 97 pr_err("Samples misordered, previous: %llu "
97 "this: %llu\n", last_timestamp, 98 "this: %llu\n", last_timestamp,
98 data.time); 99 data.time);
100 nr_unordered++;
99 } 101 }
100 last_timestamp = data.time; 102 last_timestamp = data.time;
103 return 0;
101 } 104 }
102 /* 105 /*
103 * FIXME: better resolve from pid from the struct trace_entry 106 * FIXME: better resolve from pid from the struct trace_entry
@@ -113,6 +116,15 @@ static int process_sample_event(event_t *event, struct perf_session *session)
113 return 0; 116 return 0;
114} 117}
115 118
119static u64 nr_lost;
120
121static int process_lost_event(event_t *event, struct perf_session *session __used)
122{
123 nr_lost += event->lost.lost;
124
125 return 0;
126}
127
116static struct perf_event_ops event_ops = { 128static struct perf_event_ops event_ops = {
117 .sample = process_sample_event, 129 .sample = process_sample_event,
118 .comm = event__process_comm, 130 .comm = event__process_comm,
@@ -120,6 +132,7 @@ static struct perf_event_ops event_ops = {
120 .event_type = event__process_event_type, 132 .event_type = event__process_event_type,
121 .tracing_data = event__process_tracing_data, 133 .tracing_data = event__process_tracing_data,
122 .build_id = event__process_build_id, 134 .build_id = event__process_build_id,
135 .lost = process_lost_event,
123 .ordered_samples = true, 136 .ordered_samples = true,
124}; 137};
125 138
@@ -132,9 +145,18 @@ static void sig_handler(int sig __unused)
132 145
133static int __cmd_trace(struct perf_session *session) 146static int __cmd_trace(struct perf_session *session)
134{ 147{
148 int ret;
149
135 signal(SIGINT, sig_handler); 150 signal(SIGINT, sig_handler);
136 151
137 return perf_session__process_events(session, &event_ops); 152 ret = perf_session__process_events(session, &event_ops);
153
154 if (debug_mode) {
155 pr_err("Misordered timestamps: %llu\n", nr_unordered);
156 pr_err("Lost events: %llu\n", nr_lost);
157 }
158
159 return ret;
138} 160}
139 161
140struct script_spec { 162struct script_spec {
@@ -544,8 +566,8 @@ static const struct option options[] = {
544 "generate perf-trace.xx script in specified language"), 566 "generate perf-trace.xx script in specified language"),
545 OPT_STRING('i', "input", &input_name, "file", 567 OPT_STRING('i', "input", &input_name, "file",
546 "input file name"), 568 "input file name"),
547 OPT_BOOLEAN('d', "debug-ordering", &debug_ordering, 569 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
548 "check that samples time ordering is monotonic"), 570 "do various checks like samples ordering and lost events"),
549 571
550 OPT_END() 572 OPT_END()
551}; 573};
diff --git a/tools/perf/feature-tests.mak b/tools/perf/feature-tests.mak
new file mode 100644
index 000000000000..ddb68e601f0e
--- /dev/null
+++ b/tools/perf/feature-tests.mak
@@ -0,0 +1,119 @@
1define SOURCE_HELLO
2#include <stdio.h>
3int main(void)
4{
5 return puts(\"hi\");
6}
7endef
8
9ifndef NO_DWARF
10define SOURCE_DWARF
11#include <dwarf.h>
12#include <libdw.h>
13#include <version.h>
14#ifndef _ELFUTILS_PREREQ
15#error
16#endif
17
18int main(void)
19{
20 Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
21 return (long)dbg;
22}
23endef
24endif
25
26define SOURCE_LIBELF
27#include <libelf.h>
28
29int main(void)
30{
31 Elf *elf = elf_begin(0, ELF_C_READ, 0);
32 return (long)elf;
33}
34endef
35
36define SOURCE_GLIBC
37#include <gnu/libc-version.h>
38
39int main(void)
40{
41 const char *version = gnu_get_libc_version();
42 return (long)version;
43}
44endef
45
46define SOURCE_ELF_MMAP
47#include <libelf.h>
48int main(void)
49{
50 Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0);
51 return (long)elf;
52}
53endef
54
55ifndef NO_NEWT
56define SOURCE_NEWT
57#include <newt.h>
58
59int main(void)
60{
61 newtInit();
62 newtCls();
63 return newtFinished();
64}
65endef
66endif
67
68ifndef NO_LIBPERL
69define SOURCE_PERL_EMBED
70#include <EXTERN.h>
71#include <perl.h>
72
73int main(void)
74{
75perl_alloc();
76return 0;
77}
78endef
79endif
80
81ifndef NO_LIBPYTHON
82define SOURCE_PYTHON_EMBED
83#include <Python.h>
84
85int main(void)
86{
87 Py_Initialize();
88 return 0;
89}
90endef
91endif
92
93define SOURCE_BFD
94#include <bfd.h>
95
96int main(void)
97{
98 bfd_demangle(0, 0, 0);
99 return 0;
100}
101endef
102
103define SOURCE_CPLUS_DEMANGLE
104extern char *cplus_demangle(const char *, int);
105
106int main(void)
107{
108 cplus_demangle(0, 0);
109 return 0;
110}
111endef
112
113# try-cc
114# Usage: option = $(call try-cc, source-to-build, cc-options)
115try-cc = $(shell sh -c \
116 'TMP="$(TMPOUT).$$$$"; \
117 echo "$(1)" | \
118 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
119 rm -f "$$TMP"')
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh
index 2e7a4f417e20..677e59d62a8d 100644
--- a/tools/perf/perf-archive.sh
+++ b/tools/perf/perf-archive.sh
@@ -7,7 +7,17 @@ if [ $# -ne 0 ] ; then
7 PERF_DATA=$1 7 PERF_DATA=$1
8fi 8fi
9 9
10DEBUGDIR=~/.debug/ 10#
11# PERF_BUILDID_DIR environment variable set by perf
12# path to buildid directory, default to $HOME/.debug
13#
14if [ -z $PERF_BUILDID_DIR ]; then
15 PERF_BUILDID_DIR=~/.debug/
16else
17 # append / to make substitutions work
18 PERF_BUILDID_DIR=$PERF_BUILDID_DIR/
19fi
20
11BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX) 21BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX)
12NOBUILDID=0000000000000000000000000000000000000000 22NOBUILDID=0000000000000000000000000000000000000000
13 23
@@ -22,13 +32,13 @@ MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX)
22 32
23cut -d ' ' -f 1 $BUILDIDS | \ 33cut -d ' ' -f 1 $BUILDIDS | \
24while read build_id ; do 34while read build_id ; do
25 linkname=$DEBUGDIR.build-id/${build_id:0:2}/${build_id:2} 35 linkname=$PERF_BUILDID_DIR.build-id/${build_id:0:2}/${build_id:2}
26 filename=$(readlink -f $linkname) 36 filename=$(readlink -f $linkname)
27 echo ${linkname#$DEBUGDIR} >> $MANIFEST 37 echo ${linkname#$PERF_BUILDID_DIR} >> $MANIFEST
28 echo ${filename#$DEBUGDIR} >> $MANIFEST 38 echo ${filename#$PERF_BUILDID_DIR} >> $MANIFEST
29done 39done
30 40
31tar cfj $PERF_DATA.tar.bz2 -C $DEBUGDIR -T $MANIFEST 41tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
32rm -f $MANIFEST $BUILDIDS 42rm -f $MANIFEST $BUILDIDS
33echo -e "Now please run:\n" 43echo -e "Now please run:\n"
34echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n" 44echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n"
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 6e4871191138..cdd6c03f1e14 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -458,6 +458,8 @@ int main(int argc, const char **argv)
458 handle_options(&argv, &argc, NULL); 458 handle_options(&argv, &argc, NULL);
459 commit_pager_choice(); 459 commit_pager_choice();
460 set_debugfs_path(); 460 set_debugfs_path();
461 set_buildid_dir();
462
461 if (argc > 0) { 463 if (argc > 0) {
462 if (!prefixcmp(argv[0], "--")) 464 if (!prefixcmp(argv[0], "--"))
463 argv[0] += 2; 465 argv[0] += 2;
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 70c5cf87d020..5c26e2d314af 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -43,19 +43,17 @@ struct perf_event_ops build_id__mark_dso_hit_ops = {
43char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 43char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
44{ 44{
45 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 45 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
46 const char *home;
47 46
48 if (!self->has_build_id) 47 if (!self->has_build_id)
49 return NULL; 48 return NULL;
50 49
51 build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex); 50 build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex);
52 home = getenv("HOME");
53 if (bf == NULL) { 51 if (bf == NULL) {
54 if (asprintf(&bf, "%s/%s/.build-id/%.2s/%s", home, 52 if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir,
55 DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2) < 0) 53 build_id_hex, build_id_hex + 2) < 0)
56 return NULL; 54 return NULL;
57 } else 55 } else
58 snprintf(bf, size, "%s/%s/.build-id/%.2s/%s", home, 56 snprintf(bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
59 DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2); 57 build_id_hex, build_id_hex + 2);
60 return bf; 58 return bf;
61} 59}
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 65fe664fddf6..27e9ebe4076e 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -23,6 +23,7 @@ extern int perf_config(config_fn_t fn, void *);
23extern int perf_config_int(const char *, const char *); 23extern int perf_config_int(const char *, const char *);
24extern int perf_config_bool(const char *, const char *); 24extern int perf_config_bool(const char *, const char *);
25extern int config_error_nonbool(const char *); 25extern int config_error_nonbool(const char *);
26extern const char *perf_config_dirname(const char *, const char *);
26 27
27/* pager.c */ 28/* pager.c */
28extern void setup_pager(void); 29extern void setup_pager(void);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 52c777e451ed..f231f43424d2 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -18,7 +18,7 @@
18#include "util.h" 18#include "util.h"
19#include "callchain.h" 19#include "callchain.h"
20 20
21bool ip_callchain__valid(struct ip_callchain *chain, event_t *event) 21bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
22{ 22{
23 unsigned int chain_size = event->header.size; 23 unsigned int chain_size = event->header.size;
24 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; 24 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index f2e9ee164bd8..624a96c636fd 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -63,5 +63,5 @@ int register_callchain_param(struct callchain_param *param);
63int append_chain(struct callchain_node *root, struct ip_callchain *chain, 63int append_chain(struct callchain_node *root, struct ip_callchain *chain,
64 struct map_symbol *syms, u64 period); 64 struct map_symbol *syms, u64 period);
65 65
66bool ip_callchain__valid(struct ip_callchain *chain, event_t *event); 66bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
67#endif /* __PERF_CALLCHAIN_H */ 67#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index dabe892d0e53..e02d78cae70f 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -11,6 +11,11 @@
11 11
12#define MAXNAME (256) 12#define MAXNAME (256)
13 13
14#define DEBUG_CACHE_DIR ".debug"
15
16
17char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
18
14static FILE *config_file; 19static FILE *config_file;
15static const char *config_file_name; 20static const char *config_file_name;
16static int config_linenr; 21static int config_linenr;
@@ -127,7 +132,7 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
127 break; 132 break;
128 if (!iskeychar(c)) 133 if (!iskeychar(c))
129 break; 134 break;
130 name[len++] = tolower(c); 135 name[len++] = c;
131 if (len >= MAXNAME) 136 if (len >= MAXNAME)
132 return -1; 137 return -1;
133 } 138 }
@@ -327,6 +332,13 @@ int perf_config_bool(const char *name, const char *value)
327 return !!perf_config_bool_or_int(name, value, &discard); 332 return !!perf_config_bool_or_int(name, value, &discard);
328} 333}
329 334
335const char *perf_config_dirname(const char *name, const char *value)
336{
337 if (!name)
338 return NULL;
339 return value;
340}
341
330static int perf_default_core_config(const char *var __used, const char *value __used) 342static int perf_default_core_config(const char *var __used, const char *value __used)
331{ 343{
332 /* Add other config variables here and to Documentation/config.txt. */ 344 /* Add other config variables here and to Documentation/config.txt. */
@@ -428,3 +440,53 @@ int config_error_nonbool(const char *var)
428{ 440{
429 return error("Missing value for '%s'", var); 441 return error("Missing value for '%s'", var);
430} 442}
443
444struct buildid_dir_config {
445 char *dir;
446};
447
448static int buildid_dir_command_config(const char *var, const char *value,
449 void *data)
450{
451 struct buildid_dir_config *c = data;
452 const char *v;
453
454 /* same dir for all commands */
455 if (!prefixcmp(var, "buildid.") && !strcmp(var + 8, "dir")) {
456 v = perf_config_dirname(var, value);
457 if (!v)
458 return -1;
459 strncpy(c->dir, v, MAXPATHLEN-1);
460 c->dir[MAXPATHLEN-1] = '\0';
461 }
462 return 0;
463}
464
465static void check_buildid_dir_config(void)
466{
467 struct buildid_dir_config c;
468 c.dir = buildid_dir;
469 perf_config(buildid_dir_command_config, &c);
470}
471
472void set_buildid_dir(void)
473{
474 buildid_dir[0] = '\0';
475
476 /* try config file */
477 check_buildid_dir_config();
478
479 /* default to $HOME/.debug */
480 if (buildid_dir[0] == '\0') {
481 char *v = getenv("HOME");
482 if (v) {
483 snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s",
484 v, DEBUG_CACHE_DIR);
485 } else {
486 strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
487 }
488 buildid_dir[MAXPATHLEN-1] = '\0';
489 }
490 /* for communicating with external commands */
491 setenv("PERF_BUILDID_DIR", buildid_dir, 1);
492}
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 4e01490e51e5..0f9b8d7a7d7e 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -20,7 +20,7 @@ static int default_cpu_map(void)
20 return nr_cpus; 20 return nr_cpus;
21} 21}
22 22
23int read_cpu_map(void) 23static int read_all_cpu_map(void)
24{ 24{
25 FILE *onlnf; 25 FILE *onlnf;
26 int nr_cpus = 0; 26 int nr_cpus = 0;
@@ -57,3 +57,58 @@ int read_cpu_map(void)
57 57
58 return default_cpu_map(); 58 return default_cpu_map();
59} 59}
60
61int read_cpu_map(const char *cpu_list)
62{
63 unsigned long start_cpu, end_cpu = 0;
64 char *p = NULL;
65 int i, nr_cpus = 0;
66
67 if (!cpu_list)
68 return read_all_cpu_map();
69
70 if (!isdigit(*cpu_list))
71 goto invalid;
72
73 while (isdigit(*cpu_list)) {
74 p = NULL;
75 start_cpu = strtoul(cpu_list, &p, 0);
76 if (start_cpu >= INT_MAX
77 || (*p != '\0' && *p != ',' && *p != '-'))
78 goto invalid;
79
80 if (*p == '-') {
81 cpu_list = ++p;
82 p = NULL;
83 end_cpu = strtoul(cpu_list, &p, 0);
84
85 if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
86 goto invalid;
87
88 if (end_cpu < start_cpu)
89 goto invalid;
90 } else {
91 end_cpu = start_cpu;
92 }
93
94 for (; start_cpu <= end_cpu; start_cpu++) {
95 /* check for duplicates */
96 for (i = 0; i < nr_cpus; i++)
97 if (cpumap[i] == (int)start_cpu)
98 goto invalid;
99
100 assert(nr_cpus < MAX_NR_CPUS);
101 cpumap[nr_cpus++] = (int)start_cpu;
102 }
103 if (*p)
104 ++p;
105
106 cpu_list = p;
107 }
108 if (nr_cpus > 0)
109 return nr_cpus;
110
111 return default_cpu_map();
112invalid:
113 return -1;
114}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 86c78bb33098..3e60f56e490e 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_CPUMAP_H 1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H 2#define __PERF_CPUMAP_H
3 3
4extern int read_cpu_map(void); 4extern int read_cpu_map(const char *cpu_list);
5extern int cpumap[]; 5extern int cpumap[];
6 6
7#endif /* __PERF_CPUMAP_H */ 7#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 6cddff2bc970..318dab15d177 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -86,12 +86,10 @@ void trace_event(event_t *event)
86 dump_printf_color(" ", color); 86 dump_printf_color(" ", color);
87 for (j = 0; j < 15-(i & 15); j++) 87 for (j = 0; j < 15-(i & 15); j++)
88 dump_printf_color(" ", color); 88 dump_printf_color(" ", color);
89 for (j = 0; j < (i & 15); j++) { 89 for (j = i & ~15; j <= i; j++) {
90 if (isprint(raw_event[i-15+j])) 90 dump_printf_color("%c", color,
91 dump_printf_color("%c", color, 91 isprint(raw_event[j]) ?
92 raw_event[i-15+j]); 92 raw_event[j] : '.');
93 else
94 dump_printf_color(".", color);
95 } 93 }
96 dump_printf_color("\n", color); 94 dump_printf_color("\n", color);
97 } 95 }
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 2fbf6a463c81..d7f21d71eb69 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -657,11 +657,36 @@ static void dso__calc_col_width(struct dso *self)
657} 657}
658 658
659int event__preprocess_sample(const event_t *self, struct perf_session *session, 659int event__preprocess_sample(const event_t *self, struct perf_session *session,
660 struct addr_location *al, symbol_filter_t filter) 660 struct addr_location *al, struct sample_data *data,
661 symbol_filter_t filter)
661{ 662{
662 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 663 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
663 struct thread *thread = perf_session__findnew(session, self->ip.pid); 664 struct thread *thread;
665
666 event__parse_sample(self, session->sample_type, data);
667
668 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld cpu:%d\n",
669 self->header.misc, data->pid, data->tid, data->ip,
670 data->period, data->cpu);
671
672 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
673 unsigned int i;
674
675 dump_printf("... chain: nr:%Lu\n", data->callchain->nr);
676
677 if (!ip_callchain__valid(data->callchain, self)) {
678 pr_debug("call-chain problem with event, "
679 "skipping it.\n");
680 goto out_filtered;
681 }
664 682
683 if (dump_trace) {
684 for (i = 0; i < data->callchain->nr; i++)
685 dump_printf("..... %2d: %016Lx\n",
686 i, data->callchain->ips[i]);
687 }
688 }
689 thread = perf_session__findnew(session, self->ip.pid);
665 if (thread == NULL) 690 if (thread == NULL)
666 return -1; 691 return -1;
667 692
@@ -687,6 +712,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
687 al->map ? al->map->dso->long_name : 712 al->map ? al->map->dso->long_name :
688 al->level == 'H' ? "[hypervisor]" : "<not found>"); 713 al->level == 'H' ? "[hypervisor]" : "<not found>");
689 al->sym = NULL; 714 al->sym = NULL;
715 al->cpu = data->cpu;
690 716
691 if (al->map) { 717 if (al->map) {
692 if (symbol_conf.dso_list && 718 if (symbol_conf.dso_list &&
@@ -726,9 +752,9 @@ out_filtered:
726 return 0; 752 return 0;
727} 753}
728 754
729int event__parse_sample(event_t *event, u64 type, struct sample_data *data) 755int event__parse_sample(const event_t *event, u64 type, struct sample_data *data)
730{ 756{
731 u64 *array = event->sample.array; 757 const u64 *array = event->sample.array;
732 758
733 if (type & PERF_SAMPLE_IP) { 759 if (type & PERF_SAMPLE_IP) {
734 data->ip = event->ip.ip; 760 data->ip = event->ip.ip;
@@ -767,7 +793,8 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
767 u32 *p = (u32 *)array; 793 u32 *p = (u32 *)array;
768 data->cpu = *p; 794 data->cpu = *p;
769 array++; 795 array++;
770 } 796 } else
797 data->cpu = -1;
771 798
772 if (type & PERF_SAMPLE_PERIOD) { 799 if (type & PERF_SAMPLE_PERIOD) {
773 data->period = *array; 800 data->period = *array;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 8577085db067..887ee63bbb62 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -157,8 +157,9 @@ int event__process_task(event_t *self, struct perf_session *session);
157 157
158struct addr_location; 158struct addr_location;
159int event__preprocess_sample(const event_t *self, struct perf_session *session, 159int event__preprocess_sample(const event_t *self, struct perf_session *session,
160 struct addr_location *al, symbol_filter_t filter); 160 struct addr_location *al, struct sample_data *data,
161int event__parse_sample(event_t *event, u64 type, struct sample_data *data); 161 symbol_filter_t filter);
162int event__parse_sample(const event_t *event, u64 type, struct sample_data *data);
162 163
163extern const char *event__name[]; 164extern const char *event__name[];
164 165
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1f62435f96c2..d7e67b167ea3 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -16,6 +16,8 @@
16#include "symbol.h" 16#include "symbol.h"
17#include "debug.h" 17#include "debug.h"
18 18
19static bool no_buildid_cache = false;
20
19/* 21/*
20 * Create new perf.data header attribute: 22 * Create new perf.data header attribute:
21 */ 23 */
@@ -385,8 +387,7 @@ static int perf_session__cache_build_ids(struct perf_session *self)
385 int ret; 387 int ret;
386 char debugdir[PATH_MAX]; 388 char debugdir[PATH_MAX];
387 389
388 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), 390 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
389 DEBUG_CACHE_DIR);
390 391
391 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) 392 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
392 return -1; 393 return -1;
@@ -471,7 +472,8 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
471 } 472 }
472 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - 473 buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
473 buildid_sec->offset; 474 buildid_sec->offset;
474 perf_session__cache_build_ids(session); 475 if (!no_buildid_cache)
476 perf_session__cache_build_ids(session);
475 } 477 }
476 478
477 lseek(fd, sec_start, SEEK_SET); 479 lseek(fd, sec_start, SEEK_SET);
@@ -1190,3 +1192,8 @@ int event__process_build_id(event_t *self,
1190 session); 1192 session);
1191 return 0; 1193 return 0;
1192} 1194}
1195
1196void disable_buildid_cache(void)
1197{
1198 no_buildid_cache = true;
1199}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 07f89b66b318..7b5848ce1505 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -70,6 +70,7 @@ struct hist_entry *__hists__add_entry(struct hists *self,
70 .map = al->map, 70 .map = al->map,
71 .sym = al->sym, 71 .sym = al->sym,
72 }, 72 },
73 .cpu = al->cpu,
73 .ip = al->addr, 74 .ip = al->addr,
74 .level = al->level, 75 .level = al->level,
75 .period = period, 76 .period = period,
@@ -794,6 +795,21 @@ enum hist_filter {
794 HIST_FILTER__THREAD, 795 HIST_FILTER__THREAD,
795}; 796};
796 797
798static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
799 enum hist_filter filter)
800{
801 h->filtered &= ~(1 << filter);
802 if (h->filtered)
803 return;
804
805 ++self->nr_entries;
806 self->stats.total_period += h->period;
807 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
808
809 if (h->ms.sym && self->max_sym_namelen < h->ms.sym->namelen)
810 self->max_sym_namelen = h->ms.sym->namelen;
811}
812
797void hists__filter_by_dso(struct hists *self, const struct dso *dso) 813void hists__filter_by_dso(struct hists *self, const struct dso *dso)
798{ 814{
799 struct rb_node *nd; 815 struct rb_node *nd;
@@ -813,15 +829,7 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
813 continue; 829 continue;
814 } 830 }
815 831
816 h->filtered &= ~(1 << HIST_FILTER__DSO); 832 hists__remove_entry_filter(self, h, HIST_FILTER__DSO);
817 if (!h->filtered) {
818 ++self->nr_entries;
819 self->stats.total_period += h->period;
820 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
821 if (h->ms.sym &&
822 self->max_sym_namelen < h->ms.sym->namelen)
823 self->max_sym_namelen = h->ms.sym->namelen;
824 }
825 } 833 }
826} 834}
827 835
@@ -840,15 +848,8 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
840 h->filtered |= (1 << HIST_FILTER__THREAD); 848 h->filtered |= (1 << HIST_FILTER__THREAD);
841 continue; 849 continue;
842 } 850 }
843 h->filtered &= ~(1 << HIST_FILTER__THREAD); 851
844 if (!h->filtered) { 852 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD);
845 ++self->nr_entries;
846 self->stats.total_period += h->period;
847 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
848 if (h->ms.sym &&
849 self->max_sym_namelen < h->ms.sym->namelen)
850 self->max_sym_namelen = h->ms.sym->namelen;
851 }
852 } 853 }
853} 854}
854 855
@@ -1037,7 +1038,7 @@ fallback:
1037 dso, dso->long_name, sym, sym->name); 1038 dso, dso->long_name, sym, sym->name);
1038 1039
1039 snprintf(command, sizeof(command), 1040 snprintf(command, sizeof(command),
1040 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s|expand", 1041 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
1041 map__rip_2objdump(map, sym->start), 1042 map__rip_2objdump(map, sym->start),
1042 map__rip_2objdump(map, sym->end), 1043 map__rip_2objdump(map, sym->end),
1043 filename, filename); 1044 filename, filename);
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
index 7537ca15900b..7979003adeaf 100644
--- a/tools/perf/util/newt.c
+++ b/tools/perf/util/newt.c
@@ -278,9 +278,48 @@ struct ui_browser {
278 void *first_visible_entry, *entries; 278 void *first_visible_entry, *entries;
279 u16 top, left, width, height; 279 u16 top, left, width, height;
280 void *priv; 280 void *priv;
281 unsigned int (*refresh_entries)(struct ui_browser *self);
282 void (*seek)(struct ui_browser *self,
283 off_t offset, int whence);
281 u32 nr_entries; 284 u32 nr_entries;
282}; 285};
283 286
287static void ui_browser__list_head_seek(struct ui_browser *self,
288 off_t offset, int whence)
289{
290 struct list_head *head = self->entries;
291 struct list_head *pos;
292
293 switch (whence) {
294 case SEEK_SET:
295 pos = head->next;
296 break;
297 case SEEK_CUR:
298 pos = self->first_visible_entry;
299 break;
300 case SEEK_END:
301 pos = head->prev;
302 break;
303 default:
304 return;
305 }
306
307 if (offset > 0) {
308 while (offset-- != 0)
309 pos = pos->next;
310 } else {
311 while (offset++ != 0)
312 pos = pos->prev;
313 }
314
315 self->first_visible_entry = pos;
316}
317
318static bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
319{
320 return (self->first_visible_entry_idx + row) == self->index;
321}
322
284static void ui_browser__refresh_dimensions(struct ui_browser *self) 323static void ui_browser__refresh_dimensions(struct ui_browser *self)
285{ 324{
286 int cols, rows; 325 int cols, rows;
@@ -297,8 +336,34 @@ static void ui_browser__refresh_dimensions(struct ui_browser *self)
297 336
298static void ui_browser__reset_index(struct ui_browser *self) 337static void ui_browser__reset_index(struct ui_browser *self)
299{ 338{
300 self->index = self->first_visible_entry_idx = 0; 339 self->index = self->first_visible_entry_idx = 0;
301 self->first_visible_entry = NULL; 340 self->seek(self, 0, SEEK_SET);
341}
342
343static int ui_browser__show(struct ui_browser *self, const char *title)
344{
345 if (self->form != NULL)
346 return 0;
347 ui_browser__refresh_dimensions(self);
348 newtCenteredWindow(self->width + 2, self->height, title);
349 self->form = newt_form__new();
350 if (self->form == NULL)
351 return -1;
352
353 self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height,
354 HE_COLORSET_NORMAL,
355 HE_COLORSET_SELECTED);
356 if (self->sb == NULL)
357 return -1;
358
359 newtFormAddHotKey(self->form, NEWT_KEY_UP);
360 newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
361 newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
362 newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
363 newtFormAddHotKey(self->form, NEWT_KEY_HOME);
364 newtFormAddHotKey(self->form, NEWT_KEY_END);
365 newtFormAddComponent(self->form, self->sb);
366 return 0;
302} 367}
303 368
304static int objdump_line__show(struct objdump_line *self, struct list_head *head, 369static int objdump_line__show(struct objdump_line *self, struct list_head *head,
@@ -352,26 +417,10 @@ static int objdump_line__show(struct objdump_line *self, struct list_head *head,
352 417
353static int ui_browser__refresh_entries(struct ui_browser *self) 418static int ui_browser__refresh_entries(struct ui_browser *self)
354{ 419{
355 struct objdump_line *pos; 420 int row;
356 struct list_head *head = self->entries;
357 struct hist_entry *he = self->priv;
358 int row = 0;
359 int len = he->ms.sym->end - he->ms.sym->start;
360
361 if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries)
362 self->first_visible_entry = head->next;
363
364 pos = list_entry(self->first_visible_entry, struct objdump_line, node);
365
366 list_for_each_entry_from(pos, head, node) {
367 bool current_entry = (self->first_visible_entry_idx + row) == self->index;
368 SLsmg_gotorc(self->top + row, self->left);
369 objdump_line__show(pos, head, self->width,
370 he, len, current_entry);
371 if (++row == self->height)
372 break;
373 }
374 421
422 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
423 row = self->refresh_entries(self);
375 SLsmg_set_color(HE_COLORSET_NORMAL); 424 SLsmg_set_color(HE_COLORSET_NORMAL);
376 SLsmg_fill_region(self->top + row, self->left, 425 SLsmg_fill_region(self->top + row, self->left,
377 self->height - row, self->width, ' '); 426 self->height - row, self->width, ' ');
@@ -379,42 +428,13 @@ static int ui_browser__refresh_entries(struct ui_browser *self)
379 return 0; 428 return 0;
380} 429}
381 430
382static int ui_browser__run(struct ui_browser *self, const char *title, 431static int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es)
383 struct newtExitStruct *es)
384{ 432{
385 if (self->form) {
386 newtFormDestroy(self->form);
387 newtPopWindow();
388 }
389
390 ui_browser__refresh_dimensions(self);
391 newtCenteredWindow(self->width + 2, self->height, title);
392 self->form = newt_form__new();
393 if (self->form == NULL)
394 return -1;
395
396 self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height,
397 HE_COLORSET_NORMAL,
398 HE_COLORSET_SELECTED);
399 if (self->sb == NULL)
400 return -1;
401
402 newtFormAddHotKey(self->form, NEWT_KEY_UP);
403 newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
404 newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
405 newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
406 newtFormAddHotKey(self->form, ' ');
407 newtFormAddHotKey(self->form, NEWT_KEY_HOME);
408 newtFormAddHotKey(self->form, NEWT_KEY_END);
409 newtFormAddHotKey(self->form, NEWT_KEY_TAB);
410 newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
411
412 if (ui_browser__refresh_entries(self) < 0) 433 if (ui_browser__refresh_entries(self) < 0)
413 return -1; 434 return -1;
414 newtFormAddComponent(self->form, self->sb);
415 435
416 while (1) { 436 while (1) {
417 unsigned int offset; 437 off_t offset;
418 438
419 newtFormRun(self->form, es); 439 newtFormRun(self->form, es);
420 440
@@ -428,9 +448,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
428 break; 448 break;
429 ++self->index; 449 ++self->index;
430 if (self->index == self->first_visible_entry_idx + self->height) { 450 if (self->index == self->first_visible_entry_idx + self->height) {
431 struct list_head *pos = self->first_visible_entry;
432 ++self->first_visible_entry_idx; 451 ++self->first_visible_entry_idx;
433 self->first_visible_entry = pos->next; 452 self->seek(self, +1, SEEK_CUR);
434 } 453 }
435 break; 454 break;
436 case NEWT_KEY_UP: 455 case NEWT_KEY_UP:
@@ -438,9 +457,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
438 break; 457 break;
439 --self->index; 458 --self->index;
440 if (self->index < self->first_visible_entry_idx) { 459 if (self->index < self->first_visible_entry_idx) {
441 struct list_head *pos = self->first_visible_entry;
442 --self->first_visible_entry_idx; 460 --self->first_visible_entry_idx;
443 self->first_visible_entry = pos->prev; 461 self->seek(self, -1, SEEK_CUR);
444 } 462 }
445 break; 463 break;
446 case NEWT_KEY_PGDN: 464 case NEWT_KEY_PGDN:
@@ -453,12 +471,7 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
453 offset = self->nr_entries - 1 - self->index; 471 offset = self->nr_entries - 1 - self->index;
454 self->index += offset; 472 self->index += offset;
455 self->first_visible_entry_idx += offset; 473 self->first_visible_entry_idx += offset;
456 474 self->seek(self, +offset, SEEK_CUR);
457 while (offset--) {
458 struct list_head *pos = self->first_visible_entry;
459 self->first_visible_entry = pos->next;
460 }
461
462 break; 475 break;
463 case NEWT_KEY_PGUP: 476 case NEWT_KEY_PGUP:
464 if (self->first_visible_entry_idx == 0) 477 if (self->first_visible_entry_idx == 0)
@@ -471,36 +484,22 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
471 484
472 self->index -= offset; 485 self->index -= offset;
473 self->first_visible_entry_idx -= offset; 486 self->first_visible_entry_idx -= offset;
474 487 self->seek(self, -offset, SEEK_CUR);
475 while (offset--) {
476 struct list_head *pos = self->first_visible_entry;
477 self->first_visible_entry = pos->prev;
478 }
479 break; 488 break;
480 case NEWT_KEY_HOME: 489 case NEWT_KEY_HOME:
481 ui_browser__reset_index(self); 490 ui_browser__reset_index(self);
482 break; 491 break;
483 case NEWT_KEY_END: { 492 case NEWT_KEY_END:
484 struct list_head *head = self->entries;
485 offset = self->height - 1; 493 offset = self->height - 1;
494 if (offset >= self->nr_entries)
495 offset = self->nr_entries - 1;
486 496
487 if (offset > self->nr_entries) 497 self->index = self->nr_entries - 1;
488 offset = self->nr_entries; 498 self->first_visible_entry_idx = self->index - offset;
489 499 self->seek(self, -offset, SEEK_END);
490 self->index = self->first_visible_entry_idx = self->nr_entries - 1 - offset;
491 self->first_visible_entry = head->prev;
492 while (offset-- != 0) {
493 struct list_head *pos = self->first_visible_entry;
494 self->first_visible_entry = pos->prev;
495 }
496 }
497 break; 500 break;
498 case NEWT_KEY_RIGHT:
499 case NEWT_KEY_LEFT:
500 case NEWT_KEY_TAB:
501 return es->u.key;
502 default: 501 default:
503 continue; 502 return es->u.key;
504 } 503 }
505 if (ui_browser__refresh_entries(self) < 0) 504 if (ui_browser__refresh_entries(self) < 0)
506 return -1; 505 return -1;
@@ -550,6 +549,31 @@ static char *callchain_list__sym_name(struct callchain_list *self,
550 return bf; 549 return bf;
551} 550}
552 551
552static unsigned int hist_entry__annotate_browser_refresh(struct ui_browser *self)
553{
554 struct objdump_line *pos;
555 struct list_head *head = self->entries;
556 struct hist_entry *he = self->priv;
557 int row = 0;
558 int len = he->ms.sym->end - he->ms.sym->start;
559
560 if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries)
561 self->first_visible_entry = head->next;
562
563 pos = list_entry(self->first_visible_entry, struct objdump_line, node);
564
565 list_for_each_entry_from(pos, head, node) {
566 bool current_entry = ui_browser__is_current_entry(self, row);
567 SLsmg_gotorc(self->top + row, self->left);
568 objdump_line__show(pos, head, self->width,
569 he, len, current_entry);
570 if (++row == self->height)
571 break;
572 }
573
574 return row;
575}
576
553static void __callchain__append_graph_browser(struct callchain_node *self, 577static void __callchain__append_graph_browser(struct callchain_node *self,
554 newtComponent tree, u64 total, 578 newtComponent tree, u64 total,
555 int *indexes, int depth) 579 int *indexes, int depth)
@@ -712,7 +736,9 @@ int hist_entry__tui_annotate(struct hist_entry *self)
712 ui_helpline__push("Press <- or ESC to exit"); 736 ui_helpline__push("Press <- or ESC to exit");
713 737
714 memset(&browser, 0, sizeof(browser)); 738 memset(&browser, 0, sizeof(browser));
715 browser.entries = &head; 739 browser.entries = &head;
740 browser.refresh_entries = hist_entry__annotate_browser_refresh;
741 browser.seek = ui_browser__list_head_seek;
716 browser.priv = self; 742 browser.priv = self;
717 list_for_each_entry(pos, &head, node) { 743 list_for_each_entry(pos, &head, node) {
718 size_t line_len = strlen(pos->line); 744 size_t line_len = strlen(pos->line);
@@ -722,7 +748,8 @@ int hist_entry__tui_annotate(struct hist_entry *self)
722 } 748 }
723 749
724 browser.width += 18; /* Percentage */ 750 browser.width += 18; /* Percentage */
725 ret = ui_browser__run(&browser, self->ms.sym->name, &es); 751 ui_browser__show(&browser, self->ms.sym->name);
752 ret = ui_browser__run(&browser, &es);
726 newtFormDestroy(browser.form); 753 newtFormDestroy(browser.form);
727 newtPopWindow(); 754 newtPopWindow();
728 list_for_each_entry_safe(pos, n, &head, node) { 755 list_for_each_entry_safe(pos, n, &head, node) {
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 9bf0f402ca73..4af5bd59cfd1 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -602,8 +602,15 @@ parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
602 return EVT_FAILED; 602 return EVT_FAILED;
603 } 603 }
604 604
605 /* We should find a nice way to override the access type */ 605 /*
606 attr->bp_len = HW_BREAKPOINT_LEN_4; 606 * We should find a nice way to override the access length
607 * Provide some defaults for now
608 */
609 if (attr->bp_type == HW_BREAKPOINT_X)
610 attr->bp_len = sizeof(long);
611 else
612 attr->bp_len = HW_BREAKPOINT_LEN_4;
613
607 attr->type = PERF_TYPE_BREAKPOINT; 614 attr->type = PERF_TYPE_BREAKPOINT;
608 615
609 return EVT_HANDLED; 616 return EVT_HANDLED;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 914c67095d96..4445a1e7052f 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -195,6 +195,65 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
195 return ntevs; 195 return ntevs;
196} 196}
197 197
198/*
199 * Find a src file from a DWARF tag path. Prepend optional source path prefix
200 * and chop off leading directories that do not exist. Result is passed back as
201 * a newly allocated path on success.
202 * Return 0 if file was found and readable, -errno otherwise.
203 */
204static int get_real_path(const char *raw_path, const char *comp_dir,
205 char **new_path)
206{
207 const char *prefix = symbol_conf.source_prefix;
208
209 if (!prefix) {
210 if (raw_path[0] != '/' && comp_dir)
211 /* If not an absolute path, try to use comp_dir */
212 prefix = comp_dir;
213 else {
214 if (access(raw_path, R_OK) == 0) {
215 *new_path = strdup(raw_path);
216 return 0;
217 } else
218 return -errno;
219 }
220 }
221
222 *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2));
223 if (!*new_path)
224 return -ENOMEM;
225
226 for (;;) {
227 sprintf(*new_path, "%s/%s", prefix, raw_path);
228
229 if (access(*new_path, R_OK) == 0)
230 return 0;
231
232 if (!symbol_conf.source_prefix)
233 /* In case of searching comp_dir, don't retry */
234 return -errno;
235
236 switch (errno) {
237 case ENAMETOOLONG:
238 case ENOENT:
239 case EROFS:
240 case EFAULT:
241 raw_path = strchr(++raw_path, '/');
242 if (!raw_path) {
243 free(*new_path);
244 *new_path = NULL;
245 return -ENOENT;
246 }
247 continue;
248
249 default:
250 free(*new_path);
251 *new_path = NULL;
252 return -errno;
253 }
254 }
255}
256
198#define LINEBUF_SIZE 256 257#define LINEBUF_SIZE 256
199#define NR_ADDITIONAL_LINES 2 258#define NR_ADDITIONAL_LINES 2
200 259
@@ -244,6 +303,7 @@ int show_line_range(struct line_range *lr)
244 struct line_node *ln; 303 struct line_node *ln;
245 FILE *fp; 304 FILE *fp;
246 int fd, ret; 305 int fd, ret;
306 char *tmp;
247 307
248 /* Search a line range */ 308 /* Search a line range */
249 ret = init_vmlinux(); 309 ret = init_vmlinux();
@@ -266,6 +326,15 @@ int show_line_range(struct line_range *lr)
266 return ret; 326 return ret;
267 } 327 }
268 328
329 /* Convert source file path */
330 tmp = lr->path;
331 ret = get_real_path(tmp, lr->comp_dir, &lr->path);
332 free(tmp); /* Free old path */
333 if (ret < 0) {
334 pr_warning("Failed to find source file. (%d)\n", ret);
335 return ret;
336 }
337
269 setup_pager(); 338 setup_pager();
270 339
271 if (lr->function) 340 if (lr->function)
@@ -557,7 +626,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
557/* Parse perf-probe event argument */ 626/* Parse perf-probe event argument */
558static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) 627static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
559{ 628{
560 char *tmp; 629 char *tmp, *goodname;
561 struct perf_probe_arg_field **fieldp; 630 struct perf_probe_arg_field **fieldp;
562 631
563 pr_debug("parsing arg: %s into ", str); 632 pr_debug("parsing arg: %s into ", str);
@@ -580,7 +649,7 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
580 pr_debug("type:%s ", arg->type); 649 pr_debug("type:%s ", arg->type);
581 } 650 }
582 651
583 tmp = strpbrk(str, "-."); 652 tmp = strpbrk(str, "-.[");
584 if (!is_c_varname(str) || !tmp) { 653 if (!is_c_varname(str) || !tmp) {
585 /* A variable, register, symbol or special value */ 654 /* A variable, register, symbol or special value */
586 arg->var = strdup(str); 655 arg->var = strdup(str);
@@ -590,10 +659,11 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
590 return 0; 659 return 0;
591 } 660 }
592 661
593 /* Structure fields */ 662 /* Structure fields or array element */
594 arg->var = strndup(str, tmp - str); 663 arg->var = strndup(str, tmp - str);
595 if (arg->var == NULL) 664 if (arg->var == NULL)
596 return -ENOMEM; 665 return -ENOMEM;
666 goodname = arg->var;
597 pr_debug("%s, ", arg->var); 667 pr_debug("%s, ", arg->var);
598 fieldp = &arg->field; 668 fieldp = &arg->field;
599 669
@@ -601,22 +671,38 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
601 *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); 671 *fieldp = zalloc(sizeof(struct perf_probe_arg_field));
602 if (*fieldp == NULL) 672 if (*fieldp == NULL)
603 return -ENOMEM; 673 return -ENOMEM;
604 if (*tmp == '.') { 674 if (*tmp == '[') { /* Array */
605 str = tmp + 1; 675 str = tmp;
606 (*fieldp)->ref = false; 676 (*fieldp)->index = strtol(str + 1, &tmp, 0);
607 } else if (tmp[1] == '>') {
608 str = tmp + 2;
609 (*fieldp)->ref = true; 677 (*fieldp)->ref = true;
610 } else { 678 if (*tmp != ']' || tmp == str + 1) {
611 semantic_error("Argument parse error: %s\n", str); 679 semantic_error("Array index must be a"
612 return -EINVAL; 680 " number.\n");
681 return -EINVAL;
682 }
683 tmp++;
684 if (*tmp == '\0')
685 tmp = NULL;
686 } else { /* Structure */
687 if (*tmp == '.') {
688 str = tmp + 1;
689 (*fieldp)->ref = false;
690 } else if (tmp[1] == '>') {
691 str = tmp + 2;
692 (*fieldp)->ref = true;
693 } else {
694 semantic_error("Argument parse error: %s\n",
695 str);
696 return -EINVAL;
697 }
698 tmp = strpbrk(str, "-.[");
613 } 699 }
614
615 tmp = strpbrk(str, "-.");
616 if (tmp) { 700 if (tmp) {
617 (*fieldp)->name = strndup(str, tmp - str); 701 (*fieldp)->name = strndup(str, tmp - str);
618 if ((*fieldp)->name == NULL) 702 if ((*fieldp)->name == NULL)
619 return -ENOMEM; 703 return -ENOMEM;
704 if (*str != '[')
705 goodname = (*fieldp)->name;
620 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); 706 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
621 fieldp = &(*fieldp)->next; 707 fieldp = &(*fieldp)->next;
622 } 708 }
@@ -624,11 +710,13 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
624 (*fieldp)->name = strdup(str); 710 (*fieldp)->name = strdup(str);
625 if ((*fieldp)->name == NULL) 711 if ((*fieldp)->name == NULL)
626 return -ENOMEM; 712 return -ENOMEM;
713 if (*str != '[')
714 goodname = (*fieldp)->name;
627 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); 715 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
628 716
629 /* If no name is specified, set the last field name */ 717 /* If no name is specified, set the last field name (not array index)*/
630 if (!arg->name) { 718 if (!arg->name) {
631 arg->name = strdup((*fieldp)->name); 719 arg->name = strdup(goodname);
632 if (arg->name == NULL) 720 if (arg->name == NULL)
633 return -ENOMEM; 721 return -ENOMEM;
634 } 722 }
@@ -776,8 +864,11 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
776 len -= ret; 864 len -= ret;
777 865
778 while (field) { 866 while (field) {
779 ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".", 867 if (field->name[0] == '[')
780 field->name); 868 ret = e_snprintf(tmp, len, "%s", field->name);
869 else
870 ret = e_snprintf(tmp, len, "%s%s",
871 field->ref ? "->" : ".", field->name);
781 if (ret <= 0) 872 if (ret <= 0)
782 goto error; 873 goto error;
783 tmp += ret; 874 tmp += ret;
@@ -904,6 +995,7 @@ out:
904static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, 995static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
905 char *buf, size_t buflen) 996 char *buf, size_t buflen)
906{ 997{
998 struct kprobe_trace_arg_ref *ref = arg->ref;
907 int ret, depth = 0; 999 int ret, depth = 0;
908 char *tmp = buf; 1000 char *tmp = buf;
909 1001
@@ -917,16 +1009,24 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
917 buf += ret; 1009 buf += ret;
918 buflen -= ret; 1010 buflen -= ret;
919 1011
1012 /* Special case: @XXX */
1013 if (arg->value[0] == '@' && arg->ref)
1014 ref = ref->next;
1015
920 /* Dereferencing arguments */ 1016 /* Dereferencing arguments */
921 if (arg->ref) { 1017 if (ref) {
922 depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf, 1018 depth = __synthesize_kprobe_trace_arg_ref(ref, &buf,
923 &buflen, 1); 1019 &buflen, 1);
924 if (depth < 0) 1020 if (depth < 0)
925 return depth; 1021 return depth;
926 } 1022 }
927 1023
928 /* Print argument value */ 1024 /* Print argument value */
929 ret = e_snprintf(buf, buflen, "%s", arg->value); 1025 if (arg->value[0] == '@' && arg->ref)
1026 ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
1027 arg->ref->offset);
1028 else
1029 ret = e_snprintf(buf, buflen, "%s", arg->value);
930 if (ret < 0) 1030 if (ret < 0)
931 return ret; 1031 return ret;
932 buf += ret; 1032 buf += ret;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index e9db1a214ca4..ed362acff4b6 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -50,6 +50,7 @@ struct perf_probe_point {
50struct perf_probe_arg_field { 50struct perf_probe_arg_field {
51 struct perf_probe_arg_field *next; /* Next field */ 51 struct perf_probe_arg_field *next; /* Next field */
52 char *name; /* Name of the field */ 52 char *name; /* Name of the field */
53 long index; /* Array index number */
53 bool ref; /* Referencing flag */ 54 bool ref; /* Referencing flag */
54}; 55};
55 56
@@ -85,6 +86,7 @@ struct line_range {
85 int end; /* End line number */ 86 int end; /* End line number */
86 int offset; /* Start line offset */ 87 int offset; /* Start line offset */
87 char *path; /* Real path name */ 88 char *path; /* Real path name */
89 char *comp_dir; /* Compile directory */
88 struct list_head line_list; /* Visible lines */ 90 struct list_head line_list; /* Visible lines */
89}; 91};
90 92
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index d964cb199c67..f88070ea5b90 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -37,6 +37,7 @@
37#include "event.h" 37#include "event.h"
38#include "debug.h" 38#include "debug.h"
39#include "util.h" 39#include "util.h"
40#include "symbol.h"
40#include "probe-finder.h" 41#include "probe-finder.h"
41 42
42/* Kprobe tracer basic type is up to u64 */ 43/* Kprobe tracer basic type is up to u64 */
@@ -143,12 +144,21 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
143 return src; 144 return src;
144} 145}
145 146
147/* Get DW_AT_comp_dir (should be NULL with older gcc) */
148static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
149{
150 Dwarf_Attribute attr;
151 if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
152 return NULL;
153 return dwarf_formstring(&attr);
154}
155
146/* Compare diename and tname */ 156/* Compare diename and tname */
147static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) 157static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
148{ 158{
149 const char *name; 159 const char *name;
150 name = dwarf_diename(dw_die); 160 name = dwarf_diename(dw_die);
151 return name ? strcmp(tname, name) : -1; 161 return name ? (strcmp(tname, name) == 0) : false;
152} 162}
153 163
154/* Get type die, but skip qualifiers and typedef */ 164/* Get type die, but skip qualifiers and typedef */
@@ -319,7 +329,7 @@ static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
319 tag = dwarf_tag(die_mem); 329 tag = dwarf_tag(die_mem);
320 if ((tag == DW_TAG_formal_parameter || 330 if ((tag == DW_TAG_formal_parameter ||
321 tag == DW_TAG_variable) && 331 tag == DW_TAG_variable) &&
322 (die_compare_name(die_mem, name) == 0)) 332 die_compare_name(die_mem, name))
323 return DIE_FIND_CB_FOUND; 333 return DIE_FIND_CB_FOUND;
324 334
325 return DIE_FIND_CB_CONTINUE; 335 return DIE_FIND_CB_CONTINUE;
@@ -338,7 +348,7 @@ static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
338 const char *name = data; 348 const char *name = data;
339 349
340 if ((dwarf_tag(die_mem) == DW_TAG_member) && 350 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
341 (die_compare_name(die_mem, name) == 0)) 351 die_compare_name(die_mem, name))
342 return DIE_FIND_CB_FOUND; 352 return DIE_FIND_CB_FOUND;
343 353
344 return DIE_FIND_CB_SIBLING; 354 return DIE_FIND_CB_SIBLING;
@@ -356,14 +366,50 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
356 * Probe finder related functions 366 * Probe finder related functions
357 */ 367 */
358 368
369static struct kprobe_trace_arg_ref *alloc_trace_arg_ref(long offs)
370{
371 struct kprobe_trace_arg_ref *ref;
372 ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
373 if (ref != NULL)
374 ref->offset = offs;
375 return ref;
376}
377
359/* Show a location */ 378/* Show a location */
360static int convert_location(Dwarf_Op *op, struct probe_finder *pf) 379static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
361{ 380{
381 Dwarf_Attribute attr;
382 Dwarf_Op *op;
383 size_t nops;
362 unsigned int regn; 384 unsigned int regn;
363 Dwarf_Word offs = 0; 385 Dwarf_Word offs = 0;
364 bool ref = false; 386 bool ref = false;
365 const char *regs; 387 const char *regs;
366 struct kprobe_trace_arg *tvar = pf->tvar; 388 struct kprobe_trace_arg *tvar = pf->tvar;
389 int ret;
390
391 /* TODO: handle more than 1 exprs */
392 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
393 dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
394 nops == 0) {
395 /* TODO: Support const_value */
396 pr_err("Failed to find the location of %s at this address.\n"
397 " Perhaps, it has been optimized out.\n", pf->pvar->var);
398 return -ENOENT;
399 }
400
401 if (op->atom == DW_OP_addr) {
402 /* Static variables on memory (not stack), make @varname */
403 ret = strlen(dwarf_diename(vr_die));
404 tvar->value = zalloc(ret + 2);
405 if (tvar->value == NULL)
406 return -ENOMEM;
407 snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
408 tvar->ref = alloc_trace_arg_ref((long)offs);
409 if (tvar->ref == NULL)
410 return -ENOMEM;
411 return 0;
412 }
367 413
368 /* If this is based on frame buffer, set the offset */ 414 /* If this is based on frame buffer, set the offset */
369 if (op->atom == DW_OP_fbreg) { 415 if (op->atom == DW_OP_fbreg) {
@@ -405,27 +451,72 @@ static int convert_location(Dwarf_Op *op, struct probe_finder *pf)
405 return -ENOMEM; 451 return -ENOMEM;
406 452
407 if (ref) { 453 if (ref) {
408 tvar->ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); 454 tvar->ref = alloc_trace_arg_ref((long)offs);
409 if (tvar->ref == NULL) 455 if (tvar->ref == NULL)
410 return -ENOMEM; 456 return -ENOMEM;
411 tvar->ref->offset = (long)offs;
412 } 457 }
413 return 0; 458 return 0;
414} 459}
415 460
416static int convert_variable_type(Dwarf_Die *vr_die, 461static int convert_variable_type(Dwarf_Die *vr_die,
417 struct kprobe_trace_arg *targ) 462 struct kprobe_trace_arg *tvar,
463 const char *cast)
418{ 464{
465 struct kprobe_trace_arg_ref **ref_ptr = &tvar->ref;
419 Dwarf_Die type; 466 Dwarf_Die type;
420 char buf[16]; 467 char buf[16];
421 int ret; 468 int ret;
422 469
470 /* TODO: check all types */
471 if (cast && strcmp(cast, "string") != 0) {
472 /* Non string type is OK */
473 tvar->type = strdup(cast);
474 return (tvar->type == NULL) ? -ENOMEM : 0;
475 }
476
423 if (die_get_real_type(vr_die, &type) == NULL) { 477 if (die_get_real_type(vr_die, &type) == NULL) {
424 pr_warning("Failed to get a type information of %s.\n", 478 pr_warning("Failed to get a type information of %s.\n",
425 dwarf_diename(vr_die)); 479 dwarf_diename(vr_die));
426 return -ENOENT; 480 return -ENOENT;
427 } 481 }
428 482
483 pr_debug("%s type is %s.\n",
484 dwarf_diename(vr_die), dwarf_diename(&type));
485
486 if (cast && strcmp(cast, "string") == 0) { /* String type */
487 ret = dwarf_tag(&type);
488 if (ret != DW_TAG_pointer_type &&
489 ret != DW_TAG_array_type) {
490 pr_warning("Failed to cast into string: "
491 "%s(%s) is not a pointer nor array.",
492 dwarf_diename(vr_die), dwarf_diename(&type));
493 return -EINVAL;
494 }
495 if (ret == DW_TAG_pointer_type) {
496 if (die_get_real_type(&type, &type) == NULL) {
497 pr_warning("Failed to get a type information.");
498 return -ENOENT;
499 }
500 while (*ref_ptr)
501 ref_ptr = &(*ref_ptr)->next;
502 /* Add new reference with offset +0 */
503 *ref_ptr = zalloc(sizeof(struct kprobe_trace_arg_ref));
504 if (*ref_ptr == NULL) {
505 pr_warning("Out of memory error\n");
506 return -ENOMEM;
507 }
508 }
509 if (!die_compare_name(&type, "char") &&
510 !die_compare_name(&type, "unsigned char")) {
511 pr_warning("Failed to cast into string: "
512 "%s is not (unsigned) char *.",
513 dwarf_diename(vr_die));
514 return -EINVAL;
515 }
516 tvar->type = strdup(cast);
517 return (tvar->type == NULL) ? -ENOMEM : 0;
518 }
519
429 ret = die_get_byte_size(&type) * 8; 520 ret = die_get_byte_size(&type) * 8;
430 if (ret) { 521 if (ret) {
431 /* Check the bitwidth */ 522 /* Check the bitwidth */
@@ -445,8 +536,8 @@ static int convert_variable_type(Dwarf_Die *vr_die,
445 strerror(-ret)); 536 strerror(-ret));
446 return ret; 537 return ret;
447 } 538 }
448 targ->type = strdup(buf); 539 tvar->type = strdup(buf);
449 if (targ->type == NULL) 540 if (tvar->type == NULL)
450 return -ENOMEM; 541 return -ENOMEM;
451 } 542 }
452 return 0; 543 return 0;
@@ -460,16 +551,44 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
460 struct kprobe_trace_arg_ref *ref = *ref_ptr; 551 struct kprobe_trace_arg_ref *ref = *ref_ptr;
461 Dwarf_Die type; 552 Dwarf_Die type;
462 Dwarf_Word offs; 553 Dwarf_Word offs;
463 int ret; 554 int ret, tag;
464 555
465 pr_debug("converting %s in %s\n", field->name, varname); 556 pr_debug("converting %s in %s\n", field->name, varname);
466 if (die_get_real_type(vr_die, &type) == NULL) { 557 if (die_get_real_type(vr_die, &type) == NULL) {
467 pr_warning("Failed to get the type of %s.\n", varname); 558 pr_warning("Failed to get the type of %s.\n", varname);
468 return -ENOENT; 559 return -ENOENT;
469 } 560 }
470 561 pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
471 /* Check the pointer and dereference */ 562 tag = dwarf_tag(&type);
472 if (dwarf_tag(&type) == DW_TAG_pointer_type) { 563
564 if (field->name[0] == '[' &&
565 (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
566 if (field->next)
567 /* Save original type for next field */
568 memcpy(die_mem, &type, sizeof(*die_mem));
569 /* Get the type of this array */
570 if (die_get_real_type(&type, &type) == NULL) {
571 pr_warning("Failed to get the type of %s.\n", varname);
572 return -ENOENT;
573 }
574 pr_debug2("Array real type: (%x)\n",
575 (unsigned)dwarf_dieoffset(&type));
576 if (tag == DW_TAG_pointer_type) {
577 ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
578 if (ref == NULL)
579 return -ENOMEM;
580 if (*ref_ptr)
581 (*ref_ptr)->next = ref;
582 else
583 *ref_ptr = ref;
584 }
585 ref->offset += die_get_byte_size(&type) * field->index;
586 if (!field->next)
587 /* Save vr_die for converting types */
588 memcpy(die_mem, vr_die, sizeof(*die_mem));
589 goto next;
590 } else if (tag == DW_TAG_pointer_type) {
591 /* Check the pointer and dereference */
473 if (!field->ref) { 592 if (!field->ref) {
474 pr_err("Semantic error: %s must be referred by '->'\n", 593 pr_err("Semantic error: %s must be referred by '->'\n",
475 field->name); 594 field->name);
@@ -495,10 +614,15 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
495 *ref_ptr = ref; 614 *ref_ptr = ref;
496 } else { 615 } else {
497 /* Verify it is a data structure */ 616 /* Verify it is a data structure */
498 if (dwarf_tag(&type) != DW_TAG_structure_type) { 617 if (tag != DW_TAG_structure_type) {
499 pr_warning("%s is not a data structure.\n", varname); 618 pr_warning("%s is not a data structure.\n", varname);
500 return -EINVAL; 619 return -EINVAL;
501 } 620 }
621 if (field->name[0] == '[') {
622 pr_err("Semantic error: %s is not a pointor nor array.",
623 varname);
624 return -EINVAL;
625 }
502 if (field->ref) { 626 if (field->ref) {
503 pr_err("Semantic error: %s must be referred by '.'\n", 627 pr_err("Semantic error: %s must be referred by '.'\n",
504 field->name); 628 field->name);
@@ -525,6 +649,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
525 } 649 }
526 ref->offset += (long)offs; 650 ref->offset += (long)offs;
527 651
652next:
528 /* Converting next field */ 653 /* Converting next field */
529 if (field->next) 654 if (field->next)
530 return convert_variable_fields(die_mem, field->name, 655 return convert_variable_fields(die_mem, field->name,
@@ -536,51 +661,32 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
536/* Show a variables in kprobe event format */ 661/* Show a variables in kprobe event format */
537static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 662static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
538{ 663{
539 Dwarf_Attribute attr;
540 Dwarf_Die die_mem; 664 Dwarf_Die die_mem;
541 Dwarf_Op *expr;
542 size_t nexpr;
543 int ret; 665 int ret;
544 666
545 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 667 pr_debug("Converting variable %s into trace event.\n",
546 goto error; 668 dwarf_diename(vr_die));
547 /* TODO: handle more than 1 exprs */
548 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
549 if (ret <= 0 || nexpr == 0)
550 goto error;
551 669
552 ret = convert_location(expr, pf); 670 ret = convert_variable_location(vr_die, pf);
553 if (ret == 0 && pf->pvar->field) { 671 if (ret == 0 && pf->pvar->field) {
554 ret = convert_variable_fields(vr_die, pf->pvar->var, 672 ret = convert_variable_fields(vr_die, pf->pvar->var,
555 pf->pvar->field, &pf->tvar->ref, 673 pf->pvar->field, &pf->tvar->ref,
556 &die_mem); 674 &die_mem);
557 vr_die = &die_mem; 675 vr_die = &die_mem;
558 } 676 }
559 if (ret == 0) { 677 if (ret == 0)
560 if (pf->pvar->type) { 678 ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
561 pf->tvar->type = strdup(pf->pvar->type);
562 if (pf->tvar->type == NULL)
563 ret = -ENOMEM;
564 } else
565 ret = convert_variable_type(vr_die, pf->tvar);
566 }
567 /* *expr will be cached in libdw. Don't free it. */ 679 /* *expr will be cached in libdw. Don't free it. */
568 return ret; 680 return ret;
569error:
570 /* TODO: Support const_value */
571 pr_err("Failed to find the location of %s at this address.\n"
572 " Perhaps, it has been optimized out.\n", pf->pvar->var);
573 return -ENOENT;
574} 681}
575 682
576/* Find a variable in a subprogram die */ 683/* Find a variable in a subprogram die */
577static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 684static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
578{ 685{
579 Dwarf_Die vr_die; 686 Dwarf_Die vr_die, *scopes;
580 char buf[32], *ptr; 687 char buf[32], *ptr;
581 int ret; 688 int ret, nscopes;
582 689
583 /* TODO: Support arrays */
584 if (pf->pvar->name) 690 if (pf->pvar->name)
585 pf->tvar->name = strdup(pf->pvar->name); 691 pf->tvar->name = strdup(pf->pvar->name);
586 else { 692 else {
@@ -607,12 +713,26 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
607 pr_debug("Searching '%s' variable in context.\n", 713 pr_debug("Searching '%s' variable in context.\n",
608 pf->pvar->var); 714 pf->pvar->var);
609 /* Search child die for local variables and parameters. */ 715 /* Search child die for local variables and parameters. */
610 if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) { 716 if (die_find_variable(sp_die, pf->pvar->var, &vr_die))
717 ret = convert_variable(&vr_die, pf);
718 else {
719 /* Search upper class */
720 nscopes = dwarf_getscopes_die(sp_die, &scopes);
721 if (nscopes > 0) {
722 ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,
723 0, NULL, 0, 0, &vr_die);
724 if (ret >= 0)
725 ret = convert_variable(&vr_die, pf);
726 else
727 ret = -ENOENT;
728 free(scopes);
729 } else
730 ret = -ENOENT;
731 }
732 if (ret < 0)
611 pr_warning("Failed to find '%s' in this function.\n", 733 pr_warning("Failed to find '%s' in this function.\n",
612 pf->pvar->var); 734 pf->pvar->var);
613 return -ENOENT; 735 return ret;
614 }
615 return convert_variable(&vr_die, pf);
616} 736}
617 737
618/* Show a probe point to output buffer */ 738/* Show a probe point to output buffer */
@@ -897,7 +1017,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
897 1017
898 /* Check tag and diename */ 1018 /* Check tag and diename */
899 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 1019 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
900 die_compare_name(sp_die, pp->function) != 0) 1020 !die_compare_name(sp_die, pp->function))
901 return DWARF_CB_OK; 1021 return DWARF_CB_OK;
902 1022
903 pf->fname = dwarf_decl_file(sp_die); 1023 pf->fname = dwarf_decl_file(sp_die);
@@ -1096,7 +1216,7 @@ end:
1096static int line_range_add_line(const char *src, unsigned int lineno, 1216static int line_range_add_line(const char *src, unsigned int lineno,
1097 struct line_range *lr) 1217 struct line_range *lr)
1098{ 1218{
1099 /* Copy real path */ 1219 /* Copy source path */
1100 if (!lr->path) { 1220 if (!lr->path) {
1101 lr->path = strdup(src); 1221 lr->path = strdup(src);
1102 if (lr->path == NULL) 1222 if (lr->path == NULL)
@@ -1220,7 +1340,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1220 struct line_range *lr = lf->lr; 1340 struct line_range *lr = lf->lr;
1221 1341
1222 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1342 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1223 die_compare_name(sp_die, lr->function) == 0) { 1343 die_compare_name(sp_die, lr->function)) {
1224 lf->fname = dwarf_decl_file(sp_die); 1344 lf->fname = dwarf_decl_file(sp_die);
1225 dwarf_decl_line(sp_die, &lr->offset); 1345 dwarf_decl_line(sp_die, &lr->offset);
1226 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1346 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
@@ -1263,6 +1383,7 @@ int find_line_range(int fd, struct line_range *lr)
1263 size_t cuhl; 1383 size_t cuhl;
1264 Dwarf_Die *diep; 1384 Dwarf_Die *diep;
1265 Dwarf *dbg; 1385 Dwarf *dbg;
1386 const char *comp_dir;
1266 1387
1267 dbg = dwarf_begin(fd, DWARF_C_READ); 1388 dbg = dwarf_begin(fd, DWARF_C_READ);
1268 if (!dbg) { 1389 if (!dbg) {
@@ -1298,7 +1419,18 @@ int find_line_range(int fd, struct line_range *lr)
1298 } 1419 }
1299 off = noff; 1420 off = noff;
1300 } 1421 }
1301 pr_debug("path: %lx\n", (unsigned long)lr->path); 1422
1423 /* Store comp_dir */
1424 if (lf.found) {
1425 comp_dir = cu_get_comp_dir(&lf.cu_die);
1426 if (comp_dir) {
1427 lr->comp_dir = strdup(comp_dir);
1428 if (!lr->comp_dir)
1429 ret = -ENOMEM;
1430 }
1431 }
1432
1433 pr_debug("path: %s\n", lr->path);
1302 dwarf_end(dbg); 1434 dwarf_end(dbg);
1303 1435
1304 return (ret < 0) ? ret : lf.found; 1436 return (ret < 0) ? ret : lf.found;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index c422cd676313..030791870e33 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -27,8 +27,10 @@ static int perf_session__open(struct perf_session *self, bool force)
27 27
28 self->fd = open(self->filename, O_RDONLY); 28 self->fd = open(self->filename, O_RDONLY);
29 if (self->fd < 0) { 29 if (self->fd < 0) {
30 pr_err("failed to open file: %s", self->filename); 30 int err = errno;
31 if (!strcmp(self->filename, "perf.data")) 31
32 pr_err("failed to open %s: %s", self->filename, strerror(err));
33 if (err == ENOENT && !strcmp(self->filename, "perf.data"))
32 pr_err(" (try 'perf record' first)"); 34 pr_err(" (try 'perf record' first)");
33 pr_err("\n"); 35 pr_err("\n");
34 return -errno; 36 return -errno;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 2316cb5a4116..c27b4b03fbc1 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -13,6 +13,7 @@ enum sort_type sort__first_dimension;
13unsigned int dsos__col_width; 13unsigned int dsos__col_width;
14unsigned int comms__col_width; 14unsigned int comms__col_width;
15unsigned int threads__col_width; 15unsigned int threads__col_width;
16unsigned int cpus__col_width;
16static unsigned int parent_symbol__col_width; 17static unsigned int parent_symbol__col_width;
17char * field_sep; 18char * field_sep;
18 19
@@ -28,6 +29,8 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
28 size_t size, unsigned int width); 29 size_t size, unsigned int width);
29static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, 30static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
30 size_t size, unsigned int width); 31 size_t size, unsigned int width);
32static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
33 size_t size, unsigned int width);
31 34
32struct sort_entry sort_thread = { 35struct sort_entry sort_thread = {
33 .se_header = "Command: Pid", 36 .se_header = "Command: Pid",
@@ -63,6 +66,13 @@ struct sort_entry sort_parent = {
63 .se_snprintf = hist_entry__parent_snprintf, 66 .se_snprintf = hist_entry__parent_snprintf,
64 .se_width = &parent_symbol__col_width, 67 .se_width = &parent_symbol__col_width,
65}; 68};
69
70struct sort_entry sort_cpu = {
71 .se_header = "CPU",
72 .se_cmp = sort__cpu_cmp,
73 .se_snprintf = hist_entry__cpu_snprintf,
74 .se_width = &cpus__col_width,
75};
66 76
67struct sort_dimension { 77struct sort_dimension {
68 const char *name; 78 const char *name;
@@ -76,6 +86,7 @@ static struct sort_dimension sort_dimensions[] = {
76 { .name = "dso", .entry = &sort_dso, }, 86 { .name = "dso", .entry = &sort_dso, },
77 { .name = "symbol", .entry = &sort_sym, }, 87 { .name = "symbol", .entry = &sort_sym, },
78 { .name = "parent", .entry = &sort_parent, }, 88 { .name = "parent", .entry = &sort_parent, },
89 { .name = "cpu", .entry = &sort_cpu, },
79}; 90};
80 91
81int64_t cmp_null(void *l, void *r) 92int64_t cmp_null(void *l, void *r)
@@ -242,6 +253,20 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
242 self->parent ? self->parent->name : "[other]"); 253 self->parent ? self->parent->name : "[other]");
243} 254}
244 255
256/* --sort cpu */
257
258int64_t
259sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
260{
261 return right->cpu - left->cpu;
262}
263
264static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
265 size_t size, unsigned int width)
266{
267 return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
268}
269
245int sort_dimension__add(const char *tok) 270int sort_dimension__add(const char *tok)
246{ 271{
247 unsigned int i; 272 unsigned int i;
@@ -281,6 +306,8 @@ int sort_dimension__add(const char *tok)
281 sort__first_dimension = SORT_SYM; 306 sort__first_dimension = SORT_SYM;
282 else if (!strcmp(sd->name, "parent")) 307 else if (!strcmp(sd->name, "parent"))
283 sort__first_dimension = SORT_PARENT; 308 sort__first_dimension = SORT_PARENT;
309 else if (!strcmp(sd->name, "cpu"))
310 sort__first_dimension = SORT_CPU;
284 } 311 }
285 312
286 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 313 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 0d61c4082f43..560c855417e4 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -39,6 +39,7 @@ extern struct sort_entry sort_parent;
39extern unsigned int dsos__col_width; 39extern unsigned int dsos__col_width;
40extern unsigned int comms__col_width; 40extern unsigned int comms__col_width;
41extern unsigned int threads__col_width; 41extern unsigned int threads__col_width;
42extern unsigned int cpus__col_width;
42extern enum sort_type sort__first_dimension; 43extern enum sort_type sort__first_dimension;
43 44
44struct hist_entry { 45struct hist_entry {
@@ -51,6 +52,7 @@ struct hist_entry {
51 struct map_symbol ms; 52 struct map_symbol ms;
52 struct thread *thread; 53 struct thread *thread;
53 u64 ip; 54 u64 ip;
55 s32 cpu;
54 u32 nr_events; 56 u32 nr_events;
55 char level; 57 char level;
56 u8 filtered; 58 u8 filtered;
@@ -68,7 +70,8 @@ enum sort_type {
68 SORT_COMM, 70 SORT_COMM,
69 SORT_DSO, 71 SORT_DSO,
70 SORT_SYM, 72 SORT_SYM,
71 SORT_PARENT 73 SORT_PARENT,
74 SORT_CPU,
72}; 75};
73 76
74/* 77/*
@@ -104,6 +107,7 @@ extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
104extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *); 107extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
105extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *); 108extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
106extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); 109extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
110int64_t sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right);
107extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); 111extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
108extern int sort_dimension__add(const char *); 112extern int sort_dimension__add(const char *);
109void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 113void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b63e5713849f..971d0a05d6b4 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -933,6 +933,25 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
933 } 933 }
934} 934}
935 935
936static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
937{
938 Elf_Scn *sec = NULL;
939 GElf_Shdr shdr;
940 size_t cnt = 1;
941
942 while ((sec = elf_nextscn(elf, sec)) != NULL) {
943 gelf_getshdr(sec, &shdr);
944
945 if ((addr >= shdr.sh_addr) &&
946 (addr < (shdr.sh_addr + shdr.sh_size)))
947 return cnt;
948
949 ++cnt;
950 }
951
952 return -1;
953}
954
936static int dso__load_sym(struct dso *self, struct map *map, const char *name, 955static int dso__load_sym(struct dso *self, struct map *map, const char *name,
937 int fd, symbol_filter_t filter, int kmodule) 956 int fd, symbol_filter_t filter, int kmodule)
938{ 957{
@@ -944,12 +963,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
944 int err = -1; 963 int err = -1;
945 uint32_t idx; 964 uint32_t idx;
946 GElf_Ehdr ehdr; 965 GElf_Ehdr ehdr;
947 GElf_Shdr shdr; 966 GElf_Shdr shdr, opdshdr;
948 Elf_Data *syms; 967 Elf_Data *syms, *opddata = NULL;
949 GElf_Sym sym; 968 GElf_Sym sym;
950 Elf_Scn *sec, *sec_strndx; 969 Elf_Scn *sec, *sec_strndx, *opdsec;
951 Elf *elf; 970 Elf *elf;
952 int nr = 0; 971 int nr = 0;
972 size_t opdidx = 0;
953 973
954 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 974 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
955 if (elf == NULL) { 975 if (elf == NULL) {
@@ -969,6 +989,10 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
969 goto out_elf_end; 989 goto out_elf_end;
970 } 990 }
971 991
992 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
993 if (opdsec)
994 opddata = elf_rawdata(opdsec, NULL);
995
972 syms = elf_getdata(sec, NULL); 996 syms = elf_getdata(sec, NULL);
973 if (syms == NULL) 997 if (syms == NULL)
974 goto out_elf_end; 998 goto out_elf_end;
@@ -1013,6 +1037,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1013 if (!is_label && !elf_sym__is_a(&sym, map->type)) 1037 if (!is_label && !elf_sym__is_a(&sym, map->type))
1014 continue; 1038 continue;
1015 1039
1040 if (opdsec && sym.st_shndx == opdidx) {
1041 u32 offset = sym.st_value - opdshdr.sh_addr;
1042 u64 *opd = opddata->d_buf + offset;
1043 sym.st_value = *opd;
1044 sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
1045 }
1046
1016 sec = elf_getscn(elf, sym.st_shndx); 1047 sec = elf_getscn(elf, sym.st_shndx);
1017 if (!sec) 1048 if (!sec)
1018 goto out_elf_end; 1049 goto out_elf_end;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 5e02d2c17154..80e569bbdecc 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -9,8 +9,6 @@
9#include <linux/rbtree.h> 9#include <linux/rbtree.h>
10#include <stdio.h> 10#include <stdio.h>
11 11
12#define DEBUG_CACHE_DIR ".debug"
13
14#ifdef HAVE_CPLUS_DEMANGLE 12#ifdef HAVE_CPLUS_DEMANGLE
15extern char *cplus_demangle(const char *, int); 13extern char *cplus_demangle(const char *, int);
16 14
@@ -73,6 +71,7 @@ struct symbol_conf {
73 full_paths, 71 full_paths,
74 show_cpu_utilization; 72 show_cpu_utilization;
75 const char *vmlinux_name, 73 const char *vmlinux_name,
74 *source_prefix,
76 *field_sep; 75 *field_sep;
77 const char *default_guest_vmlinux_name, 76 const char *default_guest_vmlinux_name,
78 *default_guest_kallsyms, 77 *default_guest_kallsyms,
@@ -112,7 +111,8 @@ struct addr_location {
112 u64 addr; 111 u64 addr;
113 char level; 112 char level;
114 bool filtered; 113 bool filtered;
115 unsigned int cpumode; 114 u8 cpumode;
115 s32 cpu;
116}; 116};
117 117
118enum dso_kernel_type { 118enum dso_kernel_type {
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 4e8b6b0c551c..f380fed74359 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -89,6 +89,7 @@
89 89
90extern const char *graph_line; 90extern const char *graph_line;
91extern const char *graph_dotted_line; 91extern const char *graph_dotted_line;
92extern char buildid_dir[];
92 93
93/* On most systems <limits.h> would have given us this, but 94/* On most systems <limits.h> would have given us this, but
94 * not on some systems (e.g. GNU/Hurd). 95 * not on some systems (e.g. GNU/Hurd).
@@ -152,6 +153,8 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)))
152extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); 153extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
153 154
154extern int prefixcmp(const char *str, const char *prefix); 155extern int prefixcmp(const char *str, const char *prefix);
156extern void set_buildid_dir(void);
157extern void disable_buildid_cache(void);
155 158
156static inline const char *skip_prefix(const char *str, const char *prefix) 159static inline const char *skip_prefix(const char *str, const char *prefix)
157{ 160{