aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/MANIFEST1
-rw-r--r--tools/perf/Makefile.perf39
-rw-r--r--tools/perf/arch/arm/Makefile2
-rw-r--r--tools/perf/arch/arm/util/unwind-libunwind.c (renamed from tools/perf/arch/arm/util/unwind.c)2
-rw-r--r--tools/perf/arch/x86/Makefile9
-rw-r--r--tools/perf/arch/x86/include/perf_regs.h6
-rw-r--r--tools/perf/arch/x86/tests/dwarf-unwind.c59
-rw-r--r--tools/perf/arch/x86/tests/regs_load.S92
-rw-r--r--tools/perf/arch/x86/util/unwind-libdw.c51
-rw-r--r--tools/perf/arch/x86/util/unwind-libunwind.c (renamed from tools/perf/arch/x86/util/unwind.c)4
-rw-r--r--tools/perf/builtin-inject.c1
-rw-r--r--tools/perf/builtin-probe.c12
-rw-r--r--tools/perf/builtin-record.c30
-rw-r--r--tools/perf/builtin-report.c24
-rw-r--r--tools/perf/builtin-top.c12
-rw-r--r--tools/perf/config/Makefile232
-rw-r--r--tools/perf/config/feature-checks/Makefile6
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c13
-rw-r--r--tools/perf/perf.h4
-rw-r--r--tools/perf/tests/builtin-test.c8
-rw-r--r--tools/perf/tests/dwarf-unwind.c144
-rw-r--r--tools/perf/tests/make25
-rw-r--r--tools/perf/tests/parse-events.c2
-rw-r--r--tools/perf/tests/sample-parsing.c17
-rw-r--r--tools/perf/tests/tests.h9
-rw-r--r--tools/perf/util/cpumap.c2
-rw-r--r--tools/perf/util/dso.c4
-rw-r--r--tools/perf/util/dso.h10
-rw-r--r--tools/perf/util/event.h5
-rw-r--r--tools/perf/util/evsel.c17
-rw-r--r--tools/perf/util/fs.c119
-rw-r--r--tools/perf/util/fs.h7
-rw-r--r--tools/perf/util/hist.c4
-rw-r--r--tools/perf/util/include/linux/hash.h5
-rw-r--r--tools/perf/util/include/linux/list.h1
-rw-r--r--tools/perf/util/include/linux/magic.h16
-rw-r--r--tools/perf/util/include/linux/prefetch.h6
-rw-r--r--tools/perf/util/machine.c27
-rw-r--r--tools/perf/util/machine.h10
-rw-r--r--tools/perf/util/map.h10
-rw-r--r--tools/perf/util/perf_regs.c19
-rw-r--r--tools/perf/util/perf_regs.h13
-rw-r--r--tools/perf/util/pmu.c2
-rw-r--r--tools/perf/util/probe-event.c863
-rw-r--r--tools/perf/util/probe-event.h12
-rw-r--r--tools/perf/util/probe-finder.c198
-rw-r--r--tools/perf/util/probe-finder.h5
-rw-r--r--tools/perf/util/python-ext-sources2
-rw-r--r--tools/perf/util/record.c2
-rw-r--r--tools/perf/util/session.c5
-rw-r--r--tools/perf/util/symbol-elf.c2
-rw-r--r--tools/perf/util/symbol.c63
-rw-r--r--tools/perf/util/symbol.h12
-rw-r--r--tools/perf/util/trace-event-parse.c1
-rw-r--r--tools/perf/util/unwind-libdw.c210
-rw-r--r--tools/perf/util/unwind-libdw.h21
-rw-r--r--tools/perf/util/unwind-libunwind.c (renamed from tools/perf/util/unwind.c)50
-rw-r--r--tools/perf/util/unwind.h11
-rw-r--r--tools/perf/util/util.c2
60 files changed, 1622 insertions, 923 deletions
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index f41572d0dd76..c0c87c87b60f 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -6,6 +6,7 @@ tools/lib/symbol/kallsyms.c
6tools/lib/symbol/kallsyms.h 6tools/lib/symbol/kallsyms.h
7tools/include/asm/bug.h 7tools/include/asm/bug.h
8tools/include/linux/compiler.h 8tools/include/linux/compiler.h
9tools/include/linux/hash.h
9include/linux/const.h 10include/linux/const.h
10include/linux/perf_event.h 11include/linux/perf_event.h
11include/linux/rbtree.h 12include/linux/rbtree.h
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 7257e7e9e38a..1f7ec48ac959 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -7,6 +7,8 @@ include config/utilities.mak
7 7
8# Define V to have a more verbose compile. 8# Define V to have a more verbose compile.
9# 9#
10# Define VF to have a more verbose feature check output.
11#
10# Define O to save output files in a separate directory. 12# Define O to save output files in a separate directory.
11# 13#
12# Define ARCH as name of target architecture if you want cross-builds. 14# Define ARCH as name of target architecture if you want cross-builds.
@@ -55,6 +57,9 @@ include config/utilities.mak
55# Define NO_LIBAUDIT if you do not want libaudit support 57# Define NO_LIBAUDIT if you do not want libaudit support
56# 58#
57# Define NO_LIBBIONIC if you do not want bionic support 59# Define NO_LIBBIONIC if you do not want bionic support
60#
61# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
62# for dwarf backtrace post unwind.
58 63
59ifeq ($(srctree),) 64ifeq ($(srctree),)
60srctree := $(patsubst %/,%,$(dir $(shell pwd))) 65srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -208,7 +213,7 @@ LIB_H += ../../include/uapi/linux/perf_event.h
208LIB_H += ../../include/linux/rbtree.h 213LIB_H += ../../include/linux/rbtree.h
209LIB_H += ../../include/linux/list.h 214LIB_H += ../../include/linux/list.h
210LIB_H += ../../include/uapi/linux/const.h 215LIB_H += ../../include/uapi/linux/const.h
211LIB_H += ../../include/linux/hash.h 216LIB_H += ../include/linux/hash.h
212LIB_H += ../../include/linux/stringify.h 217LIB_H += ../../include/linux/stringify.h
213LIB_H += util/include/linux/bitmap.h 218LIB_H += util/include/linux/bitmap.h
214LIB_H += util/include/linux/bitops.h 219LIB_H += util/include/linux/bitops.h
@@ -218,9 +223,7 @@ LIB_H += util/include/linux/ctype.h
218LIB_H += util/include/linux/kernel.h 223LIB_H += util/include/linux/kernel.h
219LIB_H += util/include/linux/list.h 224LIB_H += util/include/linux/list.h
220LIB_H += util/include/linux/export.h 225LIB_H += util/include/linux/export.h
221LIB_H += util/include/linux/magic.h
222LIB_H += util/include/linux/poison.h 226LIB_H += util/include/linux/poison.h
223LIB_H += util/include/linux/prefetch.h
224LIB_H += util/include/linux/rbtree.h 227LIB_H += util/include/linux/rbtree.h
225LIB_H += util/include/linux/rbtree_augmented.h 228LIB_H += util/include/linux/rbtree_augmented.h
226LIB_H += util/include/linux/string.h 229LIB_H += util/include/linux/string.h
@@ -244,7 +247,6 @@ LIB_H += util/cache.h
244LIB_H += util/callchain.h 247LIB_H += util/callchain.h
245LIB_H += util/build-id.h 248LIB_H += util/build-id.h
246LIB_H += util/debug.h 249LIB_H += util/debug.h
247LIB_H += util/fs.h
248LIB_H += util/pmu.h 250LIB_H += util/pmu.h
249LIB_H += util/event.h 251LIB_H += util/event.h
250LIB_H += util/evsel.h 252LIB_H += util/evsel.h
@@ -306,7 +308,6 @@ LIB_OBJS += $(OUTPUT)util/annotate.o
306LIB_OBJS += $(OUTPUT)util/build-id.o 308LIB_OBJS += $(OUTPUT)util/build-id.o
307LIB_OBJS += $(OUTPUT)util/config.o 309LIB_OBJS += $(OUTPUT)util/config.o
308LIB_OBJS += $(OUTPUT)util/ctype.o 310LIB_OBJS += $(OUTPUT)util/ctype.o
309LIB_OBJS += $(OUTPUT)util/fs.o
310LIB_OBJS += $(OUTPUT)util/pmu.o 311LIB_OBJS += $(OUTPUT)util/pmu.o
311LIB_OBJS += $(OUTPUT)util/environment.o 312LIB_OBJS += $(OUTPUT)util/environment.o
312LIB_OBJS += $(OUTPUT)util/event.o 313LIB_OBJS += $(OUTPUT)util/event.o
@@ -408,6 +409,11 @@ endif
408LIB_OBJS += $(OUTPUT)tests/code-reading.o 409LIB_OBJS += $(OUTPUT)tests/code-reading.o
409LIB_OBJS += $(OUTPUT)tests/sample-parsing.o 410LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
410LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o 411LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
412ifndef NO_DWARF_UNWIND
413ifeq ($(ARCH),x86)
414LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
415endif
416endif
411 417
412BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 418BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
413BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 419BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -475,8 +481,13 @@ ifndef NO_DWARF
475endif # NO_DWARF 481endif # NO_DWARF
476endif # NO_LIBELF 482endif # NO_LIBELF
477 483
484ifndef NO_LIBDW_DWARF_UNWIND
485 LIB_OBJS += $(OUTPUT)util/unwind-libdw.o
486 LIB_H += util/unwind-libdw.h
487endif
488
478ifndef NO_LIBUNWIND 489ifndef NO_LIBUNWIND
479 LIB_OBJS += $(OUTPUT)util/unwind.o 490 LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o
480endif 491endif
481LIB_OBJS += $(OUTPUT)tests/keep-tracking.o 492LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
482 493
@@ -533,6 +544,7 @@ ifeq ($(NO_PERF_REGS),0)
533 ifeq ($(ARCH),x86) 544 ifeq ($(ARCH),x86)
534 LIB_H += arch/x86/include/perf_regs.h 545 LIB_H += arch/x86/include/perf_regs.h
535 endif 546 endif
547 LIB_OBJS += $(OUTPUT)util/perf_regs.o
536endif 548endif
537 549
538ifndef NO_LIBNUMA 550ifndef NO_LIBNUMA
@@ -655,6 +667,9 @@ $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
655 -DPYTHON='"$(PYTHON_WORD)"' \ 667 -DPYTHON='"$(PYTHON_WORD)"' \
656 $< 668 $<
657 669
670$(OUTPUT)tests/dwarf-unwind.o: tests/dwarf-unwind.c
671 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -fno-optimize-sibling-calls $<
672
658$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 673$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
659 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 674 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
660 675
@@ -707,9 +722,15 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
707# we depend the various files onto their directories. 722# we depend the various files onto their directories.
708DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS) 723DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS)
709DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h 724DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
710$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS))) 725# no need to add flex objects, because they depend on bison ones
726DIRECTORY_DEPS += $(OUTPUT)util/parse-events-bison.c
727DIRECTORY_DEPS += $(OUTPUT)util/pmu-bison.c
728
729OUTPUT_DIRECTORIES := $(sort $(dir $(DIRECTORY_DEPS)))
730
731$(DIRECTORY_DEPS): | $(OUTPUT_DIRECTORIES)
711# In the second step, we make a rule to actually create these directories 732# In the second step, we make a rule to actually create these directories
712$(sort $(dir $(DIRECTORY_DEPS))): 733$(OUTPUT_DIRECTORIES):
713 $(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null 734 $(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
714 735
715$(LIB_FILE): $(LIB_OBJS) 736$(LIB_FILE): $(LIB_OBJS)
@@ -886,7 +907,7 @@ config-clean:
886clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean 907clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
887 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) 908 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
888 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf 909 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
889 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* 910 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
890 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean 911 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
891 $(python-clean) 912 $(python-clean)
892 913
diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
index fe9b61e322a5..67e9b3d38e89 100644
--- a/tools/perf/arch/arm/Makefile
+++ b/tools/perf/arch/arm/Makefile
@@ -3,5 +3,5 @@ PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5ifndef NO_LIBUNWIND 5ifndef NO_LIBUNWIND
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o 6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
7endif 7endif
diff --git a/tools/perf/arch/arm/util/unwind.c b/tools/perf/arch/arm/util/unwind-libunwind.c
index da3dc950550c..729ed69a6664 100644
--- a/tools/perf/arch/arm/util/unwind.c
+++ b/tools/perf/arch/arm/util/unwind-libunwind.c
@@ -4,7 +4,7 @@
4#include "perf_regs.h" 4#include "perf_regs.h"
5#include "../../util/unwind.h" 5#include "../../util/unwind.h"
6 6
7int unwind__arch_reg_id(int regnum) 7int libunwind__arch_reg_id(int regnum)
8{ 8{
9 switch (regnum) { 9 switch (regnum) {
10 case UNW_ARM_R0: 10 case UNW_ARM_R0:
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 8801fe02f206..1641542e3636 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -3,7 +3,14 @@ PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5ifndef NO_LIBUNWIND 5ifndef NO_LIBUNWIND
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o 6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
7endif
8ifndef NO_LIBDW_DWARF_UNWIND
9LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libdw.o
10endif
11ifndef NO_DWARF_UNWIND
12LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
13LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
7endif 14endif
8LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 15LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
9LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o 16LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index e84ca76aae77..fc819ca34a7e 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -5,14 +5,20 @@
5#include "../../util/types.h" 5#include "../../util/types.h"
6#include <asm/perf_regs.h> 6#include <asm/perf_regs.h>
7 7
8void perf_regs_load(u64 *regs);
9
8#ifndef HAVE_ARCH_X86_64_SUPPORT 10#ifndef HAVE_ARCH_X86_64_SUPPORT
9#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1) 11#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
12#define PERF_REGS_MAX PERF_REG_X86_32_MAX
13#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
10#else 14#else
11#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \ 15#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
12 (1ULL << PERF_REG_X86_ES) | \ 16 (1ULL << PERF_REG_X86_ES) | \
13 (1ULL << PERF_REG_X86_FS) | \ 17 (1ULL << PERF_REG_X86_FS) | \
14 (1ULL << PERF_REG_X86_GS)) 18 (1ULL << PERF_REG_X86_GS))
15#define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT) 19#define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT)
20#define PERF_REGS_MAX PERF_REG_X86_64_MAX
21#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
16#endif 22#endif
17#define PERF_REG_IP PERF_REG_X86_IP 23#define PERF_REG_IP PERF_REG_X86_IP
18#define PERF_REG_SP PERF_REG_X86_SP 24#define PERF_REG_SP PERF_REG_X86_SP
diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
new file mode 100644
index 000000000000..b602ad93ce63
--- /dev/null
+++ b/tools/perf/arch/x86/tests/dwarf-unwind.c
@@ -0,0 +1,59 @@
1#include <string.h>
2#include "perf_regs.h"
3#include "thread.h"
4#include "map.h"
5#include "event.h"
6#include "tests/tests.h"
7
8#define STACK_SIZE 8192
9
10static int sample_ustack(struct perf_sample *sample,
11 struct thread *thread, u64 *regs)
12{
13 struct stack_dump *stack = &sample->user_stack;
14 struct map *map;
15 unsigned long sp;
16 u64 stack_size, *buf;
17
18 buf = malloc(STACK_SIZE);
19 if (!buf) {
20 pr_debug("failed to allocate sample uregs data\n");
21 return -1;
22 }
23
24 sp = (unsigned long) regs[PERF_REG_X86_SP];
25
26 map = map_groups__find(&thread->mg, MAP__FUNCTION, (u64) sp);
27 if (!map) {
28 pr_debug("failed to get stack map\n");
29 return -1;
30 }
31
32 stack_size = map->end - sp;
33 stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
34
35 memcpy(buf, (void *) sp, stack_size);
36 stack->data = (char *) buf;
37 stack->size = stack_size;
38 return 0;
39}
40
41int test__arch_unwind_sample(struct perf_sample *sample,
42 struct thread *thread)
43{
44 struct regs_dump *regs = &sample->user_regs;
45 u64 *buf;
46
47 buf = malloc(sizeof(u64) * PERF_REGS_MAX);
48 if (!buf) {
49 pr_debug("failed to allocate sample uregs data\n");
50 return -1;
51 }
52
53 perf_regs_load(buf);
54 regs->abi = PERF_SAMPLE_REGS_ABI;
55 regs->regs = buf;
56 regs->mask = PERF_REGS_MASK;
57
58 return sample_ustack(sample, thread, buf);
59}
diff --git a/tools/perf/arch/x86/tests/regs_load.S b/tools/perf/arch/x86/tests/regs_load.S
new file mode 100644
index 000000000000..99167bf644ea
--- /dev/null
+++ b/tools/perf/arch/x86/tests/regs_load.S
@@ -0,0 +1,92 @@
1
2#include <linux/linkage.h>
3
4#define AX 0
5#define BX 1 * 8
6#define CX 2 * 8
7#define DX 3 * 8
8#define SI 4 * 8
9#define DI 5 * 8
10#define BP 6 * 8
11#define SP 7 * 8
12#define IP 8 * 8
13#define FLAGS 9 * 8
14#define CS 10 * 8
15#define SS 11 * 8
16#define DS 12 * 8
17#define ES 13 * 8
18#define FS 14 * 8
19#define GS 15 * 8
20#define R8 16 * 8
21#define R9 17 * 8
22#define R10 18 * 8
23#define R11 19 * 8
24#define R12 20 * 8
25#define R13 21 * 8
26#define R14 22 * 8
27#define R15 23 * 8
28
29.text
30#ifdef HAVE_ARCH_X86_64_SUPPORT
31ENTRY(perf_regs_load)
32 movq %rax, AX(%rdi)
33 movq %rbx, BX(%rdi)
34 movq %rcx, CX(%rdi)
35 movq %rdx, DX(%rdi)
36 movq %rsi, SI(%rdi)
37 movq %rdi, DI(%rdi)
38 movq %rbp, BP(%rdi)
39
40 leaq 8(%rsp), %rax /* exclude this call. */
41 movq %rax, SP(%rdi)
42
43 movq 0(%rsp), %rax
44 movq %rax, IP(%rdi)
45
46 movq $0, FLAGS(%rdi)
47 movq $0, CS(%rdi)
48 movq $0, SS(%rdi)
49 movq $0, DS(%rdi)
50 movq $0, ES(%rdi)
51 movq $0, FS(%rdi)
52 movq $0, GS(%rdi)
53
54 movq %r8, R8(%rdi)
55 movq %r9, R9(%rdi)
56 movq %r10, R10(%rdi)
57 movq %r11, R11(%rdi)
58 movq %r12, R12(%rdi)
59 movq %r13, R13(%rdi)
60 movq %r14, R14(%rdi)
61 movq %r15, R15(%rdi)
62 ret
63ENDPROC(perf_regs_load)
64#else
65ENTRY(perf_regs_load)
66 push %edi
67 movl 8(%esp), %edi
68 movl %eax, AX(%edi)
69 movl %ebx, BX(%edi)
70 movl %ecx, CX(%edi)
71 movl %edx, DX(%edi)
72 movl %esi, SI(%edi)
73 pop %eax
74 movl %eax, DI(%edi)
75 movl %ebp, BP(%edi)
76
77 leal 4(%esp), %eax /* exclude this call. */
78 movl %eax, SP(%edi)
79
80 movl 0(%esp), %eax
81 movl %eax, IP(%edi)
82
83 movl $0, FLAGS(%edi)
84 movl $0, CS(%edi)
85 movl $0, SS(%edi)
86 movl $0, DS(%edi)
87 movl $0, ES(%edi)
88 movl $0, FS(%edi)
89 movl $0, GS(%edi)
90 ret
91ENDPROC(perf_regs_load)
92#endif
diff --git a/tools/perf/arch/x86/util/unwind-libdw.c b/tools/perf/arch/x86/util/unwind-libdw.c
new file mode 100644
index 000000000000..c4b72176ca83
--- /dev/null
+++ b/tools/perf/arch/x86/util/unwind-libdw.c
@@ -0,0 +1,51 @@
1#include <elfutils/libdwfl.h>
2#include "../../util/unwind-libdw.h"
3#include "../../util/perf_regs.h"
4
5bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
6{
7 struct unwind_info *ui = arg;
8 struct regs_dump *user_regs = &ui->sample->user_regs;
9 Dwarf_Word dwarf_regs[17];
10 unsigned nregs;
11
12#define REG(r) ({ \
13 Dwarf_Word val = 0; \
14 perf_reg_value(&val, user_regs, PERF_REG_X86_##r); \
15 val; \
16})
17
18 if (user_regs->abi == PERF_SAMPLE_REGS_ABI_32) {
19 dwarf_regs[0] = REG(AX);
20 dwarf_regs[1] = REG(CX);
21 dwarf_regs[2] = REG(DX);
22 dwarf_regs[3] = REG(BX);
23 dwarf_regs[4] = REG(SP);
24 dwarf_regs[5] = REG(BP);
25 dwarf_regs[6] = REG(SI);
26 dwarf_regs[7] = REG(DI);
27 dwarf_regs[8] = REG(IP);
28 nregs = 9;
29 } else {
30 dwarf_regs[0] = REG(AX);
31 dwarf_regs[1] = REG(DX);
32 dwarf_regs[2] = REG(CX);
33 dwarf_regs[3] = REG(BX);
34 dwarf_regs[4] = REG(SI);
35 dwarf_regs[5] = REG(DI);
36 dwarf_regs[6] = REG(BP);
37 dwarf_regs[7] = REG(SP);
38 dwarf_regs[8] = REG(R8);
39 dwarf_regs[9] = REG(R9);
40 dwarf_regs[10] = REG(R10);
41 dwarf_regs[11] = REG(R11);
42 dwarf_regs[12] = REG(R12);
43 dwarf_regs[13] = REG(R13);
44 dwarf_regs[14] = REG(R14);
45 dwarf_regs[15] = REG(R15);
46 dwarf_regs[16] = REG(IP);
47 nregs = 17;
48 }
49
50 return dwfl_thread_state_registers(thread, 0, nregs, dwarf_regs);
51}
diff --git a/tools/perf/arch/x86/util/unwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c
index 456a88cf5b37..3261f68c6a7c 100644
--- a/tools/perf/arch/x86/util/unwind.c
+++ b/tools/perf/arch/x86/util/unwind-libunwind.c
@@ -5,7 +5,7 @@
5#include "../../util/unwind.h" 5#include "../../util/unwind.h"
6 6
7#ifdef HAVE_ARCH_X86_64_SUPPORT 7#ifdef HAVE_ARCH_X86_64_SUPPORT
8int unwind__arch_reg_id(int regnum) 8int libunwind__arch_reg_id(int regnum)
9{ 9{
10 int id; 10 int id;
11 11
@@ -69,7 +69,7 @@ int unwind__arch_reg_id(int regnum)
69 return id; 69 return id;
70} 70}
71#else 71#else
72int unwind__arch_reg_id(int regnum) 72int libunwind__arch_reg_id(int regnum)
73{ 73{
74 int id; 74 int id;
75 75
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index b3466018bbd7..3a7387551369 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -312,7 +312,6 @@ found:
312 sample_sw.period = sample->period; 312 sample_sw.period = sample->period;
313 sample_sw.time = sample->time; 313 sample_sw.time = sample->time;
314 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type, 314 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
315 evsel->attr.sample_regs_user,
316 evsel->attr.read_format, &sample_sw, 315 evsel->attr.read_format, &sample_sw,
317 false); 316 false);
318 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine); 317 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 78948882e3de..cdcd4eb3a57d 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -268,9 +268,9 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
268 return 0; 268 return 0;
269} 269}
270 270
271static void init_params(void) 271static int init_params(void)
272{ 272{
273 line_range__init(&params.line_range); 273 return line_range__init(&params.line_range);
274} 274}
275 275
276static void cleanup_params(void) 276static void cleanup_params(void)
@@ -515,9 +515,11 @@ int cmd_probe(int argc, const char **argv, const char *prefix)
515{ 515{
516 int ret; 516 int ret;
517 517
518 init_params(); 518 ret = init_params();
519 ret = __cmd_probe(argc, argv, prefix); 519 if (!ret) {
520 cleanup_params(); 520 ret = __cmd_probe(argc, argv, prefix);
521 cleanup_params();
522 }
521 523
522 return ret; 524 return ret;
523} 525}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index af47531b82ec..eb524f91bffe 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -649,7 +649,7 @@ error:
649 return ret; 649 return ret;
650} 650}
651 651
652#ifdef HAVE_LIBUNWIND_SUPPORT 652#ifdef HAVE_DWARF_UNWIND_SUPPORT
653static int get_stack_size(char *str, unsigned long *_size) 653static int get_stack_size(char *str, unsigned long *_size)
654{ 654{
655 char *endptr; 655 char *endptr;
@@ -675,7 +675,7 @@ static int get_stack_size(char *str, unsigned long *_size)
675 max_size, str); 675 max_size, str);
676 return -1; 676 return -1;
677} 677}
678#endif /* HAVE_LIBUNWIND_SUPPORT */ 678#endif /* HAVE_DWARF_UNWIND_SUPPORT */
679 679
680int record_parse_callchain(const char *arg, struct record_opts *opts) 680int record_parse_callchain(const char *arg, struct record_opts *opts)
681{ 681{
@@ -704,7 +704,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
704 "needed for -g fp\n"); 704 "needed for -g fp\n");
705 break; 705 break;
706 706
707#ifdef HAVE_LIBUNWIND_SUPPORT 707#ifdef HAVE_DWARF_UNWIND_SUPPORT
708 /* Dwarf style */ 708 /* Dwarf style */
709 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { 709 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
710 const unsigned long default_stack_dump_size = 8192; 710 const unsigned long default_stack_dump_size = 8192;
@@ -720,7 +720,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
720 ret = get_stack_size(tok, &size); 720 ret = get_stack_size(tok, &size);
721 opts->stack_dump_size = size; 721 opts->stack_dump_size = size;
722 } 722 }
723#endif /* HAVE_LIBUNWIND_SUPPORT */ 723#endif /* HAVE_DWARF_UNWIND_SUPPORT */
724 } else { 724 } else {
725 pr_err("callchain: Unknown --call-graph option " 725 pr_err("callchain: Unknown --call-graph option "
726 "value: %s\n", arg); 726 "value: %s\n", arg);
@@ -735,7 +735,9 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
735 735
736static void callchain_debug(struct record_opts *opts) 736static void callchain_debug(struct record_opts *opts)
737{ 737{
738 pr_debug("callchain: type %d\n", opts->call_graph); 738 static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
739
740 pr_debug("callchain: type %s\n", str[opts->call_graph]);
739 741
740 if (opts->call_graph == CALLCHAIN_DWARF) 742 if (opts->call_graph == CALLCHAIN_DWARF)
741 pr_debug("callchain: stack dump size %d\n", 743 pr_debug("callchain: stack dump size %d\n",
@@ -749,6 +751,8 @@ int record_parse_callchain_opt(const struct option *opt,
749 struct record_opts *opts = opt->value; 751 struct record_opts *opts = opt->value;
750 int ret; 752 int ret;
751 753
754 opts->call_graph_enabled = !unset;
755
752 /* --no-call-graph */ 756 /* --no-call-graph */
753 if (unset) { 757 if (unset) {
754 opts->call_graph = CALLCHAIN_NONE; 758 opts->call_graph = CALLCHAIN_NONE;
@@ -769,6 +773,8 @@ int record_callchain_opt(const struct option *opt,
769{ 773{
770 struct record_opts *opts = opt->value; 774 struct record_opts *opts = opt->value;
771 775
776 opts->call_graph_enabled = !unset;
777
772 if (opts->call_graph == CALLCHAIN_NONE) 778 if (opts->call_graph == CALLCHAIN_NONE)
773 opts->call_graph = CALLCHAIN_FP; 779 opts->call_graph = CALLCHAIN_FP;
774 780
@@ -776,6 +782,16 @@ int record_callchain_opt(const struct option *opt,
776 return 0; 782 return 0;
777} 783}
778 784
785static int perf_record_config(const char *var, const char *value, void *cb)
786{
787 struct record *rec = cb;
788
789 if (!strcmp(var, "record.call-graph"))
790 return record_parse_callchain(value, &rec->opts);
791
792 return perf_default_config(var, value, cb);
793}
794
779static const char * const record_usage[] = { 795static const char * const record_usage[] = {
780 "perf record [<options>] [<command>]", 796 "perf record [<options>] [<command>]",
781 "perf record [<options>] -- <command> [<options>]", 797 "perf record [<options>] -- <command> [<options>]",
@@ -807,7 +823,7 @@ static struct record record = {
807 823
808#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " 824#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
809 825
810#ifdef HAVE_LIBUNWIND_SUPPORT 826#ifdef HAVE_DWARF_UNWIND_SUPPORT
811const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf"; 827const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
812#else 828#else
813const char record_callchain_help[] = CALLCHAIN_HELP "fp"; 829const char record_callchain_help[] = CALLCHAIN_HELP "fp";
@@ -907,6 +923,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
907 if (rec->evlist == NULL) 923 if (rec->evlist == NULL)
908 return -ENOMEM; 924 return -ENOMEM;
909 925
926 perf_config(perf_record_config, rec);
927
910 argc = parse_options(argc, argv, record_options, record_usage, 928 argc = parse_options(argc, argv, record_options, record_usage,
911 PARSE_OPT_STOP_AT_NON_OPTION); 929 PARSE_OPT_STOP_AT_NON_OPTION);
912 if (!argc && target__none(&rec->opts.target)) 930 if (!argc && target__none(&rec->opts.target))
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 02f985f3a396..c47bf586fcba 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -75,13 +75,10 @@ static int report__config(const char *var, const char *value, void *cb)
75 return perf_default_config(var, value, cb); 75 return perf_default_config(var, value, cb);
76} 76}
77 77
78static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al, 78static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al,
79 struct perf_sample *sample, struct perf_evsel *evsel, 79 struct perf_sample *sample, struct perf_evsel *evsel)
80 union perf_event *event)
81{ 80{
82 struct report *rep = container_of(tool, struct report, tool);
83 struct symbol *parent = NULL; 81 struct symbol *parent = NULL;
84 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
85 struct hist_entry *he; 82 struct hist_entry *he;
86 struct mem_info *mi, *mx; 83 struct mem_info *mi, *mx;
87 uint64_t cost; 84 uint64_t cost;
@@ -90,7 +87,7 @@ static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_locati
90 if (err) 87 if (err)
91 return err; 88 return err;
92 89
93 mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode); 90 mi = sample__resolve_mem(sample, al);
94 if (!mi) 91 if (!mi)
95 return -ENOMEM; 92 return -ENOMEM;
96 93
@@ -131,10 +128,9 @@ out:
131 return err; 128 return err;
132} 129}
133 130
134static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al, 131static int report__add_branch_hist_entry(struct report *rep, struct addr_location *al,
135 struct perf_sample *sample, struct perf_evsel *evsel) 132 struct perf_sample *sample, struct perf_evsel *evsel)
136{ 133{
137 struct report *rep = container_of(tool, struct report, tool);
138 struct symbol *parent = NULL; 134 struct symbol *parent = NULL;
139 unsigned i; 135 unsigned i;
140 struct hist_entry *he; 136 struct hist_entry *he;
@@ -144,8 +140,7 @@ static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_loc
144 if (err) 140 if (err)
145 return err; 141 return err;
146 142
147 bi = machine__resolve_bstack(al->machine, al->thread, 143 bi = sample__resolve_bstack(sample, al);
148 sample->branch_stack);
149 if (!bi) 144 if (!bi)
150 return -ENOMEM; 145 return -ENOMEM;
151 146
@@ -190,10 +185,9 @@ out:
190 return err; 185 return err;
191} 186}
192 187
193static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel, 188static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel,
194 struct addr_location *al, struct perf_sample *sample) 189 struct addr_location *al, struct perf_sample *sample)
195{ 190{
196 struct report *rep = container_of(tool, struct report, tool);
197 struct symbol *parent = NULL; 191 struct symbol *parent = NULL;
198 struct hist_entry *he; 192 struct hist_entry *he;
199 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack); 193 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
@@ -244,18 +238,18 @@ static int process_sample_event(struct perf_tool *tool,
244 return 0; 238 return 0;
245 239
246 if (sort__mode == SORT_MODE__BRANCH) { 240 if (sort__mode == SORT_MODE__BRANCH) {
247 ret = report__add_branch_hist_entry(tool, &al, sample, evsel); 241 ret = report__add_branch_hist_entry(rep, &al, sample, evsel);
248 if (ret < 0) 242 if (ret < 0)
249 pr_debug("problem adding lbr entry, skipping event\n"); 243 pr_debug("problem adding lbr entry, skipping event\n");
250 } else if (rep->mem_mode == 1) { 244 } else if (rep->mem_mode == 1) {
251 ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event); 245 ret = report__add_mem_hist_entry(rep, &al, sample, evsel);
252 if (ret < 0) 246 if (ret < 0)
253 pr_debug("problem adding mem entry, skipping event\n"); 247 pr_debug("problem adding mem entry, skipping event\n");
254 } else { 248 } else {
255 if (al.map != NULL) 249 if (al.map != NULL)
256 al.map->dso->hit = 1; 250 al.map->dso->hit = 1;
257 251
258 ret = report__add_hist_entry(tool, evsel, &al, sample); 252 ret = report__add_hist_entry(rep, evsel, &al, sample);
259 if (ret < 0) 253 if (ret < 0)
260 pr_debug("problem incrementing symbol period, skipping event\n"); 254 pr_debug("problem incrementing symbol period, skipping event\n");
261 } 255 }
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 5f989a7d8bc2..65aaa5bbf7ec 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -993,6 +993,16 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
993 return record_parse_callchain_opt(opt, arg, unset); 993 return record_parse_callchain_opt(opt, arg, unset);
994} 994}
995 995
996static int perf_top_config(const char *var, const char *value, void *cb)
997{
998 struct perf_top *top = cb;
999
1000 if (!strcmp(var, "top.call-graph"))
1001 return record_parse_callchain(value, &top->record_opts);
1002
1003 return perf_default_config(var, value, cb);
1004}
1005
996static int 1006static int
997parse_percent_limit(const struct option *opt, const char *arg, 1007parse_percent_limit(const struct option *opt, const char *arg,
998 int unset __maybe_unused) 1008 int unset __maybe_unused)
@@ -1117,6 +1127,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1117 if (top.evlist == NULL) 1127 if (top.evlist == NULL)
1118 return -ENOMEM; 1128 return -ENOMEM;
1119 1129
1130 perf_config(perf_top_config, &top);
1131
1120 argc = parse_options(argc, argv, options, top_usage, 0); 1132 argc = parse_options(argc, argv, options, top_usage, 0);
1121 if (argc) 1133 if (argc)
1122 usage_with_options(top_usage, options); 1134 usage_with_options(top_usage, options);
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 0331ea2701a3..c23418225c2c 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -59,6 +59,18 @@ ifeq ($(NO_PERF_REGS),0)
59 CFLAGS += -DHAVE_PERF_REGS_SUPPORT 59 CFLAGS += -DHAVE_PERF_REGS_SUPPORT
60endif 60endif
61 61
62ifndef NO_LIBELF
63 # for linking with debug library, run like:
64 # make DEBUG=1 LIBDW_DIR=/opt/libdw/
65 ifdef LIBDW_DIR
66 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
67 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
68
69 FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
70 FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
71 endif
72endif
73
62# include ARCH specific config 74# include ARCH specific config
63-include $(src-perf)/arch/$(ARCH)/Makefile 75-include $(src-perf)/arch/$(ARCH)/Makefile
64 76
@@ -147,7 +159,35 @@ CORE_FEATURE_TESTS = \
147 libunwind \ 159 libunwind \
148 on-exit \ 160 on-exit \
149 stackprotector-all \ 161 stackprotector-all \
150 timerfd 162 timerfd \
163 libdw-dwarf-unwind
164
165LIB_FEATURE_TESTS = \
166 dwarf \
167 glibc \
168 gtk2 \
169 libaudit \
170 libbfd \
171 libelf \
172 libnuma \
173 libperl \
174 libpython \
175 libslang \
176 libunwind \
177 libdw-dwarf-unwind
178
179VF_FEATURE_TESTS = \
180 backtrace \
181 fortify-source \
182 gtk2-infobar \
183 libelf-getphdrnum \
184 libelf-mmap \
185 libpython-version \
186 on-exit \
187 stackprotector-all \
188 timerfd \
189 libunwind-debug-frame \
190 bionic
151 191
152# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features. 192# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
153# If in the future we need per-feature checks/flags for features not 193# If in the future we need per-feature checks/flags for features not
@@ -161,17 +201,6 @@ endef
161$(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat))) 201$(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat)))
162 202
163# 203#
164# So here we detect whether test-all was rebuilt, to be able
165# to skip the print-out of the long features list if the file
166# existed before and after it was built:
167#
168ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all.bin),)
169 test-all-failed := 1
170else
171 test-all-failed := 0
172endif
173
174#
175# Special fast-path for the 'all features are available' case: 204# Special fast-path for the 'all features are available' case:
176# 205#
177$(call feature_check,all,$(MSG)) 206$(call feature_check,all,$(MSG))
@@ -180,15 +209,6 @@ $(call feature_check,all,$(MSG))
180# Just in case the build freshly failed, make sure we print the 209# Just in case the build freshly failed, make sure we print the
181# feature matrix: 210# feature matrix:
182# 211#
183ifeq ($(feature-all), 0)
184 test-all-failed := 1
185endif
186
187ifeq ($(test-all-failed),1)
188 $(info )
189 $(info Auto-detecting system features:)
190endif
191
192ifeq ($(feature-all), 1) 212ifeq ($(feature-all), 1)
193 # 213 #
194 # test-all.c passed - just set all the core feature flags to 1: 214 # test-all.c passed - just set all the core feature flags to 1:
@@ -199,27 +219,6 @@ else
199 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat))) 219 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat)))
200endif 220endif
201 221
202#
203# Print the result of the feature test:
204#
205feature_print = $(eval $(feature_print_code)) $(info $(MSG))
206
207define feature_print_code
208 ifeq ($(feature-$(1)), 1)
209 MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(1))
210 else
211 MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1))
212 endif
213endef
214
215#
216# Only print out our features if we rebuilt the testcases or if a test failed:
217#
218ifeq ($(test-all-failed), 1)
219 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_print,$(feat)))
220 $(info )
221endif
222
223ifeq ($(feature-stackprotector-all), 1) 222ifeq ($(feature-stackprotector-all), 1)
224 CFLAGS += -fstack-protector-all 223 CFLAGS += -fstack-protector-all
225endif 224endif
@@ -264,6 +263,7 @@ ifdef NO_LIBELF
264 NO_DWARF := 1 263 NO_DWARF := 1
265 NO_DEMANGLE := 1 264 NO_DEMANGLE := 1
266 NO_LIBUNWIND := 1 265 NO_LIBUNWIND := 1
266 NO_LIBDW_DWARF_UNWIND := 1
267else 267else
268 ifeq ($(feature-libelf), 0) 268 ifeq ($(feature-libelf), 0)
269 ifeq ($(feature-glibc), 1) 269 ifeq ($(feature-glibc), 1)
@@ -282,13 +282,12 @@ else
282 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 282 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
283 endif 283 endif
284 else 284 else
285 # for linking with debug library, run like: 285 ifndef NO_LIBDW_DWARF_UNWIND
286 # make DEBUG=1 LIBDW_DIR=/opt/libdw/ 286 ifneq ($(feature-libdw-dwarf-unwind),1)
287 ifdef LIBDW_DIR 287 NO_LIBDW_DWARF_UNWIND := 1
288 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include 288 msg := $(warning No libdw DWARF unwind found, Please install elfutils-devel/libdw-dev >= 0.158 and/or set LIBDW_DIR);
289 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib 289 endif
290 endif 290 endif
291
292 ifneq ($(feature-dwarf), 1) 291 ifneq ($(feature-dwarf), 1)
293 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); 292 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);
294 NO_DWARF := 1 293 NO_DWARF := 1
@@ -324,25 +323,51 @@ endif # NO_LIBELF
324 323
325ifndef NO_LIBUNWIND 324ifndef NO_LIBUNWIND
326 ifneq ($(feature-libunwind), 1) 325 ifneq ($(feature-libunwind), 1)
327 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1); 326 msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
328 NO_LIBUNWIND := 1 327 NO_LIBUNWIND := 1
328 endif
329endif
330
331dwarf-post-unwind := 1
332dwarf-post-unwind-text := BUG
333
334# setup DWARF post unwinder
335ifdef NO_LIBUNWIND
336 ifdef NO_LIBDW_DWARF_UNWIND
337 msg := $(warning Disabling post unwind, no support found.);
338 dwarf-post-unwind := 0
329 else 339 else
330 ifeq ($(ARCH),arm) 340 dwarf-post-unwind-text := libdw
331 $(call feature_check,libunwind-debug-frame) 341 endif
332 ifneq ($(feature-libunwind-debug-frame), 1) 342else
333 msg := $(warning No debug_frame support found in libunwind); 343 dwarf-post-unwind-text := libunwind
334 CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME 344 # Enable libunwind support by default.
335 endif 345 ifndef NO_LIBDW_DWARF_UNWIND
336 else 346 NO_LIBDW_DWARF_UNWIND := 1
337 # non-ARM has no dwarf_find_debug_frame() function: 347 endif
348endif
349
350ifeq ($(dwarf-post-unwind),1)
351 CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT
352else
353 NO_DWARF_UNWIND := 1
354endif
355
356ifndef NO_LIBUNWIND
357 ifeq ($(ARCH),arm)
358 $(call feature_check,libunwind-debug-frame)
359 ifneq ($(feature-libunwind-debug-frame), 1)
360 msg := $(warning No debug_frame support found in libunwind);
338 CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME 361 CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
339 endif 362 endif
340 363 else
341 CFLAGS += -DHAVE_LIBUNWIND_SUPPORT 364 # non-ARM has no dwarf_find_debug_frame() function:
342 EXTLIBS += $(LIBUNWIND_LIBS) 365 CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
343 CFLAGS += $(LIBUNWIND_CFLAGS) 366 endif
344 LDFLAGS += $(LIBUNWIND_LDFLAGS) 367 CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
345 endif # ifneq ($(feature-libunwind), 1) 368 EXTLIBS += $(LIBUNWIND_LIBS)
369 CFLAGS += $(LIBUNWIND_CFLAGS)
370 LDFLAGS += $(LIBUNWIND_LDFLAGS)
346endif 371endif
347 372
348ifndef NO_LIBAUDIT 373ifndef NO_LIBAUDIT
@@ -602,3 +627,84 @@ ifdef DESTDIR
602plugindir=$(libdir)/traceevent/plugins 627plugindir=$(libdir)/traceevent/plugins
603plugindir_SQ= $(subst ','\'',$(plugindir)) 628plugindir_SQ= $(subst ','\'',$(plugindir))
604endif 629endif
630
631#
632# Print the result of the feature test:
633#
634feature_print_status = $(eval $(feature_print_status_code)) $(info $(MSG))
635
636define feature_print_status_code
637 ifeq ($(feature-$(1)), 1)
638 MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(1))
639 else
640 MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1))
641 endif
642endef
643
644feature_print_var = $(eval $(feature_print_var_code)) $(info $(MSG))
645define feature_print_var_code
646 MSG = $(shell printf '...%30s: %s' $(1) $($(1)))
647endef
648
649feature_print_text = $(eval $(feature_print_text_code)) $(info $(MSG))
650define feature_print_text_code
651 MSG = $(shell printf '...%30s: %s' $(1) $(2))
652endef
653
654PERF_FEATURES := $(foreach feat,$(LIB_FEATURE_TESTS),feature-$(feat)($(feature-$(feat))))
655PERF_FEATURES_FILE := $(shell touch $(OUTPUT)PERF-FEATURES; cat $(OUTPUT)PERF-FEATURES)
656
657ifeq ($(dwarf-post-unwind),1)
658 PERF_FEATURES += dwarf-post-unwind($(dwarf-post-unwind-text))
659endif
660
661# The $(display_lib) controls the default detection message
662# output. It's set if:
663# - detected features differes from stored features from
664# last build (in PERF-FEATURES file)
665# - one of the $(LIB_FEATURE_TESTS) is not detected
666# - VF is enabled
667
668ifneq ("$(PERF_FEATURES)","$(PERF_FEATURES_FILE)")
669 $(shell echo "$(PERF_FEATURES)" > $(OUTPUT)PERF-FEATURES)
670 display_lib := 1
671endif
672
673feature_check = $(eval $(feature_check_code))
674define feature_check_code
675 ifneq ($(feature-$(1)), 1)
676 display_lib := 1
677 endif
678endef
679
680$(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_check,$(feat)))
681
682ifeq ($(VF),1)
683 display_lib := 1
684 display_vf := 1
685endif
686
687ifeq ($(display_lib),1)
688 $(info )
689 $(info Auto-detecting system features:)
690 $(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_print_status,$(feat),))
691
692 ifeq ($(dwarf-post-unwind),1)
693 $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
694 endif
695endif
696
697ifeq ($(display_vf),1)
698 $(foreach feat,$(VF_FEATURE_TESTS),$(call feature_print_status,$(feat),))
699 $(info )
700 $(call feature_print_var,prefix)
701 $(call feature_print_var,bindir)
702 $(call feature_print_var,libdir)
703 $(call feature_print_var,sysconfdir)
704 $(call feature_print_var,LIBUNWIND_DIR)
705 $(call feature_print_var,LIBDW_DIR)
706endif
707
708ifeq ($(display_lib),1)
709 $(info )
710endif
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 523b7bc10553..2da103c53f89 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -26,7 +26,8 @@ FILES= \
26 test-libunwind-debug-frame.bin \ 26 test-libunwind-debug-frame.bin \
27 test-on-exit.bin \ 27 test-on-exit.bin \
28 test-stackprotector-all.bin \ 28 test-stackprotector-all.bin \
29 test-timerfd.bin 29 test-timerfd.bin \
30 test-libdw-dwarf-unwind.bin
30 31
31CC := $(CROSS_COMPILE)gcc -MD 32CC := $(CROSS_COMPILE)gcc -MD
32PKG_CONFIG := $(CROSS_COMPILE)pkg-config 33PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -141,6 +142,9 @@ test-backtrace.bin:
141test-timerfd.bin: 142test-timerfd.bin:
142 $(BUILD) 143 $(BUILD)
143 144
145test-libdw-dwarf-unwind.bin:
146 $(BUILD)
147
144-include *.d 148-include *.d
145 149
146############################### 150###############################
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index 9b8a544155bb..fc37eb3ca17b 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -89,6 +89,10 @@
89# include "test-stackprotector-all.c" 89# include "test-stackprotector-all.c"
90#undef main 90#undef main
91 91
92#define main main_test_libdw_dwarf_unwind
93# include "test-libdw-dwarf-unwind.c"
94#undef main
95
92int main(int argc, char *argv[]) 96int main(int argc, char *argv[])
93{ 97{
94 main_test_libpython(); 98 main_test_libpython();
@@ -111,6 +115,7 @@ int main(int argc, char *argv[])
111 main_test_libnuma(); 115 main_test_libnuma();
112 main_test_timerfd(); 116 main_test_timerfd();
113 main_test_stackprotector_all(); 117 main_test_stackprotector_all();
118 main_test_libdw_dwarf_unwind();
114 119
115 return 0; 120 return 0;
116} 121}
diff --git a/tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c b/tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
new file mode 100644
index 000000000000..f676a3ff442a
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
@@ -0,0 +1,13 @@
1
2#include <elfutils/libdwfl.h>
3
4int main(void)
5{
6 /*
7 * This function is guarded via: __nonnull_attribute__ (1, 2).
8 * Passing '1' as arguments value. This code is never executed,
9 * only compiled.
10 */
11 dwfl_thread_getframes((void *) 1, (void *) 1, NULL);
12 return 0;
13}
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index e84fa26bc1be..6898ad0e199f 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -251,12 +251,14 @@ void pthread__unblock_sigwinch(void);
251enum perf_call_graph_mode { 251enum perf_call_graph_mode {
252 CALLCHAIN_NONE, 252 CALLCHAIN_NONE,
253 CALLCHAIN_FP, 253 CALLCHAIN_FP,
254 CALLCHAIN_DWARF 254 CALLCHAIN_DWARF,
255 CALLCHAIN_MAX
255}; 256};
256 257
257struct record_opts { 258struct record_opts {
258 struct target target; 259 struct target target;
259 int call_graph; 260 int call_graph;
261 bool call_graph_enabled;
260 bool group; 262 bool group;
261 bool inherit_stat; 263 bool inherit_stat;
262 bool no_buffering; 264 bool no_buffering;
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 1e67437fb4ca..b11bf8a08430 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -115,6 +115,14 @@ static struct test {
115 .desc = "Test parsing with no sample_id_all bit set", 115 .desc = "Test parsing with no sample_id_all bit set",
116 .func = test__parse_no_sample_id_all, 116 .func = test__parse_no_sample_id_all,
117 }, 117 },
118#if defined(__x86_64__) || defined(__i386__)
119#ifdef HAVE_DWARF_UNWIND_SUPPORT
120 {
121 .desc = "Test dwarf unwind",
122 .func = test__dwarf_unwind,
123 },
124#endif
125#endif
118 { 126 {
119 .func = NULL, 127 .func = NULL,
120 }, 128 },
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
new file mode 100644
index 000000000000..f16ea2808a75
--- /dev/null
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -0,0 +1,144 @@
1#include <linux/compiler.h>
2#include <sys/types.h>
3#include <unistd.h>
4#include "tests.h"
5#include "debug.h"
6#include "machine.h"
7#include "event.h"
8#include "unwind.h"
9#include "perf_regs.h"
10#include "map.h"
11#include "thread.h"
12
13static int mmap_handler(struct perf_tool *tool __maybe_unused,
14 union perf_event *event,
15 struct perf_sample *sample __maybe_unused,
16 struct machine *machine)
17{
18 return machine__process_mmap_event(machine, event, NULL);
19}
20
21static int init_live_machine(struct machine *machine)
22{
23 union perf_event event;
24 pid_t pid = getpid();
25
26 return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
27 mmap_handler, machine, true);
28}
29
30#define MAX_STACK 6
31
32static int unwind_entry(struct unwind_entry *entry, void *arg)
33{
34 unsigned long *cnt = (unsigned long *) arg;
35 char *symbol = entry->sym ? entry->sym->name : NULL;
36 static const char *funcs[MAX_STACK] = {
37 "test__arch_unwind_sample",
38 "unwind_thread",
39 "krava_3",
40 "krava_2",
41 "krava_1",
42 "test__dwarf_unwind"
43 };
44
45 if (*cnt >= MAX_STACK) {
46 pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
47 return -1;
48 }
49
50 if (!symbol) {
51 pr_debug("failed: got unresolved address 0x%" PRIx64 "\n",
52 entry->ip);
53 return -1;
54 }
55
56 pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip);
57 return strcmp((const char *) symbol, funcs[(*cnt)++]);
58}
59
60__attribute__ ((noinline))
61static int unwind_thread(struct thread *thread, struct machine *machine)
62{
63 struct perf_sample sample;
64 unsigned long cnt = 0;
65 int err = -1;
66
67 memset(&sample, 0, sizeof(sample));
68
69 if (test__arch_unwind_sample(&sample, thread)) {
70 pr_debug("failed to get unwind sample\n");
71 goto out;
72 }
73
74 err = unwind__get_entries(unwind_entry, &cnt, machine, thread,
75 &sample, MAX_STACK);
76 if (err)
77 pr_debug("unwind failed\n");
78 else if (cnt != MAX_STACK) {
79 pr_debug("got wrong number of stack entries %lu != %d\n",
80 cnt, MAX_STACK);
81 err = -1;
82 }
83
84 out:
85 free(sample.user_stack.data);
86 free(sample.user_regs.regs);
87 return err;
88}
89
90__attribute__ ((noinline))
91static int krava_3(struct thread *thread, struct machine *machine)
92{
93 return unwind_thread(thread, machine);
94}
95
96__attribute__ ((noinline))
97static int krava_2(struct thread *thread, struct machine *machine)
98{
99 return krava_3(thread, machine);
100}
101
102__attribute__ ((noinline))
103static int krava_1(struct thread *thread, struct machine *machine)
104{
105 return krava_2(thread, machine);
106}
107
108int test__dwarf_unwind(void)
109{
110 struct machines machines;
111 struct machine *machine;
112 struct thread *thread;
113 int err = -1;
114
115 machines__init(&machines);
116
117 machine = machines__find(&machines, HOST_KERNEL_ID);
118 if (!machine) {
119 pr_err("Could not get machine\n");
120 return -1;
121 }
122
123 if (init_live_machine(machine)) {
124 pr_err("Could not init machine\n");
125 goto out;
126 }
127
128 if (verbose > 1)
129 machine__fprintf(machine, stderr);
130
131 thread = machine__find_thread(machine, getpid());
132 if (!thread) {
133 pr_err("Could not get thread\n");
134 goto out;
135 }
136
137 err = krava_1(thread, machine);
138
139 out:
140 machine__delete_threads(machine);
141 machine__exit(machine);
142 machines__exit(&machines);
143 return err;
144}
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 00544b8b644b..5daeae1cb4c0 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -27,6 +27,7 @@ make_no_ui := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
27make_no_demangle := NO_DEMANGLE=1 27make_no_demangle := NO_DEMANGLE=1
28make_no_libelf := NO_LIBELF=1 28make_no_libelf := NO_LIBELF=1
29make_no_libunwind := NO_LIBUNWIND=1 29make_no_libunwind := NO_LIBUNWIND=1
30make_no_libdw_dwarf_unwind := NO_LIBDW_DWARF_UNWIND=1
30make_no_backtrace := NO_BACKTRACE=1 31make_no_backtrace := NO_BACKTRACE=1
31make_no_libnuma := NO_LIBNUMA=1 32make_no_libnuma := NO_LIBNUMA=1
32make_no_libaudit := NO_LIBAUDIT=1 33make_no_libaudit := NO_LIBAUDIT=1
@@ -35,8 +36,9 @@ make_tags := tags
35make_cscope := cscope 36make_cscope := cscope
36make_help := help 37make_help := help
37make_doc := doc 38make_doc := doc
38make_perf_o := perf.o 39make_perf_o := perf.o
39make_util_map_o := util/map.o 40make_util_map_o := util/map.o
41make_util_pmu_bison_o := util/pmu-bison.o
40make_install := install 42make_install := install
41make_install_bin := install-bin 43make_install_bin := install-bin
42make_install_doc := install-doc 44make_install_doc := install-doc
@@ -49,6 +51,7 @@ make_install_pdf := install-pdf
49make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 51make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
50make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 52make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
51make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 53make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
54make_minimal += NO_LIBDW_DWARF_UNWIND=1
52 55
53# $(run) contains all available tests 56# $(run) contains all available tests
54run := make_pure 57run := make_pure
@@ -65,6 +68,7 @@ run += make_no_ui
65run += make_no_demangle 68run += make_no_demangle
66run += make_no_libelf 69run += make_no_libelf
67run += make_no_libunwind 70run += make_no_libunwind
71run += make_no_libdw_dwarf_unwind
68run += make_no_backtrace 72run += make_no_backtrace
69run += make_no_libnuma 73run += make_no_libnuma
70run += make_no_libaudit 74run += make_no_libaudit
@@ -73,6 +77,7 @@ run += make_help
73run += make_doc 77run += make_doc
74run += make_perf_o 78run += make_perf_o
75run += make_util_map_o 79run += make_util_map_o
80run += make_util_pmu_bison_o
76run += make_install 81run += make_install
77run += make_install_bin 82run += make_install_bin
78# FIXME 'install-*' commented out till they're fixed 83# FIXME 'install-*' commented out till they're fixed
@@ -113,8 +118,9 @@ test_make_doc_O := $(test_ok)
113 118
114test_make_python_perf_so := test -f $(PERF)/python/perf.so 119test_make_python_perf_so := test -f $(PERF)/python/perf.so
115 120
116test_make_perf_o := test -f $(PERF)/perf.o 121test_make_perf_o := test -f $(PERF)/perf.o
117test_make_util_map_o := test -f $(PERF)/util/map.o 122test_make_util_map_o := test -f $(PERF)/util/map.o
123test_make_util_pmu_bison_o := test -f $(PERF)/util/pmu-bison.o
118 124
119define test_dest_files 125define test_dest_files
120 for file in $(1); do \ 126 for file in $(1); do \
@@ -167,13 +173,10 @@ test_make_install_info_O := $(test_ok)
167test_make_install_pdf := $(test_ok) 173test_make_install_pdf := $(test_ok)
168test_make_install_pdf_O := $(test_ok) 174test_make_install_pdf_O := $(test_ok)
169 175
170# Kbuild tests only 176test_make_python_perf_so_O := test -f $$TMP_O/python/perf.so
171#test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so 177test_make_perf_o_O := test -f $$TMP_O/perf.o
172#test_make_perf_o_O := test -f $$TMP/tools/perf/perf.o 178test_make_util_map_o_O := test -f $$TMP_O/util/map.o
173#test_make_util_map_o_O := test -f $$TMP/tools/perf/util/map.o 179test_make_util_pmu_bison_o_O := test -f $$TMP_O/util/pmu-bison.o
174
175test_make_perf_o_O := true
176test_make_util_map_o_O := true
177 180
178test_default = test -x $(PERF)/perf 181test_default = test -x $(PERF)/perf
179test = $(if $(test_$1),$(test_$1),$(test_default)) 182test = $(if $(test_$1),$(test_$1),$(test_default))
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 4db0ae617d70..8605ff5572ae 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -2,7 +2,7 @@
2#include "parse-events.h" 2#include "parse-events.h"
3#include "evsel.h" 3#include "evsel.h"
4#include "evlist.h" 4#include "evlist.h"
5#include "fs.h" 5#include <api/fs/fs.h>
6#include <api/fs/debugfs.h> 6#include <api/fs/debugfs.h>
7#include "tests.h" 7#include "tests.h"
8#include <linux/hw_breakpoint.h> 8#include <linux/hw_breakpoint.h>
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 1b677202638d..0014d3c8c21c 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -22,8 +22,8 @@
22} while (0) 22} while (0)
23 23
24static bool samples_same(const struct perf_sample *s1, 24static bool samples_same(const struct perf_sample *s1,
25 const struct perf_sample *s2, u64 type, u64 regs_user, 25 const struct perf_sample *s2,
26 u64 read_format) 26 u64 type, u64 read_format)
27{ 27{
28 size_t i; 28 size_t i;
29 29
@@ -95,8 +95,9 @@ static bool samples_same(const struct perf_sample *s1,
95 } 95 }
96 96
97 if (type & PERF_SAMPLE_REGS_USER) { 97 if (type & PERF_SAMPLE_REGS_USER) {
98 size_t sz = hweight_long(regs_user) * sizeof(u64); 98 size_t sz = hweight_long(s1->user_regs.mask) * sizeof(u64);
99 99
100 COMP(user_regs.mask);
100 COMP(user_regs.abi); 101 COMP(user_regs.abi);
101 if (s1->user_regs.abi && 102 if (s1->user_regs.abi &&
102 (!s1->user_regs.regs || !s2->user_regs.regs || 103 (!s1->user_regs.regs || !s2->user_regs.regs ||
@@ -174,6 +175,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
174 .branch_stack = &branch_stack.branch_stack, 175 .branch_stack = &branch_stack.branch_stack,
175 .user_regs = { 176 .user_regs = {
176 .abi = PERF_SAMPLE_REGS_ABI_64, 177 .abi = PERF_SAMPLE_REGS_ABI_64,
178 .mask = sample_regs_user,
177 .regs = user_regs, 179 .regs = user_regs,
178 }, 180 },
179 .user_stack = { 181 .user_stack = {
@@ -201,8 +203,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
201 sample.read.one.id = 99; 203 sample.read.one.id = 99;
202 } 204 }
203 205
204 sz = perf_event__sample_event_size(&sample, sample_type, 206 sz = perf_event__sample_event_size(&sample, sample_type, read_format);
205 sample_regs_user, read_format);
206 bufsz = sz + 4096; /* Add a bit for overrun checking */ 207 bufsz = sz + 4096; /* Add a bit for overrun checking */
207 event = malloc(bufsz); 208 event = malloc(bufsz);
208 if (!event) { 209 if (!event) {
@@ -215,8 +216,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
215 event->header.misc = 0; 216 event->header.misc = 0;
216 event->header.size = sz; 217 event->header.size = sz;
217 218
218 err = perf_event__synthesize_sample(event, sample_type, 219 err = perf_event__synthesize_sample(event, sample_type, read_format,
219 sample_regs_user, read_format,
220 &sample, false); 220 &sample, false);
221 if (err) { 221 if (err) {
222 pr_debug("%s failed for sample_type %#"PRIx64", error %d\n", 222 pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
@@ -244,8 +244,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
244 goto out_free; 244 goto out_free;
245 } 245 }
246 246
247 if (!samples_same(&sample, &sample_out, sample_type, 247 if (!samples_same(&sample, &sample_out, sample_type, read_format)) {
248 sample_regs_user, read_format)) {
249 pr_debug("parsing failed for sample_type %#"PRIx64"\n", 248 pr_debug("parsing failed for sample_type %#"PRIx64"\n",
250 sample_type); 249 sample_type);
251 goto out_free; 250 goto out_free;
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index e0ac713857ba..a24795ca002d 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -40,5 +40,14 @@ int test__code_reading(void);
40int test__sample_parsing(void); 40int test__sample_parsing(void);
41int test__keep_tracking(void); 41int test__keep_tracking(void);
42int test__parse_no_sample_id_all(void); 42int test__parse_no_sample_id_all(void);
43int test__dwarf_unwind(void);
43 44
45#if defined(__x86_64__) || defined(__i386__)
46#ifdef HAVE_DWARF_UNWIND_SUPPORT
47struct thread;
48struct perf_sample;
49int test__arch_unwind_sample(struct perf_sample *sample,
50 struct thread *thread);
51#endif
52#endif
44#endif /* TESTS_H */ 53#endif /* TESTS_H */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index a9b48c42e81e..7fe4994eeb63 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -1,5 +1,5 @@
1#include "util.h" 1#include "util.h"
2#include "fs.h" 2#include <api/fs/fs.h>
3#include "../perf.h" 3#include "../perf.h"
4#include "cpumap.h" 4#include "cpumap.h"
5#include <assert.h> 5#include <assert.h>
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 4045d086d9d9..64453d63b971 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -45,8 +45,8 @@ int dso__read_binary_type_filename(const struct dso *dso,
45 debuglink--; 45 debuglink--;
46 if (*debuglink == '/') 46 if (*debuglink == '/')
47 debuglink++; 47 debuglink++;
48 filename__read_debuglink(dso->long_name, debuglink, 48 ret = filename__read_debuglink(dso->long_name, debuglink,
49 size - (debuglink - filename)); 49 size - (debuglink - filename));
50 } 50 }
51 break; 51 break;
52 case DSO_BINARY_TYPE__BUILD_ID_CACHE: 52 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index cd7d6f078cdd..ab06f1c03655 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -102,6 +102,16 @@ struct dso {
102 char name[0]; 102 char name[0];
103}; 103};
104 104
105/* dso__for_each_symbol - iterate over the symbols of given type
106 *
107 * @dso: the 'struct dso *' in which symbols itereated
108 * @pos: the 'struct symbol *' to use as a loop cursor
109 * @n: the 'struct rb_node *' to use as a temporary storage
110 * @type: the 'enum map_type' type of symbols
111 */
112#define dso__for_each_symbol(dso, pos, n, type) \
113 symbols__for_each_entry(&(dso)->symbols[(type)], pos, n)
114
105static inline void dso__set_loaded(struct dso *dso, enum map_type type) 115static inline void dso__set_loaded(struct dso *dso, enum map_type type)
106{ 116{
107 dso->loaded |= (1 << type); 117 dso->loaded |= (1 << type);
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 851fa06f4a42..38457d447a13 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -85,6 +85,7 @@ struct sample_event {
85 85
86struct regs_dump { 86struct regs_dump {
87 u64 abi; 87 u64 abi;
88 u64 mask;
88 u64 *regs; 89 u64 *regs;
89}; 90};
90 91
@@ -259,9 +260,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
259const char *perf_event__name(unsigned int id); 260const char *perf_event__name(unsigned int id);
260 261
261size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, 262size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
262 u64 sample_regs_user, u64 read_format); 263 u64 read_format);
263int perf_event__synthesize_sample(union perf_event *event, u64 type, 264int perf_event__synthesize_sample(union perf_event *event, u64 type,
264 u64 sample_regs_user, u64 read_format, 265 u64 read_format,
265 const struct perf_sample *sample, 266 const struct perf_sample *sample,
266 bool swapped); 267 bool swapped);
267 268
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 55407c594b87..adc94dd1794d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -595,7 +595,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
595 attr->mmap_data = track; 595 attr->mmap_data = track;
596 } 596 }
597 597
598 if (opts->call_graph) { 598 if (opts->call_graph_enabled) {
599 perf_evsel__set_sample_bit(evsel, CALLCHAIN); 599 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
600 600
601 if (opts->call_graph == CALLCHAIN_DWARF) { 601 if (opts->call_graph == CALLCHAIN_DWARF) {
@@ -1220,7 +1220,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1220 memset(data, 0, sizeof(*data)); 1220 memset(data, 0, sizeof(*data));
1221 data->cpu = data->pid = data->tid = -1; 1221 data->cpu = data->pid = data->tid = -1;
1222 data->stream_id = data->id = data->time = -1ULL; 1222 data->stream_id = data->id = data->time = -1ULL;
1223 data->period = 1; 1223 data->period = evsel->attr.sample_period;
1224 data->weight = 0; 1224 data->weight = 0;
1225 1225
1226 if (event->header.type != PERF_RECORD_SAMPLE) { 1226 if (event->header.type != PERF_RECORD_SAMPLE) {
@@ -1396,10 +1396,11 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1396 array++; 1396 array++;
1397 1397
1398 if (data->user_regs.abi) { 1398 if (data->user_regs.abi) {
1399 u64 regs_user = evsel->attr.sample_regs_user; 1399 u64 mask = evsel->attr.sample_regs_user;
1400 1400
1401 sz = hweight_long(regs_user) * sizeof(u64); 1401 sz = hweight_long(mask) * sizeof(u64);
1402 OVERFLOW_CHECK(array, sz, max_size); 1402 OVERFLOW_CHECK(array, sz, max_size);
1403 data->user_regs.mask = mask;
1403 data->user_regs.regs = (u64 *)array; 1404 data->user_regs.regs = (u64 *)array;
1404 array = (void *)array + sz; 1405 array = (void *)array + sz;
1405 } 1406 }
@@ -1451,7 +1452,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1451} 1452}
1452 1453
1453size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, 1454size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
1454 u64 sample_regs_user, u64 read_format) 1455 u64 read_format)
1455{ 1456{
1456 size_t sz, result = sizeof(struct sample_event); 1457 size_t sz, result = sizeof(struct sample_event);
1457 1458
@@ -1517,7 +1518,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
1517 if (type & PERF_SAMPLE_REGS_USER) { 1518 if (type & PERF_SAMPLE_REGS_USER) {
1518 if (sample->user_regs.abi) { 1519 if (sample->user_regs.abi) {
1519 result += sizeof(u64); 1520 result += sizeof(u64);
1520 sz = hweight_long(sample_regs_user) * sizeof(u64); 1521 sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
1521 result += sz; 1522 result += sz;
1522 } else { 1523 } else {
1523 result += sizeof(u64); 1524 result += sizeof(u64);
@@ -1546,7 +1547,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
1546} 1547}
1547 1548
1548int perf_event__synthesize_sample(union perf_event *event, u64 type, 1549int perf_event__synthesize_sample(union perf_event *event, u64 type,
1549 u64 sample_regs_user, u64 read_format, 1550 u64 read_format,
1550 const struct perf_sample *sample, 1551 const struct perf_sample *sample,
1551 bool swapped) 1552 bool swapped)
1552{ 1553{
@@ -1687,7 +1688,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
1687 if (type & PERF_SAMPLE_REGS_USER) { 1688 if (type & PERF_SAMPLE_REGS_USER) {
1688 if (sample->user_regs.abi) { 1689 if (sample->user_regs.abi) {
1689 *array++ = sample->user_regs.abi; 1690 *array++ = sample->user_regs.abi;
1690 sz = hweight_long(sample_regs_user) * sizeof(u64); 1691 sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
1691 memcpy(array, sample->user_regs.regs, sz); 1692 memcpy(array, sample->user_regs.regs, sz);
1692 array = (void *)array + sz; 1693 array = (void *)array + sz;
1693 } else { 1694 } else {
diff --git a/tools/perf/util/fs.c b/tools/perf/util/fs.c
deleted file mode 100644
index f5be1f26e724..000000000000
--- a/tools/perf/util/fs.c
+++ /dev/null
@@ -1,119 +0,0 @@
1
2/* TODO merge/factor into tools/lib/lk/debugfs.c */
3
4#include "util.h"
5#include "util/fs.h"
6
7static const char * const sysfs__fs_known_mountpoints[] = {
8 "/sys",
9 0,
10};
11
12static const char * const procfs__known_mountpoints[] = {
13 "/proc",
14 0,
15};
16
17struct fs {
18 const char *name;
19 const char * const *mounts;
20 char path[PATH_MAX + 1];
21 bool found;
22 long magic;
23};
24
25enum {
26 FS__SYSFS = 0,
27 FS__PROCFS = 1,
28};
29
30static struct fs fs__entries[] = {
31 [FS__SYSFS] = {
32 .name = "sysfs",
33 .mounts = sysfs__fs_known_mountpoints,
34 .magic = SYSFS_MAGIC,
35 },
36 [FS__PROCFS] = {
37 .name = "proc",
38 .mounts = procfs__known_mountpoints,
39 .magic = PROC_SUPER_MAGIC,
40 },
41};
42
43static bool fs__read_mounts(struct fs *fs)
44{
45 bool found = false;
46 char type[100];
47 FILE *fp;
48
49 fp = fopen("/proc/mounts", "r");
50 if (fp == NULL)
51 return NULL;
52
53 while (!found &&
54 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
55 fs->path, type) == 2) {
56
57 if (strcmp(type, fs->name) == 0)
58 found = true;
59 }
60
61 fclose(fp);
62 return fs->found = found;
63}
64
65static int fs__valid_mount(const char *fs, long magic)
66{
67 struct statfs st_fs;
68
69 if (statfs(fs, &st_fs) < 0)
70 return -ENOENT;
71 else if (st_fs.f_type != magic)
72 return -ENOENT;
73
74 return 0;
75}
76
77static bool fs__check_mounts(struct fs *fs)
78{
79 const char * const *ptr;
80
81 ptr = fs->mounts;
82 while (*ptr) {
83 if (fs__valid_mount(*ptr, fs->magic) == 0) {
84 fs->found = true;
85 strcpy(fs->path, *ptr);
86 return true;
87 }
88 ptr++;
89 }
90
91 return false;
92}
93
94static const char *fs__get_mountpoint(struct fs *fs)
95{
96 if (fs__check_mounts(fs))
97 return fs->path;
98
99 return fs__read_mounts(fs) ? fs->path : NULL;
100}
101
102static const char *fs__mountpoint(int idx)
103{
104 struct fs *fs = &fs__entries[idx];
105
106 if (fs->found)
107 return (const char *)fs->path;
108
109 return fs__get_mountpoint(fs);
110}
111
112#define FS__MOUNTPOINT(name, idx) \
113const char *name##__mountpoint(void) \
114{ \
115 return fs__mountpoint(idx); \
116}
117
118FS__MOUNTPOINT(sysfs, FS__SYSFS);
119FS__MOUNTPOINT(procfs, FS__PROCFS);
diff --git a/tools/perf/util/fs.h b/tools/perf/util/fs.h
deleted file mode 100644
index 5e09ce1bab0e..000000000000
--- a/tools/perf/util/fs.h
+++ /dev/null
@@ -1,7 +0,0 @@
1#ifndef __PERF_FS
2#define __PERF_FS
3
4const char *sysfs__mountpoint(void);
5const char *procfs__mountpoint(void);
6
7#endif /* __PERF_FS */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index e4e6249b87d4..0466efa71140 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -290,7 +290,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
290 if (he->branch_info) { 290 if (he->branch_info) {
291 /* 291 /*
292 * This branch info is (a part of) allocated from 292 * This branch info is (a part of) allocated from
293 * machine__resolve_bstack() and will be freed after 293 * sample__resolve_bstack() and will be freed after
294 * adding new entries. So we need to save a copy. 294 * adding new entries. So we need to save a copy.
295 */ 295 */
296 he->branch_info = malloc(sizeof(*he->branch_info)); 296 he->branch_info = malloc(sizeof(*he->branch_info));
@@ -369,7 +369,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
369 he_stat__add_period(&he->stat, period, weight); 369 he_stat__add_period(&he->stat, period, weight);
370 370
371 /* 371 /*
372 * This mem info was allocated from machine__resolve_mem 372 * This mem info was allocated from sample__resolve_mem
373 * and will not be used anymore. 373 * and will not be used anymore.
374 */ 374 */
375 zfree(&entry->mem_info); 375 zfree(&entry->mem_info);
diff --git a/tools/perf/util/include/linux/hash.h b/tools/perf/util/include/linux/hash.h
deleted file mode 100644
index 201f57397997..000000000000
--- a/tools/perf/util/include/linux/hash.h
+++ /dev/null
@@ -1,5 +0,0 @@
1#include "../../../../include/linux/hash.h"
2
3#ifndef PERF_HASH_H
4#define PERF_HASH_H
5#endif
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
index 1d928a0ce997..bfe0a2afd0d2 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -1,5 +1,4 @@
1#include <linux/kernel.h> 1#include <linux/kernel.h>
2#include <linux/prefetch.h>
3 2
4#include "../../../../include/linux/list.h" 3#include "../../../../include/linux/list.h"
5 4
diff --git a/tools/perf/util/include/linux/magic.h b/tools/perf/util/include/linux/magic.h
deleted file mode 100644
index 07d63cf3e0f6..000000000000
--- a/tools/perf/util/include/linux/magic.h
+++ /dev/null
@@ -1,16 +0,0 @@
1#ifndef _PERF_LINUX_MAGIC_H_
2#define _PERF_LINUX_MAGIC_H_
3
4#ifndef DEBUGFS_MAGIC
5#define DEBUGFS_MAGIC 0x64626720
6#endif
7
8#ifndef SYSFS_MAGIC
9#define SYSFS_MAGIC 0x62656572
10#endif
11
12#ifndef PROC_SUPER_MAGIC
13#define PROC_SUPER_MAGIC 0x9fa0
14#endif
15
16#endif
diff --git a/tools/perf/util/include/linux/prefetch.h b/tools/perf/util/include/linux/prefetch.h
deleted file mode 100644
index 7841e485d8c3..000000000000
--- a/tools/perf/util/include/linux/prefetch.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef PERF_LINUX_PREFETCH_H
2#define PERF_LINUX_PREFETCH_H
3
4static inline void prefetch(void *a __attribute__((unused))) { }
5
6#endif
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 620a1983b76b..813e94e7cf29 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1238,37 +1238,35 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread,
1238 ams->map = al.map; 1238 ams->map = al.map;
1239} 1239}
1240 1240
1241struct mem_info *machine__resolve_mem(struct machine *machine, 1241struct mem_info *sample__resolve_mem(struct perf_sample *sample,
1242 struct thread *thr, 1242 struct addr_location *al)
1243 struct perf_sample *sample,
1244 u8 cpumode)
1245{ 1243{
1246 struct mem_info *mi = zalloc(sizeof(*mi)); 1244 struct mem_info *mi = zalloc(sizeof(*mi));
1247 1245
1248 if (!mi) 1246 if (!mi)
1249 return NULL; 1247 return NULL;
1250 1248
1251 ip__resolve_ams(machine, thr, &mi->iaddr, sample->ip); 1249 ip__resolve_ams(al->machine, al->thread, &mi->iaddr, sample->ip);
1252 ip__resolve_data(machine, thr, cpumode, &mi->daddr, sample->addr); 1250 ip__resolve_data(al->machine, al->thread, al->cpumode,
1251 &mi->daddr, sample->addr);
1253 mi->data_src.val = sample->data_src; 1252 mi->data_src.val = sample->data_src;
1254 1253
1255 return mi; 1254 return mi;
1256} 1255}
1257 1256
1258struct branch_info *machine__resolve_bstack(struct machine *machine, 1257struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
1259 struct thread *thr, 1258 struct addr_location *al)
1260 struct branch_stack *bs)
1261{ 1259{
1262 struct branch_info *bi;
1263 unsigned int i; 1260 unsigned int i;
1261 const struct branch_stack *bs = sample->branch_stack;
1262 struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info));
1264 1263
1265 bi = calloc(bs->nr, sizeof(struct branch_info));
1266 if (!bi) 1264 if (!bi)
1267 return NULL; 1265 return NULL;
1268 1266
1269 for (i = 0; i < bs->nr; i++) { 1267 for (i = 0; i < bs->nr; i++) {
1270 ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to); 1268 ip__resolve_ams(al->machine, al->thread, &bi[i].to, bs->entries[i].to);
1271 ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from); 1269 ip__resolve_ams(al->machine, al->thread, &bi[i].from, bs->entries[i].from);
1272 bi[i].flags = bs->entries[i].flags; 1270 bi[i].flags = bs->entries[i].flags;
1273 } 1271 }
1274 return bi; 1272 return bi;
@@ -1385,8 +1383,7 @@ int machine__resolve_callchain(struct machine *machine,
1385 return 0; 1383 return 0;
1386 1384
1387 return unwind__get_entries(unwind_entry, &callchain_cursor, machine, 1385 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
1388 thread, evsel->attr.sample_regs_user, 1386 thread, sample, max_stack);
1389 sample, max_stack);
1390 1387
1391} 1388}
1392 1389
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index f77e91e483dc..2e6c248c870f 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -91,12 +91,10 @@ void machine__delete_dead_threads(struct machine *machine);
91void machine__delete_threads(struct machine *machine); 91void machine__delete_threads(struct machine *machine);
92void machine__delete(struct machine *machine); 92void machine__delete(struct machine *machine);
93 93
94struct branch_info *machine__resolve_bstack(struct machine *machine, 94struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
95 struct thread *thread, 95 struct addr_location *al);
96 struct branch_stack *bs); 96struct mem_info *sample__resolve_mem(struct perf_sample *sample,
97struct mem_info *machine__resolve_mem(struct machine *machine, 97 struct addr_location *al);
98 struct thread *thread,
99 struct perf_sample *sample, u8 cpumode);
100int machine__resolve_callchain(struct machine *machine, 98int machine__resolve_callchain(struct machine *machine,
101 struct perf_evsel *evsel, 99 struct perf_evsel *evsel,
102 struct thread *thread, 100 struct thread *thread,
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 257e513205ce..f00f058afb3b 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -90,6 +90,16 @@ u64 map__objdump_2mem(struct map *map, u64 ip);
90 90
91struct symbol; 91struct symbol;
92 92
93/* map__for_each_symbol - iterate over the symbols in the given map
94 *
95 * @map: the 'struct map *' in which symbols itereated
96 * @pos: the 'struct symbol *' to use as a loop cursor
97 * @n: the 'struct rb_node *' to use as a temporary storage
98 * Note: caller must ensure map->dso is not NULL (map is loaded).
99 */
100#define map__for_each_symbol(map, pos, n) \
101 dso__for_each_symbol(map->dso, pos, n, map->type)
102
93typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 103typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
94 104
95void map__init(struct map *map, enum map_type type, 105void map__init(struct map *map, enum map_type type,
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
new file mode 100644
index 000000000000..a3539ef30b15
--- /dev/null
+++ b/tools/perf/util/perf_regs.c
@@ -0,0 +1,19 @@
1#include <errno.h>
2#include "perf_regs.h"
3
4int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
5{
6 int i, idx = 0;
7 u64 mask = regs->mask;
8
9 if (!(mask & (1 << id)))
10 return -EINVAL;
11
12 for (i = 0; i < id; i++) {
13 if (mask & (1 << i))
14 idx++;
15 }
16
17 *valp = regs->regs[idx];
18 return 0;
19}
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index a3d42cd74919..d6e8b6a8d7f3 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -1,8 +1,14 @@
1#ifndef __PERF_REGS_H 1#ifndef __PERF_REGS_H
2#define __PERF_REGS_H 2#define __PERF_REGS_H
3 3
4#include "types.h"
5#include "event.h"
6
4#ifdef HAVE_PERF_REGS_SUPPORT 7#ifdef HAVE_PERF_REGS_SUPPORT
5#include <perf_regs.h> 8#include <perf_regs.h>
9
10int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
11
6#else 12#else
7#define PERF_REGS_MASK 0 13#define PERF_REGS_MASK 0
8 14
@@ -10,5 +16,12 @@ static inline const char *perf_reg_name(int id __maybe_unused)
10{ 16{
11 return NULL; 17 return NULL;
12} 18}
19
20static inline int perf_reg_value(u64 *valp __maybe_unused,
21 struct regs_dump *regs __maybe_unused,
22 int id __maybe_unused)
23{
24 return 0;
25}
13#endif /* HAVE_PERF_REGS_SUPPORT */ 26#endif /* HAVE_PERF_REGS_SUPPORT */
14#endif /* __PERF_REGS_H */ 27#endif /* __PERF_REGS_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index b752ecb40d86..00a7dcb2f55c 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -3,7 +3,7 @@
3#include <unistd.h> 3#include <unistd.h>
4#include <stdio.h> 4#include <stdio.h>
5#include <dirent.h> 5#include <dirent.h>
6#include "fs.h" 6#include <api/fs/fs.h>
7#include <locale.h> 7#include <locale.h>
8#include "util.h" 8#include "util.h"
9#include "pmu.h" 9#include "pmu.h"
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index d8b048c20cde..0d1542f33d87 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -70,34 +70,32 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
70} 70}
71 71
72static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 72static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
73static int convert_name_to_addr(struct perf_probe_event *pev,
74 const char *exec);
75static void clear_probe_trace_event(struct probe_trace_event *tev); 73static void clear_probe_trace_event(struct probe_trace_event *tev);
76static struct machine machine; 74static struct machine *host_machine;
77 75
78/* Initialize symbol maps and path of vmlinux/modules */ 76/* Initialize symbol maps and path of vmlinux/modules */
79static int init_vmlinux(void) 77static int init_symbol_maps(bool user_only)
80{ 78{
81 int ret; 79 int ret;
82 80
83 symbol_conf.sort_by_name = true; 81 symbol_conf.sort_by_name = true;
84 if (symbol_conf.vmlinux_name == NULL)
85 symbol_conf.try_vmlinux_path = true;
86 else
87 pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
88 ret = symbol__init(); 82 ret = symbol__init();
89 if (ret < 0) { 83 if (ret < 0) {
90 pr_debug("Failed to init symbol map.\n"); 84 pr_debug("Failed to init symbol map.\n");
91 goto out; 85 goto out;
92 } 86 }
93 87
94 ret = machine__init(&machine, "", HOST_KERNEL_ID); 88 if (host_machine || user_only) /* already initialized */
95 if (ret < 0) 89 return 0;
96 goto out;
97 90
98 if (machine__create_kernel_maps(&machine) < 0) { 91 if (symbol_conf.vmlinux_name)
99 pr_debug("machine__create_kernel_maps() failed.\n"); 92 pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
100 goto out; 93
94 host_machine = machine__new_host();
95 if (!host_machine) {
96 pr_debug("machine__new_host() failed.\n");
97 symbol__exit();
98 ret = -1;
101 } 99 }
102out: 100out:
103 if (ret < 0) 101 if (ret < 0)
@@ -105,21 +103,66 @@ out:
105 return ret; 103 return ret;
106} 104}
107 105
106static void exit_symbol_maps(void)
107{
108 if (host_machine) {
109 machine__delete(host_machine);
110 host_machine = NULL;
111 }
112 symbol__exit();
113}
114
108static struct symbol *__find_kernel_function_by_name(const char *name, 115static struct symbol *__find_kernel_function_by_name(const char *name,
109 struct map **mapp) 116 struct map **mapp)
110{ 117{
111 return machine__find_kernel_function_by_name(&machine, name, mapp, 118 return machine__find_kernel_function_by_name(host_machine, name, mapp,
112 NULL); 119 NULL);
113} 120}
114 121
122static struct symbol *__find_kernel_function(u64 addr, struct map **mapp)
123{
124 return machine__find_kernel_function(host_machine, addr, mapp, NULL);
125}
126
127static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void)
128{
129 /* kmap->ref_reloc_sym should be set if host_machine is initialized */
130 struct kmap *kmap;
131
132 if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
133 return NULL;
134
135 kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
136 return kmap->ref_reloc_sym;
137}
138
139static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc)
140{
141 struct ref_reloc_sym *reloc_sym;
142 struct symbol *sym;
143 struct map *map;
144
145 /* ref_reloc_sym is just a label. Need a special fix*/
146 reloc_sym = kernel_get_ref_reloc_sym();
147 if (reloc_sym && strcmp(name, reloc_sym->name) == 0)
148 return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr;
149 else {
150 sym = __find_kernel_function_by_name(name, &map);
151 if (sym)
152 return map->unmap_ip(map, sym->start) -
153 (reloc) ? 0 : map->reloc;
154 }
155 return 0;
156}
157
115static struct map *kernel_get_module_map(const char *module) 158static struct map *kernel_get_module_map(const char *module)
116{ 159{
117 struct rb_node *nd; 160 struct rb_node *nd;
118 struct map_groups *grp = &machine.kmaps; 161 struct map_groups *grp = &host_machine->kmaps;
119 162
120 /* A file path -- this is an offline module */ 163 /* A file path -- this is an offline module */
121 if (module && strchr(module, '/')) 164 if (module && strchr(module, '/'))
122 return machine__new_module(&machine, 0, module); 165 return machine__new_module(host_machine, 0, module);
123 166
124 if (!module) 167 if (!module)
125 module = "kernel"; 168 module = "kernel";
@@ -141,7 +184,7 @@ static struct dso *kernel_get_module_dso(const char *module)
141 const char *vmlinux_name; 184 const char *vmlinux_name;
142 185
143 if (module) { 186 if (module) {
144 list_for_each_entry(dso, &machine.kernel_dsos, node) { 187 list_for_each_entry(dso, &host_machine->kernel_dsos, node) {
145 if (strncmp(dso->short_name + 1, module, 188 if (strncmp(dso->short_name + 1, module,
146 dso->short_name_len - 2) == 0) 189 dso->short_name_len - 2) == 0)
147 goto found; 190 goto found;
@@ -150,7 +193,7 @@ static struct dso *kernel_get_module_dso(const char *module)
150 return NULL; 193 return NULL;
151 } 194 }
152 195
153 map = machine.vmlinux_maps[MAP__FUNCTION]; 196 map = host_machine->vmlinux_maps[MAP__FUNCTION];
154 dso = map->dso; 197 dso = map->dso;
155 198
156 vmlinux_name = symbol_conf.vmlinux_name; 199 vmlinux_name = symbol_conf.vmlinux_name;
@@ -173,20 +216,6 @@ const char *kernel_get_module_path(const char *module)
173 return (dso) ? dso->long_name : NULL; 216 return (dso) ? dso->long_name : NULL;
174} 217}
175 218
176static int init_user_exec(void)
177{
178 int ret = 0;
179
180 symbol_conf.try_vmlinux_path = false;
181 symbol_conf.sort_by_name = true;
182 ret = symbol__init();
183
184 if (ret < 0)
185 pr_debug("Failed to init symbol map.\n");
186
187 return ret;
188}
189
190static int convert_exec_to_group(const char *exec, char **result) 219static int convert_exec_to_group(const char *exec, char **result)
191{ 220{
192 char *ptr1, *ptr2, *exec_copy; 221 char *ptr1, *ptr2, *exec_copy;
@@ -218,32 +247,23 @@ out:
218 return ret; 247 return ret;
219} 248}
220 249
221static int convert_to_perf_probe_point(struct probe_trace_point *tp, 250static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
222 struct perf_probe_point *pp)
223{ 251{
224 pp->function = strdup(tp->symbol); 252 int i;
225
226 if (pp->function == NULL)
227 return -ENOMEM;
228
229 pp->offset = tp->offset;
230 pp->retprobe = tp->retprobe;
231 253
232 return 0; 254 for (i = 0; i < ntevs; i++)
255 clear_probe_trace_event(tevs + i);
233} 256}
234 257
235#ifdef HAVE_DWARF_SUPPORT 258#ifdef HAVE_DWARF_SUPPORT
259
236/* Open new debuginfo of given module */ 260/* Open new debuginfo of given module */
237static struct debuginfo *open_debuginfo(const char *module) 261static struct debuginfo *open_debuginfo(const char *module)
238{ 262{
239 const char *path; 263 const char *path = module;
240 264
241 /* A file path -- this is an offline module */ 265 if (!module || !strchr(module, '/')) {
242 if (module && strchr(module, '/'))
243 path = module;
244 else {
245 path = kernel_get_module_path(module); 266 path = kernel_get_module_path(module);
246
247 if (!path) { 267 if (!path) {
248 pr_err("Failed to find path of %s module.\n", 268 pr_err("Failed to find path of %s module.\n",
249 module ?: "kernel"); 269 module ?: "kernel");
@@ -253,46 +273,6 @@ static struct debuginfo *open_debuginfo(const char *module)
253 return debuginfo__new(path); 273 return debuginfo__new(path);
254} 274}
255 275
256/*
257 * Convert trace point to probe point with debuginfo
258 * Currently only handles kprobes.
259 */
260static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
261 struct perf_probe_point *pp)
262{
263 struct symbol *sym;
264 struct map *map;
265 u64 addr;
266 int ret = -ENOENT;
267 struct debuginfo *dinfo;
268
269 sym = __find_kernel_function_by_name(tp->symbol, &map);
270 if (sym) {
271 addr = map->unmap_ip(map, sym->start + tp->offset);
272 pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
273 tp->offset, addr);
274
275 dinfo = debuginfo__new_online_kernel(addr);
276 if (dinfo) {
277 ret = debuginfo__find_probe_point(dinfo,
278 (unsigned long)addr, pp);
279 debuginfo__delete(dinfo);
280 } else {
281 pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n",
282 addr);
283 ret = -ENOENT;
284 }
285 }
286 if (ret <= 0) {
287 pr_debug("Failed to find corresponding probes from "
288 "debuginfo. Use kprobe event information.\n");
289 return convert_to_perf_probe_point(tp, pp);
290 }
291 pp->retprobe = tp->retprobe;
292
293 return 0;
294}
295
296static int get_text_start_address(const char *exec, unsigned long *address) 276static int get_text_start_address(const char *exec, unsigned long *address)
297{ 277{
298 Elf *elf; 278 Elf *elf;
@@ -321,12 +301,62 @@ out:
321 return ret; 301 return ret;
322} 302}
323 303
304/*
305 * Convert trace point to probe point with debuginfo
306 */
307static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
308 struct perf_probe_point *pp,
309 bool is_kprobe)
310{
311 struct debuginfo *dinfo = NULL;
312 unsigned long stext = 0;
313 u64 addr = tp->address;
314 int ret = -ENOENT;
315
316 /* convert the address to dwarf address */
317 if (!is_kprobe) {
318 if (!addr) {
319 ret = -EINVAL;
320 goto error;
321 }
322 ret = get_text_start_address(tp->module, &stext);
323 if (ret < 0)
324 goto error;
325 addr += stext;
326 } else {
327 addr = kernel_get_symbol_address_by_name(tp->symbol, false);
328 if (addr == 0)
329 goto error;
330 addr += tp->offset;
331 }
332
333 pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
334 tp->module ? : "kernel");
335
336 dinfo = open_debuginfo(tp->module);
337 if (dinfo) {
338 ret = debuginfo__find_probe_point(dinfo,
339 (unsigned long)addr, pp);
340 debuginfo__delete(dinfo);
341 } else {
342 pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr);
343 ret = -ENOENT;
344 }
345
346 if (ret > 0) {
347 pp->retprobe = tp->retprobe;
348 return 0;
349 }
350error:
351 pr_debug("Failed to find corresponding probes from debuginfo.\n");
352 return ret ? : -ENOENT;
353}
354
324static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, 355static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
325 int ntevs, const char *exec) 356 int ntevs, const char *exec)
326{ 357{
327 int i, ret = 0; 358 int i, ret = 0;
328 unsigned long offset, stext = 0; 359 unsigned long stext = 0;
329 char buf[32];
330 360
331 if (!exec) 361 if (!exec)
332 return 0; 362 return 0;
@@ -337,15 +367,9 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
337 367
338 for (i = 0; i < ntevs && ret >= 0; i++) { 368 for (i = 0; i < ntevs && ret >= 0; i++) {
339 /* point.address is the addres of point.symbol + point.offset */ 369 /* point.address is the addres of point.symbol + point.offset */
340 offset = tevs[i].point.address - stext; 370 tevs[i].point.address -= stext;
341 tevs[i].point.offset = 0;
342 zfree(&tevs[i].point.symbol);
343 ret = e_snprintf(buf, 32, "0x%lx", offset);
344 if (ret < 0)
345 break;
346 tevs[i].point.module = strdup(exec); 371 tevs[i].point.module = strdup(exec);
347 tevs[i].point.symbol = strdup(buf); 372 if (!tevs[i].point.module) {
348 if (!tevs[i].point.symbol || !tevs[i].point.module) {
349 ret = -ENOMEM; 373 ret = -ENOMEM;
350 break; 374 break;
351 } 375 }
@@ -388,12 +412,40 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
388 return ret; 412 return ret;
389} 413}
390 414
391static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) 415/* Post processing the probe events */
416static int post_process_probe_trace_events(struct probe_trace_event *tevs,
417 int ntevs, const char *module,
418 bool uprobe)
392{ 419{
420 struct ref_reloc_sym *reloc_sym;
421 char *tmp;
393 int i; 422 int i;
394 423
395 for (i = 0; i < ntevs; i++) 424 if (uprobe)
396 clear_probe_trace_event(tevs + i); 425 return add_exec_to_probe_trace_events(tevs, ntevs, module);
426
427 /* Note that currently ref_reloc_sym based probe is not for drivers */
428 if (module)
429 return add_module_to_probe_trace_events(tevs, ntevs, module);
430
431 reloc_sym = kernel_get_ref_reloc_sym();
432 if (!reloc_sym) {
433 pr_warning("Relocated base symbol is not found!\n");
434 return -EINVAL;
435 }
436
437 for (i = 0; i < ntevs; i++) {
438 if (tevs[i].point.address) {
439 tmp = strdup(reloc_sym->name);
440 if (!tmp)
441 return -ENOMEM;
442 free(tevs[i].point.symbol);
443 tevs[i].point.symbol = tmp;
444 tevs[i].point.offset = tevs[i].point.address -
445 reloc_sym->unrelocated_addr;
446 }
447 }
448 return 0;
397} 449}
398 450
399/* Try to find perf_probe_event with debuginfo */ 451/* Try to find perf_probe_event with debuginfo */
@@ -416,21 +468,16 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
416 return 0; 468 return 0;
417 } 469 }
418 470
471 pr_debug("Try to find probe point from debuginfo.\n");
419 /* Searching trace events corresponding to a probe event */ 472 /* Searching trace events corresponding to a probe event */
420 ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); 473 ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
421 474
422 debuginfo__delete(dinfo); 475 debuginfo__delete(dinfo);
423 476
424 if (ntevs > 0) { /* Succeeded to find trace events */ 477 if (ntevs > 0) { /* Succeeded to find trace events */
425 pr_debug("find %d probe_trace_events.\n", ntevs); 478 pr_debug("Found %d probe_trace_events.\n", ntevs);
426 if (target) { 479 ret = post_process_probe_trace_events(*tevs, ntevs,
427 if (pev->uprobes) 480 target, pev->uprobes);
428 ret = add_exec_to_probe_trace_events(*tevs,
429 ntevs, target);
430 else
431 ret = add_module_to_probe_trace_events(*tevs,
432 ntevs, target);
433 }
434 if (ret < 0) { 481 if (ret < 0) {
435 clear_probe_trace_events(*tevs, ntevs); 482 clear_probe_trace_events(*tevs, ntevs);
436 zfree(tevs); 483 zfree(tevs);
@@ -563,20 +610,16 @@ static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
563 * Show line-range always requires debuginfo to find source file and 610 * Show line-range always requires debuginfo to find source file and
564 * line number. 611 * line number.
565 */ 612 */
566int show_line_range(struct line_range *lr, const char *module) 613static int __show_line_range(struct line_range *lr, const char *module)
567{ 614{
568 int l = 1; 615 int l = 1;
569 struct line_node *ln; 616 struct int_node *ln;
570 struct debuginfo *dinfo; 617 struct debuginfo *dinfo;
571 FILE *fp; 618 FILE *fp;
572 int ret; 619 int ret;
573 char *tmp; 620 char *tmp;
574 621
575 /* Search a line range */ 622 /* Search a line range */
576 ret = init_vmlinux();
577 if (ret < 0)
578 return ret;
579
580 dinfo = open_debuginfo(module); 623 dinfo = open_debuginfo(module);
581 if (!dinfo) { 624 if (!dinfo) {
582 pr_warning("Failed to open debuginfo file.\n"); 625 pr_warning("Failed to open debuginfo file.\n");
@@ -623,8 +666,8 @@ int show_line_range(struct line_range *lr, const char *module)
623 goto end; 666 goto end;
624 } 667 }
625 668
626 list_for_each_entry(ln, &lr->line_list, list) { 669 intlist__for_each(ln, lr->line_list) {
627 for (; ln->line > l; l++) { 670 for (; ln->i > l; l++) {
628 ret = show_one_line(fp, l - lr->offset); 671 ret = show_one_line(fp, l - lr->offset);
629 if (ret < 0) 672 if (ret < 0)
630 goto end; 673 goto end;
@@ -646,6 +689,19 @@ end:
646 return ret; 689 return ret;
647} 690}
648 691
692int show_line_range(struct line_range *lr, const char *module)
693{
694 int ret;
695
696 ret = init_symbol_maps(false);
697 if (ret < 0)
698 return ret;
699 ret = __show_line_range(lr, module);
700 exit_symbol_maps();
701
702 return ret;
703}
704
649static int show_available_vars_at(struct debuginfo *dinfo, 705static int show_available_vars_at(struct debuginfo *dinfo,
650 struct perf_probe_event *pev, 706 struct perf_probe_event *pev,
651 int max_vls, struct strfilter *_filter, 707 int max_vls, struct strfilter *_filter,
@@ -707,14 +763,15 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
707 int i, ret = 0; 763 int i, ret = 0;
708 struct debuginfo *dinfo; 764 struct debuginfo *dinfo;
709 765
710 ret = init_vmlinux(); 766 ret = init_symbol_maps(false);
711 if (ret < 0) 767 if (ret < 0)
712 return ret; 768 return ret;
713 769
714 dinfo = open_debuginfo(module); 770 dinfo = open_debuginfo(module);
715 if (!dinfo) { 771 if (!dinfo) {
716 pr_warning("Failed to open debuginfo file.\n"); 772 pr_warning("Failed to open debuginfo file.\n");
717 return -ENOENT; 773 ret = -ENOENT;
774 goto out;
718 } 775 }
719 776
720 setup_pager(); 777 setup_pager();
@@ -724,23 +781,19 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
724 externs); 781 externs);
725 782
726 debuginfo__delete(dinfo); 783 debuginfo__delete(dinfo);
784out:
785 exit_symbol_maps();
727 return ret; 786 return ret;
728} 787}
729 788
730#else /* !HAVE_DWARF_SUPPORT */ 789#else /* !HAVE_DWARF_SUPPORT */
731 790
732static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 791static int
733 struct perf_probe_point *pp) 792find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused,
793 struct perf_probe_point *pp __maybe_unused,
794 bool is_kprobe __maybe_unused)
734{ 795{
735 struct symbol *sym; 796 return -ENOSYS;
736
737 sym = __find_kernel_function_by_name(tp->symbol, NULL);
738 if (!sym) {
739 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
740 return -ENOENT;
741 }
742
743 return convert_to_perf_probe_point(tp, pp);
744} 797}
745 798
746static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 799static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
@@ -776,24 +829,22 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
776 829
777void line_range__clear(struct line_range *lr) 830void line_range__clear(struct line_range *lr)
778{ 831{
779 struct line_node *ln;
780
781 free(lr->function); 832 free(lr->function);
782 free(lr->file); 833 free(lr->file);
783 free(lr->path); 834 free(lr->path);
784 free(lr->comp_dir); 835 free(lr->comp_dir);
785 while (!list_empty(&lr->line_list)) { 836 intlist__delete(lr->line_list);
786 ln = list_first_entry(&lr->line_list, struct line_node, list);
787 list_del(&ln->list);
788 free(ln);
789 }
790 memset(lr, 0, sizeof(*lr)); 837 memset(lr, 0, sizeof(*lr));
791} 838}
792 839
793void line_range__init(struct line_range *lr) 840int line_range__init(struct line_range *lr)
794{ 841{
795 memset(lr, 0, sizeof(*lr)); 842 memset(lr, 0, sizeof(*lr));
796 INIT_LIST_HEAD(&lr->line_list); 843 lr->line_list = intlist__new(NULL);
844 if (!lr->line_list)
845 return -ENOMEM;
846 else
847 return 0;
797} 848}
798 849
799static int parse_line_num(char **ptr, int *val, const char *what) 850static int parse_line_num(char **ptr, int *val, const char *what)
@@ -1267,16 +1318,21 @@ static int parse_probe_trace_command(const char *cmd,
1267 } else 1318 } else
1268 p = argv[1]; 1319 p = argv[1];
1269 fmt1_str = strtok_r(p, "+", &fmt); 1320 fmt1_str = strtok_r(p, "+", &fmt);
1270 tp->symbol = strdup(fmt1_str); 1321 if (fmt1_str[0] == '0') /* only the address started with 0x */
1271 if (tp->symbol == NULL) { 1322 tp->address = strtoul(fmt1_str, NULL, 0);
1272 ret = -ENOMEM; 1323 else {
1273 goto out; 1324 /* Only the symbol-based probe has offset */
1325 tp->symbol = strdup(fmt1_str);
1326 if (tp->symbol == NULL) {
1327 ret = -ENOMEM;
1328 goto out;
1329 }
1330 fmt2_str = strtok_r(NULL, "", &fmt);
1331 if (fmt2_str == NULL)
1332 tp->offset = 0;
1333 else
1334 tp->offset = strtoul(fmt2_str, NULL, 10);
1274 } 1335 }
1275 fmt2_str = strtok_r(NULL, "", &fmt);
1276 if (fmt2_str == NULL)
1277 tp->offset = 0;
1278 else
1279 tp->offset = strtoul(fmt2_str, NULL, 10);
1280 1336
1281 tev->nargs = argc - 2; 1337 tev->nargs = argc - 2;
1282 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1338 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
@@ -1518,20 +1574,27 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
1518 if (buf == NULL) 1574 if (buf == NULL)
1519 return NULL; 1575 return NULL;
1520 1576
1577 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
1578 tev->group, tev->event);
1579 if (len <= 0)
1580 goto error;
1581
1582 /* Uprobes must have tp->address and tp->module */
1583 if (tev->uprobes && (!tp->address || !tp->module))
1584 goto error;
1585
1586 /* Use the tp->address for uprobes */
1521 if (tev->uprobes) 1587 if (tev->uprobes)
1522 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s", 1588 ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx",
1523 tp->retprobe ? 'r' : 'p', 1589 tp->module, tp->address);
1524 tev->group, tev->event,
1525 tp->module, tp->symbol);
1526 else 1590 else
1527 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", 1591 ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu",
1528 tp->retprobe ? 'r' : 'p',
1529 tev->group, tev->event,
1530 tp->module ?: "", tp->module ? ":" : "", 1592 tp->module ?: "", tp->module ? ":" : "",
1531 tp->symbol, tp->offset); 1593 tp->symbol, tp->offset);
1532 1594
1533 if (len <= 0) 1595 if (ret <= 0)
1534 goto error; 1596 goto error;
1597 len += ret;
1535 1598
1536 for (i = 0; i < tev->nargs; i++) { 1599 for (i = 0; i < tev->nargs; i++) {
1537 ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, 1600 ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
@@ -1547,6 +1610,79 @@ error:
1547 return NULL; 1610 return NULL;
1548} 1611}
1549 1612
1613static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
1614 struct perf_probe_point *pp,
1615 bool is_kprobe)
1616{
1617 struct symbol *sym = NULL;
1618 struct map *map;
1619 u64 addr;
1620 int ret = -ENOENT;
1621
1622 if (!is_kprobe) {
1623 map = dso__new_map(tp->module);
1624 if (!map)
1625 goto out;
1626 addr = tp->address;
1627 sym = map__find_symbol(map, addr, NULL);
1628 } else {
1629 addr = kernel_get_symbol_address_by_name(tp->symbol, true);
1630 if (addr) {
1631 addr += tp->offset;
1632 sym = __find_kernel_function(addr, &map);
1633 }
1634 }
1635 if (!sym)
1636 goto out;
1637
1638 pp->retprobe = tp->retprobe;
1639 pp->offset = addr - map->unmap_ip(map, sym->start);
1640 pp->function = strdup(sym->name);
1641 ret = pp->function ? 0 : -ENOMEM;
1642
1643out:
1644 if (map && !is_kprobe) {
1645 dso__delete(map->dso);
1646 map__delete(map);
1647 }
1648
1649 return ret;
1650}
1651
1652static int convert_to_perf_probe_point(struct probe_trace_point *tp,
1653 struct perf_probe_point *pp,
1654 bool is_kprobe)
1655{
1656 char buf[128];
1657 int ret;
1658
1659 ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe);
1660 if (!ret)
1661 return 0;
1662 ret = find_perf_probe_point_from_map(tp, pp, is_kprobe);
1663 if (!ret)
1664 return 0;
1665
1666 pr_debug("Failed to find probe point from both of dwarf and map.\n");
1667
1668 if (tp->symbol) {
1669 pp->function = strdup(tp->symbol);
1670 pp->offset = tp->offset;
1671 } else if (!tp->module && !is_kprobe) {
1672 ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address);
1673 if (ret < 0)
1674 return ret;
1675 pp->function = strdup(buf);
1676 pp->offset = 0;
1677 }
1678 if (pp->function == NULL)
1679 return -ENOMEM;
1680
1681 pp->retprobe = tp->retprobe;
1682
1683 return 0;
1684}
1685
1550static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1686static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1551 struct perf_probe_event *pev, bool is_kprobe) 1687 struct perf_probe_event *pev, bool is_kprobe)
1552{ 1688{
@@ -1560,11 +1696,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1560 return -ENOMEM; 1696 return -ENOMEM;
1561 1697
1562 /* Convert trace_point to probe_point */ 1698 /* Convert trace_point to probe_point */
1563 if (is_kprobe) 1699 ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe);
1564 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1565 else
1566 ret = convert_to_perf_probe_point(&tev->point, &pev->point);
1567
1568 if (ret < 0) 1700 if (ret < 0)
1569 return ret; 1701 return ret;
1570 1702
@@ -1731,7 +1863,8 @@ static struct strlist *get_probe_trace_command_rawlist(int fd)
1731} 1863}
1732 1864
1733/* Show an event */ 1865/* Show an event */
1734static int show_perf_probe_event(struct perf_probe_event *pev) 1866static int show_perf_probe_event(struct perf_probe_event *pev,
1867 const char *module)
1735{ 1868{
1736 int i, ret; 1869 int i, ret;
1737 char buf[128]; 1870 char buf[128];
@@ -1747,6 +1880,8 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
1747 return ret; 1880 return ret;
1748 1881
1749 printf(" %-20s (on %s", buf, place); 1882 printf(" %-20s (on %s", buf, place);
1883 if (module)
1884 printf(" in %s", module);
1750 1885
1751 if (pev->nargs > 0) { 1886 if (pev->nargs > 0) {
1752 printf(" with"); 1887 printf(" with");
@@ -1784,7 +1919,8 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
1784 ret = convert_to_perf_probe_event(&tev, &pev, 1919 ret = convert_to_perf_probe_event(&tev, &pev,
1785 is_kprobe); 1920 is_kprobe);
1786 if (ret >= 0) 1921 if (ret >= 0)
1787 ret = show_perf_probe_event(&pev); 1922 ret = show_perf_probe_event(&pev,
1923 tev.point.module);
1788 } 1924 }
1789 clear_perf_probe_event(&pev); 1925 clear_perf_probe_event(&pev);
1790 clear_probe_trace_event(&tev); 1926 clear_probe_trace_event(&tev);
@@ -1807,7 +1943,7 @@ int show_perf_probe_events(void)
1807 if (fd < 0) 1943 if (fd < 0)
1808 return fd; 1944 return fd;
1809 1945
1810 ret = init_vmlinux(); 1946 ret = init_symbol_maps(false);
1811 if (ret < 0) 1947 if (ret < 0)
1812 return ret; 1948 return ret;
1813 1949
@@ -1820,6 +1956,7 @@ int show_perf_probe_events(void)
1820 close(fd); 1956 close(fd);
1821 } 1957 }
1822 1958
1959 exit_symbol_maps();
1823 return ret; 1960 return ret;
1824} 1961}
1825 1962
@@ -1982,7 +2119,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1982 group = pev->group; 2119 group = pev->group;
1983 pev->event = tev->event; 2120 pev->event = tev->event;
1984 pev->group = tev->group; 2121 pev->group = tev->group;
1985 show_perf_probe_event(pev); 2122 show_perf_probe_event(pev, tev->point.module);
1986 /* Trick here - restore current event/group */ 2123 /* Trick here - restore current event/group */
1987 pev->event = (char *)event; 2124 pev->event = (char *)event;
1988 pev->group = (char *)group; 2125 pev->group = (char *)group;
@@ -2008,113 +2145,175 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
2008 return ret; 2145 return ret;
2009} 2146}
2010 2147
2011static int convert_to_probe_trace_events(struct perf_probe_event *pev, 2148static char *looking_function_name;
2012 struct probe_trace_event **tevs, 2149static int num_matched_functions;
2013 int max_tevs, const char *target) 2150
2151static int probe_function_filter(struct map *map __maybe_unused,
2152 struct symbol *sym)
2014{ 2153{
2154 if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
2155 strcmp(looking_function_name, sym->name) == 0) {
2156 num_matched_functions++;
2157 return 0;
2158 }
2159 return 1;
2160}
2161
2162#define strdup_or_goto(str, label) \
2163 ({ char *__p = strdup(str); if (!__p) goto label; __p; })
2164
2165/*
2166 * Find probe function addresses from map.
2167 * Return an error or the number of found probe_trace_event
2168 */
2169static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2170 struct probe_trace_event **tevs,
2171 int max_tevs, const char *target)
2172{
2173 struct map *map = NULL;
2174 struct kmap *kmap = NULL;
2175 struct ref_reloc_sym *reloc_sym = NULL;
2015 struct symbol *sym; 2176 struct symbol *sym;
2016 int ret, i; 2177 struct rb_node *nd;
2017 struct probe_trace_event *tev; 2178 struct probe_trace_event *tev;
2179 struct perf_probe_point *pp = &pev->point;
2180 struct probe_trace_point *tp;
2181 int ret, i;
2018 2182
2019 if (pev->uprobes && !pev->group) { 2183 /* Init maps of given executable or kernel */
2020 /* Replace group name if not given */ 2184 if (pev->uprobes)
2021 ret = convert_exec_to_group(target, &pev->group); 2185 map = dso__new_map(target);
2022 if (ret != 0) { 2186 else
2023 pr_warning("Failed to make a group name.\n"); 2187 map = kernel_get_module_map(target);
2024 return ret; 2188 if (!map) {
2025 } 2189 ret = -EINVAL;
2190 goto out;
2026 } 2191 }
2027 2192
2028 /* Convert perf_probe_event with debuginfo */ 2193 /*
2029 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); 2194 * Load matched symbols: Since the different local symbols may have
2030 if (ret != 0) 2195 * same name but different addresses, this lists all the symbols.
2031 return ret; /* Found in debuginfo or got an error */ 2196 */
2032 2197 num_matched_functions = 0;
2033 if (pev->uprobes) { 2198 looking_function_name = pp->function;
2034 ret = convert_name_to_addr(pev, target); 2199 ret = map__load(map, probe_function_filter);
2035 if (ret < 0) 2200 if (ret || num_matched_functions == 0) {
2036 return ret; 2201 pr_err("Failed to find symbol %s in %s\n", pp->function,
2202 target ? : "kernel");
2203 ret = -ENOENT;
2204 goto out;
2205 } else if (num_matched_functions > max_tevs) {
2206 pr_err("Too many functions matched in %s\n",
2207 target ? : "kernel");
2208 ret = -E2BIG;
2209 goto out;
2037 } 2210 }
2038 2211
2039 /* Allocate trace event buffer */ 2212 if (!pev->uprobes) {
2040 tev = *tevs = zalloc(sizeof(struct probe_trace_event)); 2213 kmap = map__kmap(map);
2041 if (tev == NULL) 2214 reloc_sym = kmap->ref_reloc_sym;
2042 return -ENOMEM; 2215 if (!reloc_sym) {
2216 pr_warning("Relocated base symbol is not found!\n");
2217 ret = -EINVAL;
2218 goto out;
2219 }
2220 }
2043 2221
2044 /* Copy parameters */ 2222 /* Setup result trace-probe-events */
2045 tev->point.symbol = strdup(pev->point.function); 2223 *tevs = zalloc(sizeof(*tev) * num_matched_functions);
2046 if (tev->point.symbol == NULL) { 2224 if (!*tevs) {
2047 ret = -ENOMEM; 2225 ret = -ENOMEM;
2048 goto error; 2226 goto out;
2049 } 2227 }
2050 2228
2051 if (target) { 2229 ret = 0;
2052 tev->point.module = strdup(target); 2230 map__for_each_symbol(map, sym, nd) {
2053 if (tev->point.module == NULL) { 2231 tev = (*tevs) + ret;
2054 ret = -ENOMEM; 2232 tp = &tev->point;
2055 goto error; 2233 if (ret == num_matched_functions) {
2234 pr_warning("Too many symbols are listed. Skip it.\n");
2235 break;
2056 } 2236 }
2057 } 2237 ret++;
2058
2059 tev->point.offset = pev->point.offset;
2060 tev->point.retprobe = pev->point.retprobe;
2061 tev->nargs = pev->nargs;
2062 tev->uprobes = pev->uprobes;
2063 2238
2064 if (tev->nargs) { 2239 if (pp->offset > sym->end - sym->start) {
2065 tev->args = zalloc(sizeof(struct probe_trace_arg) 2240 pr_warning("Offset %ld is bigger than the size of %s\n",
2066 * tev->nargs); 2241 pp->offset, sym->name);
2067 if (tev->args == NULL) { 2242 ret = -ENOENT;
2068 ret = -ENOMEM; 2243 goto err_out;
2069 goto error; 2244 }
2245 /* Add one probe point */
2246 tp->address = map->unmap_ip(map, sym->start) + pp->offset;
2247 if (reloc_sym) {
2248 tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out);
2249 tp->offset = tp->address - reloc_sym->addr;
2250 } else {
2251 tp->symbol = strdup_or_goto(sym->name, nomem_out);
2252 tp->offset = pp->offset;
2253 }
2254 tp->retprobe = pp->retprobe;
2255 if (target)
2256 tev->point.module = strdup_or_goto(target, nomem_out);
2257 tev->uprobes = pev->uprobes;
2258 tev->nargs = pev->nargs;
2259 if (tev->nargs) {
2260 tev->args = zalloc(sizeof(struct probe_trace_arg) *
2261 tev->nargs);
2262 if (tev->args == NULL)
2263 goto nomem_out;
2070 } 2264 }
2071 for (i = 0; i < tev->nargs; i++) { 2265 for (i = 0; i < tev->nargs; i++) {
2072 if (pev->args[i].name) { 2266 if (pev->args[i].name)
2073 tev->args[i].name = strdup(pev->args[i].name); 2267 tev->args[i].name =
2074 if (tev->args[i].name == NULL) { 2268 strdup_or_goto(pev->args[i].name,
2075 ret = -ENOMEM; 2269 nomem_out);
2076 goto error; 2270
2077 } 2271 tev->args[i].value = strdup_or_goto(pev->args[i].var,
2078 } 2272 nomem_out);
2079 tev->args[i].value = strdup(pev->args[i].var); 2273 if (pev->args[i].type)
2080 if (tev->args[i].value == NULL) { 2274 tev->args[i].type =
2081 ret = -ENOMEM; 2275 strdup_or_goto(pev->args[i].type,
2082 goto error; 2276 nomem_out);
2083 }
2084 if (pev->args[i].type) {
2085 tev->args[i].type = strdup(pev->args[i].type);
2086 if (tev->args[i].type == NULL) {
2087 ret = -ENOMEM;
2088 goto error;
2089 }
2090 }
2091 } 2277 }
2092 } 2278 }
2093 2279
2094 if (pev->uprobes) 2280out:
2095 return 1; 2281 if (map && pev->uprobes) {
2282 /* Only when using uprobe(exec) map needs to be released */
2283 dso__delete(map->dso);
2284 map__delete(map);
2285 }
2286 return ret;
2096 2287
2097 /* Currently just checking function name from symbol map */ 2288nomem_out:
2098 sym = __find_kernel_function_by_name(tev->point.symbol, NULL); 2289 ret = -ENOMEM;
2099 if (!sym) { 2290err_out:
2100 pr_warning("Kernel symbol \'%s\' not found.\n", 2291 clear_probe_trace_events(*tevs, num_matched_functions);
2101 tev->point.symbol); 2292 zfree(tevs);
2102 ret = -ENOENT; 2293 goto out;
2103 goto error; 2294}
2104 } else if (tev->point.offset > sym->end - sym->start) { 2295
2105 pr_warning("Offset specified is greater than size of %s\n", 2296static int convert_to_probe_trace_events(struct perf_probe_event *pev,
2106 tev->point.symbol); 2297 struct probe_trace_event **tevs,
2107 ret = -ENOENT; 2298 int max_tevs, const char *target)
2108 goto error; 2299{
2300 int ret;
2109 2301
2302 if (pev->uprobes && !pev->group) {
2303 /* Replace group name if not given */
2304 ret = convert_exec_to_group(target, &pev->group);
2305 if (ret != 0) {
2306 pr_warning("Failed to make a group name.\n");
2307 return ret;
2308 }
2110 } 2309 }
2111 2310
2112 return 1; 2311 /* Convert perf_probe_event with debuginfo */
2113error: 2312 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
2114 clear_probe_trace_event(tev); 2313 if (ret != 0)
2115 free(tev); 2314 return ret; /* Found in debuginfo or got an error */
2116 *tevs = NULL; 2315
2117 return ret; 2316 return find_probe_trace_events_from_map(pev, tevs, max_tevs, target);
2118} 2317}
2119 2318
2120struct __event_package { 2319struct __event_package {
@@ -2135,12 +2334,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
2135 if (pkgs == NULL) 2334 if (pkgs == NULL)
2136 return -ENOMEM; 2335 return -ENOMEM;
2137 2336
2138 if (!pevs->uprobes) 2337 ret = init_symbol_maps(pevs->uprobes);
2139 /* Init vmlinux path */
2140 ret = init_vmlinux();
2141 else
2142 ret = init_user_exec();
2143
2144 if (ret < 0) { 2338 if (ret < 0) {
2145 free(pkgs); 2339 free(pkgs);
2146 return ret; 2340 return ret;
@@ -2174,6 +2368,7 @@ end:
2174 zfree(&pkgs[i].tevs); 2368 zfree(&pkgs[i].tevs);
2175 } 2369 }
2176 free(pkgs); 2370 free(pkgs);
2371 exit_symbol_maps();
2177 2372
2178 return ret; 2373 return ret;
2179} 2374}
@@ -2323,159 +2518,51 @@ static struct strfilter *available_func_filter;
2323static int filter_available_functions(struct map *map __maybe_unused, 2518static int filter_available_functions(struct map *map __maybe_unused,
2324 struct symbol *sym) 2519 struct symbol *sym)
2325{ 2520{
2326 if (sym->binding == STB_GLOBAL && 2521 if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
2327 strfilter__compare(available_func_filter, sym->name)) 2522 strfilter__compare(available_func_filter, sym->name))
2328 return 0; 2523 return 0;
2329 return 1; 2524 return 1;
2330} 2525}
2331 2526
2332static int __show_available_funcs(struct map *map) 2527int show_available_funcs(const char *target, struct strfilter *_filter,
2333{ 2528 bool user)
2334 if (map__load(map, filter_available_functions)) {
2335 pr_err("Failed to load map.\n");
2336 return -EINVAL;
2337 }
2338 if (!dso__sorted_by_name(map->dso, map->type))
2339 dso__sort_by_name(map->dso, map->type);
2340
2341 dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
2342 return 0;
2343}
2344
2345static int available_kernel_funcs(const char *module)
2346{ 2529{
2347 struct map *map; 2530 struct map *map;
2348 int ret; 2531 int ret;
2349 2532
2350 ret = init_vmlinux(); 2533 ret = init_symbol_maps(user);
2351 if (ret < 0) 2534 if (ret < 0)
2352 return ret; 2535 return ret;
2353 2536
2354 map = kernel_get_module_map(module); 2537 /* Get a symbol map */
2538 if (user)
2539 map = dso__new_map(target);
2540 else
2541 map = kernel_get_module_map(target);
2355 if (!map) { 2542 if (!map) {
2356 pr_err("Failed to find %s map.\n", (module) ? : "kernel"); 2543 pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
2357 return -EINVAL; 2544 return -EINVAL;
2358 } 2545 }
2359 return __show_available_funcs(map);
2360}
2361
2362static int available_user_funcs(const char *target)
2363{
2364 struct map *map;
2365 int ret;
2366
2367 ret = init_user_exec();
2368 if (ret < 0)
2369 return ret;
2370
2371 map = dso__new_map(target);
2372 ret = __show_available_funcs(map);
2373 dso__delete(map->dso);
2374 map__delete(map);
2375 return ret;
2376}
2377 2546
2378int show_available_funcs(const char *target, struct strfilter *_filter, 2547 /* Load symbols with given filter */
2379 bool user)
2380{
2381 setup_pager();
2382 available_func_filter = _filter; 2548 available_func_filter = _filter;
2383
2384 if (!user)
2385 return available_kernel_funcs(target);
2386
2387 return available_user_funcs(target);
2388}
2389
2390/*
2391 * uprobe_events only accepts address:
2392 * Convert function and any offset to address
2393 */
2394static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
2395{
2396 struct perf_probe_point *pp = &pev->point;
2397 struct symbol *sym;
2398 struct map *map = NULL;
2399 char *function = NULL;
2400 int ret = -EINVAL;
2401 unsigned long long vaddr = 0;
2402
2403 if (!pp->function) {
2404 pr_warning("No function specified for uprobes");
2405 goto out;
2406 }
2407
2408 function = strdup(pp->function);
2409 if (!function) {
2410 pr_warning("Failed to allocate memory by strdup.\n");
2411 ret = -ENOMEM;
2412 goto out;
2413 }
2414
2415 map = dso__new_map(exec);
2416 if (!map) {
2417 pr_warning("Cannot find appropriate DSO for %s.\n", exec);
2418 goto out;
2419 }
2420 available_func_filter = strfilter__new(function, NULL);
2421 if (map__load(map, filter_available_functions)) { 2549 if (map__load(map, filter_available_functions)) {
2422 pr_err("Failed to load map.\n"); 2550 pr_err("Failed to load symbols in %s\n", (target) ? : "kernel");
2423 goto out; 2551 goto end;
2424 }
2425
2426 sym = map__find_symbol_by_name(map, function, NULL);
2427 if (!sym) {
2428 pr_warning("Cannot find %s in DSO %s\n", function, exec);
2429 goto out;
2430 }
2431
2432 if (map->start > sym->start)
2433 vaddr = map->start;
2434 vaddr += sym->start + pp->offset + map->pgoff;
2435 pp->offset = 0;
2436
2437 if (!pev->event) {
2438 pev->event = function;
2439 function = NULL;
2440 }
2441 if (!pev->group) {
2442 char *ptr1, *ptr2, *exec_copy;
2443
2444 pev->group = zalloc(sizeof(char *) * 64);
2445 exec_copy = strdup(exec);
2446 if (!exec_copy) {
2447 ret = -ENOMEM;
2448 pr_warning("Failed to copy exec string.\n");
2449 goto out;
2450 }
2451
2452 ptr1 = strdup(basename(exec_copy));
2453 if (ptr1) {
2454 ptr2 = strpbrk(ptr1, "-._");
2455 if (ptr2)
2456 *ptr2 = '\0';
2457 e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
2458 ptr1);
2459 free(ptr1);
2460 }
2461 free(exec_copy);
2462 }
2463 free(pp->function);
2464 pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
2465 if (!pp->function) {
2466 ret = -ENOMEM;
2467 pr_warning("Failed to allocate memory by zalloc.\n");
2468 goto out;
2469 } 2552 }
2470 e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr); 2553 if (!dso__sorted_by_name(map->dso, map->type))
2471 ret = 0; 2554 dso__sort_by_name(map->dso, map->type);
2472 2555
2473out: 2556 /* Show all (filtered) symbols */
2474 if (map) { 2557 setup_pager();
2558 dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
2559end:
2560 if (user) {
2475 dso__delete(map->dso); 2561 dso__delete(map->dso);
2476 map__delete(map); 2562 map__delete(map);
2477 } 2563 }
2478 if (function) 2564 exit_symbol_maps();
2479 free(function); 2565
2480 return ret; 2566 return ret;
2481} 2567}
2568
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index fcaf7273e85a..776c9347a3b6 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,6 +2,7 @@
2#define _PROBE_EVENT_H 2#define _PROBE_EVENT_H
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "intlist.h"
5#include "strlist.h" 6#include "strlist.h"
6#include "strfilter.h" 7#include "strfilter.h"
7 8
@@ -76,13 +77,6 @@ struct perf_probe_event {
76 struct perf_probe_arg *args; /* Arguments */ 77 struct perf_probe_arg *args; /* Arguments */
77}; 78};
78 79
79
80/* Line number container */
81struct line_node {
82 struct list_head list;
83 int line;
84};
85
86/* Line range */ 80/* Line range */
87struct line_range { 81struct line_range {
88 char *file; /* File name */ 82 char *file; /* File name */
@@ -92,7 +86,7 @@ struct line_range {
92 int offset; /* Start line offset */ 86 int offset; /* Start line offset */
93 char *path; /* Real path name */ 87 char *path; /* Real path name */
94 char *comp_dir; /* Compile directory */ 88 char *comp_dir; /* Compile directory */
95 struct list_head line_list; /* Visible lines */ 89 struct intlist *line_list; /* Visible lines */
96}; 90};
97 91
98/* List of variables */ 92/* List of variables */
@@ -124,7 +118,7 @@ extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
124extern void line_range__clear(struct line_range *lr); 118extern void line_range__clear(struct line_range *lr);
125 119
126/* Initialize line range */ 120/* Initialize line range */
127extern void line_range__init(struct line_range *lr); 121extern int line_range__init(struct line_range *lr);
128 122
129/* Internal use: Return kernel/module path */ 123/* Internal use: Return kernel/module path */
130extern const char *kernel_get_module_path(const char *module); 124extern const char *kernel_get_module_path(const char *module);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 061edb162b5b..df0238654698 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -34,7 +34,9 @@
34 34
35#include <linux/bitops.h> 35#include <linux/bitops.h>
36#include "event.h" 36#include "event.h"
37#include "dso.h"
37#include "debug.h" 38#include "debug.h"
39#include "intlist.h"
38#include "util.h" 40#include "util.h"
39#include "symbol.h" 41#include "symbol.h"
40#include "probe-finder.h" 42#include "probe-finder.h"
@@ -42,65 +44,6 @@
42/* Kprobe tracer basic type is up to u64 */ 44/* Kprobe tracer basic type is up to u64 */
43#define MAX_BASIC_TYPE_BITS 64 45#define MAX_BASIC_TYPE_BITS 64
44 46
45/* Line number list operations */
46
47/* Add a line to line number list */
48static int line_list__add_line(struct list_head *head, int line)
49{
50 struct line_node *ln;
51 struct list_head *p;
52
53 /* Reverse search, because new line will be the last one */
54 list_for_each_entry_reverse(ln, head, list) {
55 if (ln->line < line) {
56 p = &ln->list;
57 goto found;
58 } else if (ln->line == line) /* Already exist */
59 return 1;
60 }
61 /* List is empty, or the smallest entry */
62 p = head;
63found:
64 pr_debug("line list: add a line %u\n", line);
65 ln = zalloc(sizeof(struct line_node));
66 if (ln == NULL)
67 return -ENOMEM;
68 ln->line = line;
69 INIT_LIST_HEAD(&ln->list);
70 list_add(&ln->list, p);
71 return 0;
72}
73
74/* Check if the line in line number list */
75static int line_list__has_line(struct list_head *head, int line)
76{
77 struct line_node *ln;
78
79 /* Reverse search, because new line will be the last one */
80 list_for_each_entry(ln, head, list)
81 if (ln->line == line)
82 return 1;
83
84 return 0;
85}
86
87/* Init line number list */
88static void line_list__init(struct list_head *head)
89{
90 INIT_LIST_HEAD(head);
91}
92
93/* Free line number list */
94static void line_list__free(struct list_head *head)
95{
96 struct line_node *ln;
97 while (!list_empty(head)) {
98 ln = list_first_entry(head, struct line_node, list);
99 list_del(&ln->list);
100 free(ln);
101 }
102}
103
104/* Dwarf FL wrappers */ 47/* Dwarf FL wrappers */
105static char *debuginfo_path; /* Currently dummy */ 48static char *debuginfo_path; /* Currently dummy */
106 49
@@ -147,80 +90,7 @@ error:
147 return -ENOENT; 90 return -ENOENT;
148} 91}
149 92
150#if _ELFUTILS_PREREQ(0, 148) 93static struct debuginfo *__debuginfo__new(const char *path)
151/* This method is buggy if elfutils is older than 0.148 */
152static int __linux_kernel_find_elf(Dwfl_Module *mod,
153 void **userdata,
154 const char *module_name,
155 Dwarf_Addr base,
156 char **file_name, Elf **elfp)
157{
158 int fd;
159 const char *path = kernel_get_module_path(module_name);
160
161 pr_debug2("Use file %s for %s\n", path, module_name);
162 if (path) {
163 fd = open(path, O_RDONLY);
164 if (fd >= 0) {
165 *file_name = strdup(path);
166 return fd;
167 }
168 }
169 /* If failed, try to call standard method */
170 return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
171 file_name, elfp);
172}
173
174static const Dwfl_Callbacks kernel_callbacks = {
175 .find_debuginfo = dwfl_standard_find_debuginfo,
176 .debuginfo_path = &debuginfo_path,
177
178 .find_elf = __linux_kernel_find_elf,
179 .section_address = dwfl_linux_kernel_module_section_address,
180};
181
182/* Get a Dwarf from live kernel image */
183static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
184 Dwarf_Addr addr)
185{
186 dbg->dwfl = dwfl_begin(&kernel_callbacks);
187 if (!dbg->dwfl)
188 return -EINVAL;
189
190 /* Load the kernel dwarves: Don't care the result here */
191 dwfl_linux_kernel_report_kernel(dbg->dwfl);
192 dwfl_linux_kernel_report_modules(dbg->dwfl);
193
194 dbg->dbg = dwfl_addrdwarf(dbg->dwfl, addr, &dbg->bias);
195 /* Here, check whether we could get a real dwarf */
196 if (!dbg->dbg) {
197 pr_debug("Failed to find kernel dwarf at %lx\n",
198 (unsigned long)addr);
199 dwfl_end(dbg->dwfl);
200 memset(dbg, 0, sizeof(*dbg));
201 return -ENOENT;
202 }
203
204 return 0;
205}
206#else
207/* With older elfutils, this just support kernel module... */
208static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
209 Dwarf_Addr addr __maybe_unused)
210{
211 const char *path = kernel_get_module_path("kernel");
212
213 if (!path) {
214 pr_err("Failed to find vmlinux path\n");
215 return -ENOENT;
216 }
217
218 pr_debug2("Use file %s for debuginfo\n", path);
219 return debuginfo__init_offline_dwarf(dbg, path);
220}
221#endif
222
223struct debuginfo *debuginfo__new(const char *path)
224{ 94{
225 struct debuginfo *dbg = zalloc(sizeof(*dbg)); 95 struct debuginfo *dbg = zalloc(sizeof(*dbg));
226 if (!dbg) 96 if (!dbg)
@@ -228,21 +98,44 @@ struct debuginfo *debuginfo__new(const char *path)
228 98
229 if (debuginfo__init_offline_dwarf(dbg, path) < 0) 99 if (debuginfo__init_offline_dwarf(dbg, path) < 0)
230 zfree(&dbg); 100 zfree(&dbg);
231 101 if (dbg)
102 pr_debug("Open Debuginfo file: %s\n", path);
232 return dbg; 103 return dbg;
233} 104}
234 105
235struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) 106enum dso_binary_type distro_dwarf_types[] = {
236{ 107 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
237 struct debuginfo *dbg = zalloc(sizeof(*dbg)); 108 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
109 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
110 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
111 DSO_BINARY_TYPE__NOT_FOUND,
112};
238 113
239 if (!dbg) 114struct debuginfo *debuginfo__new(const char *path)
240 return NULL; 115{
116 enum dso_binary_type *type;
117 char buf[PATH_MAX], nil = '\0';
118 struct dso *dso;
119 struct debuginfo *dinfo = NULL;
120
121 /* Try to open distro debuginfo files */
122 dso = dso__new(path);
123 if (!dso)
124 goto out;
241 125
242 if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) 126 for (type = distro_dwarf_types;
243 zfree(&dbg); 127 !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
128 type++) {
129 if (dso__read_binary_type_filename(dso, *type, &nil,
130 buf, PATH_MAX) < 0)
131 continue;
132 dinfo = __debuginfo__new(buf);
133 }
134 dso__delete(dso);
244 135
245 return dbg; 136out:
137 /* if failed to open all distro debuginfo, open given binary */
138 return dinfo ? : __debuginfo__new(path);
246} 139}
247 140
248void debuginfo__delete(struct debuginfo *dbg) 141void debuginfo__delete(struct debuginfo *dbg)
@@ -880,7 +773,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
880} 773}
881 774
882/* Find lines which match lazy pattern */ 775/* Find lines which match lazy pattern */
883static int find_lazy_match_lines(struct list_head *head, 776static int find_lazy_match_lines(struct intlist *list,
884 const char *fname, const char *pat) 777 const char *fname, const char *pat)
885{ 778{
886 FILE *fp; 779 FILE *fp;
@@ -901,7 +794,7 @@ static int find_lazy_match_lines(struct list_head *head,
901 line[len - 1] = '\0'; 794 line[len - 1] = '\0';
902 795
903 if (strlazymatch(line, pat)) { 796 if (strlazymatch(line, pat)) {
904 line_list__add_line(head, linenum); 797 intlist__add(list, linenum);
905 count++; 798 count++;
906 } 799 }
907 linenum++; 800 linenum++;
@@ -924,7 +817,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
924 Dwarf_Die *sc_die, die_mem; 817 Dwarf_Die *sc_die, die_mem;
925 int ret; 818 int ret;
926 819
927 if (!line_list__has_line(&pf->lcache, lineno) || 820 if (!intlist__has_entry(pf->lcache, lineno) ||
928 strtailcmp(fname, pf->fname) != 0) 821 strtailcmp(fname, pf->fname) != 0)
929 return 0; 822 return 0;
930 823
@@ -952,9 +845,9 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
952{ 845{
953 int ret = 0; 846 int ret = 0;
954 847
955 if (list_empty(&pf->lcache)) { 848 if (intlist__empty(pf->lcache)) {
956 /* Matching lazy line pattern */ 849 /* Matching lazy line pattern */
957 ret = find_lazy_match_lines(&pf->lcache, pf->fname, 850 ret = find_lazy_match_lines(pf->lcache, pf->fname,
958 pf->pev->point.lazy_line); 851 pf->pev->point.lazy_line);
959 if (ret <= 0) 852 if (ret <= 0)
960 return ret; 853 return ret;
@@ -1096,7 +989,9 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
1096#endif 989#endif
1097 990
1098 off = 0; 991 off = 0;
1099 line_list__init(&pf->lcache); 992 pf->lcache = intlist__new(NULL);
993 if (!pf->lcache)
994 return -ENOMEM;
1100 995
1101 /* Fastpath: lookup by function name from .debug_pubnames section */ 996 /* Fastpath: lookup by function name from .debug_pubnames section */
1102 if (pp->function) { 997 if (pp->function) {
@@ -1149,7 +1044,8 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
1149 } 1044 }
1150 1045
1151found: 1046found:
1152 line_list__free(&pf->lcache); 1047 intlist__delete(pf->lcache);
1048 pf->lcache = NULL;
1153 1049
1154 return ret; 1050 return ret;
1155} 1051}
@@ -1537,7 +1433,7 @@ static int line_range_add_line(const char *src, unsigned int lineno,
1537 if (lr->path == NULL) 1433 if (lr->path == NULL)
1538 return -ENOMEM; 1434 return -ENOMEM;
1539 } 1435 }
1540 return line_list__add_line(&lr->line_list, lineno); 1436 return intlist__add(lr->line_list, lineno);
1541} 1437}
1542 1438
1543static int line_range_walk_cb(const char *fname, int lineno, 1439static int line_range_walk_cb(const char *fname, int lineno,
@@ -1565,7 +1461,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1565 1461
1566 /* Update status */ 1462 /* Update status */
1567 if (ret >= 0) 1463 if (ret >= 0)
1568 if (!list_empty(&lf->lr->line_list)) 1464 if (!intlist__empty(lf->lr->line_list))
1569 ret = lf->found = 1; 1465 ret = lf->found = 1;
1570 else 1466 else
1571 ret = 0; /* Lines are not found */ 1467 ret = 0; /* Lines are not found */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index ffc33cdd25cc..92590b2c7e1c 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -3,6 +3,7 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "util.h" 5#include "util.h"
6#include "intlist.h"
6#include "probe-event.h" 7#include "probe-event.h"
7 8
8#define MAX_PROBE_BUFFER 1024 9#define MAX_PROBE_BUFFER 1024
@@ -29,8 +30,8 @@ struct debuginfo {
29 Dwarf_Addr bias; 30 Dwarf_Addr bias;
30}; 31};
31 32
33/* This also tries to open distro debuginfo */
32extern struct debuginfo *debuginfo__new(const char *path); 34extern struct debuginfo *debuginfo__new(const char *path);
33extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr);
34extern void debuginfo__delete(struct debuginfo *dbg); 35extern void debuginfo__delete(struct debuginfo *dbg);
35 36
36/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 37/* Find probe_trace_events specified by perf_probe_event from debuginfo */
@@ -66,7 +67,7 @@ struct probe_finder {
66 const char *fname; /* Real file name */ 67 const char *fname; /* Real file name */
67 Dwarf_Die cu_die; /* Current CU */ 68 Dwarf_Die cu_die; /* Current CU */
68 Dwarf_Die sp_die; 69 Dwarf_Die sp_die;
69 struct list_head lcache; /* Line cache for lazy match */ 70 struct intlist *lcache; /* Line cache for lazy match */
70 71
71 /* For variable searching */ 72 /* For variable searching */
72#if _ELFUTILS_PREREQ(0, 142) 73#if _ELFUTILS_PREREQ(0, 142)
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 595bfc73d2ed..16a475a7d492 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -17,6 +17,6 @@ util/xyarray.c
17util/cgroup.c 17util/cgroup.c
18util/rblist.c 18util/rblist.c
19util/strlist.c 19util/strlist.c
20util/fs.c 20../lib/api/fs/fs.c
21util/trace-event.c 21util/trace-event.c
22../../lib/rbtree.c 22../../lib/rbtree.c
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 373762501dad..049e0a09ccd3 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -2,7 +2,7 @@
2#include "evsel.h" 2#include "evsel.h"
3#include "cpumap.h" 3#include "cpumap.h"
4#include "parse-events.h" 4#include "parse-events.h"
5#include "fs.h" 5#include <api/fs/fs.h>
6#include "util.h" 6#include "util.h"
7 7
8typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); 8typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 5da6ce74c676..1d555d652f58 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -702,11 +702,12 @@ static void regs_dump__printf(u64 mask, u64 *regs)
702 } 702 }
703} 703}
704 704
705static void regs_user__printf(struct perf_sample *sample, u64 mask) 705static void regs_user__printf(struct perf_sample *sample)
706{ 706{
707 struct regs_dump *user_regs = &sample->user_regs; 707 struct regs_dump *user_regs = &sample->user_regs;
708 708
709 if (user_regs->regs) { 709 if (user_regs->regs) {
710 u64 mask = user_regs->mask;
710 printf("... user regs: mask 0x%" PRIx64 "\n", mask); 711 printf("... user regs: mask 0x%" PRIx64 "\n", mask);
711 regs_dump__printf(mask, user_regs->regs); 712 regs_dump__printf(mask, user_regs->regs);
712 } 713 }
@@ -806,7 +807,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
806 branch_stack__printf(sample); 807 branch_stack__printf(sample);
807 808
808 if (sample_type & PERF_SAMPLE_REGS_USER) 809 if (sample_type & PERF_SAMPLE_REGS_USER)
809 regs_user__printf(sample, evsel->attr.sample_regs_user); 810 regs_user__printf(sample);
810 811
811 if (sample_type & PERF_SAMPLE_STACK_USER) 812 if (sample_type & PERF_SAMPLE_STACK_USER)
812 stack_user__printf(&sample->user_stack); 813 stack_user__printf(&sample->user_stack);
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 516d19fb999b..3b7dbf51d4a9 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -506,6 +506,8 @@ int filename__read_debuglink(const char *filename, char *debuglink,
506 /* the start of this section is a zero-terminated string */ 506 /* the start of this section is a zero-terminated string */
507 strncpy(debuglink, data->d_buf, size); 507 strncpy(debuglink, data->d_buf, size);
508 508
509 err = 0;
510
509out_elf_end: 511out_elf_end:
510 elf_end(elf); 512 elf_end(elf);
511out_close: 513out_close:
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index e89afc097d8a..95e249779931 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -410,7 +410,7 @@ struct symbol *dso__find_symbol(struct dso *dso,
410 return symbols__find(&dso->symbols[type], addr); 410 return symbols__find(&dso->symbols[type], addr);
411} 411}
412 412
413struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 413static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
414{ 414{
415 return symbols__first(&dso->symbols[type]); 415 return symbols__first(&dso->symbols[type]);
416} 416}
@@ -1251,6 +1251,46 @@ out_failure:
1251 return -1; 1251 return -1;
1252} 1252}
1253 1253
1254static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
1255 enum dso_binary_type type)
1256{
1257 switch (type) {
1258 case DSO_BINARY_TYPE__JAVA_JIT:
1259 case DSO_BINARY_TYPE__DEBUGLINK:
1260 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
1261 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
1262 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
1263 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
1264 case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
1265 return !kmod && dso->kernel == DSO_TYPE_USER;
1266
1267 case DSO_BINARY_TYPE__KALLSYMS:
1268 case DSO_BINARY_TYPE__VMLINUX:
1269 case DSO_BINARY_TYPE__KCORE:
1270 return dso->kernel == DSO_TYPE_KERNEL;
1271
1272 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
1273 case DSO_BINARY_TYPE__GUEST_VMLINUX:
1274 case DSO_BINARY_TYPE__GUEST_KCORE:
1275 return dso->kernel == DSO_TYPE_GUEST_KERNEL;
1276
1277 case DSO_BINARY_TYPE__GUEST_KMODULE:
1278 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1279 /*
1280 * kernel modules know their symtab type - it's set when
1281 * creating a module dso in machine__new_module().
1282 */
1283 return kmod && dso->symtab_type == type;
1284
1285 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
1286 return true;
1287
1288 case DSO_BINARY_TYPE__NOT_FOUND:
1289 default:
1290 return false;
1291 }
1292}
1293
1254int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 1294int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1255{ 1295{
1256 char *name; 1296 char *name;
@@ -1261,6 +1301,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1261 int ss_pos = 0; 1301 int ss_pos = 0;
1262 struct symsrc ss_[2]; 1302 struct symsrc ss_[2];
1263 struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 1303 struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
1304 bool kmod;
1264 1305
1265 dso__set_loaded(dso, map->type); 1306 dso__set_loaded(dso, map->type);
1266 1307
@@ -1301,7 +1342,11 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1301 if (!name) 1342 if (!name)
1302 return -1; 1343 return -1;
1303 1344
1304 /* Iterate over candidate debug images. 1345 kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1346 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
1347
1348 /*
1349 * Iterate over candidate debug images.
1305 * Keep track of "interesting" ones (those which have a symtab, dynsym, 1350 * Keep track of "interesting" ones (those which have a symtab, dynsym,
1306 * and/or opd section) for processing. 1351 * and/or opd section) for processing.
1307 */ 1352 */
@@ -1311,6 +1356,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1311 1356
1312 enum dso_binary_type symtab_type = binary_type_symtab[i]; 1357 enum dso_binary_type symtab_type = binary_type_symtab[i];
1313 1358
1359 if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
1360 continue;
1361
1314 if (dso__read_binary_type_filename(dso, symtab_type, 1362 if (dso__read_binary_type_filename(dso, symtab_type,
1315 root_dir, name, PATH_MAX)) 1363 root_dir, name, PATH_MAX))
1316 continue; 1364 continue;
@@ -1353,15 +1401,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1353 if (!runtime_ss && syms_ss) 1401 if (!runtime_ss && syms_ss)
1354 runtime_ss = syms_ss; 1402 runtime_ss = syms_ss;
1355 1403
1356 if (syms_ss) { 1404 if (syms_ss)
1357 int km; 1405 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
1358 1406 else
1359 km = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1360 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
1361 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, km);
1362 } else {
1363 ret = -1; 1407 ret = -1;
1364 }
1365 1408
1366 if (ret > 0) { 1409 if (ret > 0) {
1367 int nr_plt; 1410 int nr_plt;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index fffe2888a1c7..2553ae04b788 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -79,6 +79,17 @@ struct symbol {
79void symbol__delete(struct symbol *sym); 79void symbol__delete(struct symbol *sym);
80void symbols__delete(struct rb_root *symbols); 80void symbols__delete(struct rb_root *symbols);
81 81
82/* symbols__for_each_entry - iterate over symbols (rb_root)
83 *
84 * @symbols: the rb_root of symbols
85 * @pos: the 'struct symbol *' to use as a loop cursor
86 * @nd: the 'struct rb_node *' to use as a temporary storage
87 */
88#define symbols__for_each_entry(symbols, pos, nd) \
89 for (nd = rb_first(symbols); \
90 nd && (pos = rb_entry(nd, struct symbol, rb_node)); \
91 nd = rb_next(nd))
92
82static inline size_t symbol__size(const struct symbol *sym) 93static inline size_t symbol__size(const struct symbol *sym)
83{ 94{
84 return sym->end - sym->start + 1; 95 return sym->end - sym->start + 1;
@@ -223,7 +234,6 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
223 u64 addr); 234 u64 addr);
224struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 235struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
225 const char *name); 236 const char *name);
226struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
227 237
228int filename__read_build_id(const char *filename, void *bf, size_t size); 238int filename__read_build_id(const char *filename, void *bf, size_t size);
229int sysfs__read_build_id(const char *filename, void *bf, size_t size); 239int sysfs__read_build_id(const char *filename, void *bf, size_t size);
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index e0d6d07f6848..c36636fd825b 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -126,6 +126,7 @@ void event_format__print(struct event_format *event,
126 trace_seq_init(&s); 126 trace_seq_init(&s);
127 pevent_event_info(&s, event, &record); 127 pevent_event_info(&s, event, &record);
128 trace_seq_do_printf(&s); 128 trace_seq_do_printf(&s);
129 trace_seq_destroy(&s);
129} 130}
130 131
131void parse_proc_kallsyms(struct pevent *pevent, 132void parse_proc_kallsyms(struct pevent *pevent,
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
new file mode 100644
index 000000000000..67db73ec3dab
--- /dev/null
+++ b/tools/perf/util/unwind-libdw.c
@@ -0,0 +1,210 @@
1#include <linux/compiler.h>
2#include <elfutils/libdw.h>
3#include <elfutils/libdwfl.h>
4#include <inttypes.h>
5#include <errno.h>
6#include "unwind.h"
7#include "unwind-libdw.h"
8#include "machine.h"
9#include "thread.h"
10#include "types.h"
11#include "event.h"
12#include "perf_regs.h"
13
14static char *debuginfo_path;
15
16static const Dwfl_Callbacks offline_callbacks = {
17 .find_debuginfo = dwfl_standard_find_debuginfo,
18 .debuginfo_path = &debuginfo_path,
19 .section_address = dwfl_offline_section_address,
20};
21
22static int __report_module(struct addr_location *al, u64 ip,
23 struct unwind_info *ui)
24{
25 Dwfl_Module *mod;
26 struct dso *dso = NULL;
27
28 thread__find_addr_location(ui->thread, ui->machine,
29 PERF_RECORD_MISC_USER,
30 MAP__FUNCTION, ip, al);
31
32 if (al->map)
33 dso = al->map->dso;
34
35 if (!dso)
36 return 0;
37
38 mod = dwfl_addrmodule(ui->dwfl, ip);
39 if (!mod)
40 mod = dwfl_report_elf(ui->dwfl, dso->short_name,
41 dso->long_name, -1, al->map->start,
42 false);
43
44 return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1;
45}
46
47static int report_module(u64 ip, struct unwind_info *ui)
48{
49 struct addr_location al;
50
51 return __report_module(&al, ip, ui);
52}
53
54static int entry(u64 ip, struct unwind_info *ui)
55
56{
57 struct unwind_entry e;
58 struct addr_location al;
59
60 if (__report_module(&al, ip, ui))
61 return -1;
62
63 e.ip = ip;
64 e.map = al.map;
65 e.sym = al.sym;
66
67 pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
68 al.sym ? al.sym->name : "''",
69 ip,
70 al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
71
72 return ui->cb(&e, ui->arg);
73}
74
75static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
76{
77 /* We want only single thread to be processed. */
78 if (*thread_argp != NULL)
79 return 0;
80
81 *thread_argp = arg;
82 return dwfl_pid(dwfl);
83}
84
85static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
86 Dwarf_Word *data)
87{
88 struct addr_location al;
89 ssize_t size;
90
91 thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
92 MAP__FUNCTION, addr, &al);
93 if (!al.map) {
94 pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
95 return -1;
96 }
97
98 if (!al.map->dso)
99 return -1;
100
101 size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
102 addr, (u8 *) data, sizeof(*data));
103
104 return !(size == sizeof(*data));
105}
106
107static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *result,
108 void *arg)
109{
110 struct unwind_info *ui = arg;
111 struct stack_dump *stack = &ui->sample->user_stack;
112 u64 start, end;
113 int offset;
114 int ret;
115
116 ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
117 if (ret)
118 return false;
119
120 end = start + stack->size;
121
122 /* Check overflow. */
123 if (addr + sizeof(Dwarf_Word) < addr)
124 return false;
125
126 if (addr < start || addr + sizeof(Dwarf_Word) > end) {
127 ret = access_dso_mem(ui, addr, result);
128 if (ret) {
129 pr_debug("unwind: access_mem 0x%" PRIx64 " not inside range"
130 " 0x%" PRIx64 "-0x%" PRIx64 "\n",
131 addr, start, end);
132 return false;
133 }
134 return true;
135 }
136
137 offset = addr - start;
138 *result = *(Dwarf_Word *)&stack->data[offset];
139 pr_debug("unwind: access_mem addr 0x%" PRIx64 ", val %lx, offset %d\n",
140 addr, (unsigned long)*result, offset);
141 return true;
142}
143
144static const Dwfl_Thread_Callbacks callbacks = {
145 .next_thread = next_thread,
146 .memory_read = memory_read,
147 .set_initial_registers = libdw__arch_set_initial_registers,
148};
149
150static int
151frame_callback(Dwfl_Frame *state, void *arg)
152{
153 struct unwind_info *ui = arg;
154 Dwarf_Addr pc;
155
156 if (!dwfl_frame_pc(state, &pc, NULL)) {
157 pr_err("%s", dwfl_errmsg(-1));
158 return DWARF_CB_ABORT;
159 }
160
161 return entry(pc, ui) || !(--ui->max_stack) ?
162 DWARF_CB_ABORT : DWARF_CB_OK;
163}
164
165int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
166 struct machine *machine, struct thread *thread,
167 struct perf_sample *data,
168 int max_stack)
169{
170 struct unwind_info ui = {
171 .sample = data,
172 .thread = thread,
173 .machine = machine,
174 .cb = cb,
175 .arg = arg,
176 .max_stack = max_stack,
177 };
178 Dwarf_Word ip;
179 int err = -EINVAL;
180
181 if (!data->user_regs.regs)
182 return -EINVAL;
183
184 ui.dwfl = dwfl_begin(&offline_callbacks);
185 if (!ui.dwfl)
186 goto out;
187
188 err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
189 if (err)
190 goto out;
191
192 err = report_module(ip, &ui);
193 if (err)
194 goto out;
195
196 if (!dwfl_attach_state(ui.dwfl, EM_NONE, thread->tid, &callbacks, &ui))
197 goto out;
198
199 err = dwfl_getthread_frames(ui.dwfl, thread->tid, frame_callback, &ui);
200
201 if (err && !ui.max_stack)
202 err = 0;
203
204 out:
205 if (err)
206 pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
207
208 dwfl_end(ui.dwfl);
209 return 0;
210}
diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
new file mode 100644
index 000000000000..417a1426f3ad
--- /dev/null
+++ b/tools/perf/util/unwind-libdw.h
@@ -0,0 +1,21 @@
1#ifndef __PERF_UNWIND_LIBDW_H
2#define __PERF_UNWIND_LIBDW_H
3
4#include <elfutils/libdwfl.h>
5#include "event.h"
6#include "thread.h"
7#include "unwind.h"
8
9bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg);
10
11struct unwind_info {
12 Dwfl *dwfl;
13 struct perf_sample *sample;
14 struct machine *machine;
15 struct thread *thread;
16 unwind_entry_cb_t cb;
17 void *arg;
18 int max_stack;
19};
20
21#endif /* __PERF_UNWIND_LIBDW_H */
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind-libunwind.c
index 742f23bf35ff..bd5768d74f01 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -86,7 +86,6 @@ struct unwind_info {
86 struct perf_sample *sample; 86 struct perf_sample *sample;
87 struct machine *machine; 87 struct machine *machine;
88 struct thread *thread; 88 struct thread *thread;
89 u64 sample_uregs;
90}; 89};
91 90
92#define dw_read(ptr, type, end) ({ \ 91#define dw_read(ptr, type, end) ({ \
@@ -391,30 +390,13 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
391 return !(size == sizeof(*data)); 390 return !(size == sizeof(*data));
392} 391}
393 392
394static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id,
395 u64 sample_regs)
396{
397 int i, idx = 0;
398
399 if (!(sample_regs & (1 << id)))
400 return -EINVAL;
401
402 for (i = 0; i < id; i++) {
403 if (sample_regs & (1 << i))
404 idx++;
405 }
406
407 *valp = regs->regs[idx];
408 return 0;
409}
410
411static int access_mem(unw_addr_space_t __maybe_unused as, 393static int access_mem(unw_addr_space_t __maybe_unused as,
412 unw_word_t addr, unw_word_t *valp, 394 unw_word_t addr, unw_word_t *valp,
413 int __write, void *arg) 395 int __write, void *arg)
414{ 396{
415 struct unwind_info *ui = arg; 397 struct unwind_info *ui = arg;
416 struct stack_dump *stack = &ui->sample->user_stack; 398 struct stack_dump *stack = &ui->sample->user_stack;
417 unw_word_t start, end; 399 u64 start, end;
418 int offset; 400 int offset;
419 int ret; 401 int ret;
420 402
@@ -424,8 +406,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
424 return 0; 406 return 0;
425 } 407 }
426 408
427 ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP, 409 ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
428 ui->sample_uregs);
429 if (ret) 410 if (ret)
430 return ret; 411 return ret;
431 412
@@ -438,8 +419,9 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
438 if (addr < start || addr + sizeof(unw_word_t) >= end) { 419 if (addr < start || addr + sizeof(unw_word_t) >= end) {
439 ret = access_dso_mem(ui, addr, valp); 420 ret = access_dso_mem(ui, addr, valp);
440 if (ret) { 421 if (ret) {
441 pr_debug("unwind: access_mem %p not inside range %p-%p\n", 422 pr_debug("unwind: access_mem %p not inside range"
442 (void *)addr, (void *)start, (void *)end); 423 " 0x%" PRIx64 "-0x%" PRIx64 "\n",
424 (void *) addr, start, end);
443 *valp = 0; 425 *valp = 0;
444 return ret; 426 return ret;
445 } 427 }
@@ -448,8 +430,8 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
448 430
449 offset = addr - start; 431 offset = addr - start;
450 *valp = *(unw_word_t *)&stack->data[offset]; 432 *valp = *(unw_word_t *)&stack->data[offset];
451 pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n", 433 pr_debug("unwind: access_mem addr %p val %lx, offset %d\n",
452 (void *)addr, (unsigned long)*valp, offset); 434 (void *) addr, (unsigned long)*valp, offset);
453 return 0; 435 return 0;
454} 436}
455 437
@@ -459,6 +441,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
459{ 441{
460 struct unwind_info *ui = arg; 442 struct unwind_info *ui = arg;
461 int id, ret; 443 int id, ret;
444 u64 val;
462 445
463 /* Don't support write, I suspect we don't need it. */ 446 /* Don't support write, I suspect we don't need it. */
464 if (__write) { 447 if (__write) {
@@ -471,16 +454,17 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
471 return 0; 454 return 0;
472 } 455 }
473 456
474 id = unwind__arch_reg_id(regnum); 457 id = libunwind__arch_reg_id(regnum);
475 if (id < 0) 458 if (id < 0)
476 return -EINVAL; 459 return -EINVAL;
477 460
478 ret = reg_value(valp, &ui->sample->user_regs, id, ui->sample_uregs); 461 ret = perf_reg_value(&val, &ui->sample->user_regs, id);
479 if (ret) { 462 if (ret) {
480 pr_err("unwind: can't read reg %d\n", regnum); 463 pr_err("unwind: can't read reg %d\n", regnum);
481 return ret; 464 return ret;
482 } 465 }
483 466
467 *valp = (unw_word_t) val;
484 pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); 468 pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
485 return 0; 469 return 0;
486} 470}
@@ -563,7 +547,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
563 unw_word_t ip; 547 unw_word_t ip;
564 548
565 unw_get_reg(&c, UNW_REG_IP, &ip); 549 unw_get_reg(&c, UNW_REG_IP, &ip);
566 ret = entry(ip, ui->thread, ui->machine, cb, arg); 550 ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0;
567 } 551 }
568 552
569 unw_destroy_addr_space(addr_space); 553 unw_destroy_addr_space(addr_space);
@@ -572,13 +556,11 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
572 556
573int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 557int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
574 struct machine *machine, struct thread *thread, 558 struct machine *machine, struct thread *thread,
575 u64 sample_uregs, struct perf_sample *data, 559 struct perf_sample *data, int max_stack)
576 int max_stack)
577{ 560{
578 unw_word_t ip; 561 u64 ip;
579 struct unwind_info ui = { 562 struct unwind_info ui = {
580 .sample = data, 563 .sample = data,
581 .sample_uregs = sample_uregs,
582 .thread = thread, 564 .thread = thread,
583 .machine = machine, 565 .machine = machine,
584 }; 566 };
@@ -587,7 +569,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
587 if (!data->user_regs.regs) 569 if (!data->user_regs.regs)
588 return -EINVAL; 570 return -EINVAL;
589 571
590 ret = reg_value(&ip, &data->user_regs, PERF_REG_IP, sample_uregs); 572 ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
591 if (ret) 573 if (ret)
592 return ret; 574 return ret;
593 575
@@ -595,5 +577,5 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
595 if (ret) 577 if (ret)
596 return -ENOMEM; 578 return -ENOMEM;
597 579
598 return get_entries(&ui, cb, arg, max_stack); 580 return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0;
599} 581}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index d5966f49e22c..b031316f221a 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -13,24 +13,25 @@ struct unwind_entry {
13 13
14typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); 14typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
15 15
16#ifdef HAVE_LIBUNWIND_SUPPORT 16#ifdef HAVE_DWARF_UNWIND_SUPPORT
17int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 17int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
18 struct machine *machine, 18 struct machine *machine,
19 struct thread *thread, 19 struct thread *thread,
20 u64 sample_uregs,
21 struct perf_sample *data, int max_stack); 20 struct perf_sample *data, int max_stack);
22int unwind__arch_reg_id(int regnum); 21/* libunwind specific */
22#ifdef HAVE_LIBUNWIND_SUPPORT
23int libunwind__arch_reg_id(int regnum);
24#endif
23#else 25#else
24static inline int 26static inline int
25unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, 27unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
26 void *arg __maybe_unused, 28 void *arg __maybe_unused,
27 struct machine *machine __maybe_unused, 29 struct machine *machine __maybe_unused,
28 struct thread *thread __maybe_unused, 30 struct thread *thread __maybe_unused,
29 u64 sample_uregs __maybe_unused,
30 struct perf_sample *data __maybe_unused, 31 struct perf_sample *data __maybe_unused,
31 int max_stack __maybe_unused) 32 int max_stack __maybe_unused)
32{ 33{
33 return 0; 34 return 0;
34} 35}
35#endif /* HAVE_LIBUNWIND_SUPPORT */ 36#endif /* HAVE_DWARF_UNWIND_SUPPORT */
36#endif /* __UNWIND_H */ 37#endif /* __UNWIND_H */
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 42ad667bb317..9f66549562bd 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -1,6 +1,6 @@
1#include "../perf.h" 1#include "../perf.h"
2#include "util.h" 2#include "util.h"
3#include "fs.h" 3#include <api/fs/fs.h>
4#include <sys/mman.h> 4#include <sys/mman.h>
5#ifdef HAVE_BACKTRACE_SUPPORT 5#ifdef HAVE_BACKTRACE_SUPPORT
6#include <execinfo.h> 6#include <execinfo.h>