linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 00/11] Add support for remote unwind
@ 2016-05-28 11:59 He Kuang
  2016-05-28 11:59 ` [PATCH v6 01/11] perf tools: Use LIBUNWIND_DIR for remote libunwind feature check He Kuang
                   ` (10 more replies)
  0 siblings, 11 replies; 27+ messages in thread
From: He Kuang @ 2016-05-28 11:59 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

v5 url:
  http://thread.gmane.org/gmane.linux.kernel/2226821

Currently, perf script uses host unwind methods(local unwind) to parse
perf.data callchain info regardless of the target architecture. So we
get wrong result and no promotion when do remote unwind on other
platforms/machines.

This patchset checks whether a dso is 32-bit or 64-bit according to
elf class info for each thread to let perf use the correct remote
unwind methods instead.

Only x86 and aarch64 is added in this patchset to show the work flow,
other platforms can be added easily.

We can see the right result for unwind info on different machines, for
example: perf.data recorded on i686 qemu with '-g' option and parsed
on x86_64 machine.

before this patchset:

  hello  1219 [001] 72190.667975: probe:sys_close: (c1169d60)
                  c1169d61 sys_close ([kernel.kallsyms])
                  c189c0d7 sysenter_past_esp ([kernel.kallsyms])
                  b777aba9 [unknown] ([vdso32])

after:
(Add vdso into buildid-cache first by 'perf buildid-cache -a' and
libraries are provided in symfs dir)

  hello  1219 [001] 72190.667975: probe:sys_close: (c1169d60)
                  c1169d61 sys_close ([kernel.kallsyms])
                  c189c0d7 sysenter_past_esp ([kernel.kallsyms])
                  b777aba9 __kernel_vsyscall ([vdso32])
                  b76971cc close (/lib/libc-2.22.so)
                   804842e fib (/tmp/hello)
                   804849d main (/tmp/hello)
                  b75d746e __libc_start_main (/lib/libc-2.22.so)
                   8048341 _start (/tmp/hello)

For using remote libunwind libraries, reference this:
  http://thread.gmane.org/gmane.linux.kernel/2224430

and now we can use LIBUNWIND_DIR to specific custom dirctories
containing libunwind libs.

v6:
  By following the advises from Jiri Olsa:

  - Introducing struct unwind_libunwind_ops for local unwind
  - Move unwind__prepare_access from thread_new into thread__insert_map
  - Extract local libunwind code out of unwind-libunwind.c
  - Other changes mentioned in v5 mails.

Thanks.

He Kuang (11):
  perf tools: Use LIBUNWIND_DIR for remote libunwind feature check
  perf tools: Decouple thread->address_space on libunwind
  perf tools: Introducing struct unwind_libunwind_ops for local unwind
  perf tools: Move unwind__prepare_access from thread_new into
    thread__insert_map
  perf tools: Separate local/remote libunwind config
  perf tools: Extract local libunwind code out of unwind-libunwind.c
  perf tools: Export normalize_arch() function
  perf tools: Show warnings for unsupported cross-platform unwind
  perf tools: Change fixed name of libunwind__arch_reg_id to macro
  perf callchain: Support x86 target platform
  perf callchain: Support aarch64 cross-platform

 tools/perf/arch/Build                              |   2 +
 tools/perf/arch/arm/util/Build                     |   2 +-
 tools/perf/arch/arm64/util/Build                   |   2 +-
 tools/perf/arch/arm64/util/unwind-libunwind.c      |   4 +-
 .../perf/arch/arm64/util/unwind-libunwind_arm64.c  |  22 +
 tools/perf/arch/common.c                           |   2 +-
 tools/perf/arch/common.h                           |   1 +
 tools/perf/arch/x86/util/Build                     |   2 +-
 tools/perf/arch/x86/util/unwind-libunwind.c        |   7 +-
 tools/perf/arch/x86/util/unwind-libunwind_x86_32.c |  21 +
 tools/perf/config/Makefile                         |  50 +-
 tools/perf/util/Build                              |   1 +
 tools/perf/util/thread.c                           |   5 +-
 tools/perf/util/thread.h                           |  17 +-
 tools/perf/util/unwind-libunwind-local.c           | 681 ++++++++++++++++++++
 tools/perf/util/unwind-libunwind.c                 | 697 ++-------------------
 tools/perf/util/unwind.h                           |  41 +-
 17 files changed, 884 insertions(+), 673 deletions(-)
 create mode 100644 tools/perf/arch/arm64/util/unwind-libunwind_arm64.c
 create mode 100644 tools/perf/arch/x86/util/unwind-libunwind_x86_32.c
 create mode 100644 tools/perf/util/unwind-libunwind-local.c

-- 
1.8.5.2

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v6 01/11] perf tools: Use LIBUNWIND_DIR for remote libunwind feature check
  2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
@ 2016-05-28 11:59 ` He Kuang
  2016-05-28 11:59 ` [PATCH v6 02/11] perf tools: Decouple thread->address_space on libunwind He Kuang
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: He Kuang @ 2016-05-28 11:59 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

Pass LIBUNWIND_DIR to feature check flags for remote libunwind
tests. So perf can be able to detect remote libunwind libraries from
arbitrary directory.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/config/Makefile | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 1e46277..6f9f566 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -67,9 +67,18 @@ endif
 #
 #   make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
 #
+
+libunwind_arch_set_flags = $(eval $(libunwind_arch_set_flags_code))
+define libunwind_arch_set_flags_code
+  FEATURE_CHECK_CFLAGS-libunwind-$(1)  = -I$(LIBUNWIND_DIR)/include
+  FEATURE_CHECK_LDFLAGS-libunwind-$(1) = -L$(LIBUNWIND_DIR)/lib
+endef
+
 ifdef LIBUNWIND_DIR
   LIBUNWIND_CFLAGS  = -I$(LIBUNWIND_DIR)/include
   LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
+  LIBUNWIND_ARCHS = x86 x86_64 arm aarch64 debug-frame-arm debug-frame-aarch64
+  $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_flags,$(libunwind_arch)))
 endif
 LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS)
 
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v6 02/11] perf tools: Decouple thread->address_space on libunwind
  2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
  2016-05-28 11:59 ` [PATCH v6 01/11] perf tools: Use LIBUNWIND_DIR for remote libunwind feature check He Kuang
@ 2016-05-28 11:59 ` He Kuang
  2016-05-28 11:59 ` [PATCH v6 03/11] perf tools: Introducing struct unwind_libunwind_ops for local unwind He Kuang
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: He Kuang @ 2016-05-28 11:59 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

Currently, the type of thread->addr_space is unw_addr_space_t, which
is a pointer defined in libunwind headers. For local libunwind, we can
simple include "libunwind.h", but for remote libunwind, the header
file is depends on the target libunwind platform. This patch uses
'void *' instead to decouple the dependence on libunwind.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/util/thread.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 45fba13..aa3a8ff 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -9,9 +9,6 @@
 #include "symbol.h"
 #include <strlist.h>
 #include <intlist.h>
-#ifdef HAVE_LIBUNWIND_SUPPORT
-#include <libunwind.h>
-#endif
 
 struct thread_stack;
 
@@ -36,7 +33,7 @@ struct thread {
 	void			*priv;
 	struct thread_stack	*ts;
 #ifdef HAVE_LIBUNWIND_SUPPORT
-	unw_addr_space_t	addr_space;
+	void			*addr_space;
 #endif
 };
 
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v6 03/11] perf tools: Introducing struct unwind_libunwind_ops for local unwind
  2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
  2016-05-28 11:59 ` [PATCH v6 01/11] perf tools: Use LIBUNWIND_DIR for remote libunwind feature check He Kuang
  2016-05-28 11:59 ` [PATCH v6 02/11] perf tools: Decouple thread->address_space on libunwind He Kuang
@ 2016-05-28 11:59 ` He Kuang
  2016-05-30  8:53   ` Jiri Olsa
  2016-05-28 11:59 ` [PATCH v6 04/11] perf tools: Move unwind__prepare_access from thread_new into thread__insert_map He Kuang
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: He Kuang @ 2016-05-28 11:59 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

Currently, libunwind operations are fixed, and they are chosen
according to the host architecture. This will lead a problem that if a
thread is run as x86_32 on x86_64 machine, perf will use libunwind
methods for x86_64 to parse the callchain and get wrong result.

This patch changes the fixed methods of libunwind operations to
thread/map related, and each thread can have indivadual libunwind
operations. Local libunwind methods are registered as default value.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/util/thread.c           |  2 ++
 tools/perf/util/thread.h           | 14 +++++++++-
 tools/perf/util/unwind-libunwind.c | 55 ++++++++++++++++++++++++++++++++++----
 tools/perf/util/unwind.h           |  5 ++++
 4 files changed, 70 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 45fcb71..6d3900c 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -43,6 +43,8 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 		thread->cpu = -1;
 		INIT_LIST_HEAD(&thread->comm_list);
 
+		register_local_unwind_libunwind_ops(thread);
+
 		if (unwind__prepare_access(thread) < 0)
 			goto err_thread;
 
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index aa3a8ff..647b011 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -12,6 +12,17 @@
 
 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;
@@ -33,7 +44,8 @@ struct thread {
 	void			*priv;
 	struct thread_stack	*ts;
 #ifdef HAVE_LIBUNWIND_SUPPORT
-	void			*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..0277b22 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -23,7 +23,6 @@
 #include <sys/mman.h>
 #include <linux/list.h>
 #include <libunwind.h>
-#include <libunwind-ptrace.h>
 #include "callchain.h"
 #include "thread.h"
 #include "session.h"
@@ -579,7 +578,7 @@ static unw_accessors_t accessors = {
 	.get_proc_name		= get_proc_name,
 };
 
-int unwind__prepare_access(struct thread *thread)
+static int _unwind__prepare_access(struct thread *thread)
 {
 	if (callchain_param.record_mode != CALLCHAIN_DWARF)
 		return 0;
@@ -594,7 +593,7 @@ int unwind__prepare_access(struct thread *thread)
 	return 0;
 }
 
-void unwind__flush_access(struct thread *thread)
+static void _unwind__flush_access(struct thread *thread)
 {
 	if (callchain_param.record_mode != CALLCHAIN_DWARF)
 		return;
@@ -602,7 +601,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 _unwind__finish_access(struct thread *thread)
 {
 	if (callchain_param.record_mode != CALLCHAIN_DWARF)
 		return;
@@ -662,7 +661,7 @@ 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,
+static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg,
 			struct thread *thread,
 			struct perf_sample *data, int max_stack)
 {
@@ -680,3 +679,49 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
 
 	return get_entries(&ui, cb, arg, max_stack);
 }
+
+static struct unwind_libunwind_ops
+_unwind_libunwind_ops = {
+	.prepare_access = _unwind__prepare_access,
+	.flush_access   = _unwind__flush_access,
+	.finish_access  = _unwind__finish_access,
+	.get_entries    = _unwind__get_entries,
+};
+
+void register_local_unwind_libunwind_ops(struct thread *thread)
+{
+	thread->unwind_libunwind_ops = &_unwind_libunwind_ops;
+}
+
+int unwind__prepare_access(struct thread *thread)
+{
+	if (thread->unwind_libunwind_ops)
+		return thread->unwind_libunwind_ops->prepare_access(thread);
+	else
+		return 0;
+}
+
+void unwind__flush_access(struct thread *thread)
+{
+	if (thread->unwind_libunwind_ops)
+		thread->unwind_libunwind_ops->flush_access(thread);
+}
+
+void unwind__finish_access(struct thread *thread)
+{
+	if (thread->unwind_libunwind_ops)
+		thread->unwind_libunwind_ops->finish_access(thread);
+}
+
+int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+			 struct thread *thread,
+			 struct perf_sample *data, int max_stack)
+{
+	if (thread->unwind_libunwind_ops)
+		return thread->unwind_libunwind_ops->get_entries(cb, arg,
+								 thread,
+								 data,
+								 max_stack);
+	else
+		return 0;
+}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 12790cf..5f36415 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -24,6 +24,7 @@ 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 register_local_unwind_libunwind_ops(struct thread *thread);
 #else
 static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
 {
@@ -32,6 +33,8 @@ static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
 
 static inline void unwind__flush_access(struct thread *thread __maybe_unused) {}
 static inline void unwind__finish_access(struct thread *thread __maybe_unused) {}
+static inline void
+register_local_unwind_libunwind_ops(struct thread *thread __maybe_unused) {}
 #endif
 #else
 static inline int
@@ -51,5 +54,7 @@ static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
 
 static inline void unwind__flush_access(struct thread *thread __maybe_unused) {}
 static inline void unwind__finish_access(struct thread *thread __maybe_unused) {}
+static inline void
+register_local_unwind_libunwind_ops(struct thread *thread __maybe_unused) {}
 #endif /* HAVE_DWARF_UNWIND_SUPPORT */
 #endif /* __UNWIND_H */
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v6 04/11] perf tools: Move unwind__prepare_access from thread_new into thread__insert_map
  2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
                   ` (2 preceding siblings ...)
  2016-05-28 11:59 ` [PATCH v6 03/11] perf tools: Introducing struct unwind_libunwind_ops for local unwind He Kuang
@ 2016-05-28 11:59 ` He Kuang
  2016-05-30  8:52   ` Jiri Olsa
  2016-05-28 11:59 ` [PATCH v6 05/11] perf tools: Separate local/remote libunwind config He Kuang
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: He Kuang @ 2016-05-28 11:59 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

For determine the libunwind methods to use, we should get the
32bit/64bit information from maps of a thread. When a thread is newly
created, the information is not prepared. This patch moves
unwind__prepare_access() into thread__insert_map() so we can get the
information we need from maps.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/util/thread.c           | 7 ++-----
 tools/perf/util/unwind-libunwind.c | 7 +++----
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 6d3900c..045477d 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -43,11 +43,6 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 		thread->cpu = -1;
 		INIT_LIST_HEAD(&thread->comm_list);
 
-		register_local_unwind_libunwind_ops(thread);
-
-		if (unwind__prepare_access(thread) < 0)
-			goto err_thread;
-
 		comm_str = malloc(32);
 		if (!comm_str)
 			goto err_thread;
@@ -207,6 +202,8 @@ void thread__insert_map(struct thread *thread, struct map *map)
 {
 	map_groups__fixup_overlappings(thread->mg, map, stderr);
 	map_groups__insert(thread->mg, map);
+
+	unwind__prepare_access(thread);
 }
 
 static int thread__clone_map_groups(struct thread *thread,
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 0277b22..93d2d8e 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -695,10 +695,9 @@ void register_local_unwind_libunwind_ops(struct thread *thread)
 
 int unwind__prepare_access(struct thread *thread)
 {
-	if (thread->unwind_libunwind_ops)
-		return thread->unwind_libunwind_ops->prepare_access(thread);
-	else
-		return 0;
+	register_local_unwind_libunwind_ops(thread);
+
+	return thread->unwind_libunwind_ops->prepare_access(thread);
 }
 
 void unwind__flush_access(struct thread *thread)
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v6 05/11] perf tools: Separate local/remote libunwind config
  2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
                   ` (3 preceding siblings ...)
  2016-05-28 11:59 ` [PATCH v6 04/11] perf tools: Move unwind__prepare_access from thread_new into thread__insert_map He Kuang
@ 2016-05-28 11:59 ` He Kuang
  2016-05-30  8:52   ` Jiri Olsa
  2016-05-28 11:59 ` [PATCH v6 06/11] perf tools: Extract local libunwind code out of unwind-libunwind.c He Kuang
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: He Kuang @ 2016-05-28 11:59 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

CONFIG_LIBUNWIND/NO_LIBUNWIND are changed to
CONFIG_LOCAL_LIBUNWIND/NO_LOCAL_LIBUNWIND for retaining local unwind
features.

The new CONFIG_LIBUNWIND stands for either local or remote or both
unwind are supported.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/arch/arm/util/Build   |  2 +-
 tools/perf/arch/arm64/util/Build |  2 +-
 tools/perf/arch/x86/util/Build   |  2 +-
 tools/perf/config/Makefile       | 21 +++++++++++++++++++--
 tools/perf/util/unwind.h         |  8 +++++++-
 5 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
index d22e3d0..52d0ff8 100644
--- a/tools/perf/arch/arm/util/Build
+++ b/tools/perf/arch/arm/util/Build
@@ -1,4 +1,4 @@
 libperf-$(CONFIG_DWARF) += dwarf-regs.o
 
-libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
+libperf-$(CONFIG_LOCAL_LIBUNWIND)          += unwind-libunwind.o
 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build
index e58123a8..02f41db 100644
--- a/tools/perf/arch/arm64/util/Build
+++ b/tools/perf/arch/arm64/util/Build
@@ -1,2 +1,2 @@
 libperf-$(CONFIG_DWARF)     += dwarf-regs.o
-libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
+libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
index 4659703..1db8abd 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 6f9f566..3a304a3 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -354,10 +354,24 @@ ifeq ($(ARCH),powerpc)
 endif
 
 ifndef NO_LIBUNWIND
+  have_libunwind :=
   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
@@ -395,7 +409,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)
@@ -406,12 +420,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/unwind.h b/tools/perf/util/unwind.h
index 5f36415..0122797 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -18,13 +18,13 @@ typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
 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 register_local_unwind_libunwind_ops(struct thread *thread);
 #else
 static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
 {
@@ -33,9 +33,15 @@ static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
 
 static inline void unwind__flush_access(struct thread *thread __maybe_unused) {}
 static inline void unwind__finish_access(struct thread *thread __maybe_unused) {}
+#endif
+
+#ifdef HAVE_LIBUNWIND_LOCAL_SUPPORT
+void register_local_unwind_libunwind_ops(struct thread *thread);
+#else
 static inline void
 register_local_unwind_libunwind_ops(struct thread *thread __maybe_unused) {}
 #endif
+
 #else
 static inline int
 unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v6 06/11] perf tools: Extract local libunwind code out of unwind-libunwind.c
  2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
                   ` (4 preceding siblings ...)
  2016-05-28 11:59 ` [PATCH v6 05/11] perf tools: Separate local/remote libunwind config He Kuang
@ 2016-05-28 11:59 ` He Kuang
  2016-05-28 12:10   ` Wangnan (F)
  2016-05-28 11:59 ` [PATCH v6 07/11] perf tools: Export normalize_arch() function He Kuang
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: He Kuang @ 2016-05-28 11:59 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

This patch extracts codes related to specific arithecture out of
unwind-libunwind.c. The extrated part are only built if local
libunwind is supported.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/util/Build                    |   1 +
 tools/perf/util/unwind-libunwind-local.c | 677 ++++++++++++++++++++++++++++++
 tools/perf/util/unwind-libunwind.c       | 694 +------------------------------
 3 files changed, 679 insertions(+), 693 deletions(-)
 create mode 100644 tools/perf/util/unwind-libunwind-local.c

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 8c6c8a0..004fb1d 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -99,6 +99,7 @@ libperf-$(CONFIG_DWARF) += probe-finder.o
 libperf-$(CONFIG_DWARF) += dwarf-aux.o
 
 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
+libperf-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind-local.o
 libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
 
 libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
new file mode 100644
index 0000000..5599adc
--- /dev/null
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -0,0 +1,677 @@
+#include <elf.h>
+#include <gelf.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <linux/list.h>
+#include <libunwind.h>
+#include "callchain.h"
+#include "thread.h"
+#include "session.h"
+#include "perf_regs.h"
+#include "unwind.h"
+#include "symbol.h"
+#include "util.h"
+#include "debug.h"
+#include "asm/bug.h"
+
+extern int
+UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
+				    unw_word_t ip,
+				    unw_dyn_info_t *di,
+				    unw_proc_info_t *pi,
+				    int need_unwind_info, void *arg);
+
+#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
+
+extern int
+UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
+				 unw_word_t ip,
+				 unw_word_t segbase,
+				 const char *obj_name, unw_word_t start,
+				 unw_word_t end);
+
+#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
+
+#define DW_EH_PE_FORMAT_MASK	0x0f	/* format of the encoded value */
+#define DW_EH_PE_APPL_MASK	0x70	/* how the value is to be applied */
+
+/* Pointer-encoding formats: */
+#define DW_EH_PE_omit		0xff
+#define DW_EH_PE_ptr		0x00	/* pointer-sized unsigned value */
+#define DW_EH_PE_udata4		0x03	/* unsigned 32-bit value */
+#define DW_EH_PE_udata8		0x04	/* unsigned 64-bit value */
+#define DW_EH_PE_sdata4		0x0b	/* signed 32-bit value */
+#define DW_EH_PE_sdata8		0x0c	/* signed 64-bit value */
+
+/* Pointer-encoding application: */
+#define DW_EH_PE_absptr		0x00	/* absolute value */
+#define DW_EH_PE_pcrel		0x10	/* rel. to addr. of encoded value */
+
+/*
+ * The following are not documented by LSB v1.3, yet they are used by
+ * GCC, presumably they aren't documented by LSB since they aren't
+ * used on Linux:
+ */
+#define DW_EH_PE_funcrel	0x40	/* start-of-procedure-relative */
+#define DW_EH_PE_aligned	0x50	/* aligned pointer */
+
+/* Flags intentionaly not handled, since they're not needed:
+ * #define DW_EH_PE_indirect      0x80
+ * #define DW_EH_PE_uleb128       0x01
+ * #define DW_EH_PE_udata2        0x02
+ * #define DW_EH_PE_sleb128       0x09
+ * #define DW_EH_PE_sdata2        0x0a
+ * #define DW_EH_PE_textrel       0x20
+ * #define DW_EH_PE_datarel       0x30
+ */
+
+struct unwind_info {
+	struct perf_sample	*sample;
+	struct machine		*machine;
+	struct thread		*thread;
+};
+
+#define dw_read(ptr, type, end) ({	\
+	type *__p = (type *) ptr;	\
+	type  __v;			\
+	if ((__p + 1) > (type *) end)	\
+		return -EINVAL;		\
+	__v = *__p++;			\
+	ptr = (typeof(ptr)) __p;	\
+	__v;				\
+	})
+
+static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
+				   u8 encoding)
+{
+	u8 *cur = *p;
+	*val = 0;
+
+	switch (encoding) {
+	case DW_EH_PE_omit:
+		*val = 0;
+		goto out;
+	case DW_EH_PE_ptr:
+		*val = dw_read(cur, unsigned long, end);
+		goto out;
+	default:
+		break;
+	}
+
+	switch (encoding & DW_EH_PE_APPL_MASK) {
+	case DW_EH_PE_absptr:
+		break;
+	case DW_EH_PE_pcrel:
+		*val = (unsigned long) cur;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ((encoding & 0x07) == 0x00)
+		encoding |= DW_EH_PE_udata4;
+
+	switch (encoding & DW_EH_PE_FORMAT_MASK) {
+	case DW_EH_PE_sdata4:
+		*val += dw_read(cur, s32, end);
+		break;
+	case DW_EH_PE_udata4:
+		*val += dw_read(cur, u32, end);
+		break;
+	case DW_EH_PE_sdata8:
+		*val += dw_read(cur, s64, end);
+		break;
+	case DW_EH_PE_udata8:
+		*val += dw_read(cur, u64, end);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+ out:
+	*p = cur;
+	return 0;
+}
+
+#define dw_read_encoded_value(ptr, end, enc) ({			\
+	u64 __v;						\
+	if (__dw_read_encoded_value(&ptr, end, &__v, enc)) {	\
+		return -EINVAL;                                 \
+	}                                                       \
+	__v;                                                    \
+	})
+
+static u64 elf_section_offset(int fd, const char *name)
+{
+	Elf *elf;
+	GElf_Ehdr ehdr;
+	GElf_Shdr shdr;
+	u64 offset = 0;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL)
+		return 0;
+
+	do {
+		if (gelf_getehdr(elf, &ehdr) == NULL)
+			break;
+
+		if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL))
+			break;
+
+		offset = shdr.sh_offset;
+	} while (0);
+
+	elf_end(elf);
+	return offset;
+}
+
+#ifndef NO_LIBUNWIND_DEBUG_FRAME
+static int elf_is_exec(int fd, const char *name)
+{
+	Elf *elf;
+	GElf_Ehdr ehdr;
+	int retval = 0;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL)
+		return 0;
+	if (gelf_getehdr(elf, &ehdr) == NULL)
+		goto out;
+
+	retval = (ehdr.e_type == ET_EXEC);
+
+out:
+	elf_end(elf);
+	pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval);
+	return retval;
+}
+#endif
+
+struct table_entry {
+	u32 start_ip_offset;
+	u32 fde_offset;
+};
+
+struct eh_frame_hdr {
+	unsigned char version;
+	unsigned char eh_frame_ptr_enc;
+	unsigned char fde_count_enc;
+	unsigned char table_enc;
+
+	/*
+	 * The rest of the header is variable-length and consists of the
+	 * following members:
+	 *
+	 *	encoded_t eh_frame_ptr;
+	 *	encoded_t fde_count;
+	 */
+
+	/* A single encoded pointer should not be more than 8 bytes. */
+	u64 enc[2];
+
+	/*
+	 * struct {
+	 *    encoded_t start_ip;
+	 *    encoded_t fde_addr;
+	 * } binary_search_table[fde_count];
+	 */
+	char data[0];
+} __packed;
+
+static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
+			       u64 offset, u64 *table_data, u64 *segbase,
+			       u64 *fde_count)
+{
+	struct eh_frame_hdr hdr;
+	u8 *enc = (u8 *) &hdr.enc;
+	u8 *end = (u8 *) &hdr.data;
+	ssize_t r;
+
+	r = dso__data_read_offset(dso, machine, offset,
+				  (u8 *) &hdr, sizeof(hdr));
+	if (r != sizeof(hdr))
+		return -EINVAL;
+
+	/* We dont need eh_frame_ptr, just skip it. */
+	dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
+
+	*fde_count  = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
+	*segbase    = offset;
+	*table_data = (enc - (u8 *) &hdr) + offset;
+	return 0;
+}
+
+static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
+				     u64 *table_data, u64 *segbase,
+				     u64 *fde_count)
+{
+	int ret = -EINVAL, fd;
+	u64 offset = dso->data.eh_frame_hdr_offset;
+
+	if (offset == 0) {
+		fd = dso__data_get_fd(dso, machine);
+		if (fd < 0)
+			return -EINVAL;
+
+		/* Check the .eh_frame section for unwinding info */
+		offset = elf_section_offset(fd, ".eh_frame_hdr");
+		dso->data.eh_frame_hdr_offset = offset;
+		dso__data_put_fd(dso);
+	}
+
+	if (offset)
+		ret = unwind_spec_ehframe(dso, machine, offset,
+					  table_data, segbase,
+					  fde_count);
+
+	return ret;
+}
+
+#ifndef NO_LIBUNWIND_DEBUG_FRAME
+static int read_unwind_spec_debug_frame(struct dso *dso,
+					struct machine *machine, u64 *offset)
+{
+	int fd;
+	u64 ofs = dso->data.debug_frame_offset;
+
+	if (ofs == 0) {
+		fd = dso__data_get_fd(dso, machine);
+		if (fd < 0)
+			return -EINVAL;
+
+		/* Check the .debug_frame section for unwinding info */
+		ofs = elf_section_offset(fd, ".debug_frame");
+		dso->data.debug_frame_offset = ofs;
+		dso__data_put_fd(dso);
+	}
+
+	*offset = ofs;
+	if (*offset)
+		return 0;
+
+	return -EINVAL;
+}
+#endif
+
+static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
+{
+	struct addr_location al;
+
+	thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
+			      MAP__FUNCTION, ip, &al);
+	if (!al.map) {
+		/*
+		 * We've seen cases (softice) where DWARF unwinder went
+		 * through non executable mmaps, which we need to lookup
+		 * in MAP__VARIABLE tree.
+		 */
+		thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
+				      MAP__VARIABLE, ip, &al);
+	}
+	return al.map;
+}
+
+static int
+find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+	       int need_unwind_info, void *arg)
+{
+	struct unwind_info *ui = arg;
+	struct map *map;
+	unw_dyn_info_t di;
+	u64 table_data, segbase, fde_count;
+	int ret = -EINVAL;
+
+	map = find_map(ip, ui);
+	if (!map || !map->dso)
+		return -EINVAL;
+
+	pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
+
+	/* Check the .eh_frame section for unwinding info */
+	if (!read_unwind_spec_eh_frame(map->dso, ui->machine,
+				       &table_data, &segbase, &fde_count)) {
+		memset(&di, 0, sizeof(di));
+		di.format   = UNW_INFO_FORMAT_REMOTE_TABLE;
+		di.start_ip = map->start;
+		di.end_ip   = map->end;
+		di.u.rti.segbase    = map->start + segbase;
+		di.u.rti.table_data = map->start + table_data;
+		di.u.rti.table_len  = fde_count * sizeof(struct table_entry)
+				      / sizeof(unw_word_t);
+		ret = dwarf_search_unwind_table(as, ip, &di, pi,
+						need_unwind_info, arg);
+	}
+
+#ifndef NO_LIBUNWIND_DEBUG_FRAME
+	/* Check the .debug_frame section for unwinding info */
+	if (ret < 0 &&
+	    !read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
+		int fd = dso__data_get_fd(map->dso, ui->machine);
+		int is_exec = elf_is_exec(fd, map->dso->name);
+		unw_word_t base = is_exec ? 0 : map->start;
+		const char *symfile;
+
+		if (fd >= 0)
+			dso__data_put_fd(map->dso);
+
+		symfile = map->dso->symsrc_filename ?: map->dso->name;
+
+		memset(&di, 0, sizeof(di));
+		if (dwarf_find_debug_frame(0, &di, ip, base, symfile,
+					   map->start, map->end))
+			return dwarf_search_unwind_table(as, ip, &di, pi,
+							 need_unwind_info, arg);
+	}
+#endif
+
+	return ret;
+}
+
+static int access_fpreg(unw_addr_space_t __maybe_unused as,
+			unw_regnum_t __maybe_unused num,
+			unw_fpreg_t __maybe_unused *val,
+			int __maybe_unused __write,
+			void __maybe_unused *arg)
+{
+	pr_err("unwind: access_fpreg unsupported\n");
+	return -UNW_EINVAL;
+}
+
+static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,
+				  unw_word_t __maybe_unused *dil_addr,
+				  void __maybe_unused *arg)
+{
+	return -UNW_ENOINFO;
+}
+
+static int resume(unw_addr_space_t __maybe_unused as,
+		  unw_cursor_t __maybe_unused *cu,
+		  void __maybe_unused *arg)
+{
+	pr_err("unwind: resume unsupported\n");
+	return -UNW_EINVAL;
+}
+
+static int
+get_proc_name(unw_addr_space_t __maybe_unused as,
+	      unw_word_t __maybe_unused addr,
+		char __maybe_unused *bufp, size_t __maybe_unused buf_len,
+		unw_word_t __maybe_unused *offp, void __maybe_unused *arg)
+{
+	pr_err("unwind: get_proc_name unsupported\n");
+	return -UNW_EINVAL;
+}
+
+static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
+			  unw_word_t *data)
+{
+	struct map *map;
+	ssize_t size;
+
+	map = find_map(addr, ui);
+	if (!map) {
+		pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
+		return -1;
+	}
+
+	if (!map->dso)
+		return -1;
+
+	size = dso__data_read_addr(map->dso, map, ui->machine,
+				   addr, (u8 *) data, sizeof(*data));
+
+	return !(size == sizeof(*data));
+}
+
+static int access_mem(unw_addr_space_t __maybe_unused as,
+		      unw_word_t addr, unw_word_t *valp,
+		      int __write, void *arg)
+{
+	struct unwind_info *ui = arg;
+	struct stack_dump *stack = &ui->sample->user_stack;
+	u64 start, end;
+	int offset;
+	int ret;
+
+	/* Don't support write, probably not needed. */
+	if (__write || !stack || !ui->sample->user_regs.regs) {
+		*valp = 0;
+		return 0;
+	}
+
+	ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
+	if (ret)
+		return ret;
+
+	end = start + stack->size;
+
+	/* Check overflow. */
+	if (addr + sizeof(unw_word_t) < addr)
+		return -EINVAL;
+
+	if (addr < start || addr + sizeof(unw_word_t) >= end) {
+		ret = access_dso_mem(ui, addr, valp);
+		if (ret) {
+			pr_debug("unwind: access_mem %p not inside range"
+				 " 0x%" PRIx64 "-0x%" PRIx64 "\n",
+				 (void *) (uintptr_t) addr, start, end);
+			*valp = 0;
+			return ret;
+		}
+		return 0;
+	}
+
+	offset = addr - start;
+	*valp  = *(unw_word_t *)&stack->data[offset];
+	pr_debug("unwind: access_mem addr %p val %lx, offset %d\n",
+		 (void *) (uintptr_t) addr, (unsigned long)*valp, offset);
+	return 0;
+}
+
+static int access_reg(unw_addr_space_t __maybe_unused as,
+		      unw_regnum_t regnum, unw_word_t *valp,
+		      int __write, void *arg)
+{
+	struct unwind_info *ui = arg;
+	int id, ret;
+	u64 val;
+
+	/* Don't support write, I suspect we don't need it. */
+	if (__write) {
+		pr_err("unwind: access_reg w %d\n", regnum);
+		return 0;
+	}
+
+	if (!ui->sample->user_regs.regs) {
+		*valp = 0;
+		return 0;
+	}
+
+	id = libunwind__arch_reg_id(regnum);
+	if (id < 0)
+		return -EINVAL;
+
+	ret = perf_reg_value(&val, &ui->sample->user_regs, id);
+	if (ret) {
+		pr_err("unwind: can't read reg %d\n", regnum);
+		return ret;
+	}
+
+	*valp = (unw_word_t) val;
+	pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
+	return 0;
+}
+
+static void put_unwind_info(unw_addr_space_t __maybe_unused as,
+			    unw_proc_info_t *pi __maybe_unused,
+			    void *arg __maybe_unused)
+{
+	pr_debug("unwind: put_unwind_info called\n");
+}
+
+static int entry(u64 ip, struct thread *thread,
+		 unwind_entry_cb_t cb, void *arg)
+{
+	struct unwind_entry e;
+	struct addr_location al;
+
+	thread__find_addr_location(thread, PERF_RECORD_MISC_USER,
+				   MAP__FUNCTION, ip, &al);
+
+	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 cb(&e, arg);
+}
+
+static void display_error(int err)
+{
+	switch (err) {
+	case UNW_EINVAL:
+		pr_err("unwind: Only supports local.\n");
+		break;
+	case UNW_EUNSPEC:
+		pr_err("unwind: Unspecified error.\n");
+		break;
+	case UNW_EBADREG:
+		pr_err("unwind: Register unavailable.\n");
+		break;
+	default:
+		break;
+	}
+}
+
+static unw_accessors_t accessors = {
+	.find_proc_info		= find_proc_info,
+	.put_unwind_info	= put_unwind_info,
+	.get_dyn_info_list_addr	= get_dyn_info_list_addr,
+	.access_mem		= access_mem,
+	.access_reg		= access_reg,
+	.access_fpreg		= access_fpreg,
+	.resume			= resume,
+	.get_proc_name		= get_proc_name,
+};
+
+static int _unwind__prepare_access(struct thread *thread)
+{
+	if (callchain_param.record_mode != CALLCHAIN_DWARF)
+		return 0;
+
+	thread->addr_space = unw_create_addr_space(&accessors, 0);
+	if (!thread->addr_space) {
+		pr_err("unwind: Can't create unwind address space.\n");
+		return -ENOMEM;
+	}
+
+	unw_set_caching_policy(thread->addr_space, UNW_CACHE_GLOBAL);
+	return 0;
+}
+
+static void _unwind__flush_access(struct thread *thread)
+{
+	if (callchain_param.record_mode != CALLCHAIN_DWARF)
+		return;
+
+	unw_flush_cache(thread->addr_space, 0, 0);
+}
+
+static void _unwind__finish_access(struct thread *thread)
+{
+	if (callchain_param.record_mode != CALLCHAIN_DWARF)
+		return;
+
+	unw_destroy_addr_space(thread->addr_space);
+}
+
+static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
+		       void *arg, int max_stack)
+{
+	u64 val;
+	unw_word_t ips[max_stack];
+	unw_addr_space_t addr_space;
+	unw_cursor_t c;
+	int ret, i = 0;
+
+	ret = perf_reg_value(&val, &ui->sample->user_regs, PERF_REG_IP);
+	if (ret)
+		return ret;
+
+	ips[i++] = (unw_word_t) val;
+
+	/*
+	 * If we need more than one entry, do the DWARF
+	 * unwind itself.
+	 */
+	if (max_stack - 1 > 0) {
+		WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL");
+		addr_space = ui->thread->addr_space;
+
+		if (addr_space == NULL)
+			return -1;
+
+		ret = unw_init_remote(&c, addr_space, ui);
+		if (ret)
+			display_error(ret);
+
+		while (!ret && (unw_step(&c) > 0) && i < max_stack) {
+			unw_get_reg(&c, UNW_REG_IP, &ips[i]);
+			++i;
+		}
+
+		max_stack = i;
+	}
+
+	/*
+	 * Display what we got based on the order setup.
+	 */
+	for (i = 0; i < max_stack && !ret; i++) {
+		int j = i;
+
+		if (callchain_param.order == ORDER_CALLER)
+			j = max_stack - i - 1;
+		ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0;
+	}
+
+	return ret;
+}
+
+static int _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,
+		.thread       = thread,
+		.machine      = thread->mg->machine,
+	};
+
+	if (!data->user_regs.regs)
+		return -EINVAL;
+
+	if (max_stack <= 0)
+		return -EINVAL;
+
+	return get_entries(&ui, cb, arg, max_stack);
+}
+
+static struct unwind_libunwind_ops
+_unwind_libunwind_ops = {
+	.prepare_access = _unwind__prepare_access,
+	.flush_access   = _unwind__flush_access,
+	.finish_access  = _unwind__finish_access,
+	.get_entries    = _unwind__get_entries,
+};
+
+void register_local_unwind_libunwind_ops(struct thread *thread)
+{
+	thread->unwind_libunwind_ops = &_unwind_libunwind_ops;
+}
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 93d2d8e..40d0453 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -1,697 +1,5 @@
-/*
- * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps.
- *
- * Lots of this code have been borrowed or heavily inspired from parts of
- * the libunwind 0.99 code which are (amongst other contributors I may have
- * forgotten):
- *
- * Copyright (C) 2002-2007 Hewlett-Packard Co
- *	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * And the bugs have been added by:
- *
- * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com>
- * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com>
- *
- */
-
-#include <elf.h>
-#include <gelf.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <linux/list.h>
-#include <libunwind.h>
-#include "callchain.h"
-#include "thread.h"
-#include "session.h"
-#include "perf_regs.h"
 #include "unwind.h"
-#include "symbol.h"
-#include "util.h"
-#include "debug.h"
-#include "asm/bug.h"
-
-extern int
-UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
-				    unw_word_t ip,
-				    unw_dyn_info_t *di,
-				    unw_proc_info_t *pi,
-				    int need_unwind_info, void *arg);
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-extern int
-UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
-				 unw_word_t ip,
-				 unw_word_t segbase,
-				 const char *obj_name, unw_word_t start,
-				 unw_word_t end);
-
-#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
-
-#define DW_EH_PE_FORMAT_MASK	0x0f	/* format of the encoded value */
-#define DW_EH_PE_APPL_MASK	0x70	/* how the value is to be applied */
-
-/* Pointer-encoding formats: */
-#define DW_EH_PE_omit		0xff
-#define DW_EH_PE_ptr		0x00	/* pointer-sized unsigned value */
-#define DW_EH_PE_udata4		0x03	/* unsigned 32-bit value */
-#define DW_EH_PE_udata8		0x04	/* unsigned 64-bit value */
-#define DW_EH_PE_sdata4		0x0b	/* signed 32-bit value */
-#define DW_EH_PE_sdata8		0x0c	/* signed 64-bit value */
-
-/* Pointer-encoding application: */
-#define DW_EH_PE_absptr		0x00	/* absolute value */
-#define DW_EH_PE_pcrel		0x10	/* rel. to addr. of encoded value */
-
-/*
- * The following are not documented by LSB v1.3, yet they are used by
- * GCC, presumably they aren't documented by LSB since they aren't
- * used on Linux:
- */
-#define DW_EH_PE_funcrel	0x40	/* start-of-procedure-relative */
-#define DW_EH_PE_aligned	0x50	/* aligned pointer */
-
-/* Flags intentionaly not handled, since they're not needed:
- * #define DW_EH_PE_indirect      0x80
- * #define DW_EH_PE_uleb128       0x01
- * #define DW_EH_PE_udata2        0x02
- * #define DW_EH_PE_sleb128       0x09
- * #define DW_EH_PE_sdata2        0x0a
- * #define DW_EH_PE_textrel       0x20
- * #define DW_EH_PE_datarel       0x30
- */
-
-struct unwind_info {
-	struct perf_sample	*sample;
-	struct machine		*machine;
-	struct thread		*thread;
-};
-
-#define dw_read(ptr, type, end) ({	\
-	type *__p = (type *) ptr;	\
-	type  __v;			\
-	if ((__p + 1) > (type *) end)	\
-		return -EINVAL;		\
-	__v = *__p++;			\
-	ptr = (typeof(ptr)) __p;	\
-	__v;				\
-	})
-
-static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
-				   u8 encoding)
-{
-	u8 *cur = *p;
-	*val = 0;
-
-	switch (encoding) {
-	case DW_EH_PE_omit:
-		*val = 0;
-		goto out;
-	case DW_EH_PE_ptr:
-		*val = dw_read(cur, unsigned long, end);
-		goto out;
-	default:
-		break;
-	}
-
-	switch (encoding & DW_EH_PE_APPL_MASK) {
-	case DW_EH_PE_absptr:
-		break;
-	case DW_EH_PE_pcrel:
-		*val = (unsigned long) cur;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if ((encoding & 0x07) == 0x00)
-		encoding |= DW_EH_PE_udata4;
-
-	switch (encoding & DW_EH_PE_FORMAT_MASK) {
-	case DW_EH_PE_sdata4:
-		*val += dw_read(cur, s32, end);
-		break;
-	case DW_EH_PE_udata4:
-		*val += dw_read(cur, u32, end);
-		break;
-	case DW_EH_PE_sdata8:
-		*val += dw_read(cur, s64, end);
-		break;
-	case DW_EH_PE_udata8:
-		*val += dw_read(cur, u64, end);
-		break;
-	default:
-		return -EINVAL;
-	}
-
- out:
-	*p = cur;
-	return 0;
-}
-
-#define dw_read_encoded_value(ptr, end, enc) ({			\
-	u64 __v;						\
-	if (__dw_read_encoded_value(&ptr, end, &__v, enc)) {	\
-		return -EINVAL;                                 \
-	}                                                       \
-	__v;                                                    \
-	})
-
-static u64 elf_section_offset(int fd, const char *name)
-{
-	Elf *elf;
-	GElf_Ehdr ehdr;
-	GElf_Shdr shdr;
-	u64 offset = 0;
-
-	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
-	if (elf == NULL)
-		return 0;
-
-	do {
-		if (gelf_getehdr(elf, &ehdr) == NULL)
-			break;
-
-		if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL))
-			break;
-
-		offset = shdr.sh_offset;
-	} while (0);
-
-	elf_end(elf);
-	return offset;
-}
-
-#ifndef NO_LIBUNWIND_DEBUG_FRAME
-static int elf_is_exec(int fd, const char *name)
-{
-	Elf *elf;
-	GElf_Ehdr ehdr;
-	int retval = 0;
-
-	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
-	if (elf == NULL)
-		return 0;
-	if (gelf_getehdr(elf, &ehdr) == NULL)
-		goto out;
-
-	retval = (ehdr.e_type == ET_EXEC);
-
-out:
-	elf_end(elf);
-	pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval);
-	return retval;
-}
-#endif
-
-struct table_entry {
-	u32 start_ip_offset;
-	u32 fde_offset;
-};
-
-struct eh_frame_hdr {
-	unsigned char version;
-	unsigned char eh_frame_ptr_enc;
-	unsigned char fde_count_enc;
-	unsigned char table_enc;
-
-	/*
-	 * The rest of the header is variable-length and consists of the
-	 * following members:
-	 *
-	 *	encoded_t eh_frame_ptr;
-	 *	encoded_t fde_count;
-	 */
-
-	/* A single encoded pointer should not be more than 8 bytes. */
-	u64 enc[2];
-
-	/*
-	 * struct {
-	 *    encoded_t start_ip;
-	 *    encoded_t fde_addr;
-	 * } binary_search_table[fde_count];
-	 */
-	char data[0];
-} __packed;
-
-static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
-			       u64 offset, u64 *table_data, u64 *segbase,
-			       u64 *fde_count)
-{
-	struct eh_frame_hdr hdr;
-	u8 *enc = (u8 *) &hdr.enc;
-	u8 *end = (u8 *) &hdr.data;
-	ssize_t r;
-
-	r = dso__data_read_offset(dso, machine, offset,
-				  (u8 *) &hdr, sizeof(hdr));
-	if (r != sizeof(hdr))
-		return -EINVAL;
-
-	/* We dont need eh_frame_ptr, just skip it. */
-	dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
-
-	*fde_count  = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
-	*segbase    = offset;
-	*table_data = (enc - (u8 *) &hdr) + offset;
-	return 0;
-}
-
-static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
-				     u64 *table_data, u64 *segbase,
-				     u64 *fde_count)
-{
-	int ret = -EINVAL, fd;
-	u64 offset = dso->data.eh_frame_hdr_offset;
-
-	if (offset == 0) {
-		fd = dso__data_get_fd(dso, machine);
-		if (fd < 0)
-			return -EINVAL;
-
-		/* Check the .eh_frame section for unwinding info */
-		offset = elf_section_offset(fd, ".eh_frame_hdr");
-		dso->data.eh_frame_hdr_offset = offset;
-		dso__data_put_fd(dso);
-	}
-
-	if (offset)
-		ret = unwind_spec_ehframe(dso, machine, offset,
-					  table_data, segbase,
-					  fde_count);
-
-	return ret;
-}
-
-#ifndef NO_LIBUNWIND_DEBUG_FRAME
-static int read_unwind_spec_debug_frame(struct dso *dso,
-					struct machine *machine, u64 *offset)
-{
-	int fd;
-	u64 ofs = dso->data.debug_frame_offset;
-
-	if (ofs == 0) {
-		fd = dso__data_get_fd(dso, machine);
-		if (fd < 0)
-			return -EINVAL;
-
-		/* Check the .debug_frame section for unwinding info */
-		ofs = elf_section_offset(fd, ".debug_frame");
-		dso->data.debug_frame_offset = ofs;
-		dso__data_put_fd(dso);
-	}
-
-	*offset = ofs;
-	if (*offset)
-		return 0;
-
-	return -EINVAL;
-}
-#endif
-
-static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
-{
-	struct addr_location al;
-
-	thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
-			      MAP__FUNCTION, ip, &al);
-	if (!al.map) {
-		/*
-		 * We've seen cases (softice) where DWARF unwinder went
-		 * through non executable mmaps, which we need to lookup
-		 * in MAP__VARIABLE tree.
-		 */
-		thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
-				      MAP__VARIABLE, ip, &al);
-	}
-	return al.map;
-}
-
-static int
-find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
-	       int need_unwind_info, void *arg)
-{
-	struct unwind_info *ui = arg;
-	struct map *map;
-	unw_dyn_info_t di;
-	u64 table_data, segbase, fde_count;
-	int ret = -EINVAL;
-
-	map = find_map(ip, ui);
-	if (!map || !map->dso)
-		return -EINVAL;
-
-	pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
-
-	/* Check the .eh_frame section for unwinding info */
-	if (!read_unwind_spec_eh_frame(map->dso, ui->machine,
-				       &table_data, &segbase, &fde_count)) {
-		memset(&di, 0, sizeof(di));
-		di.format   = UNW_INFO_FORMAT_REMOTE_TABLE;
-		di.start_ip = map->start;
-		di.end_ip   = map->end;
-		di.u.rti.segbase    = map->start + segbase;
-		di.u.rti.table_data = map->start + table_data;
-		di.u.rti.table_len  = fde_count * sizeof(struct table_entry)
-				      / sizeof(unw_word_t);
-		ret = dwarf_search_unwind_table(as, ip, &di, pi,
-						need_unwind_info, arg);
-	}
-
-#ifndef NO_LIBUNWIND_DEBUG_FRAME
-	/* Check the .debug_frame section for unwinding info */
-	if (ret < 0 &&
-	    !read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
-		int fd = dso__data_get_fd(map->dso, ui->machine);
-		int is_exec = elf_is_exec(fd, map->dso->name);
-		unw_word_t base = is_exec ? 0 : map->start;
-		const char *symfile;
-
-		if (fd >= 0)
-			dso__data_put_fd(map->dso);
-
-		symfile = map->dso->symsrc_filename ?: map->dso->name;
-
-		memset(&di, 0, sizeof(di));
-		if (dwarf_find_debug_frame(0, &di, ip, base, symfile,
-					   map->start, map->end))
-			return dwarf_search_unwind_table(as, ip, &di, pi,
-							 need_unwind_info, arg);
-	}
-#endif
-
-	return ret;
-}
-
-static int access_fpreg(unw_addr_space_t __maybe_unused as,
-			unw_regnum_t __maybe_unused num,
-			unw_fpreg_t __maybe_unused *val,
-			int __maybe_unused __write,
-			void __maybe_unused *arg)
-{
-	pr_err("unwind: access_fpreg unsupported\n");
-	return -UNW_EINVAL;
-}
-
-static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,
-				  unw_word_t __maybe_unused *dil_addr,
-				  void __maybe_unused *arg)
-{
-	return -UNW_ENOINFO;
-}
-
-static int resume(unw_addr_space_t __maybe_unused as,
-		  unw_cursor_t __maybe_unused *cu,
-		  void __maybe_unused *arg)
-{
-	pr_err("unwind: resume unsupported\n");
-	return -UNW_EINVAL;
-}
-
-static int
-get_proc_name(unw_addr_space_t __maybe_unused as,
-	      unw_word_t __maybe_unused addr,
-		char __maybe_unused *bufp, size_t __maybe_unused buf_len,
-		unw_word_t __maybe_unused *offp, void __maybe_unused *arg)
-{
-	pr_err("unwind: get_proc_name unsupported\n");
-	return -UNW_EINVAL;
-}
-
-static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
-			  unw_word_t *data)
-{
-	struct map *map;
-	ssize_t size;
-
-	map = find_map(addr, ui);
-	if (!map) {
-		pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
-		return -1;
-	}
-
-	if (!map->dso)
-		return -1;
-
-	size = dso__data_read_addr(map->dso, map, ui->machine,
-				   addr, (u8 *) data, sizeof(*data));
-
-	return !(size == sizeof(*data));
-}
-
-static int access_mem(unw_addr_space_t __maybe_unused as,
-		      unw_word_t addr, unw_word_t *valp,
-		      int __write, void *arg)
-{
-	struct unwind_info *ui = arg;
-	struct stack_dump *stack = &ui->sample->user_stack;
-	u64 start, end;
-	int offset;
-	int ret;
-
-	/* Don't support write, probably not needed. */
-	if (__write || !stack || !ui->sample->user_regs.regs) {
-		*valp = 0;
-		return 0;
-	}
-
-	ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
-	if (ret)
-		return ret;
-
-	end = start + stack->size;
-
-	/* Check overflow. */
-	if (addr + sizeof(unw_word_t) < addr)
-		return -EINVAL;
-
-	if (addr < start || addr + sizeof(unw_word_t) >= end) {
-		ret = access_dso_mem(ui, addr, valp);
-		if (ret) {
-			pr_debug("unwind: access_mem %p not inside range"
-				 " 0x%" PRIx64 "-0x%" PRIx64 "\n",
-				 (void *) (uintptr_t) addr, start, end);
-			*valp = 0;
-			return ret;
-		}
-		return 0;
-	}
-
-	offset = addr - start;
-	*valp  = *(unw_word_t *)&stack->data[offset];
-	pr_debug("unwind: access_mem addr %p val %lx, offset %d\n",
-		 (void *) (uintptr_t) addr, (unsigned long)*valp, offset);
-	return 0;
-}
-
-static int access_reg(unw_addr_space_t __maybe_unused as,
-		      unw_regnum_t regnum, unw_word_t *valp,
-		      int __write, void *arg)
-{
-	struct unwind_info *ui = arg;
-	int id, ret;
-	u64 val;
-
-	/* Don't support write, I suspect we don't need it. */
-	if (__write) {
-		pr_err("unwind: access_reg w %d\n", regnum);
-		return 0;
-	}
-
-	if (!ui->sample->user_regs.regs) {
-		*valp = 0;
-		return 0;
-	}
-
-	id = libunwind__arch_reg_id(regnum);
-	if (id < 0)
-		return -EINVAL;
-
-	ret = perf_reg_value(&val, &ui->sample->user_regs, id);
-	if (ret) {
-		pr_err("unwind: can't read reg %d\n", regnum);
-		return ret;
-	}
-
-	*valp = (unw_word_t) val;
-	pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
-	return 0;
-}
-
-static void put_unwind_info(unw_addr_space_t __maybe_unused as,
-			    unw_proc_info_t *pi __maybe_unused,
-			    void *arg __maybe_unused)
-{
-	pr_debug("unwind: put_unwind_info called\n");
-}
-
-static int entry(u64 ip, struct thread *thread,
-		 unwind_entry_cb_t cb, void *arg)
-{
-	struct unwind_entry e;
-	struct addr_location al;
-
-	thread__find_addr_location(thread, PERF_RECORD_MISC_USER,
-				   MAP__FUNCTION, ip, &al);
-
-	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 cb(&e, arg);
-}
-
-static void display_error(int err)
-{
-	switch (err) {
-	case UNW_EINVAL:
-		pr_err("unwind: Only supports local.\n");
-		break;
-	case UNW_EUNSPEC:
-		pr_err("unwind: Unspecified error.\n");
-		break;
-	case UNW_EBADREG:
-		pr_err("unwind: Register unavailable.\n");
-		break;
-	default:
-		break;
-	}
-}
-
-static unw_accessors_t accessors = {
-	.find_proc_info		= find_proc_info,
-	.put_unwind_info	= put_unwind_info,
-	.get_dyn_info_list_addr	= get_dyn_info_list_addr,
-	.access_mem		= access_mem,
-	.access_reg		= access_reg,
-	.access_fpreg		= access_fpreg,
-	.resume			= resume,
-	.get_proc_name		= get_proc_name,
-};
-
-static int _unwind__prepare_access(struct thread *thread)
-{
-	if (callchain_param.record_mode != CALLCHAIN_DWARF)
-		return 0;
-
-	thread->addr_space = unw_create_addr_space(&accessors, 0);
-	if (!thread->addr_space) {
-		pr_err("unwind: Can't create unwind address space.\n");
-		return -ENOMEM;
-	}
-
-	unw_set_caching_policy(thread->addr_space, UNW_CACHE_GLOBAL);
-	return 0;
-}
-
-static void _unwind__flush_access(struct thread *thread)
-{
-	if (callchain_param.record_mode != CALLCHAIN_DWARF)
-		return;
-
-	unw_flush_cache(thread->addr_space, 0, 0);
-}
-
-static void _unwind__finish_access(struct thread *thread)
-{
-	if (callchain_param.record_mode != CALLCHAIN_DWARF)
-		return;
-
-	unw_destroy_addr_space(thread->addr_space);
-}
-
-static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
-		       void *arg, int max_stack)
-{
-	u64 val;
-	unw_word_t ips[max_stack];
-	unw_addr_space_t addr_space;
-	unw_cursor_t c;
-	int ret, i = 0;
-
-	ret = perf_reg_value(&val, &ui->sample->user_regs, PERF_REG_IP);
-	if (ret)
-		return ret;
-
-	ips[i++] = (unw_word_t) val;
-
-	/*
-	 * If we need more than one entry, do the DWARF
-	 * unwind itself.
-	 */
-	if (max_stack - 1 > 0) {
-		WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL");
-		addr_space = ui->thread->addr_space;
-
-		if (addr_space == NULL)
-			return -1;
-
-		ret = unw_init_remote(&c, addr_space, ui);
-		if (ret)
-			display_error(ret);
-
-		while (!ret && (unw_step(&c) > 0) && i < max_stack) {
-			unw_get_reg(&c, UNW_REG_IP, &ips[i]);
-			++i;
-		}
-
-		max_stack = i;
-	}
-
-	/*
-	 * Display what we got based on the order setup.
-	 */
-	for (i = 0; i < max_stack && !ret; i++) {
-		int j = i;
-
-		if (callchain_param.order == ORDER_CALLER)
-			j = max_stack - i - 1;
-		ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0;
-	}
-
-	return ret;
-}
-
-static int _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,
-		.thread       = thread,
-		.machine      = thread->mg->machine,
-	};
-
-	if (!data->user_regs.regs)
-		return -EINVAL;
-
-	if (max_stack <= 0)
-		return -EINVAL;
-
-	return get_entries(&ui, cb, arg, max_stack);
-}
-
-static struct unwind_libunwind_ops
-_unwind_libunwind_ops = {
-	.prepare_access = _unwind__prepare_access,
-	.flush_access   = _unwind__flush_access,
-	.finish_access  = _unwind__finish_access,
-	.get_entries    = _unwind__get_entries,
-};
-
-void register_local_unwind_libunwind_ops(struct thread *thread)
-{
-	thread->unwind_libunwind_ops = &_unwind_libunwind_ops;
-}
+#include "thread.h"
 
 int unwind__prepare_access(struct thread *thread)
 {
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v6 07/11] perf tools: Export normalize_arch() function
  2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
                   ` (5 preceding siblings ...)
  2016-05-28 11:59 ` [PATCH v6 06/11] perf tools: Extract local libunwind code out of unwind-libunwind.c He Kuang
@ 2016-05-28 11:59 ` He Kuang
  2016-05-28 11:59 ` [PATCH v6 08/11] perf tools: Show warnings for unsupported cross-platform unwind He Kuang
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: He Kuang @ 2016-05-28 11:59 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

Export normalize_arch() function, so other part of perf can get
normalized form of arch string.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/arch/common.c | 2 +-
 tools/perf/arch/common.h | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c
index e83c8ce..fa090a9 100644
--- a/tools/perf/arch/common.c
+++ b/tools/perf/arch/common.c
@@ -102,7 +102,7 @@ static int lookup_triplets(const char *const *triplets, const char *name)
  * Return architecture name in a normalized form.
  * The conversion logic comes from the Makefile.
  */
-static const char *normalize_arch(char *arch)
+const char *normalize_arch(char *arch)
 {
 	if (!strcmp(arch, "x86_64"))
 		return "x86";
diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h
index 7529cfb..6b01c73 100644
--- a/tools/perf/arch/common.h
+++ b/tools/perf/arch/common.h
@@ -6,5 +6,6 @@
 extern const char *objdump_path;
 
 int perf_env__lookup_objdump(struct perf_env *env);
+const char *normalize_arch(char *arch);
 
 #endif /* ARCH_PERF_COMMON_H */
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v6 08/11] perf tools: Show warnings for unsupported cross-platform unwind
  2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
                   ` (6 preceding siblings ...)
  2016-05-28 11:59 ` [PATCH v6 07/11] perf tools: Export normalize_arch() function He Kuang
@ 2016-05-28 11:59 ` He Kuang
  2016-05-30  8:53   ` Jiri Olsa
  2016-05-28 11:59 ` [PATCH v6 09/11] perf tools: Change fixed name of libunwind__arch_reg_id to macro He Kuang
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: He Kuang @ 2016-05-28 11:59 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

Currently, perf script uses host unwind methods to parse perf.data
callchain info regardless of the target architecture. So we get wrong
result without any warnings when unwinding callchains of x86(32-bit)
on x86(64-bit) machine.

This patch shows warning messages when we do remote unwind x86(32-bit)
on other machines. Same thing for other platforms will be added in
next patches.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/config/Makefile         |  8 ++++++++
 tools/perf/util/thread.c           |  2 +-
 tools/perf/util/unwind-libunwind.c | 30 +++++++++++++++++++++++++++++-
 tools/perf/util/unwind.h           |  5 +++--
 4 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 3a304a3..e156f76 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -355,6 +355,14 @@ 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
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 045477d..7ffee25 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -203,7 +203,7 @@ void thread__insert_map(struct thread *thread, struct map *map)
 	map_groups__fixup_overlappings(thread->mg, map, stderr);
 	map_groups__insert(thread->mg, map);
 
-	unwind__prepare_access(thread);
+	unwind__prepare_access(thread, map);
 }
 
 static int thread__clone_map_groups(struct thread *thread,
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 40d0453..037ee72 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -1,8 +1,36 @@
 #include "unwind.h"
 #include "thread.h"
+#include "session.h"
+#include "debug.h"
+#include "arch/common.h"
 
-int unwind__prepare_access(struct thread *thread)
+int unwind__prepare_access(struct thread *thread, struct map *map)
 {
+	const char *arch;
+	enum dso_type dso_type;
+
+	if (!thread->mg->machine->env)
+		return -1;
+
+	dso_type = dso__type(map->dso, thread->mg->machine);
+	if (dso_type == DSO__TYPE_UNKNOWN)
+		return -1;
+
+	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);
+
+	arch = normalize_arch(thread->mg->machine->env->arch);
+
+	if (!strcmp(arch, "x86")) {
+		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_local_unwind_libunwind_ops(thread);
 
 	return thread->unwind_libunwind_ops->prepare_access(thread);
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 0122797..4de423c 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -22,11 +22,12 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
 /* libunwind specific */
 #ifdef HAVE_LIBUNWIND_SUPPORT
 int libunwind__arch_reg_id(int regnum);
-int unwind__prepare_access(struct thread *thread);
+int unwind__prepare_access(struct thread *thread, struct map *map);
 void unwind__flush_access(struct thread *thread);
 void unwind__finish_access(struct thread *thread);
 #else
-static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
+static inline int unwind__prepare_access(struct thread *thread __maybe_unused,
+					 struct map *map __maybe_unused)
 {
 	return 0;
 }
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v6 09/11] perf tools: Change fixed name of libunwind__arch_reg_id to macro
  2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
                   ` (7 preceding siblings ...)
  2016-05-28 11:59 ` [PATCH v6 08/11] perf tools: Show warnings for unsupported cross-platform unwind He Kuang
@ 2016-05-28 11:59 ` He Kuang
  2016-05-28 11:59 ` [PATCH v6 10/11] perf callchain: Support x86 target platform He Kuang
  2016-05-28 12:00 ` [PATCH v6 11/11] perf callchain: Support aarch64 cross-platform He Kuang
  10 siblings, 0 replies; 27+ messages in thread
From: He Kuang @ 2016-05-28 11:59 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

For local libunwind, it uses the fixed methods to convert register id
according to the host platform, but in remote libunwind, this convert
function should be the one for remote architechture. This patch
changes the fixed name to macro and code for each remote platform can
be compiled indivadually.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/util/unwind-libunwind-local.c | 2 +-
 tools/perf/util/unwind.h                 | 5 ++++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index 5599adc..b391e3e 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -490,7 +490,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;
 
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 4de423c..9e4f545 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -21,7 +21,10 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
 
 /* libunwind specific */
 #ifdef HAVE_LIBUNWIND_SUPPORT
-int libunwind__arch_reg_id(int regnum);
+#ifndef LIBUNWIND__ARCH_REG_ID
+#define LIBUNWIND__ARCH_REG_ID libunwind__arch_reg_id
+#endif
+int LIBUNWIND__ARCH_REG_ID(int regnum);
 int unwind__prepare_access(struct thread *thread, struct map *map);
 void unwind__flush_access(struct thread *thread);
 void unwind__finish_access(struct thread *thread);
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v6 10/11] perf callchain: Support x86 target platform
  2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
                   ` (8 preceding siblings ...)
  2016-05-28 11:59 ` [PATCH v6 09/11] perf tools: Change fixed name of libunwind__arch_reg_id to macro He Kuang
@ 2016-05-28 11:59 ` He Kuang
  2016-05-30  8:52   ` Jiri Olsa
                     ` (2 more replies)
  2016-05-28 12:00 ` [PATCH v6 11/11] perf callchain: Support aarch64 cross-platform He Kuang
  10 siblings, 3 replies; 27+ messages in thread
From: He Kuang @ 2016-05-28 11:59 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

Support x86(32-bit) cross platform callchain unwind.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/arch/Build                              |  1 +
 tools/perf/arch/x86/util/unwind-libunwind.c        |  7 ++++---
 tools/perf/arch/x86/util/unwind-libunwind_x86_32.c | 21 +++++++++++++++++++++
 tools/perf/util/unwind-libunwind-local.c           |  4 ++++
 tools/perf/util/unwind-libunwind.c                 | 19 +++++++++++++------
 tools/perf/util/unwind.h                           | 10 ++++++++++
 6 files changed, 53 insertions(+), 9 deletions(-)
 create mode 100644 tools/perf/arch/x86/util/unwind-libunwind_x86_32.c

diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build
index 109eb75..3fc4af1 100644
--- a/tools/perf/arch/Build
+++ b/tools/perf/arch/Build
@@ -1,2 +1,3 @@
 libperf-y += common.o
 libperf-y += $(ARCH)/
+libperf-$(CONFIG_LIBUNWIND_X86)      += x86/util/unwind-libunwind_x86_32.o
diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c
index db25e93..3b0be69 100644
--- a/tools/perf/arch/x86/util/unwind-libunwind.c
+++ b/tools/perf/arch/x86/util/unwind-libunwind.c
@@ -1,12 +1,13 @@
-
+#ifndef REMOTE_UNWIND_LIBUNWIND
 #include <errno.h>
 #include <libunwind.h>
 #include "perf_regs.h"
 #include "../../util/unwind.h"
 #include "../../util/debug.h"
+#endif
 
 #ifdef HAVE_ARCH_X86_64_SUPPORT
-int libunwind__arch_reg_id(int regnum)
+int LIBUNWIND__ARCH_REG_ID(int regnum)
 {
 	int id;
 
@@ -70,7 +71,7 @@ int libunwind__arch_reg_id(int regnum)
 	return id;
 }
 #else
-int libunwind__arch_reg_id(int regnum)
+int LIBUNWIND__ARCH_REG_ID(int regnum)
 {
 	int id;
 
diff --git a/tools/perf/arch/x86/util/unwind-libunwind_x86_32.c b/tools/perf/arch/x86/util/unwind-libunwind_x86_32.c
new file mode 100644
index 0000000..9d5359e
--- /dev/null
+++ b/tools/perf/arch/x86/util/unwind-libunwind_x86_32.c
@@ -0,0 +1,21 @@
+#define REMOTE_UNWIND_LIBUNWIND
+
+#define LIBUNWIND__ARCH_REG_ID libunwind__x86_reg_id
+
+#include "unwind.h"
+#include "debug.h"
+#include "libunwind-x86.h"
+#include <../../../../../arch/x86/include/uapi/asm/perf_regs.h>
+
+#undef HAVE_ARCH_X86_64_SUPPORT
+#include "unwind-libunwind.c"
+
+#undef NO_LIBUNWIND_DEBUG_FRAME
+#define NO_LIBUNWIND_DEBUG_FRAME
+#include "util/unwind-libunwind-local.c"
+
+int register_x86_32_unwind_libunwind_ops(struct thread *thread)
+{
+	thread->unwind_libunwind_ops = &_unwind_libunwind_ops;
+	return 0;
+}
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index b391e3e..849fec1 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -5,7 +5,9 @@
 #include <unistd.h>
 #include <sys/mman.h>
 #include <linux/list.h>
+#ifndef REMOTE_UNWIND_LIBUNWIND
 #include <libunwind.h>
+#endif
 #include "callchain.h"
 #include "thread.h"
 #include "session.h"
@@ -671,7 +673,9 @@ _unwind_libunwind_ops = {
 	.get_entries    = _unwind__get_entries,
 };
 
+#ifndef REMOTE_UNWIND_LIBUNWIND
 void register_local_unwind_libunwind_ops(struct thread *thread)
 {
 	thread->unwind_libunwind_ops = &_unwind_libunwind_ops;
 }
+#endif
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 037ee72..c1d9d36 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -8,6 +8,9 @@ int unwind__prepare_access(struct thread *thread, struct map *map)
 {
 	const char *arch;
 	enum dso_type dso_type;
+	int use_local_unwind = 1;
+	int ret;
+	int (*register_func)(struct thread *thread) = NULL;
 
 	if (!thread->mg->machine->env)
 		return -1;
@@ -22,16 +25,20 @@ int unwind__prepare_access(struct thread *thread, struct map *map)
 
 	arch = normalize_arch(thread->mg->machine->env->arch);
 
-	if (!strcmp(arch, "x86")) {
+	if (!strcmp(arch, "x86"))
 		if (dso_type != DSO__TYPE_64BIT)
-#ifdef HAVE_LIBUNWIND_X86_SUPPORT
-			pr_err("unwind: target platform=%s is not implemented\n", arch);
-#else
+			register_func = register_x86_32_unwind_libunwind_ops;
+
+	if (register_func) {
+		ret = register_func(thread);
+		if (!ret)
+			use_local_unwind = 0;
+		else
 			pr_err("unwind: target platform=%s is not supported\n", arch);
-#endif
 	}
 
-	register_local_unwind_libunwind_ops(thread);
+	if (use_local_unwind)
+		register_local_unwind_libunwind_ops(thread);
 
 	return thread->unwind_libunwind_ops->prepare_access(thread);
 }
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 9e4f545..43f9f66 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -46,6 +46,16 @@ static inline void
 register_local_unwind_libunwind_ops(struct thread *thread __maybe_unused) {}
 #endif
 
+#ifdef HAVE_LIBUNWIND_X86_SUPPORT
+int register_x86_32_unwind_libunwind_ops(struct thread *thread);
+#else
+static inline int
+register_x86_32_unwind_libunwind_ops(struct thread *thread __maybe_unused)
+{
+	return -1;
+}
+#endif
+
 #else
 static inline int
 unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v6 11/11] perf callchain: Support aarch64 cross-platform
  2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
                   ` (9 preceding siblings ...)
  2016-05-28 11:59 ` [PATCH v6 10/11] perf callchain: Support x86 target platform He Kuang
@ 2016-05-28 12:00 ` He Kuang
  10 siblings, 0 replies; 27+ messages in thread
From: He Kuang @ 2016-05-28 12:00 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

Support aarch64 cross platform callchain unwind.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/arch/Build                              |  1 +
 tools/perf/arch/arm64/util/unwind-libunwind.c      |  4 +++-
 .../perf/arch/arm64/util/unwind-libunwind_arm64.c  | 22 ++++++++++++++++++++++
 tools/perf/config/Makefile                         | 12 ++++++++++++
 tools/perf/util/unwind-libunwind.c                 |  6 +++++-
 tools/perf/util/unwind.h                           | 10 ++++++++++
 6 files changed, 53 insertions(+), 2 deletions(-)
 create mode 100644 tools/perf/arch/arm64/util/unwind-libunwind_arm64.c

diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build
index 3fc4af1..bc49295 100644
--- a/tools/perf/arch/Build
+++ b/tools/perf/arch/Build
@@ -1,3 +1,4 @@
 libperf-y += common.o
 libperf-y += $(ARCH)/
 libperf-$(CONFIG_LIBUNWIND_X86)      += x86/util/unwind-libunwind_x86_32.o
+libperf-$(CONFIG_LIBUNWIND_AARCH64)  += arm64/util/unwind-libunwind_arm64.o
diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c
index a87afa9..c116b71 100644
--- a/tools/perf/arch/arm64/util/unwind-libunwind.c
+++ b/tools/perf/arch/arm64/util/unwind-libunwind.c
@@ -1,11 +1,13 @@
 
+#ifndef REMOTE_UNWIND_LIBUNWIND
 #include <errno.h>
 #include <libunwind.h>
 #include "perf_regs.h"
 #include "../../util/unwind.h"
 #include "../../util/debug.h"
+#endif
 
-int libunwind__arch_reg_id(int regnum)
+int LIBUNWIND__ARCH_REG_ID(int regnum)
 {
 	switch (regnum) {
 	case UNW_AARCH64_X0:
diff --git a/tools/perf/arch/arm64/util/unwind-libunwind_arm64.c b/tools/perf/arch/arm64/util/unwind-libunwind_arm64.c
new file mode 100644
index 0000000..ea9e7d1
--- /dev/null
+++ b/tools/perf/arch/arm64/util/unwind-libunwind_arm64.c
@@ -0,0 +1,22 @@
+#define REMOTE_UNWIND_LIBUNWIND
+
+#define LIBUNWIND__ARCH_REG_ID libunwind__arm64_reg_id
+
+#include "unwind.h"
+#include "debug.h"
+#include "libunwind-aarch64.h"
+#include <../../../../../arch/arm64/include/uapi/asm/perf_regs.h>
+#include "unwind-libunwind.c"
+
+#undef NO_LIBUNWIND_DEBUG_FRAME
+#ifdef NO_LIBUNWIND_DEBUG_FRAME_AARCH64
+#define NO_LIBUNWIND_DEBUG_FRAME
+#endif
+
+#include "util/unwind-libunwind-local.c"
+
+int register_arm64_unwind_libunwind_ops(struct thread *thread)
+{
+	thread->unwind_libunwind_ops = &_unwind_libunwind_ops;
+	return 0;
+}
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index e156f76..bb5aea8 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -363,6 +363,18 @@ ifndef NO_LIBUNWIND
     have_libunwind = 1
   endif
 
+  ifeq ($(feature-libunwind-aarch64), 1)
+    $(call detected,CONFIG_LIBUNWIND_AARCH64)
+    CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT
+    LDFLAGS += -lunwind-aarch64
+    have_libunwind = 1
+    $(call feature_check,libunwind-debug-frame-aarch64)
+    ifneq ($(feature-libunwind-debug-frame-aarch64), 1)
+      msg := $(warning No debug_frame support found in libunwind-aarch64);
+      CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64
+    endif
+  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
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index c1d9d36..5930865 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -25,9 +25,13 @@ int unwind__prepare_access(struct thread *thread, struct map *map)
 
 	arch = normalize_arch(thread->mg->machine->env->arch);
 
-	if (!strcmp(arch, "x86"))
+	if (!strcmp(arch, "x86")) {
 		if (dso_type != DSO__TYPE_64BIT)
 			register_func = register_x86_32_unwind_libunwind_ops;
+	} else if (!strcmp(arch, "arm64") || !strcmp(arch, "arm")) {
+		if (dso_type == DSO__TYPE_64BIT)
+			register_func = register_arm64_unwind_libunwind_ops;
+	}
 
 	if (register_func) {
 		ret = register_func(thread);
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 43f9f66..e203aa9 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -56,6 +56,16 @@ register_x86_32_unwind_libunwind_ops(struct thread *thread __maybe_unused)
 }
 #endif
 
+#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT
+int register_arm64_unwind_libunwind_ops(struct thread *thread);
+#else
+static inline int
+register_arm64_unwind_libunwind_ops(struct thread *thread __maybe_unused)
+{
+	return -1;
+}
+#endif
+
 #else
 static inline int
 unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 06/11] perf tools: Extract local libunwind code out of unwind-libunwind.c
  2016-05-28 11:59 ` [PATCH v6 06/11] perf tools: Extract local libunwind code out of unwind-libunwind.c He Kuang
@ 2016-05-28 12:10   ` Wangnan (F)
  2016-05-30  3:22     ` [PATCH v6 06/11 1 update 1/2] perf tools: Rename unwind-libunwind.c to unwind-libunwind-local.c He Kuang
  2016-05-30  3:24     ` [PATCH v6 06/11] perf tools: Extract local libunwind code out of unwind-libunwind.c Hekuang
  0 siblings, 2 replies; 27+ messages in thread
From: Wangnan (F) @ 2016-05-28 12:10 UTC (permalink / raw)
  To: He Kuang, peterz, mingo, acme, alexander.shishkin, jolsa,
	jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel



On 2016/5/28 19:59, He Kuang wrote:
> This patch extracts codes related to specific arithecture out of
> unwind-libunwind.c. The extrated part are only built if local
> libunwind is supported.
>
> Signed-off-by: He Kuang <hekuang@huawei.com>
> ---
>   tools/perf/util/Build                    |   1 +
>   tools/perf/util/unwind-libunwind-local.c | 677 ++++++++++++++++++++++++++++++
>   tools/perf/util/unwind-libunwind.c       | 694 +------------------------------
>   3 files changed, 679 insertions(+), 693 deletions(-)
>   create mode 100644 tools/perf/util/unwind-libunwind-local.c
>
Please use 'git format-patch -M' to avoid such a large patch.

Thank you.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v6 06/11 1 update 1/2] perf tools: Rename unwind-libunwind.c to unwind-libunwind-local.c
  2016-05-28 12:10   ` Wangnan (F)
@ 2016-05-30  3:22     ` He Kuang
  2016-05-30  3:22       ` [PATCH v6 06/11 1 update 2/2] perf tools: Extract common API out of unwind-libunwind-local.c He Kuang
  2016-05-30  3:24     ` [PATCH v6 06/11] perf tools: Extract local libunwind code out of unwind-libunwind.c Hekuang
  1 sibling, 1 reply; 27+ messages in thread
From: He Kuang @ 2016-05-30  3:22 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

Since unwind-libunwind.c contains code for specific arithecture, we
change it's name to unwind-libunwind-local.c, and let it only be built
if local libunwind is supported.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/util/Build                                            | 2 +-
 tools/perf/util/{unwind-libunwind.c => unwind-libunwind-local.c} | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename tools/perf/util/{unwind-libunwind.c => unwind-libunwind-local.c} (100%)

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 8c6c8a0..5e23d85 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-local.o
 
 libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o
 
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind-local.c
similarity index 100%
rename from tools/perf/util/unwind-libunwind.c
rename to tools/perf/util/unwind-libunwind-local.c
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v6 06/11 1 update 2/2] perf tools: Extract common API out of unwind-libunwind-local.c
  2016-05-30  3:22     ` [PATCH v6 06/11 1 update 1/2] perf tools: Rename unwind-libunwind.c to unwind-libunwind-local.c He Kuang
@ 2016-05-30  3:22       ` He Kuang
  0 siblings, 0 replies; 27+ messages in thread
From: He Kuang @ 2016-05-30  3:22 UTC (permalink / raw)
  To: peterz, mingo, acme, alexander.shishkin, jolsa, wangnan0,
	hekuang, jpoimboe, ak, eranian, namhyung, adrian.hunter, sukadev,
	masami.hiramatsu.pt, tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel

This patch extracts common unwind-libunwind APIs out of
unwind-libunwind-local.c, this part will be used by both local and
remote libunwind.

Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/perf/util/Build                    |  1 +
 tools/perf/util/unwind-libunwind-local.c | 32 ------------------------------
 tools/perf/util/unwind-libunwind.c       | 34 ++++++++++++++++++++++++++++++++
 3 files changed, 35 insertions(+), 32 deletions(-)
 create mode 100644 tools/perf/util/unwind-libunwind.c

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 5e23d85..004fb1d 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -100,6 +100,7 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o
 
 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 libperf-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind-local.o
+libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
 
 libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o
 
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index 93d2d8e..37e53f8 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -692,35 +692,3 @@ void register_local_unwind_libunwind_ops(struct thread *thread)
 {
 	thread->unwind_libunwind_ops = &_unwind_libunwind_ops;
 }
-
-int unwind__prepare_access(struct thread *thread)
-{
-	register_local_unwind_libunwind_ops(thread);
-
-	return thread->unwind_libunwind_ops->prepare_access(thread);
-}
-
-void unwind__flush_access(struct thread *thread)
-{
-	if (thread->unwind_libunwind_ops)
-		thread->unwind_libunwind_ops->flush_access(thread);
-}
-
-void unwind__finish_access(struct thread *thread)
-{
-	if (thread->unwind_libunwind_ops)
-		thread->unwind_libunwind_ops->finish_access(thread);
-}
-
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
-			 struct thread *thread,
-			 struct perf_sample *data, int max_stack)
-{
-	if (thread->unwind_libunwind_ops)
-		return thread->unwind_libunwind_ops->get_entries(cb, arg,
-								 thread,
-								 data,
-								 max_stack);
-	else
-		return 0;
-}
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
new file mode 100644
index 0000000..40d0453
--- /dev/null
+++ b/tools/perf/util/unwind-libunwind.c
@@ -0,0 +1,34 @@
+#include "unwind.h"
+#include "thread.h"
+
+int unwind__prepare_access(struct thread *thread)
+{
+	register_local_unwind_libunwind_ops(thread);
+
+	return thread->unwind_libunwind_ops->prepare_access(thread);
+}
+
+void unwind__flush_access(struct thread *thread)
+{
+	if (thread->unwind_libunwind_ops)
+		thread->unwind_libunwind_ops->flush_access(thread);
+}
+
+void unwind__finish_access(struct thread *thread)
+{
+	if (thread->unwind_libunwind_ops)
+		thread->unwind_libunwind_ops->finish_access(thread);
+}
+
+int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+			 struct thread *thread,
+			 struct perf_sample *data, int max_stack)
+{
+	if (thread->unwind_libunwind_ops)
+		return thread->unwind_libunwind_ops->get_entries(cb, arg,
+								 thread,
+								 data,
+								 max_stack);
+	else
+		return 0;
+}
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 06/11] perf tools: Extract local libunwind code out of unwind-libunwind.c
  2016-05-28 12:10   ` Wangnan (F)
  2016-05-30  3:22     ` [PATCH v6 06/11 1 update 1/2] perf tools: Rename unwind-libunwind.c to unwind-libunwind-local.c He Kuang
@ 2016-05-30  3:24     ` Hekuang
  1 sibling, 0 replies; 27+ messages in thread
From: Hekuang @ 2016-05-30  3:24 UTC (permalink / raw)
  To: Wangnan (F),
	peterz, mingo, acme, alexander.shishkin, jolsa, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern
  Cc: linux-kernel



在 2016/5/28 20:10, Wangnan (F) 写道:
>
>
> On 2016/5/28 19:59, He Kuang wrote:
>> This patch extracts codes related to specific arithecture out of
>> unwind-libunwind.c. The extrated part are only built if local
>> libunwind is supported.
>>
>> Signed-off-by: He Kuang <hekuang@huawei.com>
>> ---
>>   tools/perf/util/Build                    |   1 +
>>   tools/perf/util/unwind-libunwind-local.c | 677 
>> ++++++++++++++++++++++++++++++
>>   tools/perf/util/unwind-libunwind.c       | 694 
>> +------------------------------
>>   3 files changed, 679 insertions(+), 693 deletions(-)
>>   create mode 100644 tools/perf/util/unwind-libunwind-local.c
>>
> Please use 'git format-patch -M' to avoid such a large patch.

Currently is not a 100% similar rename, I split this patch into a
rename and a small diff.
>
> Thank you.
>
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 04/11] perf tools: Move unwind__prepare_access from thread_new into thread__insert_map
  2016-05-28 11:59 ` [PATCH v6 04/11] perf tools: Move unwind__prepare_access from thread_new into thread__insert_map He Kuang
@ 2016-05-30  8:52   ` Jiri Olsa
  0 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2016-05-30  8:52 UTC (permalink / raw)
  To: He Kuang
  Cc: peterz, mingo, acme, alexander.shishkin, wangnan0, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern, linux-kernel

On Sat, May 28, 2016 at 11:59:53AM +0000, He Kuang wrote:
> For determine the libunwind methods to use, we should get the
> 32bit/64bit information from maps of a thread. When a thread is newly
> created, the information is not prepared. This patch moves
> unwind__prepare_access() into thread__insert_map() so we can get the
> information we need from maps.
> 
> Signed-off-by: He Kuang <hekuang@huawei.com>
> ---
>  tools/perf/util/thread.c           | 7 ++-----
>  tools/perf/util/unwind-libunwind.c | 7 +++----
>  2 files changed, 5 insertions(+), 9 deletions(-)
> 
> diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
> index 6d3900c..045477d 100644
> --- a/tools/perf/util/thread.c
> +++ b/tools/perf/util/thread.c
> @@ -43,11 +43,6 @@ struct thread *thread__new(pid_t pid, pid_t tid)
>  		thread->cpu = -1;
>  		INIT_LIST_HEAD(&thread->comm_list);
>  
> -		register_local_unwind_libunwind_ops(thread);
> -
> -		if (unwind__prepare_access(thread) < 0)
> -			goto err_thread;
> -
>  		comm_str = malloc(32);
>  		if (!comm_str)
>  			goto err_thread;
> @@ -207,6 +202,8 @@ void thread__insert_map(struct thread *thread, struct map *map)
>  {
>  	map_groups__fixup_overlappings(thread->mg, map, stderr);
>  	map_groups__insert(thread->mg, map);
> +
> +	unwind__prepare_access(thread);

so thread__insert_map does not return value,
I think we should change it now when it calls
unwind__prepare_access

I was also thinking to keepcall unwind__prepare_access
separatelly but this function seems to fit better

thanks,
jirka

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 05/11] perf tools: Separate local/remote libunwind config
  2016-05-28 11:59 ` [PATCH v6 05/11] perf tools: Separate local/remote libunwind config He Kuang
@ 2016-05-30  8:52   ` Jiri Olsa
  0 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2016-05-30  8:52 UTC (permalink / raw)
  To: He Kuang
  Cc: peterz, mingo, acme, alexander.shishkin, wangnan0, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern, linux-kernel

On Sat, May 28, 2016 at 11:59:54AM +0000, He Kuang wrote:

SNIP

> diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
> index 6f9f566..3a304a3 100644
> --- a/tools/perf/config/Makefile
> +++ b/tools/perf/config/Makefile
> @@ -354,10 +354,24 @@ ifeq ($(ARCH),powerpc)
>  endif
>  
>  ifndef NO_LIBUNWIND
> +  have_libunwind :=
>    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

changelog says it's just switch, then why do we need to add above setup?

jirka

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 10/11] perf callchain: Support x86 target platform
  2016-05-28 11:59 ` [PATCH v6 10/11] perf callchain: Support x86 target platform He Kuang
@ 2016-05-30  8:52   ` Jiri Olsa
  2016-05-30  8:53   ` Jiri Olsa
  2016-05-30  8:53   ` Jiri Olsa
  2 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2016-05-30  8:52 UTC (permalink / raw)
  To: He Kuang
  Cc: peterz, mingo, acme, alexander.shishkin, wangnan0, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern, linux-kernel

On Sat, May 28, 2016 at 11:59:59AM +0000, He Kuang wrote:

SNIP

> --- /dev/null
> +++ b/tools/perf/arch/x86/util/unwind-libunwind_x86_32.c
> @@ -0,0 +1,21 @@
> +#define REMOTE_UNWIND_LIBUNWIND
> +
> +#define LIBUNWIND__ARCH_REG_ID libunwind__x86_reg_id
> +
> +#include "unwind.h"
> +#include "debug.h"
> +#include "libunwind-x86.h"
> +#include <../../../../../arch/x86/include/uapi/asm/perf_regs.h>
> +
> +#undef HAVE_ARCH_X86_64_SUPPORT
> +#include "unwind-libunwind.c"
> +
> +#undef NO_LIBUNWIND_DEBUG_FRAME
> +#define NO_LIBUNWIND_DEBUG_FRAME
> +#include "util/unwind-libunwind-local.c"
> +
> +int register_x86_32_unwind_libunwind_ops(struct thread *thread)
> +{
> +	thread->unwind_libunwind_ops = &_unwind_libunwind_ops;
> +	return 0;
> +}

hum, how about export the arch ops:

struct unwind_libunwind_ops *x86_32_unwind_libunwind_ops = &_unwind_libunwind_ops;

and have single unwind__register_ops(ops) function

jirka

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 08/11] perf tools: Show warnings for unsupported cross-platform unwind
  2016-05-28 11:59 ` [PATCH v6 08/11] perf tools: Show warnings for unsupported cross-platform unwind He Kuang
@ 2016-05-30  8:53   ` Jiri Olsa
  0 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2016-05-30  8:53 UTC (permalink / raw)
  To: He Kuang
  Cc: peterz, mingo, acme, alexander.shishkin, wangnan0, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern, linux-kernel

On Sat, May 28, 2016 at 11:59:57AM +0000, He Kuang wrote:
> Currently, perf script uses host unwind methods to parse perf.data
> callchain info regardless of the target architecture. So we get wrong
> result without any warnings when unwinding callchains of x86(32-bit)
> on x86(64-bit) machine.
> 
> This patch shows warning messages when we do remote unwind x86(32-bit)
> on other machines. Same thing for other platforms will be added in
> next patches.
> 
> Signed-off-by: He Kuang <hekuang@huawei.com>
> ---
>  tools/perf/config/Makefile         |  8 ++++++++
>  tools/perf/util/thread.c           |  2 +-
>  tools/perf/util/unwind-libunwind.c | 30 +++++++++++++++++++++++++++++-
>  tools/perf/util/unwind.h           |  5 +++--
>  4 files changed, 41 insertions(+), 4 deletions(-)
> 
> diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
> index 3a304a3..e156f76 100644
> --- a/tools/perf/config/Makefile
> +++ b/tools/perf/config/Makefile
> @@ -355,6 +355,14 @@ 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

this hunk together with the ifdef in 
unwind__prepare_access should go to patch:

  perf callchain: Support x86 target platform

thanks
jirka

SNIP

> +	arch = normalize_arch(thread->mg->machine->env->arch);
> +
> +	if (!strcmp(arch, "x86")) {
> +		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

SNIP

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 10/11] perf callchain: Support x86 target platform
  2016-05-28 11:59 ` [PATCH v6 10/11] perf callchain: Support x86 target platform He Kuang
  2016-05-30  8:52   ` Jiri Olsa
@ 2016-05-30  8:53   ` Jiri Olsa
  2016-05-30  8:53   ` Jiri Olsa
  2 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2016-05-30  8:53 UTC (permalink / raw)
  To: He Kuang
  Cc: peterz, mingo, acme, alexander.shishkin, wangnan0, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern, linux-kernel

On Sat, May 28, 2016 at 11:59:59AM +0000, He Kuang wrote:

SNIP

> diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
> index b391e3e..849fec1 100644
> --- a/tools/perf/util/unwind-libunwind-local.c
> +++ b/tools/perf/util/unwind-libunwind-local.c
> @@ -5,7 +5,9 @@
>  #include <unistd.h>
>  #include <sys/mman.h>
>  #include <linux/list.h>
> +#ifndef REMOTE_UNWIND_LIBUNWIND
>  #include <libunwind.h>
> +#endif
>  #include "callchain.h"
>  #include "thread.h"
>  #include "session.h"
> @@ -671,7 +673,9 @@ _unwind_libunwind_ops = {
>  	.get_entries    = _unwind__get_entries,
>  };
>  
> +#ifndef REMOTE_UNWIND_LIBUNWIND
>  void register_local_unwind_libunwind_ops(struct thread *thread)
>  {
>  	thread->unwind_libunwind_ops = &_unwind_libunwind_ops;
>  }
> +#endif

above hunks should go to separate patch

however I still think it'd be more clear if we separate the code like:

code template		- util/unwind-libunwind.c
arch template		- arch/x86/util/unwind-libunwind.c

wrapper for local	- util/unwind-libunwind-local.c
wrapper for x86_32	- arch/x86/util/unwind-libunwind-x86_32.c
wrapper for arm64	- arch/x86/util/unwind-libunwind-arm64.c

jirka

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 10/11] perf callchain: Support x86 target platform
  2016-05-28 11:59 ` [PATCH v6 10/11] perf callchain: Support x86 target platform He Kuang
  2016-05-30  8:52   ` Jiri Olsa
  2016-05-30  8:53   ` Jiri Olsa
@ 2016-05-30  8:53   ` Jiri Olsa
  2016-05-30  9:11     ` Hekuang
  2 siblings, 1 reply; 27+ messages in thread
From: Jiri Olsa @ 2016-05-30  8:53 UTC (permalink / raw)
  To: He Kuang
  Cc: peterz, mingo, acme, alexander.shishkin, wangnan0, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern, linux-kernel

On Sat, May 28, 2016 at 11:59:59AM +0000, He Kuang wrote:
> Support x86(32-bit) cross platform callchain unwind.
> 
> Signed-off-by: He Kuang <hekuang@huawei.com>
> ---
>  tools/perf/arch/Build                              |  1 +
>  tools/perf/arch/x86/util/unwind-libunwind.c        |  7 ++++---
>  tools/perf/arch/x86/util/unwind-libunwind_x86_32.c | 21 +++++++++++++++++++++
>  tools/perf/util/unwind-libunwind-local.c           |  4 ++++
>  tools/perf/util/unwind-libunwind.c                 | 19 +++++++++++++------
>  tools/perf/util/unwind.h                           | 10 ++++++++++
>  6 files changed, 53 insertions(+), 9 deletions(-)
>  create mode 100644 tools/perf/arch/x86/util/unwind-libunwind_x86_32.c
> 
> diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build
> index 109eb75..3fc4af1 100644
> --- a/tools/perf/arch/Build
> +++ b/tools/perf/arch/Build
> @@ -1,2 +1,3 @@
>  libperf-y += common.o
>  libperf-y += $(ARCH)/
> +libperf-$(CONFIG_LIBUNWIND_X86)      += x86/util/unwind-libunwind_x86_32.o

we have Build file directly in arch/x86/util/

if you do it like this to include generic file easily
we better fix the include then

jirka

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 03/11] perf tools: Introducing struct unwind_libunwind_ops for local unwind
  2016-05-28 11:59 ` [PATCH v6 03/11] perf tools: Introducing struct unwind_libunwind_ops for local unwind He Kuang
@ 2016-05-30  8:53   ` Jiri Olsa
  0 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2016-05-30  8:53 UTC (permalink / raw)
  To: He Kuang
  Cc: peterz, mingo, acme, alexander.shishkin, wangnan0, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern, linux-kernel

On Sat, May 28, 2016 at 11:59:52AM +0000, He Kuang wrote:
> Currently, libunwind operations are fixed, and they are chosen
> according to the host architecture. This will lead a problem that if a
> thread is run as x86_32 on x86_64 machine, perf will use libunwind
> methods for x86_64 to parse the callchain and get wrong result.
> 
> This patch changes the fixed methods of libunwind operations to
> thread/map related, and each thread can have indivadual libunwind
> operations. Local libunwind methods are registered as default value.
> 
> Signed-off-by: He Kuang <hekuang@huawei.com>
> ---
>  tools/perf/util/thread.c           |  2 ++
>  tools/perf/util/thread.h           | 14 +++++++++-
>  tools/perf/util/unwind-libunwind.c | 55 ++++++++++++++++++++++++++++++++++----
>  tools/perf/util/unwind.h           |  5 ++++
>  4 files changed, 70 insertions(+), 6 deletions(-)
> 
> diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
> index 45fcb71..6d3900c 100644
> --- a/tools/perf/util/thread.c
> +++ b/tools/perf/util/thread.c
> @@ -43,6 +43,8 @@ struct thread *thread__new(pid_t pid, pid_t tid)
>  		thread->cpu = -1;
>  		INIT_LIST_HEAD(&thread->comm_list);
>  
> +		register_local_unwind_libunwind_ops(thread);
> +
>  		if (unwind__prepare_access(thread) < 0)
>  			goto err_thread;
>  
> diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
> index aa3a8ff..647b011 100644
> --- a/tools/perf/util/thread.h
> +++ b/tools/perf/util/thread.h
> @@ -12,6 +12,17 @@
>  
>  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);
> +};
> +

this should rather go to util/unwind.h

thanks,
jirka

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 10/11] perf callchain: Support x86 target platform
  2016-05-30  8:53   ` Jiri Olsa
@ 2016-05-30  9:11     ` Hekuang
  2016-05-30  9:30       ` Jiri Olsa
  0 siblings, 1 reply; 27+ messages in thread
From: Hekuang @ 2016-05-30  9:11 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: peterz, mingo, acme, alexander.shishkin, wangnan0, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern, linux-kernel

hi

在 2016/5/30 16:53, Jiri Olsa 写道:
> On Sat, May 28, 2016 at 11:59:59AM +0000, He Kuang wrote:
>> Support x86(32-bit) cross platform callchain unwind.
>>
>> Signed-off-by: He Kuang <hekuang@huawei.com>
>> ---
>>   tools/perf/arch/Build                              |  1 +
>>   tools/perf/arch/x86/util/unwind-libunwind.c        |  7 ++++---
>>   tools/perf/arch/x86/util/unwind-libunwind_x86_32.c | 21 +++++++++++++++++++++
>>   tools/perf/util/unwind-libunwind-local.c           |  4 ++++
>>   tools/perf/util/unwind-libunwind.c                 | 19 +++++++++++++------
>>   tools/perf/util/unwind.h                           | 10 ++++++++++
>>   6 files changed, 53 insertions(+), 9 deletions(-)
>>   create mode 100644 tools/perf/arch/x86/util/unwind-libunwind_x86_32.c
>>
>> diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build
>> index 109eb75..3fc4af1 100644
>> --- a/tools/perf/arch/Build
>> +++ b/tools/perf/arch/Build
>> @@ -1,2 +1,3 @@
>>   libperf-y += common.o
>>   libperf-y += $(ARCH)/
>> +libperf-$(CONFIG_LIBUNWIND_X86)      += x86/util/unwind-libunwind_x86_32.o
> we have Build file directly in arch/x86/util/
>
> if you do it like this to include generic file easily
> we better fix the include then

This is because "libperf-y += $(ARCH)" will only sink into $(ARCH) folder,
for example on x86_64, only tools/perf/arch/x86 will be built. But for
  remote libunwind, we also need
  'tools/perf/arch/arm64/util/unwind-libunwind.o', while arm64 folder is
not added to libperf-y. Is there a gracefull to deal with this?

> jirka
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 10/11] perf callchain: Support x86 target platform
  2016-05-30  9:11     ` Hekuang
@ 2016-05-30  9:30       ` Jiri Olsa
  2016-05-30 10:58         ` Hekuang
  0 siblings, 1 reply; 27+ messages in thread
From: Jiri Olsa @ 2016-05-30  9:30 UTC (permalink / raw)
  To: Hekuang
  Cc: peterz, mingo, acme, alexander.shishkin, wangnan0, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern, linux-kernel

On Mon, May 30, 2016 at 05:11:35PM +0800, Hekuang wrote:
> hi
> 
> 在 2016/5/30 16:53, Jiri Olsa 写道:
> > On Sat, May 28, 2016 at 11:59:59AM +0000, He Kuang wrote:
> > > Support x86(32-bit) cross platform callchain unwind.
> > > 
> > > Signed-off-by: He Kuang <hekuang@huawei.com>
> > > ---
> > >   tools/perf/arch/Build                              |  1 +
> > >   tools/perf/arch/x86/util/unwind-libunwind.c        |  7 ++++---
> > >   tools/perf/arch/x86/util/unwind-libunwind_x86_32.c | 21 +++++++++++++++++++++
> > >   tools/perf/util/unwind-libunwind-local.c           |  4 ++++
> > >   tools/perf/util/unwind-libunwind.c                 | 19 +++++++++++++------
> > >   tools/perf/util/unwind.h                           | 10 ++++++++++
> > >   6 files changed, 53 insertions(+), 9 deletions(-)
> > >   create mode 100644 tools/perf/arch/x86/util/unwind-libunwind_x86_32.c
> > > 
> > > diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build
> > > index 109eb75..3fc4af1 100644
> > > --- a/tools/perf/arch/Build
> > > +++ b/tools/perf/arch/Build
> > > @@ -1,2 +1,3 @@
> > >   libperf-y += common.o
> > >   libperf-y += $(ARCH)/
> > > +libperf-$(CONFIG_LIBUNWIND_X86)      += x86/util/unwind-libunwind_x86_32.o
> > we have Build file directly in arch/x86/util/
> > 
> > if you do it like this to include generic file easily
> > we better fix the include then
> 
> This is because "libperf-y += $(ARCH)" will only sink into $(ARCH) folder,
> for example on x86_64, only tools/perf/arch/x86 will be built. But for
>  remote libunwind, we also need
>  'tools/perf/arch/arm64/util/unwind-libunwind.o', while arm64 folder is
> not added to libperf-y. Is there a gracefull to deal with this?

you just need to include the file, right?

I think it's ok to include arch/arm/....c
from arch/x86/util/unwind-libunwind-arm64.c

jirka

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 10/11] perf callchain: Support x86 target platform
  2016-05-30  9:30       ` Jiri Olsa
@ 2016-05-30 10:58         ` Hekuang
  2016-05-30 14:24           ` Jiri Olsa
  0 siblings, 1 reply; 27+ messages in thread
From: Hekuang @ 2016-05-30 10:58 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: peterz, mingo, acme, alexander.shishkin, wangnan0, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern, linux-kernel



在 2016/5/30 17:30, Jiri Olsa 写道:
> On Mon, May 30, 2016 at 05:11:35PM +0800, Hekuang wrote:
>> hi
>>
>> 在 2016/5/30 16:53, Jiri Olsa 写道:
>>> On Sat, May 28, 2016 at 11:59:59AM +0000, He Kuang wrote:
>>>> Support x86(32-bit) cross platform callchain unwind.
>>>>
>>>> Signed-off-by: He Kuang <hekuang@huawei.com>
>>>> ---
>>>>    tools/perf/arch/Build                              |  1 +
>>>>    tools/perf/arch/x86/util/unwind-libunwind.c        |  7 ++++---
>>>>    tools/perf/arch/x86/util/unwind-libunwind_x86_32.c | 21 +++++++++++++++++++++
>>>>    tools/perf/util/unwind-libunwind-local.c           |  4 ++++
>>>>    tools/perf/util/unwind-libunwind.c                 | 19 +++++++++++++------
>>>>    tools/perf/util/unwind.h                           | 10 ++++++++++
>>>>    6 files changed, 53 insertions(+), 9 deletions(-)
>>>>    create mode 100644 tools/perf/arch/x86/util/unwind-libunwind_x86_32.c
>>>>
>>>> diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build
>>>> index 109eb75..3fc4af1 100644
>>>> --- a/tools/perf/arch/Build
>>>> +++ b/tools/perf/arch/Build
>>>> @@ -1,2 +1,3 @@
>>>>    libperf-y += common.o
>>>>    libperf-y += $(ARCH)/
>>>> +libperf-$(CONFIG_LIBUNWIND_X86)      += x86/util/unwind-libunwind_x86_32.o
>>> we have Build file directly in arch/x86/util/
>>>
>>> if you do it like this to include generic file easily
>>> we better fix the include then
>> This is because "libperf-y += $(ARCH)" will only sink into $(ARCH) folder,
>> for example on x86_64, only tools/perf/arch/x86 will be built. But for
>>   remote libunwind, we also need
>>   'tools/perf/arch/arm64/util/unwind-libunwind.o', while arm64 folder is
>> not added to libperf-y. Is there a gracefull to deal with this?
> you just need to include the file, right?
>
> I think it's ok to include arch/arm/....c
> from arch/x86/util/unwind-libunwind-arm64.c
>
> jirka

By following your advise, if ARCH=x86, the file tree will
be like this:

arch/x86
-    arch/x86/util/unwind-libunwind-arm64.c
-    arch/x86/util/unwind-libunwind-x86_32.c
-    arch/x86/util/unwind-libunwind-x86_64.c
-    arch/x86/util/unwind-libunwind-arm.c

And for ARCH=arm (host machine is arm, it should be considered)
arch/arm
-    arch/arm/util/unwind-libunwind-arm64.c
-    arch/arm/util/unwind-libunwind-x86_32.c
-    arch/arm/util/unwind-libunwind-x86_64.c
-    arch/arm/util/unwind-libunwind-arm.c

For arm64:
arch/arm64
-    arch/arm64/util/unwind-libunwind-arm64.c
-    arch/arm64/util/unwind-libunwind-x86_32.c
-    arch/arm64/util/unwind-libunwind-x86_64.c
-    arch/arm64/util/unwind-libunwind-arm.c

But in my patch, the file tree is like this:

arch
-    arch/arm64/util/unwind-libunwind-arm64.c
-    arch/x86/util/unwind-libunwind-x86_64.c
-    arch/x86/util/unwind-libunwind-x86_32.c
-    arch/arm/util/unwind-libunwind-arm.c

I admit that

+libperf-$(CONFIG_LIBUNWIND_X86)      += x86/util/unwind-libunwind_x86_32.o

is not so good, but do you think the above file tree is
too redunctant?

Thank you.
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v6 10/11] perf callchain: Support x86 target platform
  2016-05-30 10:58         ` Hekuang
@ 2016-05-30 14:24           ` Jiri Olsa
  0 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2016-05-30 14:24 UTC (permalink / raw)
  To: Hekuang
  Cc: peterz, mingo, acme, alexander.shishkin, wangnan0, jpoimboe, ak,
	eranian, namhyung, adrian.hunter, sukadev, masami.hiramatsu.pt,
	tumanova, kan.liang, penberg, dsahern, linux-kernel

On Mon, May 30, 2016 at 06:58:40PM +0800, Hekuang wrote:

SNIP

> > I think it's ok to include arch/arm/....c
> > from arch/x86/util/unwind-libunwind-arm64.c
> > 
> > jirka
> 
> By following your advise, if ARCH=x86, the file tree will
> be like this:
> 
> arch/x86
> -    arch/x86/util/unwind-libunwind-arm64.c
> -    arch/x86/util/unwind-libunwind-x86_32.c
> -    arch/x86/util/unwind-libunwind-x86_64.c
> -    arch/x86/util/unwind-libunwind-arm.c
> 
> And for ARCH=arm (host machine is arm, it should be considered)
> arch/arm
> -    arch/arm/util/unwind-libunwind-arm64.c
> -    arch/arm/util/unwind-libunwind-x86_32.c
> -    arch/arm/util/unwind-libunwind-x86_64.c
> -    arch/arm/util/unwind-libunwind-arm.c
> 
> For arm64:
> arch/arm64
> -    arch/arm64/util/unwind-libunwind-arm64.c
> -    arch/arm64/util/unwind-libunwind-x86_32.c
> -    arch/arm64/util/unwind-libunwind-x86_64.c
> -    arch/arm64/util/unwind-libunwind-arm.c
> 
> But in my patch, the file tree is like this:
> 
> arch
> -    arch/arm64/util/unwind-libunwind-arm64.c
> -    arch/x86/util/unwind-libunwind-x86_64.c
> -    arch/x86/util/unwind-libunwind-x86_32.c
> -    arch/arm/util/unwind-libunwind-arm.c
> 
> I admit that
> 
> +libperf-$(CONFIG_LIBUNWIND_X86)      += x86/util/unwind-libunwind_x86_32.o
> 
> is not so good, but do you think the above file tree is
> too redunctant?

i see.. we could leave it like that, I just wish
it'd be more clear.. one last thought:

how about moving libunwind arch files into special folder:

  util/libunwind/arm64.c
  util/libunwind/x86_32.c
  util/libunwind/x86_64.c
  util/libunwind/arm.c

thanks,
jirka

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2016-05-30 14:24 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-28 11:59 [PATCH v6 00/11] Add support for remote unwind He Kuang
2016-05-28 11:59 ` [PATCH v6 01/11] perf tools: Use LIBUNWIND_DIR for remote libunwind feature check He Kuang
2016-05-28 11:59 ` [PATCH v6 02/11] perf tools: Decouple thread->address_space on libunwind He Kuang
2016-05-28 11:59 ` [PATCH v6 03/11] perf tools: Introducing struct unwind_libunwind_ops for local unwind He Kuang
2016-05-30  8:53   ` Jiri Olsa
2016-05-28 11:59 ` [PATCH v6 04/11] perf tools: Move unwind__prepare_access from thread_new into thread__insert_map He Kuang
2016-05-30  8:52   ` Jiri Olsa
2016-05-28 11:59 ` [PATCH v6 05/11] perf tools: Separate local/remote libunwind config He Kuang
2016-05-30  8:52   ` Jiri Olsa
2016-05-28 11:59 ` [PATCH v6 06/11] perf tools: Extract local libunwind code out of unwind-libunwind.c He Kuang
2016-05-28 12:10   ` Wangnan (F)
2016-05-30  3:22     ` [PATCH v6 06/11 1 update 1/2] perf tools: Rename unwind-libunwind.c to unwind-libunwind-local.c He Kuang
2016-05-30  3:22       ` [PATCH v6 06/11 1 update 2/2] perf tools: Extract common API out of unwind-libunwind-local.c He Kuang
2016-05-30  3:24     ` [PATCH v6 06/11] perf tools: Extract local libunwind code out of unwind-libunwind.c Hekuang
2016-05-28 11:59 ` [PATCH v6 07/11] perf tools: Export normalize_arch() function He Kuang
2016-05-28 11:59 ` [PATCH v6 08/11] perf tools: Show warnings for unsupported cross-platform unwind He Kuang
2016-05-30  8:53   ` Jiri Olsa
2016-05-28 11:59 ` [PATCH v6 09/11] perf tools: Change fixed name of libunwind__arch_reg_id to macro He Kuang
2016-05-28 11:59 ` [PATCH v6 10/11] perf callchain: Support x86 target platform He Kuang
2016-05-30  8:52   ` Jiri Olsa
2016-05-30  8:53   ` Jiri Olsa
2016-05-30  8:53   ` Jiri Olsa
2016-05-30  9:11     ` Hekuang
2016-05-30  9:30       ` Jiri Olsa
2016-05-30 10:58         ` Hekuang
2016-05-30 14:24           ` Jiri Olsa
2016-05-28 12:00 ` [PATCH v6 11/11] perf callchain: Support aarch64 cross-platform He Kuang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).