lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20160526175148.GB11246@krava>
Date:	Thu, 26 May 2016 19:51:48 +0200
From:	Jiri Olsa <jolsa@...hat.com>
To:	He Kuang <hekuang@...wei.com>
Cc:	peterz@...radead.org, mingo@...hat.com, acme@...nel.org,
	alexander.shishkin@...ux.intel.com, wangnan0@...wei.com,
	jpoimboe@...hat.com, ak@...ux.intel.com, eranian@...gle.com,
	namhyung@...nel.org, adrian.hunter@...el.com,
	sukadev@...ux.vnet.ibm.com, masami.hiramatsu.pt@...achi.com,
	tumanova@...ux.vnet.ibm.com, kan.liang@...el.com,
	penberg@...nel.org, dsahern@...il.com, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v5 3/5] perf callchain: Add support for cross-platform
 unwind

On Tue, May 24, 2016 at 09:20:27AM +0000, He Kuang wrote:
> Use thread specific unwind ops to unwind cross-platform callchains.
> 
> Currently, unwind methods is suitable for local unwind, this patch
> changes the fixed methods to thread/map related. Each time a map is
> inserted, we find the target arch and see if this platform can be
> remote unwind. We test for x86 platform and only show proper
> messages. The real unwind methods are not implemented, will be
> introduced in next patch.
> 
> CONFIG_LIBUNWIND/NO_LIBUNWIND are changed to
> CONFIG_LOCAL_LIBUNWIND/NO_LOCAL_LIBUNWIND for retaining local unwind
> features. CONFIG_LIBUNWIND stands for either local or remote or both
> unwind are supported and NO_LIBUNWIND means neither local nor remote
> libunwind are supported.
> 
> Signed-off-by: He Kuang <hekuang@...wei.com>
> ---
>  tools/perf/arch/x86/util/Build            |  2 +-
>  tools/perf/config/Makefile                | 23 +++++++++-
>  tools/perf/util/Build                     |  2 +-
>  tools/perf/util/thread.c                  |  5 +--
>  tools/perf/util/thread.h                  | 17 ++++++--
>  tools/perf/util/unwind-libunwind.c        | 49 +++++++++++++++++----
>  tools/perf/util/unwind-libunwind_common.c | 71 +++++++++++++++++++++++++++++--
>  tools/perf/util/unwind.h                  | 37 +++++++++++-----
>  8 files changed, 173 insertions(+), 33 deletions(-)
> 
> diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
> index 4659703..bc24b75 100644
> --- a/tools/perf/arch/x86/util/Build
> +++ b/tools/perf/arch/x86/util/Build
> @@ -7,7 +7,7 @@ libperf-y += perf_regs.o
>  libperf-$(CONFIG_DWARF) += dwarf-regs.o
>  libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
>  
> -libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
> +libperf-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
>  libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>  
>  libperf-$(CONFIG_AUXTRACE) += auxtrace.o
> diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
> index c9e1625..8ac0440 100644
> --- a/tools/perf/config/Makefile
> +++ b/tools/perf/config/Makefile
> @@ -354,15 +354,31 @@ ifeq ($(ARCH),powerpc)
>  endif
>  
>  ifndef NO_LIBUNWIND
> +  have_libunwind =
>    ifeq ($(feature-libunwind-x86), 1)
>      $(call detected,CONFIG_LIBUNWIND_X86)
>      CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT
> +    LDFLAGS += -lunwind-x86
> +    have_libunwind = 1
>    endif
>  
>    ifneq ($(feature-libunwind), 1)
>      msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
> +    NO_LOCAL_LIBUNWIND := 1
> +  else
> +    have_libunwind = 1
> +    CFLAGS += -DHAVE_LIBUNWIND_LOCAL_SUPPORT
> +    $(call detected,CONFIG_LOCAL_LIBUNWIND)
> +  endif
> +
> +  ifneq ($(have_libunwind), 1)
>      NO_LIBUNWIND := 1
> +  else
> +    CFLAGS += -I$(LIBUNWIND_DIR)/include
> +    LDFLAGS += -L$(LIBUNWIND_DIR)/lib
>    endif
> +else
> +  NO_LOCAL_LIBUNWIND := 1
>  endif
>  
>  ifndef NO_LIBBPF
> @@ -400,7 +416,7 @@ else
>    NO_DWARF_UNWIND := 1
>  endif
>  
> -ifndef NO_LIBUNWIND
> +ifndef NO_LOCAL_LIBUNWIND
>    ifeq ($(ARCH),$(filter $(ARCH),arm arm64))
>      $(call feature_check,libunwind-debug-frame)
>      ifneq ($(feature-libunwind-debug-frame), 1)
> @@ -411,12 +427,15 @@ ifndef NO_LIBUNWIND
>      # 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_LIBUNWIND
> +  CFLAGS  += -DHAVE_LIBUNWIND_SUPPORT
> +endif
> +
>  ifndef NO_LIBAUDIT
>    ifneq ($(feature-libaudit), 1)
>      msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> index 25c31fb..ce69721 100644
> --- a/tools/perf/util/Build
> +++ b/tools/perf/util/Build
> @@ -99,7 +99,7 @@ libperf-$(CONFIG_DWARF) += probe-finder.o
>  libperf-$(CONFIG_DWARF) += dwarf-aux.o
>  
>  libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> -libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
> +libperf-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
>  libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind_common.o
>  
>  libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o
> diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
> index 3043113..4e1aaf5 100644
> --- a/tools/perf/util/thread.c
> +++ b/tools/perf/util/thread.c
> @@ -43,9 +43,6 @@ struct thread *thread__new(pid_t pid, pid_t tid)
>  		thread->cpu = -1;
>  		INIT_LIST_HEAD(&thread->comm_list);
>  
> -		if (unwind__prepare_access(thread) < 0)
> -			goto err_thread;
> -
>  		comm_str = malloc(32);
>  		if (!comm_str)
>  			goto err_thread;
> @@ -59,6 +56,8 @@ struct thread *thread__new(pid_t pid, pid_t tid)
>  		list_add(&comm->list, &thread->comm_list);
>  		atomic_set(&thread->refcnt, 1);
>  		RB_CLEAR_NODE(&thread->rb_node);
> +
> +		register_null_unwind_libunwind_ops(thread);
>  	}
>  
>  	return thread;
> diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
> index 45fba13..647b011 100644
> --- a/tools/perf/util/thread.h
> +++ b/tools/perf/util/thread.h
> @@ -9,12 +9,20 @@
>  #include "symbol.h"
>  #include <strlist.h>
>  #include <intlist.h>
> -#ifdef HAVE_LIBUNWIND_SUPPORT
> -#include <libunwind.h>
> -#endif
>  
>  struct thread_stack;
>  
> +struct unwind_entry;
> +typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
> +struct unwind_libunwind_ops {
> +	int (*prepare_access)(struct thread *thread);
> +	void (*flush_access)(struct thread *thread);
> +	void (*finish_access)(struct thread *thread);
> +	int (*get_entries)(unwind_entry_cb_t cb, void *arg,
> +			   struct thread *thread,
> +			   struct perf_sample *data, int max_stack);
> +};
> +
>  struct thread {
>  	union {
>  		struct rb_node	 rb_node;
> @@ -36,7 +44,8 @@ struct thread {
>  	void			*priv;
>  	struct thread_stack	*ts;
>  #ifdef HAVE_LIBUNWIND_SUPPORT
> -	unw_addr_space_t	addr_space;
> +	void				*addr_space;
> +	struct unwind_libunwind_ops	*unwind_libunwind_ops;
>  #endif
>  };
>  
> diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
> index 63687d3..a6ec587 100644
> --- a/tools/perf/util/unwind-libunwind.c
> +++ b/tools/perf/util/unwind-libunwind.c
> @@ -22,8 +22,11 @@
>  #include <unistd.h>
>  #include <sys/mman.h>
>  #include <linux/list.h>
> +#ifdef REMOTE_UNWIND_LIBUNWIND
> +#include "libunwind-arch.h"
> +#else
>  #include <libunwind.h>
> -#include <libunwind-ptrace.h>
> +#endif
>  #include "callchain.h"
>  #include "thread.h"
>  #include "session.h"
> @@ -34,6 +37,20 @@
>  #include "debug.h"
>  #include "asm/bug.h"
>  
> +#ifndef REMOTE_UNWIND_LIBUNWIND
> +  #define LOCAL_UNWIND_LIBUNWIND
> +  #undef UNWT_OBJ
> +  #define UNWT_OBJ(x) _##x
> +#else
> +  #undef NO_LIBUNWIND_DEBUG_FRAME
> +  #if defined(LIBUNWIND_ARM) && !defined(NO_LIBUNWIND_DEBUG_FRAME_ARM)
> +  #elif defined(LIBUNWIND_AARCH64) &&                    \
> +	  defined(NO_LIBUNWIND_DEBUG_FRAME_ARM_AARCH64)
> +  #else
> +    #define NO_LIBUNWIND_DEBUG_FRAME
> +  #endif
> +#endif
> +
>  extern int
>  UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
>  				    unw_word_t ip,
> @@ -508,7 +525,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
>  		return 0;
>  	}
>  
> -	id = libunwind__arch_reg_id(regnum);
> +	id = LIBUNWIND__ARCH_REG_ID(regnum);
>  	if (id < 0)
>  		return -EINVAL;
>  
> @@ -579,7 +596,7 @@ static unw_accessors_t accessors = {
>  	.get_proc_name		= get_proc_name,
>  };
>  
> -int unwind__prepare_access(struct thread *thread)
> +static int UNWT_OBJ(_unwind__prepare_access)(struct thread *thread)
>  {
>  	if (callchain_param.record_mode != CALLCHAIN_DWARF)
>  		return 0;
> @@ -594,7 +611,7 @@ int unwind__prepare_access(struct thread *thread)
>  	return 0;
>  }
>  
> -void unwind__flush_access(struct thread *thread)
> +static void UNWT_OBJ(_unwind__flush_access)(struct thread *thread)
>  {
>  	if (callchain_param.record_mode != CALLCHAIN_DWARF)
>  		return;
> @@ -602,7 +619,7 @@ void unwind__flush_access(struct thread *thread)
>  	unw_flush_cache(thread->addr_space, 0, 0);
>  }
>  
> -void unwind__finish_access(struct thread *thread)
> +static void UNWT_OBJ(_unwind__finish_access)(struct thread *thread)
>  {
>  	if (callchain_param.record_mode != CALLCHAIN_DWARF)
>  		return;
> @@ -662,9 +679,10 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
>  	return ret;
>  }
>  
> -int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
> -			struct thread *thread,
> -			struct perf_sample *data, int max_stack)
> +static int UNWT_OBJ(_unwind__get_entries)(unwind_entry_cb_t cb, void *arg,
> +					 struct thread *thread,
> +					 struct perf_sample *data,
> +					 int max_stack)
>  {
>  	struct unwind_info ui = {
>  		.sample       = data,
> @@ -680,3 +698,18 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
>  
>  	return get_entries(&ui, cb, arg, max_stack);
>  }
> +
> +struct unwind_libunwind_ops
> +UNWT_OBJ(unwind_libunwind_ops) = {
> +	.prepare_access = UNWT_OBJ(_unwind__prepare_access),
> +	.flush_access   = UNWT_OBJ(_unwind__flush_access),
> +	.finish_access  = UNWT_OBJ(_unwind__finish_access),
> +	.get_entries    = UNWT_OBJ(_unwind__get_entries),
> +};
> +
> +#ifdef LOCAL_UNWIND_LIBUNWIND
> +void register_local_unwind_libunwind_ops(struct thread *thread)
> +{
> +	thread->unwind_libunwind_ops = &UNWT_OBJ(unwind_libunwind_ops);
> +}
> +#endif
> diff --git a/tools/perf/util/unwind-libunwind_common.c b/tools/perf/util/unwind-libunwind_common.c
> index 3946c99..f44833b 100644
> --- a/tools/perf/util/unwind-libunwind_common.c
> +++ b/tools/perf/util/unwind-libunwind_common.c
> @@ -5,10 +5,64 @@
>  #include "debug.h"
>  #include "arch/common.h"
>  
> +static int __null__prepare_access(struct thread *thread __maybe_unused)
> +{
> +	return 0;
> +}
> +
> +static void __null__flush_access(struct thread *thread __maybe_unused)
> +{
> +}
> +
> +static void __null__finish_access(struct thread *thread __maybe_unused)
> +{
> +}
> +
> +static int __null__get_entries(unwind_entry_cb_t cb __maybe_unused,
> +			       void *arg __maybe_unused,
> +			       struct thread *thread __maybe_unused,
> +			       struct perf_sample *data __maybe_unused,
> +			       int max_stack __maybe_unused)
> +{
> +	return 0;
> +}
> +
> +static struct unwind_libunwind_ops null_unwind_libunwind_ops = {
> +	.prepare_access = __null__prepare_access,
> +	.flush_access   = __null__flush_access,
> +	.finish_access  = __null__finish_access,
> +	.get_entries    = __null__get_entries,
> +};
> +
> +void register_null_unwind_libunwind_ops(struct thread *thread)
> +{
> +	thread->unwind_libunwind_ops = &null_unwind_libunwind_ops;
> +	if (thread->mg)
> +		pr_err("unwind: target platform=%s unwind unsupported\n",
> +		       thread->mg->machine->env->arch);
> +}
> +
> +void register_unwind_libunwind_ops(struct unwind_libunwind_ops *ops,
> +				   struct thread *thread)
> +{
> +	thread->unwind_libunwind_ops = ops;
> +}
> +
> +void unwind__flush_access(struct thread *thread)
> +{
> +	thread->unwind_libunwind_ops->flush_access(thread);
> +}
> +
> +void unwind__finish_access(struct thread *thread)
> +{
> +	thread->unwind_libunwind_ops->finish_access(thread);
> +}
> +
>  void unwind__get_arch(struct thread *thread, struct map *map)
>  {
>  	const char *arch;
>  	enum dso_type dso_type;
> +	int use_local_unwind = 1;
>  
>  	if (!thread->mg->machine->env)
>  		return;
> @@ -17,18 +71,27 @@ void unwind__get_arch(struct thread *thread, struct map *map)
>  	if (dso_type == DSO__TYPE_UNKNOWN)
>  		return;
>  
> -	if (thread->addr_space)
> +	if (thread->addr_space) {
>  		pr_debug("unwind: thread map already set, 64bit is %d, dso=%s\n",
>  			 dso_type == DSO__TYPE_64BIT, map->dso->name);
> +		return;
> +	}
>  
>  	arch = normalize_arch(thread->mg->machine->env->arch);
>  
>  	if (!strcmp(arch, "x86")) {
> -		if (dso_type != DSO__TYPE_64BIT)
> +		if (dso_type != DSO__TYPE_64BIT) {
>  #ifdef HAVE_LIBUNWIND_X86_SUPPORT
>  			pr_err("unwind: target platform=%s is not implemented\n", arch);
> -#else
> -			pr_err("unwind: target platform=%s is not supported\n", arch);
>  #endif
> +			register_null_unwind_libunwind_ops(thread);
> +			use_local_unwind = 0;
> +		}
>  	}
> +
> +	if (use_local_unwind)
> +		register_local_unwind_libunwind_ops(thread);
> +
> +	if (thread->unwind_libunwind_ops->prepare_access(thread) < 0)
> +		return;
>  }
> diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
> index 889d630..e170be7 100644
> --- a/tools/perf/util/unwind.h
> +++ b/tools/perf/util/unwind.h
> @@ -15,26 +15,46 @@ struct unwind_entry {
>  typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
>  
>  #ifdef HAVE_DWARF_UNWIND_SUPPORT
> +
> +#ifndef LIBUNWIND__ARCH_REG_ID
> +#define LIBUNWIND__ARCH_REG_ID libunwind__arch_reg_id
> +#endif
> +
>  int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
>  			struct thread *thread,
>  			struct perf_sample *data, int max_stack);
>  /* libunwind specific */
>  #ifdef HAVE_LIBUNWIND_SUPPORT
>  int libunwind__arch_reg_id(int regnum);
> -int unwind__prepare_access(struct thread *thread);
>  void unwind__flush_access(struct thread *thread);
>  void unwind__finish_access(struct thread *thread);
>  void unwind__get_arch(struct thread *thread, struct map *map);
> -#else
> -static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
> -{
> -	return 0;
> +void register_unwind_libunwind_ops(struct unwind_libunwind_ops *ops,
> +				   struct thread *thread);
> +void register_null_unwind_libunwind_ops(struct thread *thread);
> +
> +#ifndef HAVE_LIBUNWIND_LOCAL_SUPPORT
> +static inline void
> +register_local_unwind_libunwind_ops(struct thread *thread) {
> +	register_null_unwind_libunwind_ops(thread);
>  }
> +#else
> +void register_local_unwind_libunwind_ops(struct thread *thread);
> +#endif
> +
> +#define unwind__get_entries(cb, arg,					\
> +			    thread,					\
> +			    data, max_stack)				\
> +	thread->unwind_libunwind_ops->get_entries(cb, arg, thread,	\
> +						  data, max_stack)

I think this should go along with other ops wrappers like
unwind__flush_access/unwind__finish_access.. in unwind-libunwind_common.c

jirka

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ