فهرست منبع

Merge tag 'perf-core-for-mingo-2' 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:

  - Handle legacy syscalls tracepoints (David Ahern, Arnaldo Carvalho de Melo)

  - Indicate which callchain entries are annotated in the
    TUI hists browser (report/top) (Arnaldo Carvalho de Melo)

  - Fix failure to add multiple probes without debuginfo (He Kuang)

  - Fix 'trace' summary_only option (David Ahern)

  - Fix race in build_id_cache__add_s() in 'buildid-cache' (Milos Vyletel)

  - Don't allow empty argument for field-separator, fixing segfault (Wang Nan)

Infrastructure:

  - Add destructor for format_field in libtraceevent (David Ahern)

  - Prep work for support lzma compressed kernel modules (Jiri Olsa)

  - Update .gitignore with recently added/renamed feature detection files (Yunlong Song)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Ingo Molnar 10 سال پیش
والد
کامیت
963a70b8a2
55فایلهای تغییر یافته به همراه557 افزوده شده و 235 حذف شده
  1. 171 0
      tools/build/Makefile.feature
  2. 1 0
      tools/build/feature/.gitignore
  3. 6 2
      tools/build/feature/Makefile
  4. 5 0
      tools/build/feature/test-all.c
  5. 0 0
      tools/build/feature/test-backtrace.c
  6. 0 0
      tools/build/feature/test-bionic.c
  7. 0 0
      tools/build/feature/test-compile.c
  8. 0 0
      tools/build/feature/test-cplus-demangle.c
  9. 0 0
      tools/build/feature/test-dwarf.c
  10. 0 0
      tools/build/feature/test-fortify-source.c
  11. 0 0
      tools/build/feature/test-glibc.c
  12. 0 0
      tools/build/feature/test-gtk2-infobar.c
  13. 0 0
      tools/build/feature/test-gtk2.c
  14. 0 0
      tools/build/feature/test-hello.c
  15. 0 0
      tools/build/feature/test-libaudit.c
  16. 0 0
      tools/build/feature/test-libbabeltrace.c
  17. 0 0
      tools/build/feature/test-libbfd.c
  18. 0 0
      tools/build/feature/test-libdw-dwarf-unwind.c
  19. 0 0
      tools/build/feature/test-libelf-getphdrnum.c
  20. 0 0
      tools/build/feature/test-libelf-mmap.c
  21. 0 0
      tools/build/feature/test-libelf.c
  22. 0 0
      tools/build/feature/test-libnuma.c
  23. 0 0
      tools/build/feature/test-libperl.c
  24. 0 0
      tools/build/feature/test-libpython-version.c
  25. 0 0
      tools/build/feature/test-libpython.c
  26. 0 0
      tools/build/feature/test-libslang.c
  27. 0 0
      tools/build/feature/test-libunwind-debug-frame.c
  28. 0 0
      tools/build/feature/test-libunwind.c
  29. 10 0
      tools/build/feature/test-lzma.c
  30. 0 0
      tools/build/feature/test-pthread-attr-setaffinity-np.c
  31. 0 0
      tools/build/feature/test-stackprotector-all.c
  32. 0 0
      tools/build/feature/test-sync-compare-and-swap.c
  33. 0 0
      tools/build/feature/test-timerfd.c
  34. 0 0
      tools/build/feature/test-zlib.c
  35. 8 3
      tools/lib/traceevent/event-parse.c
  36. 1 0
      tools/lib/traceevent/event-parse.h
  37. 1 1
      tools/perf/.gitignore
  38. 3 1
      tools/perf/Makefile.perf
  39. 1 1
      tools/perf/builtin-diff.c
  40. 1 1
      tools/perf/builtin-mem.c
  41. 16 5
      tools/perf/builtin-trace.c
  42. 12 164
      tools/perf/config/Makefile
  43. 1 0
      tools/perf/tests/Build
  44. 4 0
      tools/perf/tests/builtin-test.c
  45. 73 0
      tools/perf/tests/kmod-path.c
  46. 1 0
      tools/perf/tests/tests.h
  47. 3 1
      tools/perf/ui/browsers/hists.c
  48. 1 0
      tools/perf/util/Build
  49. 2 1
      tools/perf/util/build-id.c
  50. 81 9
      tools/perf/util/dso.c
  51. 15 0
      tools/perf/util/dso.h
  52. 95 0
      tools/perf/util/lzma.c
  53. 40 43
      tools/perf/util/machine.c
  54. 1 3
      tools/perf/util/probe-event.c
  55. 4 0
      tools/perf/util/util.h

+ 171 - 0
tools/build/Makefile.feature

@@ -0,0 +1,171 @@
+feature_dir := $(srctree)/tools/build/feature
+
+ifneq ($(OUTPUT),)
+  OUTPUT_FEATURES = $(OUTPUT)feature/
+  $(shell mkdir -p $(OUTPUT_FEATURES))
+endif
+
+feature_check = $(eval $(feature_check_code))
+define feature_check_code
+  feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
+endef
+
+feature_set = $(eval $(feature_set_code))
+define feature_set_code
+  feature-$(1) := 1
+endef
+
+#
+# Build the feature check binaries in parallel, ignore errors, ignore return value and suppress output:
+#
+
+#
+# Note that this is not a complete list of all feature tests, just
+# those that are typically built on a fully configured system.
+#
+# [ Feature tests not mentioned here have to be built explicitly in
+#   the rule that uses them - an example for that is the 'bionic'
+#   feature check. ]
+#
+FEATURE_TESTS =			\
+	backtrace			\
+	dwarf				\
+	fortify-source			\
+	sync-compare-and-swap		\
+	glibc				\
+	gtk2				\
+	gtk2-infobar			\
+	libaudit			\
+	libbfd				\
+	libelf				\
+	libelf-getphdrnum		\
+	libelf-mmap			\
+	libnuma				\
+	libperl				\
+	libpython			\
+	libpython-version		\
+	libslang			\
+	libunwind			\
+	pthread-attr-setaffinity-np	\
+	stackprotector-all		\
+	timerfd				\
+	libdw-dwarf-unwind		\
+	zlib				\
+	lzma
+
+FEATURE_DISPLAY =			\
+	dwarf				\
+	glibc				\
+	gtk2				\
+	libaudit			\
+	libbfd				\
+	libelf				\
+	libnuma				\
+	libperl				\
+	libpython			\
+	libslang			\
+	libunwind			\
+	libdw-dwarf-unwind		\
+	zlib				\
+	lzma
+
+# Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
+# If in the future we need per-feature checks/flags for features not
+# mentioned in this list we need to refactor this ;-).
+set_test_all_flags = $(eval $(set_test_all_flags_code))
+define set_test_all_flags_code
+  FEATURE_CHECK_CFLAGS-all  += $(FEATURE_CHECK_CFLAGS-$(1))
+  FEATURE_CHECK_LDFLAGS-all += $(FEATURE_CHECK_LDFLAGS-$(1))
+endef
+
+$(foreach feat,$(FEATURE_TESTS),$(call set_test_all_flags,$(feat)))
+
+#
+# Special fast-path for the 'all features are available' case:
+#
+$(call feature_check,all,$(MSG))
+
+#
+# Just in case the build freshly failed, make sure we print the
+# feature matrix:
+#
+ifeq ($(feature-all), 1)
+  #
+  # test-all.c passed - just set all the core feature flags to 1:
+  #
+  $(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat)))
+else
+  $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C $(feature_dir) $(addsuffix .bin,$(FEATURE_TESTS)) >/dev/null 2>&1)
+  $(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat)))
+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_text = $(eval $(feature_print_text_code)) $(info $(MSG))
+define feature_print_text_code
+    MSG = $(shell printf '...%30s: %s' $(1) $(2))
+endef
+
+FEATURE_DUMP := $(foreach feat,$(FEATURE_DISPLAY),feature-$(feat)($(feature-$(feat))))
+FEATURE_DUMP_FILE := $(shell touch $(OUTPUT)FEATURE-DUMP; cat $(OUTPUT)FEATURE-DUMP)
+
+ifeq ($(dwarf-post-unwind),1)
+  FEATURE_DUMP += dwarf-post-unwind($(dwarf-post-unwind-text))
+endif
+
+# The $(feature_display) controls the default detection message
+# output. It's set if:
+# - detected features differes from stored features from
+#   last build (in FEATURE-DUMP file)
+# - one of the $(FEATURE_DISPLAY) is not detected
+# - VF is enabled
+
+ifneq ("$(FEATURE_DUMP)","$(FEATURE_DUMP_FILE)")
+  $(shell echo "$(FEATURE_DUMP)" > $(OUTPUT)FEATURE-DUMP)
+  feature_display := 1
+endif
+
+feature_display_check = $(eval $(feature_check_code))
+define feature_display_check_code
+  ifneq ($(feature-$(1)), 1)
+    feature_display := 1
+  endif
+endef
+
+$(foreach feat,$(FEATURE_DISPLAY),$(call feature_display_check,$(feat)))
+
+ifeq ($(VF),1)
+  feature_display := 1
+  feature_verbose := 1
+endif
+
+ifeq ($(feature_display),1)
+  $(info )
+  $(info Auto-detecting system features:)
+  $(foreach feat,$(FEATURE_DISPLAY),$(call feature_print_status,$(feat),))
+
+  ifeq ($(dwarf-post-unwind),1)
+    $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
+  endif
+
+  ifneq ($(feature_verbose),1)
+    $(info )
+  endif
+endif
+
+ifeq ($(feature_verbose),1)
+  TMP := $(filter-out $(FEATURE_DISPLAY),$(FEATURE_TESTS))
+  $(foreach feat,$(TMP),$(call feature_print_status,$(feat),))
+  $(info )
+endif

+ 1 - 0
tools/perf/config/feature-checks/.gitignore → tools/build/feature/.gitignore

@@ -1,2 +1,3 @@
 *.d
 *.d
 *.bin
 *.bin
+*.output

+ 6 - 2
tools/perf/config/feature-checks/Makefile → tools/build/feature/Makefile

@@ -32,7 +32,8 @@ FILES=					\
 	test-libbabeltrace.bin		\
 	test-libbabeltrace.bin		\
 	test-compile-32.bin		\
 	test-compile-32.bin		\
 	test-compile-x32.bin		\
 	test-compile-x32.bin		\
-	test-zlib.bin
+	test-zlib.bin			\
+	test-lzma.bin
 
 
 CC := $(CROSS_COMPILE)gcc -MD
 CC := $(CROSS_COMPILE)gcc -MD
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -45,7 +46,7 @@ __BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@)
 ###############################
 ###############################
 
 
 test-all.bin:
 test-all.bin:
-	$(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz
+	$(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma
 
 
 test-hello.bin:
 test-hello.bin:
 	$(BUILD)
 	$(BUILD)
@@ -152,6 +153,9 @@ test-compile-x32.bin:
 test-zlib.bin:
 test-zlib.bin:
 	$(BUILD) -lz
 	$(BUILD) -lz
 
 
+test-lzma.bin:
+	$(BUILD) -llzma
+
 -include *.d
 -include *.d
 
 
 ###############################
 ###############################

+ 5 - 0
tools/perf/config/feature-checks/test-all.c → tools/build/feature/test-all.c

@@ -113,6 +113,10 @@
 #undef main
 #undef main
 #endif
 #endif
 
 
+#define main main_test_lzma
+# include "test-lzma.c"
+#undef main
+
 int main(int argc, char *argv[])
 int main(int argc, char *argv[])
 {
 {
 	main_test_libpython();
 	main_test_libpython();
@@ -138,6 +142,7 @@ int main(int argc, char *argv[])
 	main_test_sync_compare_and_swap(argc, argv);
 	main_test_sync_compare_and_swap(argc, argv);
 	main_test_zlib();
 	main_test_zlib();
 	main_test_pthread_attr_setaffinity_np();
 	main_test_pthread_attr_setaffinity_np();
+	main_test_lzma();
 
 
 	return 0;
 	return 0;
 }
 }

+ 0 - 0
tools/perf/config/feature-checks/test-backtrace.c → tools/build/feature/test-backtrace.c


+ 0 - 0
tools/perf/config/feature-checks/test-bionic.c → tools/build/feature/test-bionic.c


+ 0 - 0
tools/perf/config/feature-checks/test-compile.c → tools/build/feature/test-compile.c


+ 0 - 0
tools/perf/config/feature-checks/test-cplus-demangle.c → tools/build/feature/test-cplus-demangle.c


+ 0 - 0
tools/perf/config/feature-checks/test-dwarf.c → tools/build/feature/test-dwarf.c


+ 0 - 0
tools/perf/config/feature-checks/test-fortify-source.c → tools/build/feature/test-fortify-source.c


+ 0 - 0
tools/perf/config/feature-checks/test-glibc.c → tools/build/feature/test-glibc.c


+ 0 - 0
tools/perf/config/feature-checks/test-gtk2-infobar.c → tools/build/feature/test-gtk2-infobar.c


+ 0 - 0
tools/perf/config/feature-checks/test-gtk2.c → tools/build/feature/test-gtk2.c


+ 0 - 0
tools/perf/config/feature-checks/test-hello.c → tools/build/feature/test-hello.c


+ 0 - 0
tools/perf/config/feature-checks/test-libaudit.c → tools/build/feature/test-libaudit.c


+ 0 - 0
tools/perf/config/feature-checks/test-libbabeltrace.c → tools/build/feature/test-libbabeltrace.c


+ 0 - 0
tools/perf/config/feature-checks/test-libbfd.c → tools/build/feature/test-libbfd.c


+ 0 - 0
tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c → tools/build/feature/test-libdw-dwarf-unwind.c


+ 0 - 0
tools/perf/config/feature-checks/test-libelf-getphdrnum.c → tools/build/feature/test-libelf-getphdrnum.c


+ 0 - 0
tools/perf/config/feature-checks/test-libelf-mmap.c → tools/build/feature/test-libelf-mmap.c


+ 0 - 0
tools/perf/config/feature-checks/test-libelf.c → tools/build/feature/test-libelf.c


+ 0 - 0
tools/perf/config/feature-checks/test-libnuma.c → tools/build/feature/test-libnuma.c


+ 0 - 0
tools/perf/config/feature-checks/test-libperl.c → tools/build/feature/test-libperl.c


+ 0 - 0
tools/perf/config/feature-checks/test-libpython-version.c → tools/build/feature/test-libpython-version.c


+ 0 - 0
tools/perf/config/feature-checks/test-libpython.c → tools/build/feature/test-libpython.c


+ 0 - 0
tools/perf/config/feature-checks/test-libslang.c → tools/build/feature/test-libslang.c


+ 0 - 0
tools/perf/config/feature-checks/test-libunwind-debug-frame.c → tools/build/feature/test-libunwind-debug-frame.c


+ 0 - 0
tools/perf/config/feature-checks/test-libunwind.c → tools/build/feature/test-libunwind.c


+ 10 - 0
tools/build/feature/test-lzma.c

@@ -0,0 +1,10 @@
+#include <lzma.h>
+
+int main(void)
+{
+	lzma_stream strm = LZMA_STREAM_INIT;
+	int ret;
+
+	ret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED);
+	return ret ? -1 : 0;
+}

+ 0 - 0
tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c → tools/build/feature/test-pthread-attr-setaffinity-np.c


+ 0 - 0
tools/perf/config/feature-checks/test-stackprotector-all.c → tools/build/feature/test-stackprotector-all.c


+ 0 - 0
tools/perf/config/feature-checks/test-sync-compare-and-swap.c → tools/build/feature/test-sync-compare-and-swap.c


+ 0 - 0
tools/perf/config/feature-checks/test-timerfd.c → tools/build/feature/test-timerfd.c


+ 0 - 0
tools/perf/config/feature-checks/test-zlib.c → tools/build/feature/test-zlib.c


+ 8 - 3
tools/lib/traceevent/event-parse.c

@@ -6228,15 +6228,20 @@ void pevent_ref(struct pevent *pevent)
 	pevent->ref_count++;
 	pevent->ref_count++;
 }
 }
 
 
+void pevent_free_format_field(struct format_field *field)
+{
+	free(field->type);
+	free(field->name);
+	free(field);
+}
+
 static void free_format_fields(struct format_field *field)
 static void free_format_fields(struct format_field *field)
 {
 {
 	struct format_field *next;
 	struct format_field *next;
 
 
 	while (field) {
 	while (field) {
 		next = field->next;
 		next = field->next;
-		free(field->type);
-		free(field->name);
-		free(field);
+		pevent_free_format_field(field);
 		field = next;
 		field = next;
 	}
 	}
 }
 }

+ 1 - 0
tools/lib/traceevent/event-parse.h

@@ -619,6 +619,7 @@ enum pevent_errno pevent_parse_format(struct pevent *pevent,
 				      const char *buf,
 				      const char *buf,
 				      unsigned long size, const char *sys);
 				      unsigned long size, const char *sys);
 void pevent_free_format(struct event_format *event);
 void pevent_free_format(struct event_format *event);
+void pevent_free_format_field(struct format_field *field);
 
 
 void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
 void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
 			   const char *name, struct pevent_record *record,
 			   const char *name, struct pevent_record *record,

+ 1 - 1
tools/perf/.gitignore

@@ -1,7 +1,7 @@
 PERF-CFLAGS
 PERF-CFLAGS
 PERF-GUI-VARS
 PERF-GUI-VARS
 PERF-VERSION-FILE
 PERF-VERSION-FILE
-PERF-FEATURES
+FEATURE-DUMP
 perf
 perf
 perf-read-vdso32
 perf-read-vdso32
 perf-read-vdsox32
 perf-read-vdsox32

+ 3 - 1
tools/perf/Makefile.perf

@@ -71,6 +71,8 @@ include config/utilities.mak
 #
 #
 # Define NO_LIBBABELTRACE if you do not want libbabeltrace support
 # Define NO_LIBBABELTRACE if you do not want libbabeltrace support
 # for CTF data format.
 # for CTF data format.
+#
+# Define NO_LZMA if you do not want to support compressed (xz) kernel modules
 
 
 ifeq ($(srctree),)
 ifeq ($(srctree),)
 srctree := $(patsubst %/,%,$(dir $(shell pwd)))
 srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -521,7 +523,7 @@ $(INSTALL_DOC_TARGETS):
 #
 #
 config-clean:
 config-clean:
 	$(call QUIET_CLEAN, config)
 	$(call QUIET_CLEAN, config)
-	$(Q)$(MAKE) -C config/feature-checks clean >/dev/null
+	$(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null
 
 
 clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean
 clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean
 	$(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
 	$(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)

+ 1 - 1
tools/perf/builtin-diff.c

@@ -802,7 +802,7 @@ static const struct option options[] = {
 	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
 	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
 		   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
 		   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
 		   " Please refer the man page for the complete list."),
 		   " Please refer the man page for the complete list."),
-	OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
+	OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
 		   "separator for columns, no spaces will be added between "
 		   "separator for columns, no spaces will be added between "
 		   "columns '.' is reserved."),
 		   "columns '.' is reserved."),
 	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
 	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",

+ 1 - 1
tools/perf/builtin-mem.c

@@ -286,7 +286,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
 		   "input file name"),
 		   "input file name"),
 	OPT_STRING('C', "cpu", &mem.cpu_list, "cpu",
 	OPT_STRING('C', "cpu", &mem.cpu_list, "cpu",
 		   "list of cpus to profile"),
 		   "list of cpus to profile"),
-	OPT_STRING('x', "field-separator", &symbol_conf.field_sep,
+	OPT_STRING_NOEMPTY('x', "field-separator", &symbol_conf.field_sep,
 		   "separator",
 		   "separator",
 		   "separator for columns, no spaces will be added"
 		   "separator for columns, no spaces will be added"
 		   " between columns '.' is reserved."),
 		   " between columns '.' is reserved."),

+ 16 - 5
tools/perf/builtin-trace.c

@@ -1135,6 +1135,8 @@ static struct syscall_fmt *syscall_fmt__find(const char *name)
 
 
 struct syscall {
 struct syscall {
 	struct event_format *tp_format;
 	struct event_format *tp_format;
+	int		    nr_args;
+	struct format_field *args;
 	const char	    *name;
 	const char	    *name;
 	bool		    filtered;
 	bool		    filtered;
 	bool		    is_exit;
 	bool		    is_exit;
@@ -1442,14 +1444,14 @@ static int syscall__set_arg_fmts(struct syscall *sc)
 	struct format_field *field;
 	struct format_field *field;
 	int idx = 0;
 	int idx = 0;
 
 
-	sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
+	sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
 	if (sc->arg_scnprintf == NULL)
 	if (sc->arg_scnprintf == NULL)
 		return -1;
 		return -1;
 
 
 	if (sc->fmt)
 	if (sc->fmt)
 		sc->arg_parm = sc->fmt->arg_parm;
 		sc->arg_parm = sc->fmt->arg_parm;
 
 
-	for (field = sc->tp_format->format.fields->next; field; field = field->next) {
+	for (field = sc->args; field; field = field->next) {
 		if (sc->fmt && sc->fmt->arg_scnprintf[idx])
 		if (sc->fmt && sc->fmt->arg_scnprintf[idx])
 			sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
 			sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
 		else if (field->flags & FIELD_IS_POINTER)
 		else if (field->flags & FIELD_IS_POINTER)
@@ -1515,6 +1517,14 @@ static int trace__read_syscall_info(struct trace *trace, int id)
 	if (sc->tp_format == NULL)
 	if (sc->tp_format == NULL)
 		return -1;
 		return -1;
 
 
+	sc->args = sc->tp_format->format.fields;
+	sc->nr_args = sc->tp_format->format.nr_fields;
+	/* drop nr field - not relevant here; does not exist on older kernels */
+	if (sc->args && strcmp(sc->args->name, "nr") == 0) {
+		sc->args = sc->args->next;
+		--sc->nr_args;
+	}
+
 	sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
 	sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
 
 
 	return syscall__set_arg_fmts(sc);
 	return syscall__set_arg_fmts(sc);
@@ -1537,7 +1547,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
 	unsigned char *p;
 	unsigned char *p;
 	unsigned long val;
 	unsigned long val;
 
 
-	if (sc->tp_format != NULL) {
+	if (sc->args != NULL) {
 		struct format_field *field;
 		struct format_field *field;
 		u8 bit = 1;
 		u8 bit = 1;
 		struct syscall_arg arg = {
 		struct syscall_arg arg = {
@@ -1547,7 +1557,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
 			.thread = thread,
 			.thread = thread,
 		};
 		};
 
 
-		for (field = sc->tp_format->format.fields->next; field;
+		for (field = sc->args; field;
 		     field = field->next, ++arg.idx, bit <<= 1) {
 		     field = field->next, ++arg.idx, bit <<= 1) {
 			if (arg.mask & bit)
 			if (arg.mask & bit)
 				continue;
 				continue;
@@ -1724,7 +1734,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
 			return -1;
 			return -1;
 	}
 	}
 
 
-	printed += trace__printf_interrupted_entry(trace, sample);
+	if (!trace->summary_only)
+		printed += trace__printf_interrupted_entry(trace, sample);
 
 
 	ttrace->entry_time = sample->time;
 	ttrace->entry_time = sample->time;
 	msg = ttrace->entry_str;
 	msg = ttrace->entry_str;

+ 12 - 164
tools/perf/config/Makefile

@@ -176,102 +176,7 @@ LDFLAGS += -Wl,-z,noexecstack
 
 
 EXTLIBS = -lpthread -lrt -lm -ldl
 EXTLIBS = -lpthread -lrt -lm -ldl
 
 
-ifneq ($(OUTPUT),)
-  OUTPUT_FEATURES = $(OUTPUT)config/feature-checks/
-  $(shell mkdir -p $(OUTPUT_FEATURES))
-endif
-
-feature_check = $(eval $(feature_check_code))
-define feature_check_code
-  feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C config/feature-checks test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
-endef
-
-feature_set = $(eval $(feature_set_code))
-define feature_set_code
-  feature-$(1) := 1
-endef
-
-#
-# Build the feature check binaries in parallel, ignore errors, ignore return value and suppress output:
-#
-
-#
-# Note that this is not a complete list of all feature tests, just
-# those that are typically built on a fully configured system.
-#
-# [ Feature tests not mentioned here have to be built explicitly in
-#   the rule that uses them - an example for that is the 'bionic'
-#   feature check. ]
-#
-FEATURE_TESTS =			\
-	backtrace			\
-	dwarf				\
-	fortify-source			\
-	sync-compare-and-swap		\
-	glibc				\
-	gtk2				\
-	gtk2-infobar			\
-	libaudit			\
-	libbfd				\
-	libelf				\
-	libelf-getphdrnum		\
-	libelf-mmap			\
-	libnuma				\
-	libperl				\
-	libpython			\
-	libpython-version		\
-	libslang			\
-	libunwind			\
-	pthread-attr-setaffinity-np	\
-	stackprotector-all		\
-	timerfd				\
-	libdw-dwarf-unwind		\
-	zlib
-
-FEATURE_DISPLAY =			\
-	dwarf				\
-	glibc				\
-	gtk2				\
-	libaudit			\
-	libbfd				\
-	libelf				\
-	libnuma				\
-	libperl				\
-	libpython			\
-	libslang			\
-	libunwind			\
-	libdw-dwarf-unwind		\
-	zlib
-
-# Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
-# If in the future we need per-feature checks/flags for features not
-# mentioned in this list we need to refactor this ;-).
-set_test_all_flags = $(eval $(set_test_all_flags_code))
-define set_test_all_flags_code
-  FEATURE_CHECK_CFLAGS-all  += $(FEATURE_CHECK_CFLAGS-$(1))
-  FEATURE_CHECK_LDFLAGS-all += $(FEATURE_CHECK_LDFLAGS-$(1))
-endef
-
-$(foreach feat,$(FEATURE_TESTS),$(call set_test_all_flags,$(feat)))
-
-#
-# Special fast-path for the 'all features are available' case:
-#
-$(call feature_check,all,$(MSG))
-
-#
-# Just in case the build freshly failed, make sure we print the
-# feature matrix:
-#
-ifeq ($(feature-all), 1)
-  #
-  # test-all.c passed - just set all the core feature flags to 1:
-  #
-  $(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat)))
-else
-  $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(addsuffix .bin,$(FEATURE_TESTS)) >/dev/null 2>&1)
-  $(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat)))
-endif
+include $(srctree)/tools/build/Makefile.feature
 
 
 ifeq ($(feature-stackprotector-all), 1)
 ifeq ($(feature-stackprotector-all), 1)
   CFLAGS += -fstack-protector-all
   CFLAGS += -fstack-protector-all
@@ -636,6 +541,17 @@ ifndef NO_ZLIB
   endif
   endif
 endif
 endif
 
 
+ifndef NO_LZMA
+  ifeq ($(feature-lzma), 1)
+    CFLAGS += -DHAVE_LZMA_SUPPORT
+    EXTLIBS += -llzma
+    $(call detected,CONFIG_LZMA)
+  else
+    msg := $(warning No liblzma found, disables xz kernel module decompression, please install xz-devel/liblzma-dev);
+    NO_LZMA := 1
+  endif
+endif
+
 ifndef NO_BACKTRACE
 ifndef NO_BACKTRACE
   ifeq ($(feature-backtrace), 1)
   ifeq ($(feature-backtrace), 1)
     CFLAGS += -DHAVE_BACKTRACE_SUPPORT
     CFLAGS += -DHAVE_BACKTRACE_SUPPORT
@@ -763,80 +679,12 @@ 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
-
 print_var = $(eval $(print_var_code)) $(info $(MSG))
 print_var = $(eval $(print_var_code)) $(info $(MSG))
 define print_var_code
 define print_var_code
     MSG = $(shell printf '...%30s: %s' $(1) $($(1)))
     MSG = $(shell printf '...%30s: %s' $(1) $($(1)))
 endef
 endef
 
 
-feature_print_text = $(eval $(feature_print_text_code)) $(info $(MSG))
-define feature_print_text_code
-    MSG = $(shell printf '...%30s: %s' $(1) $(2))
-endef
-
-FEATURE_DUMP := $(foreach feat,$(FEATURE_DISPLAY),feature-$(feat)($(feature-$(feat))))
-FEATURE_DUMP_FILE := $(shell touch $(OUTPUT)FEATURE-DUMP; cat $(OUTPUT)FEATURE-DUMP)
-
-ifeq ($(dwarf-post-unwind),1)
-  FEATURE_DUMP += dwarf-post-unwind($(dwarf-post-unwind-text))
-endif
-
-# The $(feature_display) controls the default detection message
-# output. It's set if:
-# - detected features differes from stored features from
-#   last build (in FEATURE-DUMP file)
-# - one of the $(FEATURE_DISPLAY) is not detected
-# - VF is enabled
-
-ifneq ("$(FEATURE_DUMP)","$(FEATURE_DUMP_FILE)")
-  $(shell echo "$(FEATURE_DUMP)" > $(OUTPUT)FEATURE-DUMP)
-  feature_display := 1
-endif
-
-feature_check = $(eval $(feature_check_code))
-define feature_check_code
-  ifneq ($(feature-$(1)), 1)
-    feature_display := 1
-  endif
-endef
-
-$(foreach feat,$(FEATURE_DISPLAY),$(call feature_check,$(feat)))
-
 ifeq ($(VF),1)
 ifeq ($(VF),1)
-  feature_display := 1
-  feature_verbose := 1
-endif
-
-ifeq ($(feature_display),1)
-  $(info )
-  $(info Auto-detecting system features:)
-  $(foreach feat,$(FEATURE_DISPLAY),$(call feature_print_status,$(feat),))
-
-  ifeq ($(dwarf-post-unwind),1)
-    $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
-  endif
-
-  ifneq ($(feature_verbose),1)
-    $(info )
-  endif
-endif
-
-ifeq ($(feature_verbose),1)
-  TMP := $(filter-out $(FEATURE_DISPLAY),$(FEATURE_TESTS))
-  $(foreach feat,$(TMP),$(call feature_print_status,$(feat),))
-  $(info )
   $(call print_var,prefix)
   $(call print_var,prefix)
   $(call print_var,bindir)
   $(call print_var,bindir)
   $(call print_var,libdir)
   $(call print_var,libdir)

+ 1 - 0
tools/perf/tests/Build

@@ -30,6 +30,7 @@ perf-y += keep-tracking.o
 perf-y += code-reading.o
 perf-y += code-reading.o
 perf-y += sample-parsing.o
 perf-y += sample-parsing.o
 perf-y += parse-no-sample-id-all.o
 perf-y += parse-no-sample-id-all.o
+perf-y += kmod-path.o
 
 
 perf-$(CONFIG_X86) += perf-time-to-tsc.o
 perf-$(CONFIG_X86) += perf-time-to-tsc.o
 
 

+ 4 - 0
tools/perf/tests/builtin-test.c

@@ -166,6 +166,10 @@ static struct test {
 		.desc = "Add fd to a fdarray, making it autogrow",
 		.desc = "Add fd to a fdarray, making it autogrow",
 		.func = test__fdarray__add,
 		.func = test__fdarray__add,
 	},
 	},
+	{
+		.desc = "Test kmod_path__parse function",
+		.func = test__kmod_path__parse,
+	},
 	{
 	{
 		.func = NULL,
 		.func = NULL,
 	},
 	},

+ 73 - 0
tools/perf/tests/kmod-path.c

@@ -0,0 +1,73 @@
+#include <stdbool.h>
+#include "tests.h"
+#include "dso.h"
+#include "debug.h"
+
+static int test(const char *path, bool alloc_name, bool alloc_ext,
+		bool kmod, bool comp, const char *name, const char *ext)
+{
+	struct kmod_path m;
+
+	memset(&m, 0x0, sizeof(m));
+
+	TEST_ASSERT_VAL("kmod_path__parse",
+			!__kmod_path__parse(&m, path, alloc_name, alloc_ext));
+
+	pr_debug("%s - alloc name %d, alloc ext %d, kmod %d, comp %d, name '%s', ext '%s'\n",
+		 path, alloc_name, alloc_ext, m.kmod, m.comp, m.name, m.ext);
+
+	TEST_ASSERT_VAL("wrong kmod", m.kmod == kmod);
+	TEST_ASSERT_VAL("wrong comp", m.comp == comp);
+
+	if (ext)
+		TEST_ASSERT_VAL("wrong ext", m.ext && !strcmp(ext, m.ext));
+	else
+		TEST_ASSERT_VAL("wrong ext", !m.ext);
+
+	if (name)
+		TEST_ASSERT_VAL("wrong name", m.name && !strcmp(name, m.name));
+	else
+		TEST_ASSERT_VAL("wrong name", !m.name);
+
+	free(m.name);
+	free(m.ext);
+	return 0;
+}
+
+#define T(path, an, ae, k, c, n, e) \
+	TEST_ASSERT_VAL("failed", !test(path, an, ae, k, c, n, e))
+
+int test__kmod_path__parse(void)
+{
+	/* path                alloc_name  alloc_ext   kmod  comp   name     ext */
+	T("/xxxx/xxxx/x-x.ko", true      , true      , true, false, "[x_x]", NULL);
+	T("/xxxx/xxxx/x-x.ko", false     , true      , true, false, NULL   , NULL);
+	T("/xxxx/xxxx/x-x.ko", true      , false     , true, false, "[x_x]", NULL);
+	T("/xxxx/xxxx/x-x.ko", false     , false     , true, false, NULL   , NULL);
+
+	/* path                alloc_name  alloc_ext   kmod  comp  name   ext */
+	T("/xxxx/xxxx/x.ko.gz", true     , true      , true, true, "[x]", "gz");
+	T("/xxxx/xxxx/x.ko.gz", false    , true      , true, true, NULL , "gz");
+	T("/xxxx/xxxx/x.ko.gz", true     , false     , true, true, "[x]", NULL);
+	T("/xxxx/xxxx/x.ko.gz", false    , false     , true, true, NULL , NULL);
+
+	/* path              alloc_name  alloc_ext  kmod   comp  name    ext */
+	T("/xxxx/xxxx/x.gz", true      , true     , false, true, "x.gz" ,"gz");
+	T("/xxxx/xxxx/x.gz", false     , true     , false, true, NULL   ,"gz");
+	T("/xxxx/xxxx/x.gz", true      , false    , false, true, "x.gz" , NULL);
+	T("/xxxx/xxxx/x.gz", false     , false    , false, true, NULL   , NULL);
+
+	/* path   alloc_name  alloc_ext  kmod   comp  name     ext */
+	T("x.gz", true      , true     , false, true, "x.gz", "gz");
+	T("x.gz", false     , true     , false, true, NULL  , "gz");
+	T("x.gz", true      , false    , false, true, "x.gz", NULL);
+	T("x.gz", false     , false    , false, true, NULL  , NULL);
+
+	/* path      alloc_name  alloc_ext  kmod  comp  name  ext */
+	T("x.ko.gz", true      , true     , true, true, "[x]", "gz");
+	T("x.ko.gz", false     , true     , true, true, NULL , "gz");
+	T("x.ko.gz", true      , false    , true, true, "[x]", NULL);
+	T("x.ko.gz", false     , false    , true, true, NULL , NULL);
+
+	return 0;
+}

+ 1 - 0
tools/perf/tests/tests.h

@@ -51,6 +51,7 @@ int test__hists_cumulate(void);
 int test__switch_tracking(void);
 int test__switch_tracking(void);
 int test__fdarray__filter(void);
 int test__fdarray__filter(void);
 int test__fdarray__add(void);
 int test__fdarray__add(void);
+int test__kmod_path__parse(void);
 
 
 #if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
 #if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
 #ifdef HAVE_DWARF_UNWIND_SUPPORT

+ 3 - 1
tools/perf/ui/browsers/hists.c

@@ -511,6 +511,7 @@ static void hist_browser__show_callchain_entry(struct hist_browser *browser,
 {
 {
 	int color, width;
 	int color, width;
 	char folded_sign = callchain_list__folded(chain);
 	char folded_sign = callchain_list__folded(chain);
+	bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src;
 
 
 	color = HE_COLORSET_NORMAL;
 	color = HE_COLORSET_NORMAL;
 	width = browser->b.width - (offset + 2);
 	width = browser->b.width - (offset + 2);
@@ -523,7 +524,8 @@ static void hist_browser__show_callchain_entry(struct hist_browser *browser,
 	ui_browser__set_color(&browser->b, color);
 	ui_browser__set_color(&browser->b, color);
 	hist_browser__gotorc(browser, row, 0);
 	hist_browser__gotorc(browser, row, 0);
 	slsmg_write_nstring(" ", offset);
 	slsmg_write_nstring(" ", offset);
-	slsmg_printf("%c ", folded_sign);
+	slsmg_printf("%c", folded_sign);
+	ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
 	slsmg_write_nstring(str, width);
 	slsmg_write_nstring(str, width);
 }
 }
 
 

+ 1 - 0
tools/perf/util/Build

@@ -94,6 +94,7 @@ libperf-y += scripting-engines/
 
 
 libperf-$(CONFIG_PERF_REGS) += perf_regs.o
 libperf-$(CONFIG_PERF_REGS) += perf_regs.o
 libperf-$(CONFIG_ZLIB) += zlib.o
 libperf-$(CONFIG_ZLIB) += zlib.o
+libperf-$(CONFIG_LZMA) += lzma.o
 
 
 CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 CFLAGS_exec_cmd.o += -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" -DPREFIX="BUILD_STR($(prefix_SQ))"
 CFLAGS_exec_cmd.o += -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" -DPREFIX="BUILD_STR($(prefix_SQ))"

+ 2 - 1
tools/perf/util/build-id.c

@@ -374,7 +374,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 		if (is_kallsyms) {
 		if (is_kallsyms) {
 			 if (copyfile("/proc/kallsyms", filename))
 			 if (copyfile("/proc/kallsyms", filename))
 				goto out_free;
 				goto out_free;
-		} else if (link(realname, filename) && copyfile(name, filename))
+		} else if (link(realname, filename) && errno != EEXIST &&
+				copyfile(name, filename))
 			goto out_free;
 			goto out_free;
 	}
 	}
 
 

+ 81 - 9
tools/perf/util/dso.c

@@ -147,6 +147,9 @@ static const struct {
 } compressions[] = {
 } compressions[] = {
 #ifdef HAVE_ZLIB_SUPPORT
 #ifdef HAVE_ZLIB_SUPPORT
 	{ "gz", gzip_decompress_to_file },
 	{ "gz", gzip_decompress_to_file },
+#endif
+#ifdef HAVE_LZMA_SUPPORT
+	{ "xz", lzma_decompress_to_file },
 #endif
 #endif
 	{ NULL, NULL },
 	{ NULL, NULL },
 };
 };
@@ -208,6 +211,72 @@ bool dso__needs_decompress(struct dso *dso)
 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
 }
 }
 
 
+/*
+ * Parses kernel module specified in @path and updates
+ * @m argument like:
+ *
+ *    @comp - true if @path contains supported compression suffix,
+ *            false otherwise
+ *    @kmod - true if @path contains '.ko' suffix in right position,
+ *            false otherwise
+ *    @name - if (@alloc_name && @kmod) is true, it contains strdup-ed base name
+ *            of the kernel module without suffixes, otherwise strudup-ed
+ *            base name of @path
+ *    @ext  - if (@alloc_ext && @comp) is true, it contains strdup-ed string
+ *            the compression suffix
+ *
+ * Returns 0 if there's no strdup error, -ENOMEM otherwise.
+ */
+int __kmod_path__parse(struct kmod_path *m, const char *path,
+		       bool alloc_name, bool alloc_ext)
+{
+	const char *name = strrchr(path, '/');
+	const char *ext  = strrchr(path, '.');
+
+	memset(m, 0x0, sizeof(*m));
+	name = name ? name + 1 : path;
+
+	/* No extension, just return name. */
+	if (ext == NULL) {
+		if (alloc_name) {
+			m->name = strdup(name);
+			return m->name ? 0 : -ENOMEM;
+		}
+		return 0;
+	}
+
+	if (is_supported_compression(ext + 1)) {
+		m->comp = true;
+		ext -= 3;
+	}
+
+	/* Check .ko extension only if there's enough name left. */
+	if (ext > name)
+		m->kmod = !strncmp(ext, ".ko", 3);
+
+	if (alloc_name) {
+		if (m->kmod) {
+			if (asprintf(&m->name, "[%.*s]", (int) (ext - name), name) == -1)
+				return -ENOMEM;
+		} else {
+			if (asprintf(&m->name, "%s", name) == -1)
+				return -ENOMEM;
+		}
+
+		strxfrchar(m->name, '-', '_');
+	}
+
+	if (alloc_ext && m->comp) {
+		m->ext = strdup(ext + 4);
+		if (!m->ext) {
+			free((void *) m->name);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
 /*
 /*
  * Global list of open DSOs and the counter.
  * Global list of open DSOs and the counter.
  */
  */
@@ -1002,21 +1071,24 @@ struct dso *dsos__find(const struct dsos *dsos, const char *name,
 	return dso__find_by_longname(&dsos->root, name);
 	return dso__find_by_longname(&dsos->root, name);
 }
 }
 
 
-struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
+struct dso *dsos__addnew(struct dsos *dsos, const char *name)
 {
 {
-	struct dso *dso = dsos__find(dsos, name, false);
+	struct dso *dso = dso__new(name);
 
 
-	if (!dso) {
-		dso = dso__new(name);
-		if (dso != NULL) {
-			dsos__add(dsos, dso);
-			dso__set_basename(dso);
-		}
+	if (dso != NULL) {
+		dsos__add(dsos, dso);
+		dso__set_basename(dso);
 	}
 	}
-
 	return dso;
 	return dso;
 }
 }
 
 
+struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
+{
+	struct dso *dso = dsos__find(dsos, name, false);
+
+	return dso ? dso : dsos__addnew(dsos, name);
+}
+
 size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
 size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
 			       bool (skip)(struct dso *dso, int parm), int parm)
 			       bool (skip)(struct dso *dso, int parm), int parm)
 {
 {

+ 15 - 0
tools/perf/util/dso.h

@@ -195,6 +195,20 @@ bool is_kernel_module(const char *pathname, bool *compressed);
 bool decompress_to_file(const char *ext, const char *filename, int output_fd);
 bool decompress_to_file(const char *ext, const char *filename, int output_fd);
 bool dso__needs_decompress(struct dso *dso);
 bool dso__needs_decompress(struct dso *dso);
 
 
+struct kmod_path {
+	char *name;
+	char *ext;
+	bool  comp;
+	bool  kmod;
+};
+
+int __kmod_path__parse(struct kmod_path *m, const char *path,
+		     bool alloc_name, bool alloc_ext);
+
+#define kmod_path__parse(__m, __p)      __kmod_path__parse(__m, __p, false, false)
+#define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true , false)
+#define kmod_path__parse_ext(__m, __p)  __kmod_path__parse(__m, __p, false, true)
+
 /*
 /*
  * The dso__data_* external interface provides following functions:
  * The dso__data_* external interface provides following functions:
  *   dso__data_fd
  *   dso__data_fd
@@ -250,6 +264,7 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
 				const char *short_name, int dso_type);
 				const char *short_name, int dso_type);
 
 
 void dsos__add(struct dsos *dsos, struct dso *dso);
 void dsos__add(struct dsos *dsos, struct dso *dso);
+struct dso *dsos__addnew(struct dsos *dsos, const char *name);
 struct dso *dsos__find(const struct dsos *dsos, const char *name,
 struct dso *dsos__find(const struct dsos *dsos, const char *name,
 		       bool cmp_short);
 		       bool cmp_short);
 struct dso *__dsos__findnew(struct dsos *dsos, const char *name);
 struct dso *__dsos__findnew(struct dsos *dsos, const char *name);

+ 95 - 0
tools/perf/util/lzma.c

@@ -0,0 +1,95 @@
+#include <lzma.h>
+#include <stdio.h>
+#include <linux/compiler.h>
+#include "util.h"
+#include "debug.h"
+
+#define BUFSIZE 8192
+
+static const char *lzma_strerror(lzma_ret ret)
+{
+	switch ((int) ret) {
+	case LZMA_MEM_ERROR:
+		return "Memory allocation failed";
+	case LZMA_OPTIONS_ERROR:
+		return "Unsupported decompressor flags";
+	case LZMA_FORMAT_ERROR:
+		return "The input is not in the .xz format";
+	case LZMA_DATA_ERROR:
+		return "Compressed file is corrupt";
+	case LZMA_BUF_ERROR:
+		return "Compressed file is truncated or otherwise corrupt";
+	default:
+		return "Unknown error, possibly a bug";
+	}
+}
+
+int lzma_decompress_to_file(const char *input, int output_fd)
+{
+	lzma_action action = LZMA_RUN;
+	lzma_stream strm   = LZMA_STREAM_INIT;
+	lzma_ret ret;
+
+	u8 buf_in[BUFSIZE];
+	u8 buf_out[BUFSIZE];
+	FILE *infile;
+
+	infile = fopen(input, "rb");
+	if (!infile) {
+		pr_err("lzma: fopen failed on %s: '%s'\n",
+		       input, strerror(errno));
+		return -1;
+	}
+
+	ret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED);
+	if (ret != LZMA_OK) {
+		pr_err("lzma: lzma_stream_decoder failed %s (%d)\n",
+			lzma_strerror(ret), ret);
+		return -1;
+	}
+
+	strm.next_in   = NULL;
+	strm.avail_in  = 0;
+	strm.next_out  = buf_out;
+	strm.avail_out = sizeof(buf_out);
+
+	while (1) {
+		if (strm.avail_in == 0 && !feof(infile)) {
+			strm.next_in  = buf_in;
+			strm.avail_in = fread(buf_in, 1, sizeof(buf_in), infile);
+
+			if (ferror(infile)) {
+				pr_err("lzma: read error: %s\n", strerror(errno));
+				return -1;
+			}
+
+			if (feof(infile))
+				action = LZMA_FINISH;
+		}
+
+		ret = lzma_code(&strm, action);
+
+		if (strm.avail_out == 0 || ret == LZMA_STREAM_END) {
+			ssize_t write_size = sizeof(buf_out) - strm.avail_out;
+
+			if (writen(output_fd, buf_out, write_size) != write_size) {
+				pr_err("lzma: write error: %s\n", strerror(errno));
+				return -1;
+			}
+
+			strm.next_out  = buf_out;
+			strm.avail_out = sizeof(buf_out);
+		}
+
+		if (ret != LZMA_OK) {
+			if (ret == LZMA_STREAM_END)
+				return 0;
+
+			pr_err("lzma: failed %s\n", lzma_strerror(ret));
+			return -1;
+		}
+	}
+
+	fclose(infile);
+	return 0;
+}

+ 40 - 43
tools/perf/util/machine.c

@@ -460,30 +460,56 @@ int machine__process_lost_event(struct machine *machine __maybe_unused,
 	return 0;
 	return 0;
 }
 }
 
 
+static struct dso*
+machine__module_dso(struct machine *machine, struct kmod_path *m,
+		    const char *filename)
+{
+	struct dso *dso;
+
+	dso = dsos__find(&machine->kernel_dsos, m->name, true);
+	if (!dso) {
+		dso = dsos__addnew(&machine->kernel_dsos, m->name);
+		if (dso == NULL)
+			return NULL;
+
+		if (machine__is_host(machine))
+			dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
+		else
+			dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
+
+		/* _KMODULE_COMP should be next to _KMODULE */
+		if (m->kmod && m->comp)
+			dso->symtab_type++;
+
+		dso__set_short_name(dso, strdup(m->name), true);
+		dso__set_long_name(dso, strdup(filename), true);
+	}
+
+	return dso;
+}
+
 struct map *machine__new_module(struct machine *machine, u64 start,
 struct map *machine__new_module(struct machine *machine, u64 start,
 				const char *filename)
 				const char *filename)
 {
 {
-	struct map *map;
-	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
-	bool compressed;
+	struct map *map = NULL;
+	struct dso *dso;
+	struct kmod_path m;
 
 
-	if (dso == NULL)
+	if (kmod_path__parse_name(&m, filename))
 		return NULL;
 		return NULL;
 
 
+	dso = machine__module_dso(machine, &m, filename);
+	if (dso == NULL)
+		goto out;
+
 	map = map__new2(start, dso, MAP__FUNCTION);
 	map = map__new2(start, dso, MAP__FUNCTION);
 	if (map == NULL)
 	if (map == NULL)
-		return NULL;
-
-	if (machine__is_host(machine))
-		dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
-	else
-		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
-
-	/* _KMODULE_COMP should be next to _KMODULE */
-	if (is_kernel_module(filename, &compressed) && compressed)
-		dso->symtab_type++;
+		goto out;
 
 
 	map_groups__insert(&machine->kmaps, map);
 	map_groups__insert(&machine->kmaps, map);
+
+out:
+	free(m.name);
 	return map;
 	return map;
 }
 }
 
 
@@ -1044,40 +1070,11 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 				strlen(kmmap_prefix) - 1) == 0;
 				strlen(kmmap_prefix) - 1) == 0;
 	if (event->mmap.filename[0] == '/' ||
 	if (event->mmap.filename[0] == '/' ||
 	    (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
 	    (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
-
-		char short_module_name[1024];
-		char *name, *dot;
-
-		if (event->mmap.filename[0] == '/') {
-			name = strrchr(event->mmap.filename, '/');
-			if (name == NULL)
-				goto out_problem;
-
-			++name; /* skip / */
-			dot = strrchr(name, '.');
-			if (dot == NULL)
-				goto out_problem;
-			/* On some system, modules are compressed like .ko.gz */
-			if (is_supported_compression(dot + 1))
-				dot -= 3;
-			if (!is_kmodule_extension(dot + 1))
-				goto out_problem;
-			snprintf(short_module_name, sizeof(short_module_name),
-					"[%.*s]", (int)(dot - name), name);
-			strxfrchar(short_module_name, '-', '_');
-		} else
-			strcpy(short_module_name, event->mmap.filename);
-
 		map = machine__new_module(machine, event->mmap.start,
 		map = machine__new_module(machine, event->mmap.start,
 					  event->mmap.filename);
 					  event->mmap.filename);
 		if (map == NULL)
 		if (map == NULL)
 			goto out_problem;
 			goto out_problem;
 
 
-		name = strdup(short_module_name);
-		if (name == NULL)
-			goto out_problem;
-
-		dso__set_short_name(map->dso, name, true);
 		map->end = map->start + event->mmap.len;
 		map->end = map->start + event->mmap.len;
 	} else if (is_kernel_mmap) {
 	} else if (is_kernel_mmap) {
 		const char *symbol_name = (event->mmap.filename +
 		const char *symbol_name = (event->mmap.filename +

+ 1 - 3
tools/perf/util/probe-event.c

@@ -2507,7 +2507,6 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
 					    int max_tevs, const char *target)
 					    int max_tevs, const char *target)
 {
 {
 	struct map *map = NULL;
 	struct map *map = NULL;
-	struct kmap *kmap = NULL;
 	struct ref_reloc_sym *reloc_sym = NULL;
 	struct ref_reloc_sym *reloc_sym = NULL;
 	struct symbol *sym;
 	struct symbol *sym;
 	struct probe_trace_event *tev;
 	struct probe_trace_event *tev;
@@ -2540,8 +2539,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
 	}
 	}
 
 
 	if (!pev->uprobes && !pp->retprobe) {
 	if (!pev->uprobes && !pp->retprobe) {
-		kmap = map__kmap(map);
-		reloc_sym = kmap->ref_reloc_sym;
+		reloc_sym = kernel_get_ref_reloc_sym();
 		if (!reloc_sym) {
 		if (!reloc_sym) {
 			pr_warning("Relocated base symbol is not found!\n");
 			pr_warning("Relocated base symbol is not found!\n");
 			ret = -EINVAL;
 			ret = -EINVAL;

+ 4 - 0
tools/perf/util/util.h

@@ -329,4 +329,8 @@ bool find_process(const char *name);
 int gzip_decompress_to_file(const char *input, int output_fd);
 int gzip_decompress_to_file(const char *input, int output_fd);
 #endif
 #endif
 
 
+#ifdef HAVE_LZMA_SUPPORT
+int lzma_decompress_to_file(const char *input, int output_fd);
+#endif
+
 #endif /* GIT_COMPAT_UTIL_H */
 #endif /* GIT_COMPAT_UTIL_H */