mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 20:51:44 +00:00
perf/core improvements and fixes
. Add support for the new DWARF unwinder library in elfutils (Jiri Olsa) . Fix build race in the generation of bison files (Jiri Olsa) . Further streamline the feature detection display, trimming it a bit to show just the libraries detected, using VF=1 gets a more verbose output, showing the less interesting feature checks as well (Jiri Olsa). . Check compatible symtab type before loading dso (Namhyung Kim) . Check return value of filename__read_debuglink() (Stephane Eranian) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJTC6KPAAoJENZQFvNTUqpAckAP/0mOm9e1s+ml+unBCGpJ2lOJ q5jf1GGQuTJoX6gOunpq26BlR8Tx9ke4Vi2c04HHm3xzfde9FVNS3VbmfVWL8GPW 1Ar3VXdQNNDydgtoDPvOA0XRO/keYh/+M07Ls9PkDBh6QwRmWEeWHkSBnofYPQ0s 8pmKmMfpsyREyj8fk8P2pad4U9SDWG+Ih51DlcH0rdwfDZh2/NpDFZCbGe8R45+L E0cAnHl8A1+nq9mAxesnAD145917Z863teSW/iCubP/kGus5cNr7PQuT779C6q3F z50NH/Pyl4lebqFuBYMz+e9+y+Ly6qPEZAKjAJ7tOftXkkVEwsP1cfPiKgzS0+6E j1kM9AE8HIPe7Z1OkGIyLC9ibmE9p6q0GkckuG6APnCV/fNP0x2I3UA/Sv8CYpim Y+YFqVWF0mna0p/GvEr2dUSzz/O1/ZirhCieZR9rmEC6jUrH0X9JG5hlCuZtVt58 IRBIormRsD8eLLDkvbzucPX+oYAnVrSRmj0wqCzuokS687ABMGFEWqshRRiWGf/l gfTkjWnfTxAd21J3ZeQ5D7U+lpOkfdV5o20IZuDOSN46KtR3ByZygMvcnzqRoV6x PU+4Htg+pawUvR7mBEllAWuqTt0bMsnhna6Adt0kiqDvh/UWWnNcSEmbUwRAzkLM G7/rfoQVPL3/xsynvxN3 =qQm6 -----END PGP SIGNATURE----- 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: * Add support for the new DWARF unwinder library in elfutils (Jiri Olsa) * Fix build race in the generation of bison files (Jiri Olsa) * Further streamline the feature detection display, trimming it a bit to show just the libraries detected, using VF=1 gets a more verbose output, showing the less interesting feature checks as well (Jiri Olsa). * Check compatible symtab type before loading dso (Namhyung Kim) * Check return value of filename__read_debuglink() (Stephane Eranian) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
e65312fe86
@ -7,6 +7,8 @@ include config/utilities.mak
|
||||
|
||||
# Define V to have a more verbose compile.
|
||||
#
|
||||
# Define VF to have a more verbose feature check output.
|
||||
#
|
||||
# Define O to save output files in a separate directory.
|
||||
#
|
||||
# Define ARCH as name of target architecture if you want cross-builds.
|
||||
@ -55,6 +57,9 @@ include config/utilities.mak
|
||||
# Define NO_LIBAUDIT if you do not want libaudit support
|
||||
#
|
||||
# Define NO_LIBBIONIC if you do not want bionic support
|
||||
#
|
||||
# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
|
||||
# for dwarf backtrace post unwind.
|
||||
|
||||
ifeq ($(srctree),)
|
||||
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
|
||||
@ -404,7 +409,7 @@ endif
|
||||
LIB_OBJS += $(OUTPUT)tests/code-reading.o
|
||||
LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
|
||||
LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
|
||||
ifndef NO_LIBUNWIND
|
||||
ifndef NO_DWARF_UNWIND
|
||||
ifeq ($(ARCH),x86)
|
||||
LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
|
||||
endif
|
||||
@ -476,6 +481,11 @@ ifndef NO_DWARF
|
||||
endif # NO_DWARF
|
||||
endif # NO_LIBELF
|
||||
|
||||
ifndef NO_LIBDW_DWARF_UNWIND
|
||||
LIB_OBJS += $(OUTPUT)util/unwind-libdw.o
|
||||
LIB_H += util/unwind-libdw.h
|
||||
endif
|
||||
|
||||
ifndef NO_LIBUNWIND
|
||||
LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o
|
||||
endif
|
||||
@ -712,9 +722,15 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
|
||||
# we depend the various files onto their directories.
|
||||
DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS)
|
||||
DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
|
||||
$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
|
||||
# no need to add flex objects, because they depend on bison ones
|
||||
DIRECTORY_DEPS += $(OUTPUT)util/parse-events-bison.c
|
||||
DIRECTORY_DEPS += $(OUTPUT)util/pmu-bison.c
|
||||
|
||||
OUTPUT_DIRECTORIES := $(sort $(dir $(DIRECTORY_DEPS)))
|
||||
|
||||
$(DIRECTORY_DEPS): | $(OUTPUT_DIRECTORIES)
|
||||
# In the second step, we make a rule to actually create these directories
|
||||
$(sort $(dir $(DIRECTORY_DEPS))):
|
||||
$(OUTPUT_DIRECTORIES):
|
||||
$(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
|
||||
|
||||
$(LIB_FILE): $(LIB_OBJS)
|
||||
@ -891,7 +907,7 @@ 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-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)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
|
||||
$(python-clean)
|
||||
|
||||
|
@ -4,6 +4,11 @@ LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
|
||||
endif
|
||||
ifndef NO_LIBUNWIND
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
|
||||
endif
|
||||
ifndef NO_LIBDW_DWARF_UNWIND
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libdw.o
|
||||
endif
|
||||
ifndef NO_DWARF_UNWIND
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
|
||||
endif
|
||||
|
51
tools/perf/arch/x86/util/unwind-libdw.c
Normal file
51
tools/perf/arch/x86/util/unwind-libdw.c
Normal file
@ -0,0 +1,51 @@
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include "../../util/unwind-libdw.h"
|
||||
#include "../../util/perf_regs.h"
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
struct regs_dump *user_regs = &ui->sample->user_regs;
|
||||
Dwarf_Word dwarf_regs[17];
|
||||
unsigned nregs;
|
||||
|
||||
#define REG(r) ({ \
|
||||
Dwarf_Word val = 0; \
|
||||
perf_reg_value(&val, user_regs, PERF_REG_X86_##r); \
|
||||
val; \
|
||||
})
|
||||
|
||||
if (user_regs->abi == PERF_SAMPLE_REGS_ABI_32) {
|
||||
dwarf_regs[0] = REG(AX);
|
||||
dwarf_regs[1] = REG(CX);
|
||||
dwarf_regs[2] = REG(DX);
|
||||
dwarf_regs[3] = REG(BX);
|
||||
dwarf_regs[4] = REG(SP);
|
||||
dwarf_regs[5] = REG(BP);
|
||||
dwarf_regs[6] = REG(SI);
|
||||
dwarf_regs[7] = REG(DI);
|
||||
dwarf_regs[8] = REG(IP);
|
||||
nregs = 9;
|
||||
} else {
|
||||
dwarf_regs[0] = REG(AX);
|
||||
dwarf_regs[1] = REG(DX);
|
||||
dwarf_regs[2] = REG(CX);
|
||||
dwarf_regs[3] = REG(BX);
|
||||
dwarf_regs[4] = REG(SI);
|
||||
dwarf_regs[5] = REG(DI);
|
||||
dwarf_regs[6] = REG(BP);
|
||||
dwarf_regs[7] = REG(SP);
|
||||
dwarf_regs[8] = REG(R8);
|
||||
dwarf_regs[9] = REG(R9);
|
||||
dwarf_regs[10] = REG(R10);
|
||||
dwarf_regs[11] = REG(R11);
|
||||
dwarf_regs[12] = REG(R12);
|
||||
dwarf_regs[13] = REG(R13);
|
||||
dwarf_regs[14] = REG(R14);
|
||||
dwarf_regs[15] = REG(R15);
|
||||
dwarf_regs[16] = REG(IP);
|
||||
nregs = 17;
|
||||
}
|
||||
|
||||
return dwfl_thread_state_registers(thread, 0, nregs, dwarf_regs);
|
||||
}
|
@ -59,6 +59,18 @@ ifeq ($(NO_PERF_REGS),0)
|
||||
CFLAGS += -DHAVE_PERF_REGS_SUPPORT
|
||||
endif
|
||||
|
||||
ifndef NO_LIBELF
|
||||
# for linking with debug library, run like:
|
||||
# make DEBUG=1 LIBDW_DIR=/opt/libdw/
|
||||
ifdef LIBDW_DIR
|
||||
LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
|
||||
LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
|
||||
|
||||
FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
|
||||
endif
|
||||
endif
|
||||
|
||||
# include ARCH specific config
|
||||
-include $(src-perf)/arch/$(ARCH)/Makefile
|
||||
|
||||
@ -147,7 +159,35 @@ CORE_FEATURE_TESTS = \
|
||||
libunwind \
|
||||
on-exit \
|
||||
stackprotector-all \
|
||||
timerfd
|
||||
timerfd \
|
||||
libdw-dwarf-unwind
|
||||
|
||||
LIB_FEATURE_TESTS = \
|
||||
dwarf \
|
||||
glibc \
|
||||
gtk2 \
|
||||
libaudit \
|
||||
libbfd \
|
||||
libelf \
|
||||
libnuma \
|
||||
libperl \
|
||||
libpython \
|
||||
libslang \
|
||||
libunwind \
|
||||
libdw-dwarf-unwind
|
||||
|
||||
VF_FEATURE_TESTS = \
|
||||
backtrace \
|
||||
fortify-source \
|
||||
gtk2-infobar \
|
||||
libelf-getphdrnum \
|
||||
libelf-mmap \
|
||||
libpython-version \
|
||||
on-exit \
|
||||
stackprotector-all \
|
||||
timerfd \
|
||||
libunwind-debug-frame \
|
||||
bionic
|
||||
|
||||
# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
|
||||
# If in the future we need per-feature checks/flags for features not
|
||||
@ -160,17 +200,6 @@ endef
|
||||
|
||||
$(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat)))
|
||||
|
||||
#
|
||||
# So here we detect whether test-all was rebuilt, to be able
|
||||
# to skip the print-out of the long features list if the file
|
||||
# existed before and after it was built:
|
||||
#
|
||||
ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all.bin),)
|
||||
test-all-failed := 1
|
||||
else
|
||||
test-all-failed := 0
|
||||
endif
|
||||
|
||||
#
|
||||
# Special fast-path for the 'all features are available' case:
|
||||
#
|
||||
@ -180,15 +209,6 @@ $(call feature_check,all,$(MSG))
|
||||
# Just in case the build freshly failed, make sure we print the
|
||||
# feature matrix:
|
||||
#
|
||||
ifeq ($(feature-all), 0)
|
||||
test-all-failed := 1
|
||||
endif
|
||||
|
||||
ifeq ($(test-all-failed),1)
|
||||
$(info )
|
||||
$(info Auto-detecting system features:)
|
||||
endif
|
||||
|
||||
ifeq ($(feature-all), 1)
|
||||
#
|
||||
# test-all.c passed - just set all the core feature flags to 1:
|
||||
@ -199,27 +219,6 @@ else
|
||||
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat)))
|
||||
endif
|
||||
|
||||
#
|
||||
# Print the result of the feature test:
|
||||
#
|
||||
feature_print = $(eval $(feature_print_code)) $(info $(MSG))
|
||||
|
||||
define feature_print_code
|
||||
ifeq ($(feature-$(1)), 1)
|
||||
MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(1))
|
||||
else
|
||||
MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1))
|
||||
endif
|
||||
endef
|
||||
|
||||
#
|
||||
# Only print out our features if we rebuilt the testcases or if a test failed:
|
||||
#
|
||||
ifeq ($(test-all-failed), 1)
|
||||
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_print,$(feat)))
|
||||
$(info )
|
||||
endif
|
||||
|
||||
ifeq ($(feature-stackprotector-all), 1)
|
||||
CFLAGS += -fstack-protector-all
|
||||
endif
|
||||
@ -264,6 +263,7 @@ ifdef NO_LIBELF
|
||||
NO_DWARF := 1
|
||||
NO_DEMANGLE := 1
|
||||
NO_LIBUNWIND := 1
|
||||
NO_LIBDW_DWARF_UNWIND := 1
|
||||
else
|
||||
ifeq ($(feature-libelf), 0)
|
||||
ifeq ($(feature-glibc), 1)
|
||||
@ -282,13 +282,12 @@ else
|
||||
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
|
||||
endif
|
||||
else
|
||||
# for linking with debug library, run like:
|
||||
# make DEBUG=1 LIBDW_DIR=/opt/libdw/
|
||||
ifdef LIBDW_DIR
|
||||
LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
|
||||
LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
|
||||
ifndef NO_LIBDW_DWARF_UNWIND
|
||||
ifneq ($(feature-libdw-dwarf-unwind),1)
|
||||
NO_LIBDW_DWARF_UNWIND := 1
|
||||
msg := $(warning No libdw DWARF unwind found, Please install elfutils-devel/libdw-dev >= 0.158 and/or set LIBDW_DIR);
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(feature-dwarf), 1)
|
||||
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);
|
||||
NO_DWARF := 1
|
||||
@ -324,25 +323,51 @@ endif # NO_LIBELF
|
||||
|
||||
ifndef NO_LIBUNWIND
|
||||
ifneq ($(feature-libunwind), 1)
|
||||
msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1);
|
||||
msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
|
||||
NO_LIBUNWIND := 1
|
||||
endif
|
||||
endif
|
||||
|
||||
dwarf-post-unwind := 1
|
||||
dwarf-post-unwind-text := BUG
|
||||
|
||||
# setup DWARF post unwinder
|
||||
ifdef NO_LIBUNWIND
|
||||
ifdef NO_LIBDW_DWARF_UNWIND
|
||||
msg := $(warning Disabling post unwind, no support found.);
|
||||
dwarf-post-unwind := 0
|
||||
else
|
||||
ifeq ($(ARCH),arm)
|
||||
$(call feature_check,libunwind-debug-frame)
|
||||
ifneq ($(feature-libunwind-debug-frame), 1)
|
||||
msg := $(warning No debug_frame support found in libunwind);
|
||||
CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
|
||||
endif
|
||||
else
|
||||
# non-ARM has no dwarf_find_debug_frame() function:
|
||||
dwarf-post-unwind-text := libdw
|
||||
endif
|
||||
else
|
||||
dwarf-post-unwind-text := libunwind
|
||||
# Enable libunwind support by default.
|
||||
ifndef NO_LIBDW_DWARF_UNWIND
|
||||
NO_LIBDW_DWARF_UNWIND := 1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(dwarf-post-unwind),1)
|
||||
CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT
|
||||
else
|
||||
NO_DWARF_UNWIND := 1
|
||||
endif
|
||||
|
||||
ifndef NO_LIBUNWIND
|
||||
ifeq ($(ARCH),arm)
|
||||
$(call feature_check,libunwind-debug-frame)
|
||||
ifneq ($(feature-libunwind-debug-frame), 1)
|
||||
msg := $(warning No debug_frame support found in libunwind);
|
||||
CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
|
||||
endif
|
||||
|
||||
CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT -DHAVE_LIBUNWIND_SUPPORT
|
||||
EXTLIBS += $(LIBUNWIND_LIBS)
|
||||
CFLAGS += $(LIBUNWIND_CFLAGS)
|
||||
LDFLAGS += $(LIBUNWIND_LDFLAGS)
|
||||
endif # ifneq ($(feature-libunwind), 1)
|
||||
else
|
||||
# non-ARM has no dwarf_find_debug_frame() function:
|
||||
CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
|
||||
endif
|
||||
CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
|
||||
EXTLIBS += $(LIBUNWIND_LIBS)
|
||||
CFLAGS += $(LIBUNWIND_CFLAGS)
|
||||
LDFLAGS += $(LIBUNWIND_LDFLAGS)
|
||||
endif
|
||||
|
||||
ifndef NO_LIBAUDIT
|
||||
@ -602,3 +627,84 @@ ifdef DESTDIR
|
||||
plugindir=$(libdir)/traceevent/plugins
|
||||
plugindir_SQ= $(subst ','\'',$(plugindir))
|
||||
endif
|
||||
|
||||
#
|
||||
# Print the result of the feature test:
|
||||
#
|
||||
feature_print_status = $(eval $(feature_print_status_code)) $(info $(MSG))
|
||||
|
||||
define feature_print_status_code
|
||||
ifeq ($(feature-$(1)), 1)
|
||||
MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(1))
|
||||
else
|
||||
MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1))
|
||||
endif
|
||||
endef
|
||||
|
||||
feature_print_var = $(eval $(feature_print_var_code)) $(info $(MSG))
|
||||
define feature_print_var_code
|
||||
MSG = $(shell printf '...%30s: %s' $(1) $($(1)))
|
||||
endef
|
||||
|
||||
feature_print_text = $(eval $(feature_print_text_code)) $(info $(MSG))
|
||||
define feature_print_text_code
|
||||
MSG = $(shell printf '...%30s: %s' $(1) $(2))
|
||||
endef
|
||||
|
||||
PERF_FEATURES := $(foreach feat,$(LIB_FEATURE_TESTS),feature-$(feat)($(feature-$(feat))))
|
||||
PERF_FEATURES_FILE := $(shell touch $(OUTPUT)PERF-FEATURES; cat $(OUTPUT)PERF-FEATURES)
|
||||
|
||||
ifeq ($(dwarf-post-unwind),1)
|
||||
PERF_FEATURES += dwarf-post-unwind($(dwarf-post-unwind-text))
|
||||
endif
|
||||
|
||||
# The $(display_lib) controls the default detection message
|
||||
# output. It's set if:
|
||||
# - detected features differes from stored features from
|
||||
# last build (in PERF-FEATURES file)
|
||||
# - one of the $(LIB_FEATURE_TESTS) is not detected
|
||||
# - VF is enabled
|
||||
|
||||
ifneq ("$(PERF_FEATURES)","$(PERF_FEATURES_FILE)")
|
||||
$(shell echo "$(PERF_FEATURES)" > $(OUTPUT)PERF-FEATURES)
|
||||
display_lib := 1
|
||||
endif
|
||||
|
||||
feature_check = $(eval $(feature_check_code))
|
||||
define feature_check_code
|
||||
ifneq ($(feature-$(1)), 1)
|
||||
display_lib := 1
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_check,$(feat)))
|
||||
|
||||
ifeq ($(VF),1)
|
||||
display_lib := 1
|
||||
display_vf := 1
|
||||
endif
|
||||
|
||||
ifeq ($(display_lib),1)
|
||||
$(info )
|
||||
$(info Auto-detecting system features:)
|
||||
$(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_print_status,$(feat),))
|
||||
|
||||
ifeq ($(dwarf-post-unwind),1)
|
||||
$(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(display_vf),1)
|
||||
$(foreach feat,$(VF_FEATURE_TESTS),$(call feature_print_status,$(feat),))
|
||||
$(info )
|
||||
$(call feature_print_var,prefix)
|
||||
$(call feature_print_var,bindir)
|
||||
$(call feature_print_var,libdir)
|
||||
$(call feature_print_var,sysconfdir)
|
||||
$(call feature_print_var,LIBUNWIND_DIR)
|
||||
$(call feature_print_var,LIBDW_DIR)
|
||||
endif
|
||||
|
||||
ifeq ($(display_lib),1)
|
||||
$(info )
|
||||
endif
|
||||
|
@ -26,7 +26,8 @@ FILES= \
|
||||
test-libunwind-debug-frame.bin \
|
||||
test-on-exit.bin \
|
||||
test-stackprotector-all.bin \
|
||||
test-timerfd.bin
|
||||
test-timerfd.bin \
|
||||
test-libdw-dwarf-unwind.bin
|
||||
|
||||
CC := $(CROSS_COMPILE)gcc -MD
|
||||
PKG_CONFIG := $(CROSS_COMPILE)pkg-config
|
||||
@ -141,6 +142,9 @@ test-backtrace.bin:
|
||||
test-timerfd.bin:
|
||||
$(BUILD)
|
||||
|
||||
test-libdw-dwarf-unwind.bin:
|
||||
$(BUILD)
|
||||
|
||||
-include *.d
|
||||
|
||||
###############################
|
||||
|
@ -89,6 +89,10 @@
|
||||
# include "test-stackprotector-all.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_libdw_dwarf_unwind
|
||||
# include "test-libdw-dwarf-unwind.c"
|
||||
#undef main
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
main_test_libpython();
|
||||
@ -111,6 +115,7 @@ int main(int argc, char *argv[])
|
||||
main_test_libnuma();
|
||||
main_test_timerfd();
|
||||
main_test_stackprotector_all();
|
||||
main_test_libdw_dwarf_unwind();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
13
tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
Normal file
13
tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
#include <elfutils/libdwfl.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/*
|
||||
* This function is guarded via: __nonnull_attribute__ (1, 2).
|
||||
* Passing '1' as arguments value. This code is never executed,
|
||||
* only compiled.
|
||||
*/
|
||||
dwfl_thread_getframes((void *) 1, (void *) 1, NULL);
|
||||
return 0;
|
||||
}
|
@ -27,6 +27,7 @@ make_no_ui := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
|
||||
make_no_demangle := NO_DEMANGLE=1
|
||||
make_no_libelf := NO_LIBELF=1
|
||||
make_no_libunwind := NO_LIBUNWIND=1
|
||||
make_no_libdw_dwarf_unwind := NO_LIBDW_DWARF_UNWIND=1
|
||||
make_no_backtrace := NO_BACKTRACE=1
|
||||
make_no_libnuma := NO_LIBNUMA=1
|
||||
make_no_libaudit := NO_LIBAUDIT=1
|
||||
@ -35,8 +36,9 @@ make_tags := tags
|
||||
make_cscope := cscope
|
||||
make_help := help
|
||||
make_doc := doc
|
||||
make_perf_o := perf.o
|
||||
make_util_map_o := util/map.o
|
||||
make_perf_o := perf.o
|
||||
make_util_map_o := util/map.o
|
||||
make_util_pmu_bison_o := util/pmu-bison.o
|
||||
make_install := install
|
||||
make_install_bin := install-bin
|
||||
make_install_doc := install-doc
|
||||
@ -49,6 +51,7 @@ make_install_pdf := install-pdf
|
||||
make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
|
||||
make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
|
||||
make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
|
||||
make_minimal += NO_LIBDW_DWARF_UNWIND=1
|
||||
|
||||
# $(run) contains all available tests
|
||||
run := make_pure
|
||||
@ -65,6 +68,7 @@ run += make_no_ui
|
||||
run += make_no_demangle
|
||||
run += make_no_libelf
|
||||
run += make_no_libunwind
|
||||
run += make_no_libdw_dwarf_unwind
|
||||
run += make_no_backtrace
|
||||
run += make_no_libnuma
|
||||
run += make_no_libaudit
|
||||
@ -73,6 +77,7 @@ run += make_help
|
||||
run += make_doc
|
||||
run += make_perf_o
|
||||
run += make_util_map_o
|
||||
run += make_util_pmu_bison_o
|
||||
run += make_install
|
||||
run += make_install_bin
|
||||
# FIXME 'install-*' commented out till they're fixed
|
||||
@ -113,8 +118,9 @@ test_make_doc_O := $(test_ok)
|
||||
|
||||
test_make_python_perf_so := test -f $(PERF)/python/perf.so
|
||||
|
||||
test_make_perf_o := test -f $(PERF)/perf.o
|
||||
test_make_util_map_o := test -f $(PERF)/util/map.o
|
||||
test_make_perf_o := test -f $(PERF)/perf.o
|
||||
test_make_util_map_o := test -f $(PERF)/util/map.o
|
||||
test_make_util_pmu_bison_o := test -f $(PERF)/util/pmu-bison.o
|
||||
|
||||
define test_dest_files
|
||||
for file in $(1); do \
|
||||
@ -167,13 +173,10 @@ test_make_install_info_O := $(test_ok)
|
||||
test_make_install_pdf := $(test_ok)
|
||||
test_make_install_pdf_O := $(test_ok)
|
||||
|
||||
# Kbuild tests only
|
||||
#test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so
|
||||
#test_make_perf_o_O := test -f $$TMP/tools/perf/perf.o
|
||||
#test_make_util_map_o_O := test -f $$TMP/tools/perf/util/map.o
|
||||
|
||||
test_make_perf_o_O := true
|
||||
test_make_util_map_o_O := true
|
||||
test_make_python_perf_so_O := test -f $$TMP_O/python/perf.so
|
||||
test_make_perf_o_O := test -f $$TMP_O/perf.o
|
||||
test_make_util_map_o_O := test -f $$TMP_O/util/map.o
|
||||
test_make_util_pmu_bison_o_O := test -f $$TMP_O/util/pmu-bison.o
|
||||
|
||||
test_default = test -x $(PERF)/perf
|
||||
test = $(if $(test_$1),$(test_$1),$(test_default))
|
||||
|
@ -45,8 +45,8 @@ int dso__read_binary_type_filename(const struct dso *dso,
|
||||
debuglink--;
|
||||
if (*debuglink == '/')
|
||||
debuglink++;
|
||||
filename__read_debuglink(dso->long_name, debuglink,
|
||||
size - (debuglink - filename));
|
||||
ret = filename__read_debuglink(dso->long_name, debuglink,
|
||||
size - (debuglink - filename));
|
||||
}
|
||||
break;
|
||||
case DSO_BINARY_TYPE__BUILD_ID_CACHE:
|
||||
|
@ -506,6 +506,8 @@ int filename__read_debuglink(const char *filename, char *debuglink,
|
||||
/* the start of this section is a zero-terminated string */
|
||||
strncpy(debuglink, data->d_buf, size);
|
||||
|
||||
err = 0;
|
||||
|
||||
out_elf_end:
|
||||
elf_end(elf);
|
||||
out_close:
|
||||
|
@ -1251,6 +1251,46 @@ out_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
|
||||
enum dso_binary_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case DSO_BINARY_TYPE__JAVA_JIT:
|
||||
case DSO_BINARY_TYPE__DEBUGLINK:
|
||||
case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
|
||||
case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
|
||||
case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
|
||||
case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
|
||||
case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
|
||||
return !kmod && dso->kernel == DSO_TYPE_USER;
|
||||
|
||||
case DSO_BINARY_TYPE__KALLSYMS:
|
||||
case DSO_BINARY_TYPE__VMLINUX:
|
||||
case DSO_BINARY_TYPE__KCORE:
|
||||
return dso->kernel == DSO_TYPE_KERNEL;
|
||||
|
||||
case DSO_BINARY_TYPE__GUEST_KALLSYMS:
|
||||
case DSO_BINARY_TYPE__GUEST_VMLINUX:
|
||||
case DSO_BINARY_TYPE__GUEST_KCORE:
|
||||
return dso->kernel == DSO_TYPE_GUEST_KERNEL;
|
||||
|
||||
case DSO_BINARY_TYPE__GUEST_KMODULE:
|
||||
case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
|
||||
/*
|
||||
* kernel modules know their symtab type - it's set when
|
||||
* creating a module dso in machine__new_module().
|
||||
*/
|
||||
return kmod && dso->symtab_type == type;
|
||||
|
||||
case DSO_BINARY_TYPE__BUILD_ID_CACHE:
|
||||
return true;
|
||||
|
||||
case DSO_BINARY_TYPE__NOT_FOUND:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
||||
{
|
||||
char *name;
|
||||
@ -1261,6 +1301,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
||||
int ss_pos = 0;
|
||||
struct symsrc ss_[2];
|
||||
struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
|
||||
bool kmod;
|
||||
|
||||
dso__set_loaded(dso, map->type);
|
||||
|
||||
@ -1301,7 +1342,11 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
/* Iterate over candidate debug images.
|
||||
kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
|
||||
dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
|
||||
|
||||
/*
|
||||
* Iterate over candidate debug images.
|
||||
* Keep track of "interesting" ones (those which have a symtab, dynsym,
|
||||
* and/or opd section) for processing.
|
||||
*/
|
||||
@ -1311,6 +1356,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
||||
|
||||
enum dso_binary_type symtab_type = binary_type_symtab[i];
|
||||
|
||||
if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
|
||||
continue;
|
||||
|
||||
if (dso__read_binary_type_filename(dso, symtab_type,
|
||||
root_dir, name, PATH_MAX))
|
||||
continue;
|
||||
@ -1351,15 +1399,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
||||
if (!runtime_ss && syms_ss)
|
||||
runtime_ss = syms_ss;
|
||||
|
||||
if (syms_ss) {
|
||||
int km;
|
||||
|
||||
km = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
|
||||
dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
|
||||
ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, km);
|
||||
} else {
|
||||
if (syms_ss)
|
||||
ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
|
||||
else
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
int nr_plt;
|
||||
|
210
tools/perf/util/unwind-libdw.c
Normal file
210
tools/perf/util/unwind-libdw.c
Normal file
@ -0,0 +1,210 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <elfutils/libdw.h>
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include "unwind.h"
|
||||
#include "unwind-libdw.h"
|
||||
#include "machine.h"
|
||||
#include "thread.h"
|
||||
#include "types.h"
|
||||
#include "event.h"
|
||||
#include "perf_regs.h"
|
||||
|
||||
static char *debuginfo_path;
|
||||
|
||||
static const Dwfl_Callbacks offline_callbacks = {
|
||||
.find_debuginfo = dwfl_standard_find_debuginfo,
|
||||
.debuginfo_path = &debuginfo_path,
|
||||
.section_address = dwfl_offline_section_address,
|
||||
};
|
||||
|
||||
static int __report_module(struct addr_location *al, u64 ip,
|
||||
struct unwind_info *ui)
|
||||
{
|
||||
Dwfl_Module *mod;
|
||||
struct dso *dso = NULL;
|
||||
|
||||
thread__find_addr_location(ui->thread, ui->machine,
|
||||
PERF_RECORD_MISC_USER,
|
||||
MAP__FUNCTION, ip, al);
|
||||
|
||||
if (al->map)
|
||||
dso = al->map->dso;
|
||||
|
||||
if (!dso)
|
||||
return 0;
|
||||
|
||||
mod = dwfl_addrmodule(ui->dwfl, ip);
|
||||
if (!mod)
|
||||
mod = dwfl_report_elf(ui->dwfl, dso->short_name,
|
||||
dso->long_name, -1, al->map->start,
|
||||
false);
|
||||
|
||||
return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1;
|
||||
}
|
||||
|
||||
static int report_module(u64 ip, struct unwind_info *ui)
|
||||
{
|
||||
struct addr_location al;
|
||||
|
||||
return __report_module(&al, ip, ui);
|
||||
}
|
||||
|
||||
static int entry(u64 ip, struct unwind_info *ui)
|
||||
|
||||
{
|
||||
struct unwind_entry e;
|
||||
struct addr_location al;
|
||||
|
||||
if (__report_module(&al, ip, ui))
|
||||
return -1;
|
||||
|
||||
e.ip = ip;
|
||||
e.map = al.map;
|
||||
e.sym = al.sym;
|
||||
|
||||
pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
|
||||
al.sym ? al.sym->name : "''",
|
||||
ip,
|
||||
al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
|
||||
|
||||
return ui->cb(&e, ui->arg);
|
||||
}
|
||||
|
||||
static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
|
||||
{
|
||||
/* We want only single thread to be processed. */
|
||||
if (*thread_argp != NULL)
|
||||
return 0;
|
||||
|
||||
*thread_argp = arg;
|
||||
return dwfl_pid(dwfl);
|
||||
}
|
||||
|
||||
static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
|
||||
Dwarf_Word *data)
|
||||
{
|
||||
struct addr_location al;
|
||||
ssize_t size;
|
||||
|
||||
thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
|
||||
MAP__FUNCTION, addr, &al);
|
||||
if (!al.map) {
|
||||
pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!al.map->dso)
|
||||
return -1;
|
||||
|
||||
size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
|
||||
addr, (u8 *) data, sizeof(*data));
|
||||
|
||||
return !(size == sizeof(*data));
|
||||
}
|
||||
|
||||
static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *result,
|
||||
void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
struct stack_dump *stack = &ui->sample->user_stack;
|
||||
u64 start, end;
|
||||
int offset;
|
||||
int ret;
|
||||
|
||||
ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
end = start + stack->size;
|
||||
|
||||
/* Check overflow. */
|
||||
if (addr + sizeof(Dwarf_Word) < addr)
|
||||
return false;
|
||||
|
||||
if (addr < start || addr + sizeof(Dwarf_Word) > end) {
|
||||
ret = access_dso_mem(ui, addr, result);
|
||||
if (ret) {
|
||||
pr_debug("unwind: access_mem 0x%" PRIx64 " not inside range"
|
||||
" 0x%" PRIx64 "-0x%" PRIx64 "\n",
|
||||
addr, start, end);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
offset = addr - start;
|
||||
*result = *(Dwarf_Word *)&stack->data[offset];
|
||||
pr_debug("unwind: access_mem addr 0x%" PRIx64 ", val %lx, offset %d\n",
|
||||
addr, (unsigned long)*result, offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const Dwfl_Thread_Callbacks callbacks = {
|
||||
.next_thread = next_thread,
|
||||
.memory_read = memory_read,
|
||||
.set_initial_registers = libdw__arch_set_initial_registers,
|
||||
};
|
||||
|
||||
static int
|
||||
frame_callback(Dwfl_Frame *state, void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
Dwarf_Addr pc;
|
||||
|
||||
if (!dwfl_frame_pc(state, &pc, NULL)) {
|
||||
pr_err("%s", dwfl_errmsg(-1));
|
||||
return DWARF_CB_ABORT;
|
||||
}
|
||||
|
||||
return entry(pc, ui) || !(--ui->max_stack) ?
|
||||
DWARF_CB_ABORT : DWARF_CB_OK;
|
||||
}
|
||||
|
||||
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
|
||||
struct machine *machine, struct thread *thread,
|
||||
struct perf_sample *data,
|
||||
int max_stack)
|
||||
{
|
||||
struct unwind_info ui = {
|
||||
.sample = data,
|
||||
.thread = thread,
|
||||
.machine = machine,
|
||||
.cb = cb,
|
||||
.arg = arg,
|
||||
.max_stack = max_stack,
|
||||
};
|
||||
Dwarf_Word ip;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (!data->user_regs.regs)
|
||||
return -EINVAL;
|
||||
|
||||
ui.dwfl = dwfl_begin(&offline_callbacks);
|
||||
if (!ui.dwfl)
|
||||
goto out;
|
||||
|
||||
err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = report_module(ip, &ui);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!dwfl_attach_state(ui.dwfl, EM_NONE, thread->tid, &callbacks, &ui))
|
||||
goto out;
|
||||
|
||||
err = dwfl_getthread_frames(ui.dwfl, thread->tid, frame_callback, &ui);
|
||||
|
||||
if (err && !ui.max_stack)
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if (err)
|
||||
pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
|
||||
|
||||
dwfl_end(ui.dwfl);
|
||||
return 0;
|
||||
}
|
21
tools/perf/util/unwind-libdw.h
Normal file
21
tools/perf/util/unwind-libdw.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef __PERF_UNWIND_LIBDW_H
|
||||
#define __PERF_UNWIND_LIBDW_H
|
||||
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include "event.h"
|
||||
#include "thread.h"
|
||||
#include "unwind.h"
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg);
|
||||
|
||||
struct unwind_info {
|
||||
Dwfl *dwfl;
|
||||
struct perf_sample *sample;
|
||||
struct machine *machine;
|
||||
struct thread *thread;
|
||||
unwind_entry_cb_t cb;
|
||||
void *arg;
|
||||
int max_stack;
|
||||
};
|
||||
|
||||
#endif /* __PERF_UNWIND_LIBDW_H */
|
Loading…
Reference in New Issue
Block a user