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:
@@ -7,6 +7,8 @@ include config/utilities.mak
|
|||||||
|
|
||||||
# Define V to have a more verbose compile.
|
# 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 O to save output files in a separate directory.
|
||||||
#
|
#
|
||||||
# Define ARCH as name of target architecture if you want cross-builds.
|
# 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_LIBAUDIT if you do not want libaudit support
|
||||||
#
|
#
|
||||||
# Define NO_LIBBIONIC if you do not want bionic 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),)
|
ifeq ($(srctree),)
|
||||||
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
|
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
|
||||||
@@ -404,7 +409,7 @@ endif
|
|||||||
LIB_OBJS += $(OUTPUT)tests/code-reading.o
|
LIB_OBJS += $(OUTPUT)tests/code-reading.o
|
||||||
LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
|
LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
|
||||||
LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
|
LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
|
||||||
ifndef NO_LIBUNWIND
|
ifndef NO_DWARF_UNWIND
|
||||||
ifeq ($(ARCH),x86)
|
ifeq ($(ARCH),x86)
|
||||||
LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
|
LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
|
||||||
endif
|
endif
|
||||||
@@ -476,6 +481,11 @@ ifndef NO_DWARF
|
|||||||
endif # NO_DWARF
|
endif # NO_DWARF
|
||||||
endif # NO_LIBELF
|
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
|
ifndef NO_LIBUNWIND
|
||||||
LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o
|
LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o
|
||||||
endif
|
endif
|
||||||
@@ -712,9 +722,15 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
|
|||||||
# we depend the various files onto their directories.
|
# we depend the various files onto their directories.
|
||||||
DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS)
|
DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS)
|
||||||
DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
|
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
|
# 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
|
$(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
|
||||||
|
|
||||||
$(LIB_FILE): $(LIB_OBJS)
|
$(LIB_FILE): $(LIB_OBJS)
|
||||||
@@ -891,7 +907,7 @@ config-clean:
|
|||||||
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.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)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
|
||||||
$(python-clean)
|
$(python-clean)
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
|
|||||||
endif
|
endif
|
||||||
ifndef NO_LIBUNWIND
|
ifndef NO_LIBUNWIND
|
||||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
|
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/regs_load.o
|
||||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
|
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
|
||||||
endif
|
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
|
CFLAGS += -DHAVE_PERF_REGS_SUPPORT
|
||||||
endif
|
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 ARCH specific config
|
||||||
-include $(src-perf)/arch/$(ARCH)/Makefile
|
-include $(src-perf)/arch/$(ARCH)/Makefile
|
||||||
|
|
||||||
@@ -147,7 +159,35 @@ CORE_FEATURE_TESTS = \
|
|||||||
libunwind \
|
libunwind \
|
||||||
on-exit \
|
on-exit \
|
||||||
stackprotector-all \
|
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.
|
# 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
|
# 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)))
|
$(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:
|
# 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
|
# Just in case the build freshly failed, make sure we print the
|
||||||
# feature matrix:
|
# 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)
|
ifeq ($(feature-all), 1)
|
||||||
#
|
#
|
||||||
# test-all.c passed - just set all the core feature flags to 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)))
|
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat)))
|
||||||
endif
|
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)
|
ifeq ($(feature-stackprotector-all), 1)
|
||||||
CFLAGS += -fstack-protector-all
|
CFLAGS += -fstack-protector-all
|
||||||
endif
|
endif
|
||||||
@@ -264,6 +263,7 @@ ifdef NO_LIBELF
|
|||||||
NO_DWARF := 1
|
NO_DWARF := 1
|
||||||
NO_DEMANGLE := 1
|
NO_DEMANGLE := 1
|
||||||
NO_LIBUNWIND := 1
|
NO_LIBUNWIND := 1
|
||||||
|
NO_LIBDW_DWARF_UNWIND := 1
|
||||||
else
|
else
|
||||||
ifeq ($(feature-libelf), 0)
|
ifeq ($(feature-libelf), 0)
|
||||||
ifeq ($(feature-glibc), 1)
|
ifeq ($(feature-glibc), 1)
|
||||||
@@ -282,13 +282,12 @@ else
|
|||||||
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
|
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
# for linking with debug library, run like:
|
ifndef NO_LIBDW_DWARF_UNWIND
|
||||||
# make DEBUG=1 LIBDW_DIR=/opt/libdw/
|
ifneq ($(feature-libdw-dwarf-unwind),1)
|
||||||
ifdef LIBDW_DIR
|
NO_LIBDW_DWARF_UNWIND := 1
|
||||||
LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
|
msg := $(warning No libdw DWARF unwind found, Please install elfutils-devel/libdw-dev >= 0.158 and/or set LIBDW_DIR);
|
||||||
LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(feature-dwarf), 1)
|
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);
|
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
|
NO_DWARF := 1
|
||||||
@@ -324,25 +323,51 @@ endif # NO_LIBELF
|
|||||||
|
|
||||||
ifndef NO_LIBUNWIND
|
ifndef NO_LIBUNWIND
|
||||||
ifneq ($(feature-libunwind), 1)
|
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
|
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
|
else
|
||||||
ifeq ($(ARCH),arm)
|
dwarf-post-unwind-text := libdw
|
||||||
$(call feature_check,libunwind-debug-frame)
|
endif
|
||||||
ifneq ($(feature-libunwind-debug-frame), 1)
|
else
|
||||||
msg := $(warning No debug_frame support found in libunwind);
|
dwarf-post-unwind-text := libunwind
|
||||||
CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
|
# Enable libunwind support by default.
|
||||||
endif
|
ifndef NO_LIBDW_DWARF_UNWIND
|
||||||
else
|
NO_LIBDW_DWARF_UNWIND := 1
|
||||||
# non-ARM has no dwarf_find_debug_frame() function:
|
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
|
CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
|
||||||
endif
|
endif
|
||||||
|
else
|
||||||
CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT -DHAVE_LIBUNWIND_SUPPORT
|
# non-ARM has no dwarf_find_debug_frame() function:
|
||||||
EXTLIBS += $(LIBUNWIND_LIBS)
|
CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
|
||||||
CFLAGS += $(LIBUNWIND_CFLAGS)
|
endif
|
||||||
LDFLAGS += $(LIBUNWIND_LDFLAGS)
|
CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
|
||||||
endif # ifneq ($(feature-libunwind), 1)
|
EXTLIBS += $(LIBUNWIND_LIBS)
|
||||||
|
CFLAGS += $(LIBUNWIND_CFLAGS)
|
||||||
|
LDFLAGS += $(LIBUNWIND_LDFLAGS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef NO_LIBAUDIT
|
ifndef NO_LIBAUDIT
|
||||||
@@ -602,3 +627,84 @@ ifdef DESTDIR
|
|||||||
plugindir=$(libdir)/traceevent/plugins
|
plugindir=$(libdir)/traceevent/plugins
|
||||||
plugindir_SQ= $(subst ','\'',$(plugindir))
|
plugindir_SQ= $(subst ','\'',$(plugindir))
|
||||||
endif
|
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-libunwind-debug-frame.bin \
|
||||||
test-on-exit.bin \
|
test-on-exit.bin \
|
||||||
test-stackprotector-all.bin \
|
test-stackprotector-all.bin \
|
||||||
test-timerfd.bin
|
test-timerfd.bin \
|
||||||
|
test-libdw-dwarf-unwind.bin
|
||||||
|
|
||||||
CC := $(CROSS_COMPILE)gcc -MD
|
CC := $(CROSS_COMPILE)gcc -MD
|
||||||
PKG_CONFIG := $(CROSS_COMPILE)pkg-config
|
PKG_CONFIG := $(CROSS_COMPILE)pkg-config
|
||||||
@@ -141,6 +142,9 @@ test-backtrace.bin:
|
|||||||
test-timerfd.bin:
|
test-timerfd.bin:
|
||||||
$(BUILD)
|
$(BUILD)
|
||||||
|
|
||||||
|
test-libdw-dwarf-unwind.bin:
|
||||||
|
$(BUILD)
|
||||||
|
|
||||||
-include *.d
|
-include *.d
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
|
|||||||
@@ -89,6 +89,10 @@
|
|||||||
# include "test-stackprotector-all.c"
|
# include "test-stackprotector-all.c"
|
||||||
#undef main
|
#undef main
|
||||||
|
|
||||||
|
#define main main_test_libdw_dwarf_unwind
|
||||||
|
# include "test-libdw-dwarf-unwind.c"
|
||||||
|
#undef main
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
main_test_libpython();
|
main_test_libpython();
|
||||||
@@ -111,6 +115,7 @@ int main(int argc, char *argv[])
|
|||||||
main_test_libnuma();
|
main_test_libnuma();
|
||||||
main_test_timerfd();
|
main_test_timerfd();
|
||||||
main_test_stackprotector_all();
|
main_test_stackprotector_all();
|
||||||
|
main_test_libdw_dwarf_unwind();
|
||||||
|
|
||||||
return 0;
|
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_demangle := NO_DEMANGLE=1
|
||||||
make_no_libelf := NO_LIBELF=1
|
make_no_libelf := NO_LIBELF=1
|
||||||
make_no_libunwind := NO_LIBUNWIND=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_backtrace := NO_BACKTRACE=1
|
||||||
make_no_libnuma := NO_LIBNUMA=1
|
make_no_libnuma := NO_LIBNUMA=1
|
||||||
make_no_libaudit := NO_LIBAUDIT=1
|
make_no_libaudit := NO_LIBAUDIT=1
|
||||||
@@ -35,8 +36,9 @@ make_tags := tags
|
|||||||
make_cscope := cscope
|
make_cscope := cscope
|
||||||
make_help := help
|
make_help := help
|
||||||
make_doc := doc
|
make_doc := doc
|
||||||
make_perf_o := perf.o
|
make_perf_o := perf.o
|
||||||
make_util_map_o := util/map.o
|
make_util_map_o := util/map.o
|
||||||
|
make_util_pmu_bison_o := util/pmu-bison.o
|
||||||
make_install := install
|
make_install := install
|
||||||
make_install_bin := install-bin
|
make_install_bin := install-bin
|
||||||
make_install_doc := install-doc
|
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_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_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_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
|
||||||
|
make_minimal += NO_LIBDW_DWARF_UNWIND=1
|
||||||
|
|
||||||
# $(run) contains all available tests
|
# $(run) contains all available tests
|
||||||
run := make_pure
|
run := make_pure
|
||||||
@@ -65,6 +68,7 @@ run += make_no_ui
|
|||||||
run += make_no_demangle
|
run += make_no_demangle
|
||||||
run += make_no_libelf
|
run += make_no_libelf
|
||||||
run += make_no_libunwind
|
run += make_no_libunwind
|
||||||
|
run += make_no_libdw_dwarf_unwind
|
||||||
run += make_no_backtrace
|
run += make_no_backtrace
|
||||||
run += make_no_libnuma
|
run += make_no_libnuma
|
||||||
run += make_no_libaudit
|
run += make_no_libaudit
|
||||||
@@ -73,6 +77,7 @@ run += make_help
|
|||||||
run += make_doc
|
run += make_doc
|
||||||
run += make_perf_o
|
run += make_perf_o
|
||||||
run += make_util_map_o
|
run += make_util_map_o
|
||||||
|
run += make_util_pmu_bison_o
|
||||||
run += make_install
|
run += make_install
|
||||||
run += make_install_bin
|
run += make_install_bin
|
||||||
# FIXME 'install-*' commented out till they're fixed
|
# 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_python_perf_so := test -f $(PERF)/python/perf.so
|
||||||
|
|
||||||
test_make_perf_o := test -f $(PERF)/perf.o
|
test_make_perf_o := test -f $(PERF)/perf.o
|
||||||
test_make_util_map_o := test -f $(PERF)/util/map.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
|
define test_dest_files
|
||||||
for file in $(1); do \
|
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 := $(test_ok)
|
||||||
test_make_install_pdf_O := $(test_ok)
|
test_make_install_pdf_O := $(test_ok)
|
||||||
|
|
||||||
# Kbuild tests only
|
test_make_python_perf_so_O := test -f $$TMP_O/python/perf.so
|
||||||
#test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so
|
test_make_perf_o_O := test -f $$TMP_O/perf.o
|
||||||
#test_make_perf_o_O := test -f $$TMP/tools/perf/perf.o
|
test_make_util_map_o_O := test -f $$TMP_O/util/map.o
|
||||||
#test_make_util_map_o_O := test -f $$TMP/tools/perf/util/map.o
|
test_make_util_pmu_bison_o_O := test -f $$TMP_O/util/pmu-bison.o
|
||||||
|
|
||||||
test_make_perf_o_O := true
|
|
||||||
test_make_util_map_o_O := true
|
|
||||||
|
|
||||||
test_default = test -x $(PERF)/perf
|
test_default = test -x $(PERF)/perf
|
||||||
test = $(if $(test_$1),$(test_$1),$(test_default))
|
test = $(if $(test_$1),$(test_$1),$(test_default))
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ int dso__read_binary_type_filename(const struct dso *dso,
|
|||||||
debuglink--;
|
debuglink--;
|
||||||
if (*debuglink == '/')
|
if (*debuglink == '/')
|
||||||
debuglink++;
|
debuglink++;
|
||||||
filename__read_debuglink(dso->long_name, debuglink,
|
ret = filename__read_debuglink(dso->long_name, debuglink,
|
||||||
size - (debuglink - filename));
|
size - (debuglink - filename));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DSO_BINARY_TYPE__BUILD_ID_CACHE:
|
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 */
|
/* the start of this section is a zero-terminated string */
|
||||||
strncpy(debuglink, data->d_buf, size);
|
strncpy(debuglink, data->d_buf, size);
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
|
||||||
out_elf_end:
|
out_elf_end:
|
||||||
elf_end(elf);
|
elf_end(elf);
|
||||||
out_close:
|
out_close:
|
||||||
|
|||||||
@@ -1251,6 +1251,46 @@ out_failure:
|
|||||||
return -1;
|
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)
|
int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
@@ -1261,6 +1301,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
|||||||
int ss_pos = 0;
|
int ss_pos = 0;
|
||||||
struct symsrc ss_[2];
|
struct symsrc ss_[2];
|
||||||
struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
|
struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
|
||||||
|
bool kmod;
|
||||||
|
|
||||||
dso__set_loaded(dso, map->type);
|
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)
|
if (!name)
|
||||||
return -1;
|
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,
|
* Keep track of "interesting" ones (those which have a symtab, dynsym,
|
||||||
* and/or opd section) for processing.
|
* 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];
|
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,
|
if (dso__read_binary_type_filename(dso, symtab_type,
|
||||||
root_dir, name, PATH_MAX))
|
root_dir, name, PATH_MAX))
|
||||||
continue;
|
continue;
|
||||||
@@ -1351,15 +1399,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
|||||||
if (!runtime_ss && syms_ss)
|
if (!runtime_ss && syms_ss)
|
||||||
runtime_ss = syms_ss;
|
runtime_ss = syms_ss;
|
||||||
|
|
||||||
if (syms_ss) {
|
if (syms_ss)
|
||||||
int km;
|
ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
|
||||||
|
else
|
||||||
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 {
|
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
|
||||||
|
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
int nr_plt;
|
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 */
|
||||||
Reference in New Issue
Block a user