Commit 4f7cf3a9 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents c88f2096 e5685730
...@@ -15,6 +15,7 @@ perf.data ...@@ -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*
......
...@@ -104,6 +104,9 @@ OPTIONS ...@@ -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.
......
...@@ -276,6 +276,9 @@ OPTIONS ...@@ -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
......
...@@ -98,6 +98,9 @@ Default is to monitor all CPUS. ...@@ -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.
......
...@@ -126,6 +126,7 @@ PYRF_OBJS = ...@@ -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 ...@@ -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: ...@@ -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
......
...@@ -3,6 +3,7 @@ ...@@ -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
......
...@@ -3,6 +3,7 @@ ...@@ -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)
{ {
......
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
...@@ -26,7 +26,7 @@ ...@@ -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>
......
...@@ -543,14 +543,12 @@ static void print_vcpu_info(struct perf_kvm_stat *kvm) ...@@ -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) if (kvm->opts.target.system_wide)
pr_info("all VMs, "); pr_info("all VMs, ");
else if (kvm->opts.target.pid) else if (kvm->opts.target.pid)
pr_info("pid(s) %s, ", kvm->opts.target.pid); pr_info("pid(s) %s, ", kvm->opts.target.pid);
else else
pr_info("dazed and confused on what is monitored, "); 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) ...@@ -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) { if (kvm->opts.target.pid) {
kvm->pid_list = intlist__new(kvm->pid_str); 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) ...@@ -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) ...@@ -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);
} }
......
...@@ -376,6 +376,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -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) ...@@ -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;
......
...@@ -65,8 +65,9 @@ static int process_synthesized_event(struct perf_tool *tool, ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
...@@ -680,6 +680,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -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),
......
...@@ -59,7 +59,7 @@ ...@@ -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) ...@@ -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",
......
...@@ -48,10 +48,6 @@ ifneq ($(ARCH),$(filter $(ARCH),x86 arm)) ...@@ -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 ...@@ -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 ...@@ -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);
......
...@@ -132,7 +132,7 @@ endef ...@@ -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
# #
......
#!/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
...@@ -152,7 +152,7 @@ int test__pmu(void) ...@@ -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;
......
...@@ -92,7 +92,6 @@ struct perf_kvm_stat { ...@@ -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;
......
...@@ -643,7 +643,18 @@ int parse_events_add_pmu(struct list_head *list, int *idx, ...@@ -643,7 +643,18 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
if (!pmu) if (!pmu)
return -EINVAL; return -EINVAL;
if (pmu->default_config) {
memcpy(&attr, pmu->default_config,
sizeof(struct perf_event_attr));
} else {
memset(&attr, 0, sizeof(attr)); 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;
......
...@@ -210,6 +210,16 @@ PE_NAME '/' event_config '/' ...@@ -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
......
...@@ -2,6 +2,8 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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++))) if (value & (1llu << vbit++))
continue; *v |= (1llu << fbit);
else if (zero)
v |= (1llu << fbit); *v &= ~(1llu << fbit);
} }
return v;
} }
/* /*
...@@ -509,7 +516,8 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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;
}
...@@ -13,9 +13,12 @@ enum { ...@@ -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, ...@@ -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); ...@@ -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 */
...@@ -697,11 +697,11 @@ static int __show_line_range(struct line_range *lr, const char *module) ...@@ -697,11 +697,11 @@ static int __show_line_range(struct line_range *lr, const char *module)
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, ...@@ -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, ...@@ -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;
......
...@@ -128,7 +128,8 @@ extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, ...@@ -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);
......
...@@ -609,14 +609,18 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, ...@@ -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 = dwarf_diename(sp_die);
if (!symbol) {
/* Try to get the symbol name from symtab */
symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
if (!symbol) { if (!symbol) {
pr_warning("Failed to find symbol at 0x%lx\n", pr_warning("Failed to find symbol at 0x%lx\n",
(unsigned long)paddr); (unsigned long)paddr);
return -ENOENT; return -ENOENT;
} }
tp->offset = (unsigned long)(paddr - sym.st_value); eaddr = 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)
......
...@@ -1446,12 +1446,47 @@ static const char *get_default_sort_order(void) ...@@ -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)) {
/* /*
......
...@@ -680,6 +680,11 @@ static u64 ref_reloc(struct kmap *kmap) ...@@ -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, ...@@ -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 @@ int dso__load_sym(struct dso *dso, struct map *map, ...@@ -938,7 +951,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
* 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;
......
...@@ -34,6 +34,7 @@ struct symbol_conf symbol_conf = { ...@@ -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) ...@@ -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) ...@@ -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)
......
...@@ -120,6 +120,7 @@ struct symbol_conf { ...@@ -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,
......
...@@ -39,6 +39,8 @@ ...@@ -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 @@ ...@@ -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>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment