Browse Source

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

  o Add +field argument support for --sort option (Jiri Olsa)

  o Do not access kallsyms when analyzing user binaries with 'probe' (Masami Hiramatsu)

  o Ignore stripped vmlinux and fallback to kallsyms (Anton Blanchard)

  o Add path to Ubuntu kernel debuginfo file (Anton Blanchard)

  o Disable kernel symbol demangling by default (Avi Kivity)

Infrastructure changes:

  o More intel PT prep work, from Adrian Hunter, including:

    - Let a user specify a PMU event without any config terms
    - Add perf-with-kcore script
    - Let default config be defined for a PMU
    - Add perf_pmu__scan_file()

  o "perf kvm stat report" improvements by Alexander Yarygin:
    o  Save pid string in opts.target.pid
    o  Enable the target.system_wide flag
    o  Unify the title bar output

  o Fix build issue on powerpc when DWARF support is disabled (Anton Blanchard)

  o Allow to specify lib compile variable for spec usage (Jiri Olsa)

  o Fix build on ARM (Stephane Eranian)

  o Fix build on powerpc when DWARF support is disabled (Anton Blanchard)

  o Don't include sys/poll.h directly (Arnaldo Carvalho de Melo)

  o Use ring buffer consume method to look like other tools (Arnaldo Carvalho de Melo)

  o Allow to specify lib compile variable for spec usage (Jiri Olsa)

  o Fix GNU-only grep usage in Makefile (John Spencer)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Ingo Molnar 11 years ago
parent
commit
4f7cf3a992

+ 1 - 0
tools/perf/.gitignore

@@ -15,6 +15,7 @@ perf.data
 perf.data.old
 perf.data.old
 output.svg
 output.svg
 perf-archive
 perf-archive
+perf-with-kcore
 tags
 tags
 TAGS
 TAGS
 cscope*
 cscope*

+ 3 - 0
tools/perf/Documentation/perf-probe.txt

@@ -104,6 +104,9 @@ OPTIONS
 	Specify path to the executable or shared library file for user
 	Specify path to the executable or shared library file for user
 	space tracing. Can also be used with --funcs option.
 	space tracing. Can also be used with --funcs option.
 
 
+--demangle-kernel::
+	Demangle kernel symbols.
+
 In absence of -m/-x options, perf probe checks if the first argument after
 In absence of -m/-x options, perf probe checks if the first argument after
 the options is an absolute path name. If its an absolute path, perf probe
 the options is an absolute path name. If its an absolute path, perf probe
 uses it as a target module/target user space binary to probe.
 uses it as a target module/target user space binary to probe.

+ 3 - 0
tools/perf/Documentation/perf-report.txt

@@ -276,6 +276,9 @@ OPTIONS
 	Demangle symbol names to human readable form. It's enabled by default,
 	Demangle symbol names to human readable form. It's enabled by default,
 	disable with --no-demangle.
 	disable with --no-demangle.
 
 
+--demangle-kernel::
+	Demangle kernel symbol names to human readable form (for C++ kernels).
+
 --mem-mode::
 --mem-mode::
 	Use the data addresses of samples in addition to instruction addresses
 	Use the data addresses of samples in addition to instruction addresses
 	to build the histograms.  To generate meaningful output, the perf.data
 	to build the histograms.  To generate meaningful output, the perf.data

+ 3 - 0
tools/perf/Documentation/perf-top.txt

@@ -98,6 +98,9 @@ Default is to monitor all CPUS.
 --hide_user_symbols::
 --hide_user_symbols::
         Hide user symbols.
         Hide user symbols.
 
 
+--demangle-kernel::
+        Demangle kernel symbols.
+
 -D::
 -D::
 --dump-symtab::
 --dump-symtab::
         Dump the symbol table used for profiling.
         Dump the symbol table used for profiling.

+ 4 - 1
tools/perf/Makefile.perf

@@ -126,6 +126,7 @@ PYRF_OBJS =
 SCRIPT_SH =
 SCRIPT_SH =
 
 
 SCRIPT_SH += perf-archive.sh
 SCRIPT_SH += perf-archive.sh
+SCRIPT_SH += perf-with-kcore.sh
 
 
 grep-libs = $(filter -l%,$(1))
 grep-libs = $(filter -l%,$(1))
 strip-libs = $(filter-out -l%,$(1))
 strip-libs = $(filter-out -l%,$(1))
@@ -878,6 +879,8 @@ install-bin: all install-gtk
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 	$(call QUIET_INSTALL, perf-archive) \
 	$(call QUIET_INSTALL, perf-archive) \
 		$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 		$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
+	$(call QUIET_INSTALL, perf-with-kcore) \
+		$(INSTALL) $(OUTPUT)perf-with-kcore -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 ifndef NO_LIBPERL
 ifndef NO_LIBPERL
 	$(call QUIET_INSTALL, perl-scripts) \
 	$(call QUIET_INSTALL, perl-scripts) \
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
@@ -923,7 +926,7 @@ config-clean:
 	@$(MAKE) -C config/feature-checks clean >/dev/null
 	@$(MAKE) -C config/feature-checks clean >/dev/null
 
 
 clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
 clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
-	$(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
+	$(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
 	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
 	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
 	$(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*
 	$(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*
 	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
 	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean

+ 1 - 0
tools/perf/arch/arm/tests/dwarf-unwind.c

@@ -3,6 +3,7 @@
 #include "thread.h"
 #include "thread.h"
 #include "map.h"
 #include "map.h"
 #include "event.h"
 #include "event.h"
+#include "debug.h"
 #include "tests/tests.h"
 #include "tests/tests.h"
 
 
 #define STACK_SIZE 8192
 #define STACK_SIZE 8192

+ 1 - 0
tools/perf/arch/arm/util/unwind-libunwind.c

@@ -3,6 +3,7 @@
 #include <libunwind.h>
 #include <libunwind.h>
 #include "perf_regs.h"
 #include "perf_regs.h"
 #include "../../util/unwind.h"
 #include "../../util/unwind.h"
+#include "../../util/debug.h"
 
 
 int libunwind__arch_reg_id(int regnum)
 int libunwind__arch_reg_id(int regnum)
 {
 {

+ 1 - 1
tools/perf/arch/powerpc/Makefile

@@ -1,6 +1,6 @@
 ifndef NO_DWARF
 ifndef NO_DWARF
 PERF_HAVE_DWARF_REGS := 1
 PERF_HAVE_DWARF_REGS := 1
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o
 endif
 endif
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o

+ 1 - 1
tools/perf/bench/sched-messaging.c

@@ -26,7 +26,7 @@
 #include <sys/socket.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include <sys/wait.h>
 #include <sys/time.h>
 #include <sys/time.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <limits.h>
 #include <limits.h>
 #include <err.h>
 #include <err.h>
 
 

+ 12 - 11
tools/perf/builtin-kvm.c

@@ -543,14 +543,12 @@ static void print_vcpu_info(struct perf_kvm_stat *kvm)
 
 
 	pr_info("Analyze events for ");
 	pr_info("Analyze events for ");
 
 
-	if (kvm->live) {
-		if (kvm->opts.target.system_wide)
-			pr_info("all VMs, ");
-		else if (kvm->opts.target.pid)
-			pr_info("pid(s) %s, ", kvm->opts.target.pid);
-		else
-			pr_info("dazed and confused on what is monitored, ");
-	}
+	if (kvm->opts.target.system_wide)
+		pr_info("all VMs, ");
+	else if (kvm->opts.target.pid)
+		pr_info("pid(s) %s, ", kvm->opts.target.pid);
+	else
+		pr_info("dazed and confused on what is monitored, ");
 
 
 	if (vcpu == -1)
 	if (vcpu == -1)
 		pr_info("all VCPUs:\n\n");
 		pr_info("all VCPUs:\n\n");
@@ -1085,8 +1083,8 @@ static int read_events(struct perf_kvm_stat *kvm)
 
 
 static int parse_target_str(struct perf_kvm_stat *kvm)
 static int parse_target_str(struct perf_kvm_stat *kvm)
 {
 {
-	if (kvm->pid_str) {
-		kvm->pid_list = intlist__new(kvm->pid_str);
+	if (kvm->opts.target.pid) {
+		kvm->pid_list = intlist__new(kvm->opts.target.pid);
 		if (kvm->pid_list == NULL) {
 		if (kvm->pid_list == NULL) {
 			pr_err("Error parsing process id string\n");
 			pr_err("Error parsing process id string\n");
 			return -EINVAL;
 			return -EINVAL;
@@ -1188,7 +1186,7 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
 		OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
 		OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
 			    "key for sorting: sample(sort by samples number)"
 			    "key for sorting: sample(sort by samples number)"
 			    " time (sort by avg time)"),
 			    " time (sort by avg time)"),
-		OPT_STRING('p', "pid", &kvm->pid_str, "pid",
+		OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
 			   "analyze events only for given process id(s)"),
 			   "analyze events only for given process id(s)"),
 		OPT_END()
 		OPT_END()
 	};
 	};
@@ -1207,6 +1205,9 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
 					   kvm_events_report_options);
 					   kvm_events_report_options);
 	}
 	}
 
 
+	if (!kvm->opts.target.pid)
+		kvm->opts.target.system_wide = true;
+
 	return kvm_events_report_vcpu(kvm);
 	return kvm_events_report_vcpu(kvm);
 }
 }
 
 

+ 4 - 1
tools/perf/builtin-probe.c

@@ -376,6 +376,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 			"target executable name or path", opt_set_target),
 			"target executable name or path", opt_set_target),
 	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
 	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
 		    "Disable symbol demangling"),
 		    "Disable symbol demangling"),
+	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
+		    "Enable kernel symbol demangling"),
 	OPT_END()
 	OPT_END()
 	};
 	};
 	int ret;
 	int ret;
@@ -470,7 +472,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 			usage_with_options(probe_usage, options);
 			usage_with_options(probe_usage, options);
 		}
 		}
 
 
-		ret = show_line_range(&params.line_range, params.target);
+		ret = show_line_range(&params.line_range, params.target,
+				      params.uprobes);
 		if (ret < 0)
 		if (ret < 0)
 			pr_err_with_code("  Error: Failed to show lines.", ret);
 			pr_err_with_code("  Error: Failed to show lines.", ret);
 		return ret;
 		return ret;

+ 4 - 4
tools/perf/builtin-record.c

@@ -65,8 +65,9 @@ static int process_synthesized_event(struct perf_tool *tool,
 	return record__write(rec, event, event->header.size);
 	return record__write(rec, event, event->header.size);
 }
 }
 
 
-static int record__mmap_read(struct record *rec, struct perf_mmap *md)
+static int record__mmap_read(struct record *rec, int idx)
 {
 {
+	struct perf_mmap *md = &rec->evlist->mmap[idx];
 	unsigned int head = perf_mmap__read_head(md);
 	unsigned int head = perf_mmap__read_head(md);
 	unsigned int old = md->prev;
 	unsigned int old = md->prev;
 	unsigned char *data = md->base + page_size;
 	unsigned char *data = md->base + page_size;
@@ -102,8 +103,7 @@ static int record__mmap_read(struct record *rec, struct perf_mmap *md)
 	}
 	}
 
 
 	md->prev = old;
 	md->prev = old;
-	perf_mmap__write_tail(md, old);
-
+	perf_evlist__mmap_consume(rec->evlist, idx);
 out:
 out:
 	return rc;
 	return rc;
 }
 }
@@ -245,7 +245,7 @@ static int record__mmap_read_all(struct record *rec)
 
 
 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
 		if (rec->evlist->mmap[i].base) {
 		if (rec->evlist->mmap[i].base) {
-			if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
+			if (record__mmap_read(rec, i) != 0) {
 				rc = -1;
 				rc = -1;
 				goto out;
 				goto out;
 			}
 			}

+ 2 - 0
tools/perf/builtin-report.c

@@ -680,6 +680,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 		   "objdump binary to use for disassembly and annotations"),
 		   "objdump binary to use for disassembly and annotations"),
 	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
 	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
 		    "Disable symbol demangling"),
 		    "Disable symbol demangling"),
+	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
+		    "Enable kernel symbol demangling"),
 	OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
 	OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
 	OPT_CALLBACK(0, "percent-limit", &report, "percent",
 	OPT_CALLBACK(0, "percent-limit", &report, "percent",
 		     "Don't show entries under that percent", parse_percent_limit),
 		     "Don't show entries under that percent", parse_percent_limit),

+ 3 - 1
tools/perf/builtin-top.c

@@ -59,7 +59,7 @@
 
 
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <sys/prctl.h>
 #include <sys/prctl.h>
 #include <sys/wait.h>
 #include <sys/wait.h>
 #include <sys/uio.h>
 #include <sys/uio.h>
@@ -1142,6 +1142,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
 		    "Interleave source code with assembly code (default)"),
 		    "Interleave source code with assembly code (default)"),
 	OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
 	OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
 		    "Display raw encoding of assembly instructions (default)"),
 		    "Display raw encoding of assembly instructions (default)"),
+	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
+		    "Enable kernel symbol demangling"),
 	OPT_STRING(0, "objdump", &objdump_path, "path",
 	OPT_STRING(0, "objdump", &objdump_path, "path",
 		    "objdump binary to use for disassembly and annotations"),
 		    "objdump binary to use for disassembly and annotations"),
 	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
 	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",

+ 8 - 4
tools/perf/config/Makefile

@@ -48,10 +48,6 @@ ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
   NO_LIBDW_DWARF_UNWIND := 1
   NO_LIBDW_DWARF_UNWIND := 1
 endif
 endif
 
 
-ifeq ($(ARCH),powerpc)
-  CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
-endif
-
 ifeq ($(LIBUNWIND_LIBS),)
 ifeq ($(LIBUNWIND_LIBS),)
   NO_LIBUNWIND := 1
   NO_LIBUNWIND := 1
 else
 else
@@ -378,6 +374,12 @@ ifndef NO_LIBELF
   endif # NO_DWARF
   endif # NO_DWARF
 endif # NO_LIBELF
 endif # NO_LIBELF
 
 
+ifeq ($(ARCH),powerpc)
+  ifndef NO_DWARF
+    CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
+  endif
+endif
+
 ifndef NO_LIBUNWIND
 ifndef NO_LIBUNWIND
   ifneq ($(feature-libunwind), 1)
   ifneq ($(feature-libunwind), 1)
     msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
     msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
@@ -651,11 +653,13 @@ else
 sysconfdir = $(prefix)/etc
 sysconfdir = $(prefix)/etc
 ETC_PERFCONFIG = etc/perfconfig
 ETC_PERFCONFIG = etc/perfconfig
 endif
 endif
+ifndef lib
 ifeq ($(IS_X86_64),1)
 ifeq ($(IS_X86_64),1)
 lib = lib64
 lib = lib64
 else
 else
 lib = lib
 lib = lib
 endif
 endif
+endif # lib
 libdir = $(prefix)/$(lib)
 libdir = $(prefix)/$(lib)
 
 
 # Shell quote (do not use $(call) to accommodate ancient setups);
 # Shell quote (do not use $(call) to accommodate ancient setups);

+ 1 - 1
tools/perf/config/utilities.mak

@@ -132,7 +132,7 @@ endef
 #
 #
 # Usage: bool-value = $(call is-absolute,path)
 # Usage: bool-value = $(call is-absolute,path)
 #
 #
-is-absolute = $(shell echo $(shell-sq) | grep ^/ -q && echo y)
+is-absolute = $(shell echo $(shell-sq) | grep -q ^/ && echo y)
 
 
 # lookup
 # lookup
 #
 #

+ 259 - 0
tools/perf/perf-with-kcore.sh

@@ -0,0 +1,259 @@
+#!/bin/bash
+# perf-with-kcore: use perf with a copy of kcore
+# Copyright (c) 2014, Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+
+set -e
+
+usage()
+{
+        echo "Usage: perf-with-kcore <perf sub-command> <perf.data directory> [<sub-command options> [ -- <workload>]]" >&2
+        echo "       <perf sub-command> can be record, script, report or inject" >&2
+        echo "   or: perf-with-kcore fix_buildid_cache_permissions" >&2
+        exit 1
+}
+
+find_perf()
+{
+	if [ -n "$PERF" ] ; then
+		return
+	fi
+	PERF=`which perf || true`
+	if [ -z "$PERF" ] ; then
+		echo "Failed to find perf" >&2
+	        exit 1
+	fi
+	if [ ! -x "$PERF" ] ; then
+		echo "Failed to find perf" >&2
+	        exit 1
+	fi
+	echo "Using $PERF"
+	"$PERF" version
+}
+
+copy_kcore()
+{
+	echo "Copying kcore"
+
+	if [ $EUID -eq 0 ] ; then
+		SUDO=""
+	else
+		SUDO="sudo"
+	fi
+
+	rm -f perf.data.junk
+	("$PERF" record -o perf.data.junk $PERF_OPTIONS -- sleep 60) >/dev/null 2>/dev/null &
+	PERF_PID=$!
+
+	# Need to make sure that perf has started
+	sleep 1
+
+	KCORE=$(($SUDO "$PERF" buildid-cache -v -f -k /proc/kcore >/dev/null) 2>&1)
+	case "$KCORE" in
+	"kcore added to build-id cache directory "*)
+		KCORE_DIR=${KCORE#"kcore added to build-id cache directory "}
+	;;
+	*)
+		kill $PERF_PID
+		wait >/dev/null 2>/dev/null || true
+		rm perf.data.junk
+		echo "$KCORE"
+		echo "Failed to find kcore" >&2
+		exit 1
+	;;
+	esac
+
+	kill $PERF_PID
+	wait >/dev/null 2>/dev/null || true
+	rm perf.data.junk
+
+	$SUDO cp -a "$KCORE_DIR" "$(pwd)/$PERF_DATA_DIR"
+	$SUDO rm -f "$KCORE_DIR/kcore"
+	$SUDO rm -f "$KCORE_DIR/kallsyms"
+	$SUDO rm -f "$KCORE_DIR/modules"
+	$SUDO rmdir "$KCORE_DIR"
+
+	KCORE_DIR_BASENAME=$(basename "$KCORE_DIR")
+	KCORE_DIR="$(pwd)/$PERF_DATA_DIR/$KCORE_DIR_BASENAME"
+
+	$SUDO chown $UID "$KCORE_DIR"
+	$SUDO chown $UID "$KCORE_DIR/kcore"
+	$SUDO chown $UID "$KCORE_DIR/kallsyms"
+	$SUDO chown $UID "$KCORE_DIR/modules"
+
+	$SUDO chgrp $GROUPS "$KCORE_DIR"
+	$SUDO chgrp $GROUPS "$KCORE_DIR/kcore"
+	$SUDO chgrp $GROUPS "$KCORE_DIR/kallsyms"
+	$SUDO chgrp $GROUPS "$KCORE_DIR/modules"
+
+	ln -s "$KCORE_DIR_BASENAME" "$PERF_DATA_DIR/kcore_dir"
+}
+
+fix_buildid_cache_permissions()
+{
+	if [ $EUID -ne 0 ] ; then
+		echo "This script must be run as root via sudo " >&2
+		exit 1
+	fi
+
+	if [ -z "$SUDO_USER" ] ; then
+		echo "This script must be run via sudo" >&2
+		exit 1
+	fi
+
+	USER_HOME=$(bash <<< "echo ~$SUDO_USER")
+
+	if [ "$HOME" != "$USER_HOME" ] ; then
+		echo "Fix unnecessary because root has a home: $HOME" >&2
+		exit 1
+	fi
+
+	echo "Fixing buildid cache permissions"
+
+	find "$USER_HOME/.debug" -xdev -type d          ! -user "$SUDO_USER" -ls -exec chown    "$SUDO_USER" \{\} \;
+	find "$USER_HOME/.debug" -xdev -type f -links 1 ! -user "$SUDO_USER" -ls -exec chown    "$SUDO_USER" \{\} \;
+	find "$USER_HOME/.debug" -xdev -type l          ! -user "$SUDO_USER" -ls -exec chown -h "$SUDO_USER" \{\} \;
+
+	if [ -n "$SUDO_GID" ] ; then
+		find "$USER_HOME/.debug" -xdev -type d          ! -group "$SUDO_GID" -ls -exec chgrp    "$SUDO_GID" \{\} \;
+		find "$USER_HOME/.debug" -xdev -type f -links 1 ! -group "$SUDO_GID" -ls -exec chgrp    "$SUDO_GID" \{\} \;
+		find "$USER_HOME/.debug" -xdev -type l          ! -group "$SUDO_GID" -ls -exec chgrp -h "$SUDO_GID" \{\} \;
+	fi
+
+	echo "Done"
+}
+
+check_buildid_cache_permissions()
+{
+	if [ $EUID -eq 0 ] ; then
+		return
+	fi
+
+	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d          ! -user "$USER" -print -quit)
+	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -user "$USER" -print -quit)
+	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l          ! -user "$USER" -print -quit)
+
+	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d          ! -group "$GROUPS" -print -quit)
+	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -group "$GROUPS" -print -quit)
+	PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l          ! -group "$GROUPS" -print -quit)
+
+	if [ -n "$PERMISSIONS_OK" ] ; then
+		echo "*** WARNING *** buildid cache permissions may need fixing" >&2
+	fi
+}
+
+record()
+{
+	echo "Recording"
+
+	if [ $EUID -ne 0 ] ; then
+
+		if [ "$(cat /proc/sys/kernel/kptr_restrict)" -ne 0 ] ; then
+			echo "*** WARNING *** /proc/sys/kernel/kptr_restrict prevents access to kernel addresses" >&2
+		fi
+
+		if echo "$PERF_OPTIONS" | grep -q ' -a \|^-a \| -a$\|^-a$\| --all-cpus \|^--all-cpus \| --all-cpus$\|^--all-cpus$' ; then
+			echo "*** WARNING *** system-wide tracing without root access will not be able to read all necessary information from /proc" >&2
+		fi
+
+		if echo "$PERF_OPTIONS" | grep -q 'intel_pt\|intel_bts\| -I\|^-I' ; then
+			if [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt -1 ] ; then
+				echo "*** WARNING *** /proc/sys/kernel/perf_event_paranoid restricts buffer size and tracepoint (sched_switch) use" >&2
+			fi
+
+			if echo "$PERF_OPTIONS" | grep -q ' --per-thread \|^--per-thread \| --per-thread$\|^--per-thread$' ; then
+				true
+			elif echo "$PERF_OPTIONS" | grep -q ' -t \|^-t \| -t$\|^-t$' ; then
+				true
+			elif [ ! -r /sys/kernel/debug -o ! -x /sys/kernel/debug ] ; then
+				echo "*** WARNING *** /sys/kernel/debug permissions prevent tracepoint (sched_switch) use" >&2
+			fi
+		fi
+	fi
+
+	if [ -z "$1" ] ; then
+		echo "Workload is required for recording" >&2
+		usage
+	fi
+
+	if [ -e "$PERF_DATA_DIR" ] ; then
+		echo "'$PERF_DATA_DIR' exists" >&2
+		exit 1
+	fi
+
+	find_perf
+
+	mkdir "$PERF_DATA_DIR"
+
+	echo "$PERF record -o $PERF_DATA_DIR/perf.data $PERF_OPTIONS -- $*"
+	"$PERF" record -o "$PERF_DATA_DIR/perf.data" $PERF_OPTIONS -- $* || true
+
+	if rmdir "$PERF_DATA_DIR" > /dev/null 2>/dev/null ; then
+		exit 1
+	fi
+
+	copy_kcore
+
+	echo "Done"
+}
+
+subcommand()
+{
+	find_perf
+	check_buildid_cache_permissions
+	echo "$PERF $PERF_SUB_COMMAND -i $PERF_DATA_DIR/perf.data --kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms $*"
+	"$PERF" $PERF_SUB_COMMAND -i "$PERF_DATA_DIR/perf.data" "--kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms" $*
+}
+
+if [ "$1" = "fix_buildid_cache_permissions" ] ; then
+	fix_buildid_cache_permissions
+	exit 0
+fi
+
+PERF_SUB_COMMAND=$1
+PERF_DATA_DIR=$2
+shift || true
+shift || true
+
+if [ -z "$PERF_SUB_COMMAND" ] ; then
+	usage
+fi
+
+if [ -z "$PERF_DATA_DIR" ] ; then
+	usage
+fi
+
+case "$PERF_SUB_COMMAND" in
+"record")
+	while [ "$1" != "--" ] ; do
+		PERF_OPTIONS+="$1 "
+		shift || break
+	done
+	if [ "$1" != "--" ] ; then
+		echo "Options and workload are required for recording" >&2
+		usage
+	fi
+	shift
+	record $*
+;;
+"script")
+	subcommand $*
+;;
+"report")
+	subcommand $*
+;;
+"inject")
+	subcommand $*
+;;
+*)
+	usage
+;;
+esac

+ 1 - 1
tools/perf/tests/pmu.c

@@ -152,7 +152,7 @@ int test__pmu(void)
 		if (ret)
 		if (ret)
 			break;
 			break;
 
 
-		ret = perf_pmu__config_terms(&formats, &attr, terms);
+		ret = perf_pmu__config_terms(&formats, &attr, terms, false);
 		if (ret)
 		if (ret)
 			break;
 			break;
 
 

+ 0 - 1
tools/perf/util/kvm-stat.h

@@ -92,7 +92,6 @@ struct perf_kvm_stat {
 	u64 lost_events;
 	u64 lost_events;
 	u64 duration;
 	u64 duration;
 
 
-	const char *pid_str;
 	struct intlist *pid_list;
 	struct intlist *pid_list;
 
 
 	struct rb_root result;
 	struct rb_root result;

+ 12 - 1
tools/perf/util/parse-events.c

@@ -643,7 +643,18 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
 	if (!pmu)
 	if (!pmu)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	memset(&attr, 0, sizeof(attr));
+	if (pmu->default_config) {
+		memcpy(&attr, pmu->default_config,
+		       sizeof(struct perf_event_attr));
+	} else {
+		memset(&attr, 0, sizeof(attr));
+	}
+
+	if (!head_config) {
+		attr.type = pmu->type;
+		evsel = __add_event(list, idx, &attr, NULL, pmu->cpus);
+		return evsel ? 0 : -ENOMEM;
+	}
 
 
 	if (perf_pmu__check_alias(pmu, head_config, &unit, &scale))
 	if (perf_pmu__check_alias(pmu, head_config, &unit, &scale))
 		return -EINVAL;
 		return -EINVAL;

+ 10 - 0
tools/perf/util/parse-events.y

@@ -210,6 +210,16 @@ PE_NAME '/' event_config '/'
 	parse_events__free_terms($3);
 	parse_events__free_terms($3);
 	$$ = list;
 	$$ = list;
 }
 }
+|
+PE_NAME '/' '/'
+{
+	struct parse_events_evlist *data = _data;
+	struct list_head *list;
+
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, NULL));
+	$$ = list;
+}
 
 
 value_sym:
 value_sym:
 PE_VALUE_SYM_HW
 PE_VALUE_SYM_HW

+ 63 - 16
tools/perf/util/pmu.c

@@ -2,6 +2,8 @@
 #include <sys/types.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <stdio.h>
+#include <stdbool.h>
+#include <stdarg.h>
 #include <dirent.h>
 #include <dirent.h>
 #include <api/fs/fs.h>
 #include <api/fs/fs.h>
 #include <locale.h>
 #include <locale.h>
@@ -387,6 +389,12 @@ static struct cpu_map *pmu_cpumask(const char *name)
 	return cpus;
 	return cpus;
 }
 }
 
 
+struct perf_event_attr *__attribute__((weak))
+perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
+{
+	return NULL;
+}
+
 static struct perf_pmu *pmu_lookup(const char *name)
 static struct perf_pmu *pmu_lookup(const char *name)
 {
 {
 	struct perf_pmu *pmu;
 	struct perf_pmu *pmu;
@@ -421,6 +429,9 @@ static struct perf_pmu *pmu_lookup(const char *name)
 	pmu->name = strdup(name);
 	pmu->name = strdup(name);
 	pmu->type = type;
 	pmu->type = type;
 	list_add_tail(&pmu->list, &pmus);
 	list_add_tail(&pmu->list, &pmus);
+
+	pmu->default_config = perf_pmu__get_default_config(pmu);
+
 	return pmu;
 	return pmu;
 }
 }
 
 
@@ -479,28 +490,24 @@ pmu_find_format(struct list_head *formats, char *name)
 }
 }
 
 
 /*
 /*
- * Returns value based on the format definition (format parameter)
+ * Sets value based on the format definition (format parameter)
  * and unformated value (value parameter).
  * and unformated value (value parameter).
- *
- * TODO maybe optimize a little ;)
  */
  */
-static __u64 pmu_format_value(unsigned long *format, __u64 value)
+static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
+			     bool zero)
 {
 {
 	unsigned long fbit, vbit;
 	unsigned long fbit, vbit;
-	__u64 v = 0;
 
 
 	for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
 	for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
 
 
 		if (!test_bit(fbit, format))
 		if (!test_bit(fbit, format))
 			continue;
 			continue;
 
 
-		if (!(value & (1llu << vbit++)))
-			continue;
-
-		v |= (1llu << fbit);
+		if (value & (1llu << vbit++))
+			*v |= (1llu << fbit);
+		else if (zero)
+			*v &= ~(1llu << fbit);
 	}
 	}
-
-	return v;
 }
 }
 
 
 /*
 /*
@@ -509,7 +516,8 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
  */
  */
 static int pmu_config_term(struct list_head *formats,
 static int pmu_config_term(struct list_head *formats,
 			   struct perf_event_attr *attr,
 			   struct perf_event_attr *attr,
-			   struct parse_events_term *term)
+			   struct parse_events_term *term,
+			   bool zero)
 {
 {
 	struct perf_pmu_format *format;
 	struct perf_pmu_format *format;
 	__u64 *vp;
 	__u64 *vp;
@@ -548,18 +556,19 @@ static int pmu_config_term(struct list_head *formats,
 	 * non-hardcoded terms, here's the place to translate
 	 * non-hardcoded terms, here's the place to translate
 	 * them into value.
 	 * them into value.
 	 */
 	 */
-	*vp |= pmu_format_value(format->bits, term->val.num);
+	pmu_format_value(format->bits, term->val.num, vp, zero);
 	return 0;
 	return 0;
 }
 }
 
 
 int perf_pmu__config_terms(struct list_head *formats,
 int perf_pmu__config_terms(struct list_head *formats,
 			   struct perf_event_attr *attr,
 			   struct perf_event_attr *attr,
-			   struct list_head *head_terms)
+			   struct list_head *head_terms,
+			   bool zero)
 {
 {
 	struct parse_events_term *term;
 	struct parse_events_term *term;
 
 
 	list_for_each_entry(term, head_terms, list)
 	list_for_each_entry(term, head_terms, list)
-		if (pmu_config_term(formats, attr, term))
+		if (pmu_config_term(formats, attr, term, zero))
 			return -EINVAL;
 			return -EINVAL;
 
 
 	return 0;
 	return 0;
@@ -573,8 +582,10 @@ int perf_pmu__config_terms(struct list_head *formats,
 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
 		     struct list_head *head_terms)
 		     struct list_head *head_terms)
 {
 {
+	bool zero = !!pmu->default_config;
+
 	attr->type = pmu->type;
 	attr->type = pmu->type;
-	return perf_pmu__config_terms(&pmu->format, attr, head_terms);
+	return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero);
 }
 }
 
 
 static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
 static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
@@ -794,3 +805,39 @@ bool pmu_have_event(const char *pname, const char *name)
 	}
 	}
 	return false;
 	return false;
 }
 }
+
+static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs__mountpoint();
+	if (!sysfs)
+		return NULL;
+
+	snprintf(path, PATH_MAX,
+		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
+
+	if (stat(path, &st) < 0)
+		return NULL;
+
+	return fopen(path, "r");
+}
+
+int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
+			...)
+{
+	va_list args;
+	FILE *file;
+	int ret = EOF;
+
+	va_start(args, fmt);
+	file = perf_pmu__open_file(pmu, name);
+	if (file) {
+		ret = vfscanf(file, fmt, args);
+		fclose(file);
+	}
+	va_end(args);
+	return ret;
+}

+ 11 - 1
tools/perf/util/pmu.h

@@ -13,9 +13,12 @@ enum {
 
 
 #define PERF_PMU_FORMAT_BITS 64
 #define PERF_PMU_FORMAT_BITS 64
 
 
+struct perf_event_attr;
+
 struct perf_pmu {
 struct perf_pmu {
 	char *name;
 	char *name;
 	__u32 type;
 	__u32 type;
+	struct perf_event_attr *default_config;
 	struct cpu_map *cpus;
 	struct cpu_map *cpus;
 	struct list_head format;  /* HEAD struct perf_pmu_format -> list */
 	struct list_head format;  /* HEAD struct perf_pmu_format -> list */
 	struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */
 	struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */
@@ -27,7 +30,8 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
 		     struct list_head *head_terms);
 		     struct list_head *head_terms);
 int perf_pmu__config_terms(struct list_head *formats,
 int perf_pmu__config_terms(struct list_head *formats,
 			   struct perf_event_attr *attr,
 			   struct perf_event_attr *attr,
-			   struct list_head *head_terms);
+			   struct list_head *head_terms,
+			   bool zero);
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
 			  const char **unit, double *scale);
 			  const char **unit, double *scale);
 struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
 struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
@@ -45,5 +49,11 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
 void print_pmu_events(const char *event_glob, bool name_only);
 void print_pmu_events(const char *event_glob, bool name_only);
 bool pmu_have_event(const char *pname, const char *name);
 bool pmu_have_event(const char *pname, const char *name);
 
 
+int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
+			...) __attribute__((format(scanf, 3, 4)));
+
 int perf_pmu__test(void);
 int perf_pmu__test(void);
+
+struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
+
 #endif /* __PMU_H */
 #endif /* __PMU_H */

+ 5 - 4
tools/perf/util/probe-event.c

@@ -697,11 +697,11 @@ end:
 	return ret;
 	return ret;
 }
 }
 
 
-int show_line_range(struct line_range *lr, const char *module)
+int show_line_range(struct line_range *lr, const char *module, bool user)
 {
 {
 	int ret;
 	int ret;
 
 
-	ret = init_symbol_maps(false);
+	ret = init_symbol_maps(user);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 	ret = __show_line_range(lr, module);
 	ret = __show_line_range(lr, module);
@@ -776,7 +776,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 	int i, ret = 0;
 	int i, ret = 0;
 	struct debuginfo *dinfo;
 	struct debuginfo *dinfo;
 
 
-	ret = init_symbol_maps(false);
+	ret = init_symbol_maps(pevs->uprobes);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
@@ -822,7 +822,8 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 }
 }
 
 
 int show_line_range(struct line_range *lr __maybe_unused,
 int show_line_range(struct line_range *lr __maybe_unused,
-		    const char *module __maybe_unused)
+		    const char *module __maybe_unused,
+		    bool user __maybe_unused)
 {
 {
 	pr_warning("Debuginfo-analysis is not supported.\n");
 	pr_warning("Debuginfo-analysis is not supported.\n");
 	return -ENOSYS;
 	return -ENOSYS;

+ 2 - 1
tools/perf/util/probe-event.h

@@ -128,7 +128,8 @@ extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
 				 bool force_add);
 				 bool force_add);
 extern int del_perf_probe_events(struct strlist *dellist);
 extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
 extern int show_perf_probe_events(void);
-extern int show_line_range(struct line_range *lr, const char *module);
+extern int show_line_range(struct line_range *lr, const char *module,
+			   bool user);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
 			       int max_probe_points, const char *module,
 			       int max_probe_points, const char *module,
 			       struct strfilter *filter, bool externs);
 			       struct strfilter *filter, bool externs);

+ 10 - 6
tools/perf/util/probe-finder.c

@@ -609,14 +609,18 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	/* Get an appropriate symbol from symtab */
-	symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
+	symbol = dwarf_diename(sp_die);
 	if (!symbol) {
 	if (!symbol) {
-		pr_warning("Failed to find symbol at 0x%lx\n",
-			   (unsigned long)paddr);
-		return -ENOENT;
+		/* Try to get the symbol name from symtab */
+		symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
+		if (!symbol) {
+			pr_warning("Failed to find symbol at 0x%lx\n",
+				   (unsigned long)paddr);
+			return -ENOENT;
+		}
+		eaddr = sym.st_value;
 	}
 	}
-	tp->offset = (unsigned long)(paddr - sym.st_value);
+	tp->offset = (unsigned long)(paddr - eaddr);
 	tp->address = (unsigned long)paddr;
 	tp->address = (unsigned long)paddr;
 	tp->symbol = strdup(symbol);
 	tp->symbol = strdup(symbol);
 	if (!tp->symbol)
 	if (!tp->symbol)

+ 36 - 1
tools/perf/util/sort.c

@@ -1446,12 +1446,47 @@ static const char *get_default_sort_order(void)
 	return default_sort_orders[sort__mode];
 	return default_sort_orders[sort__mode];
 }
 }
 
 
+static int setup_sort_order(void)
+{
+	char *new_sort_order;
+
+	/*
+	 * Append '+'-prefixed sort order to the default sort
+	 * order string.
+	 */
+	if (!sort_order || is_strict_order(sort_order))
+		return 0;
+
+	if (sort_order[1] == '\0') {
+		error("Invalid --sort key: `+'");
+		return -EINVAL;
+	}
+
+	/*
+	 * We allocate new sort_order string, but we never free it,
+	 * because it's checked over the rest of the code.
+	 */
+	if (asprintf(&new_sort_order, "%s,%s",
+		     get_default_sort_order(), sort_order + 1) < 0) {
+		error("Not enough memory to set up --sort");
+		return -ENOMEM;
+	}
+
+	sort_order = new_sort_order;
+	return 0;
+}
+
 static int __setup_sorting(void)
 static int __setup_sorting(void)
 {
 {
 	char *tmp, *tok, *str;
 	char *tmp, *tok, *str;
-	const char *sort_keys = sort_order;
+	const char *sort_keys;
 	int ret = 0;
 	int ret = 0;
 
 
+	ret = setup_sort_order();
+	if (ret)
+		return ret;
+
+	sort_keys = sort_order;
 	if (sort_keys == NULL) {
 	if (sort_keys == NULL) {
 		if (is_strict_order(field_order)) {
 		if (is_strict_order(field_order)) {
 			/*
 			/*

+ 14 - 1
tools/perf/util/symbol-elf.c

@@ -680,6 +680,11 @@ static u64 ref_reloc(struct kmap *kmap)
 	return 0;
 	return 0;
 }
 }
 
 
+static bool want_demangle(bool is_kernel_sym)
+{
+	return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
+}
+
 int dso__load_sym(struct dso *dso, struct map *map,
 int dso__load_sym(struct dso *dso, struct map *map,
 		  struct symsrc *syms_ss, struct symsrc *runtime_ss,
 		  struct symsrc *syms_ss, struct symsrc *runtime_ss,
 		  symbol_filter_t filter, int kmodule)
 		  symbol_filter_t filter, int kmodule)
@@ -712,6 +717,14 @@ int dso__load_sym(struct dso *dso, struct map *map,
 		symbols__delete(&dso->symbols[map->type]);
 		symbols__delete(&dso->symbols[map->type]);
 
 
 	if (!syms_ss->symtab) {
 	if (!syms_ss->symtab) {
+		/*
+		 * If the vmlinux is stripped, fail so we will fall back
+		 * to using kallsyms. The vmlinux runtime symbols aren't
+		 * of much use.
+		 */
+		if (dso->kernel)
+			goto out_elf_end;
+
 		syms_ss->symtab  = syms_ss->dynsym;
 		syms_ss->symtab  = syms_ss->dynsym;
 		syms_ss->symshdr = syms_ss->dynshdr;
 		syms_ss->symshdr = syms_ss->dynshdr;
 	}
 	}
@@ -938,7 +951,7 @@ new_symbol:
 		 * DWARF DW_compile_unit has this, but we don't always have access
 		 * DWARF DW_compile_unit has this, but we don't always have access
 		 * to it...
 		 * to it...
 		 */
 		 */
-		if (symbol_conf.demangle) {
+		if (want_demangle(dso->kernel || kmodule)) {
 			int demangle_flags = DMGL_NO_OPTS;
 			int demangle_flags = DMGL_NO_OPTS;
 			if (verbose)
 			if (verbose)
 				demangle_flags = DMGL_PARAMS | DMGL_ANSI;
 				demangle_flags = DMGL_PARAMS | DMGL_ANSI;

+ 8 - 1
tools/perf/util/symbol.c

@@ -34,6 +34,7 @@ struct symbol_conf symbol_conf = {
 	.try_vmlinux_path	= true,
 	.try_vmlinux_path	= true,
 	.annotate_src		= true,
 	.annotate_src		= true,
 	.demangle		= true,
 	.demangle		= true,
+	.demangle_kernel	= false,
 	.cumulate_callchain	= true,
 	.cumulate_callchain	= true,
 	.show_hist_headers	= true,
 	.show_hist_headers	= true,
 	.symfs			= "",
 	.symfs			= "",
@@ -1756,7 +1757,7 @@ static int vmlinux_path__init(struct perf_session_env *env)
 	char bf[PATH_MAX];
 	char bf[PATH_MAX];
 	char *kernel_version;
 	char *kernel_version;
 
 
-	vmlinux_path = malloc(sizeof(char *) * 5);
+	vmlinux_path = malloc(sizeof(char *) * 6);
 	if (vmlinux_path == NULL)
 	if (vmlinux_path == NULL)
 		return -1;
 		return -1;
 
 
@@ -1787,6 +1788,12 @@ static int vmlinux_path__init(struct perf_session_env *env)
 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
 		goto out_fail;
 		goto out_fail;
 	++vmlinux_path__nr_entries;
 	++vmlinux_path__nr_entries;
+	snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
+		 kernel_version);
+	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
+	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+		goto out_fail;
+        ++vmlinux_path__nr_entries;
 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)

+ 1 - 0
tools/perf/util/symbol.h

@@ -120,6 +120,7 @@ struct symbol_conf {
 			annotate_src,
 			annotate_src,
 			event_group,
 			event_group,
 			demangle,
 			demangle,
+			demangle_kernel,
 			filter_relative,
 			filter_relative,
 			show_hist_headers;
 			show_hist_headers;
 	const char	*vmlinux_name,
 	const char	*vmlinux_name,

+ 3 - 1
tools/perf/util/util.h

@@ -39,6 +39,8 @@
 
 
 #define _ALL_SOURCE 1
 #define _ALL_SOURCE 1
 #define _BSD_SOURCE 1
 #define _BSD_SOURCE 1
+/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */
+#define _DEFAULT_SOURCE 1
 #define HAS_BOOL
 #define HAS_BOOL
 
 
 #include <unistd.h>
 #include <unistd.h>
@@ -64,7 +66,7 @@
 #include <regex.h>
 #include <regex.h>
 #include <utime.h>
 #include <utime.h>
 #include <sys/wait.h>
 #include <sys/wait.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <sys/socket.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
 #include <inttypes.h>
 #include <inttypes.h>