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:
Ingo Molnar 2014-02-27 12:44:06 +01:00
commit e65312fe86
13 changed files with 569 additions and 90 deletions

View File

@ -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)

View File

@ -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

View 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);
}

View File

@ -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

View File

@ -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
###############################

View File

@ -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;
}

View 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;
}

View File

@ -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))

View File

@ -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:

View File

@ -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:

View File

@ -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;

View 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;
}

View 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 */