Skip to contentSkip to conversation

Add support for remote unwind

PATCH Applied He Kuang 5 participants 25 messages May 10, 2016 – May 12, 2016

Subsystems (2)

v2 of 9 Applied Latest is v9 →

lore
Share & tools
lore

He Kuang

author
#0 lore raw

v2 cover Add support for remote unwind

v1 url:
http://thread.gmane.org/gmane.linux.kernel/2216256

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 adds build tests for the supported platforms for remote unwinding, and 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 1071 [000] 417.567832: probe:sys_close: (c1169d60)

                  c1169d61 sys_close ([kernel.kallsyms])
                  c189c0d7 sysenter_past_esp ([kernel.kallsyms])
                  b77c8ba9 [unknown] ([vdso32])

after:

hello 1071 [000] 417.567832: probe:sys_close: (c1169d60)

                  c1169d61 sys_close ([kernel.kallsyms])
                  c189c0d7 sysenter_past_esp ([kernel.kallsyms])
                  b77c8ba9 [unknown] ([vdso32])
                  b76e51cc close (/lib/libc-2.22.so)
                   804842e fib (/tmp/hello)
                   804849d main (/tmp/hello)
                  b762546e __libc_start_main (/lib/libc-2.22.so)
                   8048341 _start (/tmp/hello)

v2:

- Explain the reason why we can omit dwarf judgement when recording in commit message.
- Elaborate on why we need to add a custom vdso path option, and change the type name to DSO_BINARY_TYPE__VDSO.
- Hide the build tests status for cross platform unwind.
- Keep generic version of libunwind-debug-frame test.
- Put 32/64-bit test functions into separate patch.
- Extract unwind related functions to unwind-libunwind.c and add new file for common parts used by both local and remote unwind.
- Eliminate most of the ifdefs in .c file.

Thanks.

He Kuang (9):
perf tools: Omit DWARF judgement when recording dwarf callchain perf script: Add options for custom vdso path
perf build: Add build-test for libunwind cross-platforms support perf build: Add build-test for debug-frame on arm/arm64 perf tools: Add methods to test dso is 64-bit or 32-bit perf tools: Promote proper messages for cross-platform unwind perf callchain: Add support for cross-platform unwind perf callchain: Support x86 target platform
perf callchain: Support aarch64 cross-platform

 tools/build/Makefile.feature                       |   8 +-
 tools/build/feature/Makefile                       |  23 +++++
 tools/build/feature/test-libunwind-aarch64.c       |  26 +++++
 tools/build/feature/test-libunwind-arm.c           |  27 +++++
 .../feature/test-libunwind-debug-frame-aarch64.c   |  16 +++
 .../build/feature/test-libunwind-debug-frame-arm.c |  16 +++
 tools/build/feature/test-libunwind-x86.c           |  27 +++++
 tools/build/feature/test-libunwind-x86_64.c        |  27 +++++
 .../arch/arm64/include/libunwind/libunwind-arch.h  |  18 ++++
 tools/perf/arch/arm64/util/unwind-libunwind.c      |   5 +-
 .../arch/x86/include/libunwind/libunwind-arch.h    |  18 ++++
 tools/perf/arch/x86/util/unwind-libunwind.c        |  42 ++++++++
 tools/perf/builtin-script.c                        |   2 +
 tools/perf/config/Makefile                         |  35 ++++++-
 tools/perf/util/Build                              |  13 ++-
 tools/perf/util/dso.c                              |   7 ++
 tools/perf/util/dso.h                              |   1 +
 tools/perf/util/symbol-elf.c                       |  16 +++
 tools/perf/util/symbol.c                           |  50 +++++++++
 tools/perf/util/symbol.h                           |   3 +
 tools/perf/util/thread.c                           |   7 +-
 tools/perf/util/thread.h                           |  14 ++-
 tools/perf/util/unwind-libunwind.c                 |  49 +++++++--
 tools/perf/util/unwind-libunwind_common.c          | 113 +++++++++++++++++++++
 tools/perf/util/unwind.h                           |  48 +++++++--
 tools/perf/util/util.c                             |   2 -
 26 files changed, 585 insertions(+), 28 deletions(-)
 create mode 100644 tools/build/feature/test-libunwind-aarch64.c
 create mode 100644 tools/build/feature/test-libunwind-arm.c
 create mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c
 create mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c
 create mode 100644 tools/build/feature/test-libunwind-x86.c
 create mode 100644 tools/build/feature/test-libunwind-x86_64.c
 create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h
 create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h
 create mode 100644 tools/perf/util/unwind-libunwind_common.c
Signature · 1 line
1.8.5.2
author
#1 lore raw

PATCH v2 1/9 perf tools: Omit DWARF judgement when recording dwarf callchain

There is no need to check for DWARF unwinding support when using the 'dwarf' callchain record method, as this will only ask the kernel to collect stack dumps for later DWARF CFI processing, which can be done in another machine, where the support for DWARF unwinding need to be present.

---
 tools/perf/util/util.c | 2 --
 1 file changed, 2 deletions(-)
tools/perf/util/util.c +0 -2
index b7766c5..e5ebfd4 100644
@@ -471,7 +471,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param)
 				       "needed for --call-graph fp\n");
 			break;
 
-#ifdef HAVE_DWARF_UNWIND_SUPPORT
 		/* Dwarf style */
 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
 			const unsigned long default_stack_dump_size = 8192;
@@ -487,7 +486,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param)
 				ret = get_stack_size(tok, &size);
 				param->dump_size = size;
 			}
-#endif /* HAVE_DWARF_UNWIND_SUPPORT */
 		} else if (!strncmp(name, "lbr", sizeof("lbr"))) {
 			if (!strtok_r(NULL, ",", &saveptr)) {
 				param->record_mode = CALLCHAIN_LBR;
Signature · 1 line
1.8.5.2
#2 lore raw

Re: [PATCH v2 1/9] perf tools: Omit DWARF judgement when recording dwarf callchain

Em Tue, May 10, 2016 at 07:40:29AM +0000, He Kuang escreveu:

Quoted 5 lines

There is no need to check for DWARF unwinding support when using the 'dwarf' callchain record method, as this will only ask the kernel to collect stack dumps for later DWARF CFI processing, which can be done in another machine, where the support for DWARF unwinding need to be present.

I had this one already applied, thanks.

- Arnaldo

Quoted 28 lines
---
 tools/perf/util/util.c | 2 --
 1 file changed, 2 deletions(-)
tools/perf/util/util.c +0 -2
index b7766c5..e5ebfd4 100644
@@ -471,7 +471,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param)
 				       "needed for --call-graph fp\n");
 			break;
 
-#ifdef HAVE_DWARF_UNWIND_SUPPORT
 		/* Dwarf style */
 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
 			const unsigned long default_stack_dump_size = 8192;
@@ -487,7 +486,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param)
 				ret = get_stack_size(tok, &size);
 				param->dump_size = size;
 			}
-#endif /* HAVE_DWARF_UNWIND_SUPPORT */
 		} else if (!strncmp(name, "lbr", sizeof("lbr"))) {
 			if (!strtok_r(NULL, ",", &saveptr)) {
 				param->record_mode = CALLCHAIN_LBR;
Signature · 1 line
1.8.5.2
author
#3 lore raw

PATCH v2 2/9 perf script: Add options for custom vdso path

In reply to He Kuang

When unwinding callchains on a different machine, vdso info should be provided so the unwind process won't be interrupted if address falls into vdso region.

Currently, perf does try to read vdso binary in '.debug' folder, but the filename of the vdso file is generated randomly based on VDSO__TEMP_FILE_NAME template, such a filename is not reliable and users need a way to provide the path of their own vdso binary file.

---
 tools/perf/builtin-script.c | 2 ++
 tools/perf/util/dso.c       | 7 +++++++
 tools/perf/util/dso.h       | 1 +
 tools/perf/util/symbol.c    | 1 +
 tools/perf/util/symbol.h    | 1 +
 5 files changed, 12 insertions(+)
tools/perf/builtin-script.c +2 -0
index 8f6ab2a..c88b547 100644
@@ -2001,6 +2001,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 		   "file", "vmlinux pathname"),
 	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
 		   "file", "kallsyms pathname"),
+	OPT_STRING(0, "vdso", &symbol_conf.vdso_name,
+		   "file", "vdso pathname"),
 	OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
 		    "When printing symbols do not display call chain"),
 	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
tools/perf/util/dso.c +7 -0
index 8e639543..6ed1cce 100644
@@ -13,6 +13,7 @@ char dso__symtab_origin(const struct dso *dso)
 	static const char origin[] = {
 		[DSO_BINARY_TYPE__KALLSYMS]			= 'k',
 		[DSO_BINARY_TYPE__VMLINUX]			= 'v',
+		[DSO_BINARY_TYPE__VDSO]				= 'D',
 		[DSO_BINARY_TYPE__JAVA_JIT]			= 'j',
 		[DSO_BINARY_TYPE__DEBUGLINK]			= 'l',
 		[DSO_BINARY_TYPE__BUILD_ID_CACHE]		= 'B',
@@ -113,6 +114,11 @@ int dso__read_binary_type_filename(const struct dso *dso,
 			 build_id_hex, build_id_hex + 2);
 		break;
 
+	case DSO_BINARY_TYPE__VDSO:
+	{
+		snprintf(filename, size, "%s", symbol_conf.vdso_name);
+		break;
+	}
 	case DSO_BINARY_TYPE__VMLINUX:
 	case DSO_BINARY_TYPE__GUEST_VMLINUX:
 	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
@@ -487,6 +493,7 @@ static void try_to_open_dso(struct dso *dso, struct machine *machine)
 	enum dso_binary_type binary_type_data[] = {
 		DSO_BINARY_TYPE__BUILD_ID_CACHE,
 		DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
+		DSO_BINARY_TYPE__VDSO,
 		DSO_BINARY_TYPE__NOT_FOUND,
 	};
 	int i = 0;
tools/perf/util/dso.h +1 -0
index 0953280..05fac98 100644
@@ -30,6 +30,7 @@ enum dso_binary_type {
 	DSO_BINARY_TYPE__KCORE,
 	DSO_BINARY_TYPE__GUEST_KCORE,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+	DSO_BINARY_TYPE__VDSO,
 	DSO_BINARY_TYPE__NOT_FOUND,
 };
 
tools/perf/util/symbol.c +1 -0
index e7588dc..4630751 100644
@@ -1363,6 +1363,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
 	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
 	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
 	case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
+	case DSO_BINARY_TYPE__VDSO:
 		return !kmod && dso->kernel == DSO_TYPE_USER;
 
 	case DSO_BINARY_TYPE__KALLSYMS:
tools/perf/util/symbol.h +1 -0
index c8b7544..4e6910e 100644
@@ -114,6 +114,7 @@ struct symbol_conf {
 			report_hierarchy;
 	const char	*vmlinux_name,
 			*kallsyms_name,
+			*vdso_name,
 			*source_prefix,
 			*field_sep;
 	const char	*default_guest_vmlinux_name,
Signature · 1 line
1.8.5.2
#4 lore raw

Re: [PATCH v2 2/9] perf script: Add options for custom vdso path

Em Tue, May 10, 2016 at 07:40:30AM +0000, He Kuang escreveu:

Quoted 8 lines

When unwinding callchains on a different machine, vdso info should be provided so the unwind process won't be interrupted if address falls into vdso region.

Currently, perf does try to read vdso binary in '.debug' folder, but the filename of the vdso file is generated randomly based on VDSO__TEMP_FILE_NAME template, such a filename is not reliable and users need a way to provide the path of their own vdso binary file.

But this becomes one more burden to the user :-\ Why not calculate a build-id from the VDSO file contents, copy it to ~/.debug/.build-id/ab/cdef01020304 and insert that into the perf.data file so that at analysis time we do all this automatically?

We can of course have a way to manually provide it, but having it as the main way for users doesn't seem a good interface. Am I missing something?

- Arnaldo

Quoted 92 lines
---
 tools/perf/builtin-script.c | 2 ++
 tools/perf/util/dso.c       | 7 +++++++
 tools/perf/util/dso.h       | 1 +
 tools/perf/util/symbol.c    | 1 +
 tools/perf/util/symbol.h    | 1 +
 5 files changed, 12 insertions(+)
tools/perf/builtin-script.c +2 -0
index 8f6ab2a..c88b547 100644
@@ -2001,6 +2001,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 		   "file", "vmlinux pathname"),
 	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
 		   "file", "kallsyms pathname"),
+	OPT_STRING(0, "vdso", &symbol_conf.vdso_name,
+		   "file", "vdso pathname"),
 	OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
 		    "When printing symbols do not display call chain"),
 	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
tools/perf/util/dso.c +7 -0
index 8e639543..6ed1cce 100644
@@ -13,6 +13,7 @@ char dso__symtab_origin(const struct dso *dso)
 	static const char origin[] = {
 		[DSO_BINARY_TYPE__KALLSYMS]			= 'k',
 		[DSO_BINARY_TYPE__VMLINUX]			= 'v',
+		[DSO_BINARY_TYPE__VDSO]				= 'D',
 		[DSO_BINARY_TYPE__JAVA_JIT]			= 'j',
 		[DSO_BINARY_TYPE__DEBUGLINK]			= 'l',
 		[DSO_BINARY_TYPE__BUILD_ID_CACHE]		= 'B',
@@ -113,6 +114,11 @@ int dso__read_binary_type_filename(const struct dso *dso,
 			 build_id_hex, build_id_hex + 2);
 		break;
 
+	case DSO_BINARY_TYPE__VDSO:
+	{
+		snprintf(filename, size, "%s", symbol_conf.vdso_name);
+		break;
+	}
 	case DSO_BINARY_TYPE__VMLINUX:
 	case DSO_BINARY_TYPE__GUEST_VMLINUX:
 	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
@@ -487,6 +493,7 @@ static void try_to_open_dso(struct dso *dso, struct machine *machine)
 	enum dso_binary_type binary_type_data[] = {
 		DSO_BINARY_TYPE__BUILD_ID_CACHE,
 		DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
+		DSO_BINARY_TYPE__VDSO,
 		DSO_BINARY_TYPE__NOT_FOUND,
 	};
 	int i = 0;
tools/perf/util/dso.h +1 -0
index 0953280..05fac98 100644
@@ -30,6 +30,7 @@ enum dso_binary_type {
 	DSO_BINARY_TYPE__KCORE,
 	DSO_BINARY_TYPE__GUEST_KCORE,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+	DSO_BINARY_TYPE__VDSO,
 	DSO_BINARY_TYPE__NOT_FOUND,
 };
 
tools/perf/util/symbol.c +1 -0
index e7588dc..4630751 100644
@@ -1363,6 +1363,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
 	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
 	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
 	case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
+	case DSO_BINARY_TYPE__VDSO:
 		return !kmod && dso->kernel == DSO_TYPE_USER;
 
 	case DSO_BINARY_TYPE__KALLSYMS:
tools/perf/util/symbol.h +1 -0
index c8b7544..4e6910e 100644
@@ -114,6 +114,7 @@ struct symbol_conf {
 			report_hierarchy;
 	const char	*vmlinux_name,
 			*kallsyms_name,
+			*vdso_name,
 			*source_prefix,
 			*field_sep;
 	const char	*default_guest_vmlinux_name,
Signature · 1 line
1.8.5.2
author
#5 lore raw

Re: [PATCH v2 2/9] perf script: Add options for custom vdso path

Quoted 14 lines · Arnaldo Carvalho de Melo

Em Tue, May 10, 2016 at 07:40:30AM +0000, He Kuang escreveu:

Quoted 8 lines

When unwinding callchains on a different machine, vdso info should be provided so the unwind process won't be interrupted if address falls into vdso region.

Currently, perf does try to read vdso binary in '.debug' folder, but the filename of the vdso file is generated randomly based on VDSO__TEMP_FILE_NAME template, such a filename is not reliable and users need a way to provide the path of their own vdso binary file.

But this becomes one more burden to the user :-\ Why not calculate a build-id from the VDSO file contents, copy it to ~/.debug/.build-id/ab/cdef01020304 and insert that into the perf.data file so that at analysis time we do all this automatically?

Quoted 5 lines

We can of course have a way to manually provide it, but having it as the main way for users doesn't seem a good interface. Am I missing something?

- Arnaldo

OK, I'll try as you suggested!

Quoted 93 lines
Quoted 93 lines
---
  tools/perf/builtin-script.c | 2 ++
  tools/perf/util/dso.c       | 7 +++++++
  tools/perf/util/dso.h       | 1 +
  tools/perf/util/symbol.c    | 1 +
  tools/perf/util/symbol.h    | 1 +
  5 files changed, 12 insertions(+)
tools/perf/builtin-script.c +2 -0
index 8f6ab2a..c88b547 100644
@@ -2001,6 +2001,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
  		   "file", "vmlinux pathname"),
  	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
  		   "file", "kallsyms pathname"),
+	OPT_STRING(0, "vdso", &symbol_conf.vdso_name,
+		   "file", "vdso pathname"),
  	OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
  		    "When printing symbols do not display call chain"),
  	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
tools/perf/util/dso.c +7 -0
index 8e639543..6ed1cce 100644
@@ -13,6 +13,7 @@ char dso__symtab_origin(const struct dso *dso)
  	static const char origin[] = {
  		[DSO_BINARY_TYPE__KALLSYMS]			= 'k',
  		[DSO_BINARY_TYPE__VMLINUX]			= 'v',
+		[DSO_BINARY_TYPE__VDSO]				= 'D',
  		[DSO_BINARY_TYPE__JAVA_JIT]			= 'j',
  		[DSO_BINARY_TYPE__DEBUGLINK]			= 'l',
  		[DSO_BINARY_TYPE__BUILD_ID_CACHE]		= 'B',
@@ -113,6 +114,11 @@ int dso__read_binary_type_filename(const struct dso *dso,
  			 build_id_hex, build_id_hex + 2);
  		break;
 
+	case DSO_BINARY_TYPE__VDSO:
+	{
+		snprintf(filename, size, "%s", symbol_conf.vdso_name);
+		break;
+	}
  	case DSO_BINARY_TYPE__VMLINUX:
  	case DSO_BINARY_TYPE__GUEST_VMLINUX:
  	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
@@ -487,6 +493,7 @@ static void try_to_open_dso(struct dso *dso, struct machine *machine)
  	enum dso_binary_type binary_type_data[] = {
  		DSO_BINARY_TYPE__BUILD_ID_CACHE,
  		DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
+		DSO_BINARY_TYPE__VDSO,
  		DSO_BINARY_TYPE__NOT_FOUND,
  	};
  	int i = 0;
tools/perf/util/dso.h +1 -0
index 0953280..05fac98 100644
@@ -30,6 +30,7 @@ enum dso_binary_type {
  	DSO_BINARY_TYPE__KCORE,
  	DSO_BINARY_TYPE__GUEST_KCORE,
  	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+	DSO_BINARY_TYPE__VDSO,
  	DSO_BINARY_TYPE__NOT_FOUND,
  };
 
tools/perf/util/symbol.c +1 -0
index e7588dc..4630751 100644
@@ -1363,6 +1363,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
  	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
  	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
  	case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
+	case DSO_BINARY_TYPE__VDSO:
  		return !kmod && dso->kernel == DSO_TYPE_USER;
 
  	case DSO_BINARY_TYPE__KALLSYMS:
tools/perf/util/symbol.h +1 -0
index c8b7544..4e6910e 100644
@@ -114,6 +114,7 @@ struct symbol_conf {
  			report_hierarchy;
  	const char	*vmlinux_name,
  			*kallsyms_name,
+			*vdso_name,
  			*source_prefix,
  			*field_sep;
  	const char	*default_guest_vmlinux_name,
Signature · 1 line
1.8.5.2
author
#6 lore raw

PATCH v2 3/9 perf build: Add build-test for libunwind cross-platforms support

In reply to He Kuang

Currently only test for local libunwind. We should check all supported platforms so we can use them to parse perf.data with callchain info on different machines.

---
 tools/build/Makefile.feature                 |  4 ++++
 tools/build/feature/Makefile                 | 16 ++++++++++++++++
 tools/build/feature/test-libunwind-aarch64.c | 26 ++++++++++++++++++++++++++
 tools/build/feature/test-libunwind-arm.c     | 27 +++++++++++++++++++++++++++
 tools/build/feature/test-libunwind-x86.c     | 27 +++++++++++++++++++++++++++
 tools/build/feature/test-libunwind-x86_64.c  | 27 +++++++++++++++++++++++++++
 6 files changed, 127 insertions(+)
 create mode 100644 tools/build/feature/test-libunwind-aarch64.c
 create mode 100644 tools/build/feature/test-libunwind-arm.c
 create mode 100644 tools/build/feature/test-libunwind-x86.c
 create mode 100644 tools/build/feature/test-libunwind-x86_64.c
tools/build/Makefile.feature +4 -0
index 9f87861..7e36e91 100644
@@ -49,6 +49,10 @@ FEATURE_TESTS_BASIC :=			\
 	libslang			\
 	libcrypto			\
 	libunwind			\
+	libunwind-x86			\
+	libunwind-x86_64		\
+	libunwind-arm			\
+	libunwind-aarch64		\
 	pthread-attr-setaffinity-np	\
 	stackprotector-all		\
 	timerfd				\
tools/build/feature/Makefile +16 -0
index 4ae94db..f4fe3bc 100644
@@ -27,6 +27,10 @@ FILES=					\
 	test-libcrypto.bin		\
 	test-libunwind.bin		\
 	test-libunwind-debug-frame.bin	\
+	test-libunwind-x86.bin		\
+	test-libunwind-x86_64.bin	\
+	test-libunwind-arm.bin		\
+	test-libunwind-aarch64.bin	\
 	test-pthread-attr-setaffinity-np.bin	\
 	test-stackprotector-all.bin	\
 	test-timerfd.bin		\
@@ -103,6 +107,18 @@ $(OUTPUT)test-libunwind.bin:
 
 $(OUTPUT)test-libunwind-debug-frame.bin:
 	$(BUILD) -lelf
+$(OUTPUT)test-libunwind-x86.bin:
+	$(BUILD) -lelf -lunwind-x86
+
+$(OUTPUT)test-libunwind-x86_64.bin:
+	$(BUILD) -lelf -lunwind-x86_64
+
+$(OUTPUT)test-libunwind-arm.bin:
+	$(BUILD) -lelf -lunwind-arm
+
+$(OUTPUT)test-libunwind-aarch64.bin:
+	$(BUILD) -lelf -lunwind-aarch64
+
 
 $(OUTPUT)test-libaudit.bin:
 	$(BUILD) -laudit
tools/build/feature/test-libunwind-aarch64.c new file +26 -0
new file mode 100644
index 0000000..fc03fb6
@@ -0,0 +1,26 @@
+#include <libunwind-aarch64.h>
+#include <stdlib.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)
+
+static unw_accessors_t accessors;
+
+int main(void)
+{
+	unw_addr_space_t addr_space;
+
+	addr_space = unw_create_addr_space(&accessors, 0);
+	if (addr_space)
+		return 0;
+
+	unw_init_remote(NULL, addr_space, NULL);
+	dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
+
+	return 0;
+}
tools/build/feature/test-libunwind-arm.c new file +27 -0
new file mode 100644
index 0000000..632d95e
@@ -0,0 +1,27 @@
+#include <libunwind-arm.h>
+#include <stdlib.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)
+
+static unw_accessors_t accessors;
+
+int main(void)
+{
+	unw_addr_space_t addr_space;
+
+	addr_space = unw_create_addr_space(&accessors, 0);
+	if (addr_space)
+		return 0;
+
+	unw_init_remote(NULL, addr_space, NULL);
+	dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
+
+	return 0;
+}
tools/build/feature/test-libunwind-x86.c new file +27 -0
new file mode 100644
index 0000000..3561edc
@@ -0,0 +1,27 @@
+#include <libunwind-x86.h>
+#include <stdlib.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)
+
+static unw_accessors_t accessors;
+
+int main(void)
+{
+	unw_addr_space_t addr_space;
+
+	addr_space = unw_create_addr_space(&accessors, 0);
+	if (addr_space)
+		return 0;
+
+	unw_init_remote(NULL, addr_space, NULL);
+	dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
+
+	return 0;
+}
tools/build/feature/test-libunwind-x86_64.c new file +27 -0
new file mode 100644
index 0000000..5add251
@@ -0,0 +1,27 @@
+#include <libunwind-x86_64.h>
+#include <stdlib.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)
+
+static unw_accessors_t accessors;
+
+int main(void)
+{
+	unw_addr_space_t addr_space;
+
+	addr_space = unw_create_addr_space(&accessors, 0);
+	if (addr_space)
+		return 0;
+
+	unw_init_remote(NULL, addr_space, NULL);
+	dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
+
+	return 0;
+}
Signature · 1 line
1.8.5.2
Acked-by on v2 3/9
#7 lore raw

Re: [PATCH v2 3/9] perf build: Add build-test for libunwind cross-platforms support

Quoted 5 lines · He Kuang

Currently only test for local libunwind. We should check all supported platforms so we can use them to parse perf.data with callchain info on different machines.

thanks,
jirka

maintainer Applied
#8 lore raw

Re: [PATCH v2 3/9] perf build: Add build-test for libunwind cross-platforms support

Em Wed, May 11, 2016 at 01:52:30PM +0200, Jiri Olsa escreveu:

Quoted 8 lines · He Kuang
Quoted 5 lines

Currently only test for local libunwind. We should check all supported platforms so we can use them to parse perf.data with callchain info on different machines.

Thanks, applied

#9 lore raw

[tip:perf/core] perf build: Add build-test for libunwind cross-platforms support

In reply to He Kuang
perf build: Add build-test for libunwind cross-platforms support
Commit-ID:  b1d960000ca12508c25776f1fd375ee81578ae1f
Gitweb:     http://git.kernel.org/tip/b1d960000ca12508c25776f1fd375ee81578ae1f
Author:     He Kuang <[email protected]>
AuthorDate: Tue, 10 May 2016 07:40:31 +0000
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 11 May 2016 12:24:58 -0300

perf build: Add build-test for libunwind cross-platforms support

Currently only test for local libunwind. We should check all supported platforms so we can use them to parse perf.data with callchain info on different machines.

Cc Adrian Hunter <[email protected]>
Cc Alexander Shishkin <[email protected]>
Cc Andi Kleen <[email protected]>
Cc David Ahern <[email protected]>
Cc Ekaterina Tumanova <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Kan Liang <[email protected]>
Cc Masami Hiramatsu <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Pekka Enberg <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Stephane Eranian <[email protected]>
Cc Sukadev Bhattiprolu <[email protected]>
Cc Wang Nan <[email protected]>
---
 tools/build/Makefile.feature                 |  4 ++++
 tools/build/feature/Makefile                 | 16 ++++++++++++++++
 tools/build/feature/test-libunwind-aarch64.c | 26 ++++++++++++++++++++++++++
 tools/build/feature/test-libunwind-arm.c     | 27 +++++++++++++++++++++++++++
 tools/build/feature/test-libunwind-x86.c     | 27 +++++++++++++++++++++++++++
 tools/build/feature/test-libunwind-x86_64.c  | 27 +++++++++++++++++++++++++++
 6 files changed, 127 insertions(+)
tools/build/Makefile.feature +4 -0
index 9f87861..7e36e91 100644
@@ -49,6 +49,10 @@ FEATURE_TESTS_BASIC :=			\
 	libslang			\
 	libcrypto			\
 	libunwind			\
+	libunwind-x86			\
+	libunwind-x86_64		\
+	libunwind-arm			\
+	libunwind-aarch64		\
 	pthread-attr-setaffinity-np	\
 	stackprotector-all		\
 	timerfd				\
tools/build/feature/Makefile +16 -0
index 4ae94db..f4fe3bc 100644
@@ -27,6 +27,10 @@ FILES=					\
 	test-libcrypto.bin		\
 	test-libunwind.bin		\
 	test-libunwind-debug-frame.bin	\
+	test-libunwind-x86.bin		\
+	test-libunwind-x86_64.bin	\
+	test-libunwind-arm.bin		\
+	test-libunwind-aarch64.bin	\
 	test-pthread-attr-setaffinity-np.bin	\
 	test-stackprotector-all.bin	\
 	test-timerfd.bin		\
@@ -103,6 +107,18 @@ $(OUTPUT)test-libunwind.bin:
 
 $(OUTPUT)test-libunwind-debug-frame.bin:
 	$(BUILD) -lelf
+$(OUTPUT)test-libunwind-x86.bin:
+	$(BUILD) -lelf -lunwind-x86
+
+$(OUTPUT)test-libunwind-x86_64.bin:
+	$(BUILD) -lelf -lunwind-x86_64
+
+$(OUTPUT)test-libunwind-arm.bin:
+	$(BUILD) -lelf -lunwind-arm
+
+$(OUTPUT)test-libunwind-aarch64.bin:
+	$(BUILD) -lelf -lunwind-aarch64
+
 
 $(OUTPUT)test-libaudit.bin:
 	$(BUILD) -laudit
tools/build/feature/test-libunwind-aarch64.c new file +26 -0
new file mode 100644
index 0000000..fc03fb6
@@ -0,0 +1,26 @@
+#include <libunwind-aarch64.h>
+#include <stdlib.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)
+
+static unw_accessors_t accessors;
+
+int main(void)
+{
+	unw_addr_space_t addr_space;
+
+	addr_space = unw_create_addr_space(&accessors, 0);
+	if (addr_space)
+		return 0;
+
+	unw_init_remote(NULL, addr_space, NULL);
+	dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
+
+	return 0;
+}
tools/build/feature/test-libunwind-arm.c new file +27 -0
new file mode 100644
index 0000000..632d95e
@@ -0,0 +1,27 @@
+#include <libunwind-arm.h>
+#include <stdlib.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)
+
+static unw_accessors_t accessors;
+
+int main(void)
+{
+	unw_addr_space_t addr_space;
+
+	addr_space = unw_create_addr_space(&accessors, 0);
+	if (addr_space)
+		return 0;
+
+	unw_init_remote(NULL, addr_space, NULL);
+	dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
+
+	return 0;
+}
tools/build/feature/test-libunwind-x86.c new file +27 -0
new file mode 100644
index 0000000..3561edc
@@ -0,0 +1,27 @@
+#include <libunwind-x86.h>
+#include <stdlib.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)
+
+static unw_accessors_t accessors;
+
+int main(void)
+{
+	unw_addr_space_t addr_space;
+
+	addr_space = unw_create_addr_space(&accessors, 0);
+	if (addr_space)
+		return 0;
+
+	unw_init_remote(NULL, addr_space, NULL);
+	dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
+
+	return 0;
+}
tools/build/feature/test-libunwind-x86_64.c new file +27 -0
new file mode 100644
index 0000000..5add251
@@ -0,0 +1,27 @@
+#include <libunwind-x86_64.h>
+#include <stdlib.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)
+
+static unw_accessors_t accessors;
+
+int main(void)
+{
+	unw_addr_space_t addr_space;
+
+	addr_space = unw_create_addr_space(&accessors, 0);
+	if (addr_space)
+		return 0;
+
+	unw_init_remote(NULL, addr_space, NULL);
+	dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
+
+	return 0;
+}
author
#10 lore raw

PATCH v2 4/9 perf build: Add build-test for debug-frame on arm/arm64

In reply to He Kuang

Debug-frame for remote platforms is not related to the host platform, so we should test each platform separately.

---
 tools/build/Makefile.feature                             |  4 +++-
 tools/build/feature/Makefile                             |  7 +++++++
 tools/build/feature/test-libunwind-debug-frame-aarch64.c | 16 ++++++++++++++++
 tools/build/feature/test-libunwind-debug-frame-arm.c     | 16 ++++++++++++++++
 4 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c
 create mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c
tools/build/Makefile.feature +3 -1
index 7e36e91..57c8f98 100644
@@ -73,7 +73,9 @@ FEATURE_TESTS_EXTRA :=			\
 	libbabeltrace			\
 	liberty				\
 	liberty-z			\
-	libunwind-debug-frame
+	libunwind-debug-frame		\
+	libunwind-debug-frame-arm	\
+	libunwind-debug-frame-aarch64
 
 FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC)
 
tools/build/feature/Makefile +7 -0
index f4fe3bc..3d88f09 100644
@@ -31,6 +31,8 @@ FILES=					\
 	test-libunwind-x86_64.bin	\
 	test-libunwind-arm.bin		\
 	test-libunwind-aarch64.bin	\
+	test-libunwind-debug-frame-arm.bin	\
+	test-libunwind-debug-frame-aarch64.bin	\
 	test-pthread-attr-setaffinity-np.bin	\
 	test-stackprotector-all.bin	\
 	test-timerfd.bin		\
@@ -119,6 +121,11 @@ $(OUTPUT)test-libunwind-arm.bin:
 $(OUTPUT)test-libunwind-aarch64.bin:
 	$(BUILD) -lelf -lunwind-aarch64
 
+$(OUTPUT)test-libunwind-debug-frame-arm.bin:
+	$(BUILD) -lelf -lunwind-arm
+
+$(OUTPUT)test-libunwind-debug-frame-aarch64.bin:
+	$(BUILD) -lelf -lunwind-aarch64
 
 $(OUTPUT)test-libaudit.bin:
 	$(BUILD) -laudit
tools/build/feature/test-libunwind-debug-frame-aarch64.c new file +16 -0
new file mode 100644
index 0000000..2284467
@@ -0,0 +1,16 @@
+#include <libunwind-aarch64.h>
+#include <stdlib.h>
+
+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)
+
+int main(void)
+{
+	dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0);
+	return 0;
+}
tools/build/feature/test-libunwind-debug-frame-arm.c new file +16 -0
new file mode 100644
index 0000000..f988596
@@ -0,0 +1,16 @@
+#include <libunwind-arm.h>
+#include <stdlib.h>
+
+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)
+
+int main(void)
+{
+	dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0);
+	return 0;
+}
Signature · 1 line
1.8.5.2
maintainer Applied
#12 lore raw

Re: [PATCH v2 4/9] perf build: Add build-test for debug-frame on arm/arm64

Em Wed, May 11, 2016 at 01:58:41PM +0200, Jiri Olsa escreveu:

Quoted 7 lines · He Kuang
Quoted 4 lines

Debug-frame for remote platforms is not related to the host platform, so we should test each platform separately.

Thanks, applied

#13 lore raw

[tip:perf/core] perf build: Add build-test for debug-frame on arm/arm64

In reply to He Kuang
perf build: Add build-test for debug-frame on arm/arm64
Commit-ID:  f9be7eefcce9de7323c922bea6b45183eb9ef5f0
Gitweb:     http://git.kernel.org/tip/f9be7eefcce9de7323c922bea6b45183eb9ef5f0
Author:     He Kuang <[email protected]>
AuthorDate: Tue, 10 May 2016 07:40:32 +0000
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 11 May 2016 12:24:58 -0300

perf build: Add build-test for debug-frame on arm/arm64

Debug-frame for remote platforms is not related to the host platform, so we should test each platform separately.

Cc Adrian Hunter <[email protected]>
Cc Alexander Shishkin <[email protected]>
Cc Andi Kleen <[email protected]>
Cc David Ahern <[email protected]>
Cc Ekaterina Tumanova <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Kan Liang <[email protected]>
Cc Masami Hiramatsu <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Pekka Enberg <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Stephane Eranian <[email protected]>
Cc Sukadev Bhattiprolu <[email protected]>
Cc Wang Nan <[email protected]>
---
 tools/build/Makefile.feature                                       | 4 +++-
 tools/build/feature/Makefile                                       | 7 +++++++
 ...ibunwind-debug-frame.c => test-libunwind-debug-frame-aarch64.c} | 2 +-
 ...st-libunwind-debug-frame.c => test-libunwind-debug-frame-arm.c} | 2 +-
 4 files changed, 12 insertions(+), 3 deletions(-)
tools/build/Makefile.feature +3 -1
index 7e36e91..57c8f98 100644
@@ -73,7 +73,9 @@ FEATURE_TESTS_EXTRA :=			\
 	libbabeltrace			\
 	liberty				\
 	liberty-z			\
-	libunwind-debug-frame
+	libunwind-debug-frame		\
+	libunwind-debug-frame-arm	\
+	libunwind-debug-frame-aarch64
 
 FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC)
 
tools/build/feature/Makefile +7 -0
index f4fe3bc..3d88f09 100644
@@ -31,6 +31,8 @@ FILES=					\
 	test-libunwind-x86_64.bin	\
 	test-libunwind-arm.bin		\
 	test-libunwind-aarch64.bin	\
+	test-libunwind-debug-frame-arm.bin	\
+	test-libunwind-debug-frame-aarch64.bin	\
 	test-pthread-attr-setaffinity-np.bin	\
 	test-stackprotector-all.bin	\
 	test-timerfd.bin		\
@@ -119,6 +121,11 @@ $(OUTPUT)test-libunwind-arm.bin:
 $(OUTPUT)test-libunwind-aarch64.bin:
 	$(BUILD) -lelf -lunwind-aarch64
 
+$(OUTPUT)test-libunwind-debug-frame-arm.bin:
+	$(BUILD) -lelf -lunwind-arm
+
+$(OUTPUT)test-libunwind-debug-frame-aarch64.bin:
+	$(BUILD) -lelf -lunwind-aarch64
 
 $(OUTPUT)test-libaudit.bin:
 	$(BUILD) -laudit
tools/build/feature/test-libunwind-debug-frame-aarch64.c renamed from tools/build/feature/test-libunwind-debug-frame.c +1 -1
similarity index 91%
copy from tools/build/feature/test-libunwind-debug-frame.c
copy to tools/build/feature/test-libunwind-debug-frame-aarch64.c
index 0ef8087..2284467 100644
@@ -1,4 +1,4 @@
-#include <libunwind.h>
+#include <libunwind-aarch64.h>
 #include <stdlib.h>
 
 extern int
tools/build/feature/test-libunwind-debug-frame-arm.c renamed from tools/build/feature/test-libunwind-debug-frame.c +1 -1
similarity index 92%
copy from tools/build/feature/test-libunwind-debug-frame.c
copy to tools/build/feature/test-libunwind-debug-frame-arm.c
index 0ef8087..f988596 100644
@@ -1,4 +1,4 @@
-#include <libunwind.h>
+#include <libunwind-arm.h>
 #include <stdlib.h>
 
 extern int
author
#14 lore raw

PATCH v2 5/9 perf tools: Add methods to test dso is 64-bit or 32-bit

In reply to He Kuang

32-bit programs can be run on 64-bit machines, so we should choose unwind methods according to 'thread->map' instead of the host architecture.

This patch adds methods to test whether a dso is 64-bit or 32-bit by the class info in elf.

---
 tools/perf/util/symbol-elf.c | 16 +++++++++++++++
 tools/perf/util/symbol.c     | 49 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/symbol.h     |  2 ++
 3 files changed, 67 insertions(+)
tools/perf/util/symbol-elf.c +16 -0
index 3f9d679..9f290b9 100644
@@ -636,6 +636,22 @@ bool __weak elf__needs_adjust_symbols(GElf_Ehdr ehdr)
 	return ehdr.e_type == ET_EXEC || ehdr.e_type == ET_REL;
 }
 
+int elf_is_64_bit(char *name)
+{
+	Elf *elf;
+	int fd;
+
+	fd = open(name, O_RDONLY);
+	if (fd < 0)
+		return -1;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL)
+		return -1;
+
+	return (gelf_getclass(elf) == ELFCLASS64);
+}
+
 int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 		 enum dso_binary_type type)
 {
tools/perf/util/symbol.c +49 -0

55 lines not on this page · raw message

tools/perf/util/symbol.h +2 -0
index 4e6910e..d33fbf4 100644
@@ -308,6 +308,8 @@ int setup_list(struct strlist **list, const char *list_str,
 	       const char *list_name);
 int setup_intlist(struct intlist **list, const char *list_str,
 		  const char *list_name);
+int elf_is_64_bit(char *name);
+int dso_is_64_bit(struct dso *dso, struct map *map);
 
 #ifdef HAVE_LIBELF_SUPPORT
 bool elf__needs_adjust_symbols(GElf_Ehdr ehdr);
Signature · 1 line
1.8.5.2
reviewer
#15 lore raw

Re: [PATCH v2 5/9] perf tools: Add methods to test dso is 64-bit or 32-bit

Quoted 6 lines · He Kuang

32-bit programs can be run on 64-bit machines, so we should choose unwind methods according to 'thread->map' instead of the host architecture.

This patch adds methods to test whether a dso is 64-bit or 32-bit by the class info in elf.

What about using dso->is_64_bit set by dso__load_sym() ?

Quoted 109 lines
---
 tools/perf/util/symbol-elf.c | 16 +++++++++++++++
 tools/perf/util/symbol.c     | 49 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/symbol.h     |  2 ++
 3 files changed, 67 insertions(+)
tools/perf/util/symbol-elf.c +16 -0
index 3f9d679..9f290b9 100644
@@ -636,6 +636,22 @@ bool __weak elf__needs_adjust_symbols(GElf_Ehdr ehdr)
 	return ehdr.e_type == ET_EXEC || ehdr.e_type == ET_REL;
 }
 
+int elf_is_64_bit(char *name)
+{
+	Elf *elf;
+	int fd;
+
+	fd = open(name, O_RDONLY);
+	if (fd < 0)
+		return -1;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL)
+		return -1;
+
+	return (gelf_getclass(elf) == ELFCLASS64);
+}
+
 int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 		 enum dso_binary_type type)
 {
tools/perf/util/symbol.c +49 -0
index 4630751..592bf8c 100644
@@ -1395,6 +1395,55 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
 	}
 }
 
+int dso_is_64_bit(struct dso *dso, struct map *map)
+{
+	char *name;
+	u_int i;
+	bool kmod;
+	char *root_dir = (char *) "";
+	struct machine *machine;
+
+	if (map->groups && map->groups->machine)
+		machine = map->groups->machine;
+	else
+		machine = NULL;
+
+	if (machine)
+		root_dir = machine->root_dir;
+
+	name = malloc(PATH_MAX);
+	if (!name)
+		return -1;
+
+	kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
+		dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+
+	/*
+	 * Iterate over candidate debug images.
+	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
+	 * and/or opd section) for processing.
+	 */
+	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
+		enum dso_binary_type symtab_type = binary_type_symtab[i];
+
+		if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
+			continue;
+
+		if (dso__read_binary_type_filename(dso, symtab_type,
+						   root_dir, name, PATH_MAX))
+			continue;
+
+		if (!is_regular_file(name))
+			continue;
+
+		return elf_is_64_bit(name);
+	}
+
+	return -1;
+}
+
 int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 {
 	char *name;
tools/perf/util/symbol.h +2 -0
index 4e6910e..d33fbf4 100644
@@ -308,6 +308,8 @@ int setup_list(struct strlist **list, const char *list_str,
 	       const char *list_name);
 int setup_intlist(struct intlist **list, const char *list_str,
 		  const char *list_name);
+int elf_is_64_bit(char *name);
+int dso_is_64_bit(struct dso *dso, struct map *map);
 
 #ifdef HAVE_LIBELF_SUPPORT
 bool elf__needs_adjust_symbols(GElf_Ehdr ehdr);
author
#16 lore raw

Re: [PATCH v2 5/9] perf tools: Add methods to test dso is 64-bit or 32-bit

hi

Quoted 8 lines · Adrian Hunter
Quoted 6 lines · He Kuang

32-bit programs can be run on 64-bit machines, so we should choose unwind methods according to 'thread->map' instead of the host architecture.

This patch adds methods to test whether a dso is 64-bit or 32-bit by the class info in elf.

What about using dso->is_64_bit set by dso__load_sym() ?

I've noticed this variable, but it's value is not as its name said:

util/dso.c: 1067 dso->is_64_bit = (sizeof(void *) == 8);

This is only related to the host architecture.

A closer one is 'is_64_bit' in 'struct symsrc', but the value is assigned after dso loaded. So I think we should provide individual methods to get that value.

Thanks.

Quoted 110 lines
Quoted 109 lines
---
  tools/perf/util/symbol-elf.c | 16 +++++++++++++++
  tools/perf/util/symbol.c     | 49 ++++++++++++++++++++++++++++++++++++++++++++
  tools/perf/util/symbol.h     |  2 ++
  3 files changed, 67 insertions(+)
tools/perf/util/symbol-elf.c +16 -0
index 3f9d679..9f290b9 100644
@@ -636,6 +636,22 @@ bool __weak elf__needs_adjust_symbols(GElf_Ehdr ehdr)
  	return ehdr.e_type == ET_EXEC || ehdr.e_type == ET_REL;
  }
 
+int elf_is_64_bit(char *name)
+{
+	Elf *elf;
+	int fd;
+
+	fd = open(name, O_RDONLY);
+	if (fd < 0)
+		return -1;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL)
+		return -1;
+
+	return (gelf_getclass(elf) == ELFCLASS64);
+}
+
  int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
  		 enum dso_binary_type type)
  {
tools/perf/util/symbol.c +49 -0
index 4630751..592bf8c 100644
@@ -1395,6 +1395,55 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
  	}
  }
 
+int dso_is_64_bit(struct dso *dso, struct map *map)
+{
+	char *name;
+	u_int i;
+	bool kmod;
+	char *root_dir = (char *) "";
+	struct machine *machine;
+
+	if (map->groups && map->groups->machine)
+		machine = map->groups->machine;
+	else
+		machine = NULL;
+
+	if (machine)
+		root_dir = machine->root_dir;
+
+	name = malloc(PATH_MAX);
+	if (!name)
+		return -1;
+
+	kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
+		dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+
+	/*
+	 * Iterate over candidate debug images.
+	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
+	 * and/or opd section) for processing.
+	 */
+	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
+		enum dso_binary_type symtab_type = binary_type_symtab[i];
+
+		if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
+			continue;
+
+		if (dso__read_binary_type_filename(dso, symtab_type,
+						   root_dir, name, PATH_MAX))
+			continue;
+
+		if (!is_regular_file(name))
+			continue;
+
+		return elf_is_64_bit(name);
+	}
+
+	return -1;
+}
+
  int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
  {
  	char *name;
tools/perf/util/symbol.h +2 -0
index 4e6910e..d33fbf4 100644
@@ -308,6 +308,8 @@ int setup_list(struct strlist **list, const char *list_str,
  	       const char *list_name);
  int setup_intlist(struct intlist **list, const char *list_str,
  		  const char *list_name);
+int elf_is_64_bit(char *name);
+int dso_is_64_bit(struct dso *dso, struct map *map);
 
  #ifdef HAVE_LIBELF_SUPPORT
  bool elf__needs_adjust_symbols(GElf_Ehdr ehdr);
reviewer
#17 lore raw

Re: [PATCH v2 5/9] perf tools: Add methods to test dso is 64-bit or 32-bit

Quoted 8 lines · Hekuang

hi

Quoted 5 lines · Adrian Hunter
Quoted 4 lines · He Kuang

32-bit programs can be run on 64-bit machines, so we should choose unwind methods according to 'thread->map' instead of the host architecture.

Quoted 7 lines
Quoted 3 lines
Quoted 2 lines

This patch adds methods to test whether a dso is 64-bit or 32-bit by the class info in elf.

What about using dso->is_64_bit set by dso__load_sym() ?

I've noticed this variable, but it's value is not as its name said:

util/dso.c: 1067 dso->is_64_bit = (sizeof(void *) == 8);

That is just initialization i.e. before we know what it is we assume it is the same as the host.

Quoted 6 lines

This is only related to the host architecture.

A closer one is 'is_64_bit' in 'struct symsrc', but the value is assigned after dso
loaded. So I think we should provide individual methods to get that value.

Are you saying you don't load dsos? Or that is_64_bit is set incorrectly?

Quoted 116 lines

Thanks.

Quoted 110 lines
Quoted 109 lines
---
  tools/perf/util/symbol-elf.c | 16 +++++++++++++++
  tools/perf/util/symbol.c     | 49
++++++++++++++++++++++++++++++++++++++++++++
  tools/perf/util/symbol.h     |  2 ++
  3 files changed, 67 insertions(+)
tools/perf/util/symbol-elf.c +15 -0
index 3f9d679..9f290b9 100644
@@ -636,6 +636,22 @@ bool __weak elf__needs_adjust_symbols(GElf_Ehdr ehdr)
      return ehdr.e_type == ET_EXEC || ehdr.e_type == ET_REL;
  }
  +int elf_is_64_bit(char *name)
+{
+    Elf *elf;
+    int fd;
+
+    fd = open(name, O_RDONLY);
+    if (fd < 0)
+        return -1;
+
+    elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+    if (elf == NULL)
+        return -1;
+
+    return (gelf_getclass(elf) == ELFCLASS64);
+}
+
  int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
           enum dso_binary_type type)
  {
tools/perf/util/symbol.c +48 -0
index 4630751..592bf8c 100644
@@ -1395,6 +1395,55 @@ static bool dso__is_compatible_symtab_type(struct
 dso *dso, bool kmod,
      }
  }
  +int dso_is_64_bit(struct dso *dso, struct map *map)
+{
+    char *name;
+    u_int i;
+    bool kmod;
+    char *root_dir = (char *) "";
+    struct machine *machine;
+
+    if (map->groups && map->groups->machine)
+        machine = map->groups->machine;
+    else
+        machine = NULL;
+
+    if (machine)
+        root_dir = machine->root_dir;
+
+    name = malloc(PATH_MAX);
+    if (!name)
+        return -1;
+
+    kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
+        dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+        dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
+        dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+
+    /*
+     * Iterate over candidate debug images.
+     * Keep track of "interesting" ones (those which have a symtab, dynsym,
+     * and/or opd section) for processing.
+     */
+    for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
+        enum dso_binary_type symtab_type = binary_type_symtab[i];
+
+        if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
+            continue;
+
+        if (dso__read_binary_type_filename(dso, symtab_type,
+                           root_dir, name, PATH_MAX))
+            continue;
+
+        if (!is_regular_file(name))
+            continue;
+
+        return elf_is_64_bit(name);
+    }
+
+    return -1;
+}
+
  int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
  {
      char *name;
tools/perf/util/symbol.h +2 -0
index 4e6910e..d33fbf4 100644
@@ -308,6 +308,8 @@ int setup_list(struct strlist **list, const char
 *list_str,
             const char *list_name);
  int setup_intlist(struct intlist **list, const char *list_str,
            const char *list_name);
+int elf_is_64_bit(char *name);
+int dso_is_64_bit(struct dso *dso, struct map *map);
    #ifdef HAVE_LIBELF_SUPPORT
  bool elf__needs_adjust_symbols(GElf_Ehdr ehdr);
author
#18 lore raw

Re: [PATCH v2 5/9] perf tools: Add methods to test dso is 64-bit or 32-bit

Quoted 18 lines · Adrian Hunter
Quoted 8 lines · Hekuang

hi

Quoted 5 lines · Adrian Hunter
Quoted 4 lines · He Kuang

32-bit programs can be run on 64-bit machines, so we should choose unwind methods according to 'thread->map' instead of the host architecture.

Quoted 6 lines
Quoted 3 lines
Quoted 2 lines

This patch adds methods to test whether a dso is 64-bit or 32-bit by the class info in elf.

What about using dso->is_64_bit set by dso__load_sym() ?

I've noticed this variable, but it's value is not as its name said:

util/dso.c: 1067 dso->is_64_bit = (sizeof(void *) == 8);

That is just initialization i.e. before we know what it is we assume it is the same as the host.

Quoted 7 lines
Quoted 5 lines

This is only related to the host architecture.

A closer one is 'is_64_bit' in 'struct symsrc', but the value is assigned after dso
loaded. So I think we should provide individual methods to get that value.

Are you saying you don't load dsos? Or that is_64_bit is set incorrectly?

Yes, I know it's the inital value, but the correct value is assigned in function dso__load_sym(), and have a look at the call stack(gdb):

#0  dso__load_sym
#1  in dso__load
#2  in map__load
#3  in map__find_symbol
#4  in thread__find_addr_location
#5  in entry
#6  in get_entries
#7  in _Ux86__unwind__get_entries
#8  in thread__resolve_callchain

I think we should choose the right unwind method before dso__load_sym(). i.e. line#7, which is called before dso__load_sym().

I'm not very familiar with this, what's your opinion?

Thanks.

Quoted 113 lines
Quoted 112 lines

Thanks.

Quoted 108 lines
Quoted 108 lines
---
   tools/perf/util/symbol-elf.c | 16 +++++++++++++++
   tools/perf/util/symbol.c     | 49
++++++++++++++++++++++++++++++++++++++++++++
   tools/perf/util/symbol.h     |  2 ++
   3 files changed, 67 insertions(+)
tools/perf/util/symbol-elf.c +15 -0
index 3f9d679..9f290b9 100644
@@ -636,6 +636,22 @@ bool __weak elf__needs_adjust_symbols(GElf_Ehdr ehdr)
       return ehdr.e_type == ET_EXEC || ehdr.e_type == ET_REL;
   }
   +int elf_is_64_bit(char *name)
+{
+    Elf *elf;
+    int fd;
+
+    fd = open(name, O_RDONLY);
+    if (fd < 0)
+        return -1;
+
+    elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+    if (elf == NULL)
+        return -1;
+
+    return (gelf_getclass(elf) == ELFCLASS64);
+}
+
   int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
            enum dso_binary_type type)
   {
tools/perf/util/symbol.c +48 -0
index 4630751..592bf8c 100644
@@ -1395,6 +1395,55 @@ static bool dso__is_compatible_symtab_type(struct
 dso *dso, bool kmod,
       }
   }
   +int dso_is_64_bit(struct dso *dso, struct map *map)
+{
+    char *name;
+    u_int i;
+    bool kmod;
+    char *root_dir = (char *) "";
+    struct machine *machine;
+
+    if (map->groups && map->groups->machine)
+        machine = map->groups->machine;
+    else
+        machine = NULL;
+
+    if (machine)
+        root_dir = machine->root_dir;
+
+    name = malloc(PATH_MAX);
+    if (!name)
+        return -1;
+
+    kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
+        dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+        dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
+        dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+
+    /*
+     * Iterate over candidate debug images.
+     * Keep track of "interesting" ones (those which have a symtab, dynsym,
+     * and/or opd section) for processing.
+     */
+    for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
+        enum dso_binary_type symtab_type = binary_type_symtab[i];
+
+        if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
+            continue;
+
+        if (dso__read_binary_type_filename(dso, symtab_type,
+                           root_dir, name, PATH_MAX))
+            continue;
+
+        if (!is_regular_file(name))
+            continue;
+
+        return elf_is_64_bit(name);
+    }
+
+    return -1;
+}
+
   int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
   {
       char *name;
tools/perf/util/symbol.h +2 -0
index 4e6910e..d33fbf4 100644
@@ -308,6 +308,8 @@ int setup_list(struct strlist **list, const char
 *list_str,
              const char *list_name);
   int setup_intlist(struct intlist **list, const char *list_str,
             const char *list_name);
+int elf_is_64_bit(char *name);
+int dso_is_64_bit(struct dso *dso, struct map *map);
     #ifdef HAVE_LIBELF_SUPPORT
   bool elf__needs_adjust_symbols(GElf_Ehdr ehdr);
reviewer
#19 lore raw

Re: [PATCH v2 5/9] perf tools: Add methods to test dso is 64-bit or 32-bit

Quoted 43 lines · Hekuang
Quoted 18 lines · Adrian Hunter
Quoted 8 lines · Hekuang

hi

Quoted 5 lines · Adrian Hunter
Quoted 4 lines · He Kuang

32-bit programs can be run on 64-bit machines, so we should choose unwind methods according to 'thread->map' instead of the host architecture.

Quoted 6 lines
Quoted 3 lines
Quoted 2 lines

This patch adds methods to test whether a dso is 64-bit or 32-bit by the class info in elf.

What about using dso->is_64_bit set by dso__load_sym() ?

I've noticed this variable, but it's value is not as its name said:

util/dso.c: 1067 dso->is_64_bit = (sizeof(void *) == 8);

That is just initialization i.e. before we know what it is we assume it is the same as the host.

Quoted 7 lines
Quoted 5 lines

This is only related to the host architecture.

A closer one is 'is_64_bit' in 'struct symsrc', but the value is assigned after dso
loaded. So I think we should provide individual methods to get that value.

Are you saying you don't load dsos? Or that is_64_bit is set incorrectly?

Yes, I know it's the inital value, but the correct value is assigned in function dso__load_sym(), and have a look at the call stack(gdb):

#0  dso__load_sym
#1  in dso__load
#2  in map__load
#3  in map__find_symbol
#4  in thread__find_addr_location
#5  in entry
#6  in get_entries
#7  in _Ux86__unwind__get_entries
#8  in thread__resolve_callchain
Quoted 4 lines

I think we should choose the right unwind method before dso__load_sym(). i.e. line#7, which is called before dso__load_sym().

I'm not very familiar with this, what's your opinion?

Have you considered calling map__load() instead of dso_is_64_bit()

author
#20 lore raw

Re: [PATCH v2 5/9] perf tools: Add methods to test dso is 64-bit or 32-bit

Quoted 42 lines · Adrian Hunter
Quoted 41 lines · Hekuang
Quoted 18 lines · Adrian Hunter
Quoted 8 lines · Hekuang

hi

Quoted 5 lines · Adrian Hunter
Quoted 4 lines · He Kuang

32-bit programs can be run on 64-bit machines, so we should choose unwind methods according to 'thread->map' instead of the host architecture.

Quoted 6 lines
Quoted 3 lines
Quoted 2 lines

This patch adds methods to test whether a dso is 64-bit or 32-bit by the class info in elf.

What about using dso->is_64_bit set by dso__load_sym() ?

I've noticed this variable, but it's value is not as its name said:

util/dso.c: 1067 dso->is_64_bit = (sizeof(void *) == 8);

That is just initialization i.e. before we know what it is we assume it is the same as the host.

Quoted 7 lines
Quoted 5 lines

This is only related to the host architecture.

A closer one is 'is_64_bit' in 'struct symsrc', but the value is assigned after dso
loaded. So I think we should provide individual methods to get that value.

Are you saying you don't load dsos? Or that is_64_bit is set incorrectly?

Yes, I know it's the inital value, but the correct value is assigned in function dso__load_sym(), and have a look at the call stack(gdb):

#0  dso__load_sym
#1  in dso__load
#2  in map__load
#3  in map__find_symbol
#4  in thread__find_addr_location
#5  in entry
#6  in get_entries
#7  in _Ux86__unwind__get_entries
#8  in thread__resolve_callchain
Quoted 5 lines
Quoted 4 lines

I think we should choose the right unwind method before dso__load_sym(). i.e. line#7, which is called before dso__load_sym().

I'm not very familiar with this, what's your opinion?

Have you considered calling map__load() instead of dso_is_64_bit()

IMO, map__load() is heavy than dso_is_64_bit() test, because the dso tested by unwind_get_arch(thread, map) may or may not be referenced in the unwind process. For example, a thread can have a large map but that map never appeared in the callcains in perf.data.

Or in other words, should we load all symbols for that elf flag or add a new method targeted for that purpose only.

Thanks.

Quoted 3 lines
author
#21 lore raw

PATCH v2 6/9 perf tools: Promote proper messages for cross-platform unwind

In reply to He Kuang

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

This patch shows proper error messages when we do remote unwind x86(32-bit) on other machines.

Same thing for other platforms will be added in next patches.

---
 tools/perf/config/Makefile         |  6 ++++++
 tools/perf/util/thread.c           |  2 ++
 tools/perf/util/unwind-libunwind.c | 32 ++++++++++++++++++++++++++++++++
 tools/perf/util/unwind.h           |  5 +++++
 4 files changed, 45 insertions(+)
tools/perf/config/Makefile +6 -0
index 1e46277..a86b864 100644
@@ -345,6 +345,12 @@ ifeq ($(ARCH),powerpc)
 endif
 
 ifndef NO_LIBUNWIND
+  ifeq ($(feature-libunwind-x86), 1)
+    LIBUNWIND_LIBS += -lunwind-x86
+    $(call detected,CONFIG_LIBUNWIND_X86)
+    CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT
+  endif
+
   ifneq ($(feature-libunwind), 1)
     msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
     NO_LIBUNWIND := 1
tools/perf/util/thread.c +2 -0
index dfd00c6..244c4f6 100644
@@ -186,6 +186,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__get_arch(thread, map);
 }
 
 static int thread__clone_map_groups(struct thread *thread,
tools/perf/util/unwind-libunwind.c +32 -0
index 63687d3..b6eb317 100644
@@ -680,3 +680,35 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
 
 	return get_entries(&ui, cb, arg, max_stack);
 }
+
+void unwind__get_arch(struct thread *thread, struct map *map)
+{
+	char *arch;
+	int is_64_bit;
+
+	if (!thread->mg->machine->env)
+		return;
+
+	is_64_bit = dso_is_64_bit(map->dso, map);
+	if (is_64_bit < 0)
+		return;
+
+	if (thread->addr_space)
+		pr_debug("Thread map already set, 64bit is %d, dso=%s\n",
+			 is_64_bit, map->dso->name);
+
+	arch = thread->mg->machine->env->arch;
+
+	if (!strcmp(arch, "x86_64")
+		   || !strcmp(arch, "x86")
+		   || !strcmp(arch, "i686")) {
+		pr_debug("Thread map is X86, 64bit is %d\n", is_64_bit);
+		if (!is_64_bit)
+#ifdef HAVE_LIBUNWIND_X86_SUPPORT
+			pr_err("target platform=%s is not implemented!\n",
+			       arch);
+#else
+			pr_err("target platform=%s is not supported!\n", arch);
+#endif
+	}
+}
tools/perf/util/unwind.h +5 -0
index 12790cf..889d630 100644
@@ -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 unwind__get_arch(struct thread *thread, struct map *map);
 #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 unwind__get_arch(struct thread *thread __maybe_unused,
+				    struct map *map __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 unwind__get_arch(struct thread *thread __maybe_unused,
+				    struct map *map __maybe_unused) {}
 #endif /* HAVE_DWARF_UNWIND_SUPPORT */
 #endif /* __UNWIND_H */
Signature · 1 line
1.8.5.2
author
#22 lore raw

PATCH v2 7/9 perf callchain: Add support for cross-platform unwind

In reply to He Kuang

Use thread specific unwind ops to unwind cross-platform callchains.

Before this patch, unwind methods is suitable for local unwind, this patch changes the fixed methods to thread/map related. Each time a map is inserted, we find the target arch and see if this platform can be remote unwind. In this patch, we test for x86 platform and only show proper messages. The real unwind methods are not implemented, will be introduced in next patch.

Common function used by both local unwind and remote unwind are separated into new file 'unwind-libunwind_common.c'.

---
 tools/perf/config/Makefile                |  19 +++++-
 tools/perf/util/Build                     |   3 +-
 tools/perf/util/thread.c                  |   5 +-
 tools/perf/util/thread.h                  |  14 ++++-
 tools/perf/util/unwind-libunwind.c        |  73 +++++++++++-----------
 tools/perf/util/unwind-libunwind_common.c | 100 ++++++++++++++++++++++++++++++
 tools/perf/util/unwind.h                  |  35 ++++++++---
 7 files changed, 196 insertions(+), 53 deletions(-)
 create mode 100644 tools/perf/util/unwind-libunwind_common.c
tools/perf/config/Makefile +16 -3
index a86b864..16f14b1 100644
@@ -345,14 +345,24 @@ ifeq ($(ARCH),powerpc)
 endif
 
 ifndef NO_LIBUNWIND
+  have_libunwind =
   ifeq ($(feature-libunwind-x86), 1)
-    LIBUNWIND_LIBS += -lunwind-x86
     $(call detected,CONFIG_LIBUNWIND_X86)
     CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT
+    LDFLAGS += -lunwind -lunwind-x86
+    have_libunwind = 1
   endif
 
   ifneq ($(feature-libunwind), 1)
     msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
+    NO_LOCAL_LIBUNWIND := 1
+  else
+    have_libunwind = 1
+    CFLAGS += -DHAVE_LIBUNWIND_LOCAL_SUPPORT
+    $(call detected,CONFIG_LOCAL_LIBUNWIND)
+  endif
+
+  ifneq ($(have_libunwind), 1)
     NO_LIBUNWIND := 1
   endif
 endif
@@ -392,7 +402,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)
@@ -403,12 +413,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);
tools/perf/util/Build +2 -1
index ea4ac03..2e21529 100644
@@ -97,7 +97,8 @@ libperf-$(CONFIG_DWARF) += probe-finder.o
 libperf-$(CONFIG_DWARF) += dwarf-aux.o
 
 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
-libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
+libperf-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
+libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind_common.o
 
 libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o
 
tools/perf/util/thread.c +2 -3
index 244c4f6..2274263 100644
@@ -41,9 +41,6 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 		thread->cpu = -1;
 		INIT_LIST_HEAD(&thread->comm_list);
 
-		if (unwind__prepare_access(thread) < 0)
-			goto err_thread;
-
 		comm_str = malloc(32);
 		if (!comm_str)
 			goto err_thread;
@@ -57,6 +54,8 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 		list_add(&comm->list, &thread->comm_list);
 		atomic_set(&thread->refcnt, 1);
 		RB_CLEAR_NODE(&thread->rb_node);
+
+		register_null_unwind_libunwind_ops(thread);
 	}
 
 	return thread;
tools/perf/util/thread.h +13 -1
index e214207..6f2d4cd 100644
@@ -15,6 +15,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;
@@ -36,7 +47,8 @@ struct thread {
 	void			*priv;
 	struct thread_stack	*ts;
 #ifdef HAVE_LIBUNWIND_SUPPORT
-	unw_addr_space_t	addr_space;
+	unw_addr_space_t		addr_space;
+	struct unwind_libunwind_ops	*unwind_libunwind_ops;
 #endif
 };
 
tools/perf/util/unwind-libunwind.c +38 -35

114 lines not on this page · raw message

tools/perf/util/unwind-libunwind_common.c new file +100 -0

100 lines not on this page · raw message

tools/perf/util/unwind.h +25 -10
index 889d630..e045600 100644
@@ -21,20 +21,38 @@ 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);
 void unwind__flush_access(struct thread *thread);
 void unwind__finish_access(struct thread *thread);
 void unwind__get_arch(struct thread *thread, struct map *map);
-#else
-static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
-{
-	return 0;
+void register_unwind_libunwind_ops(struct unwind_libunwind_ops *ops,
+				   struct thread *thread);
+void register_null_unwind_libunwind_ops(struct thread *thread);
+
+#ifndef HAVE_LIBUNWIND_LOCAL_SUPPORT
+static inline void
+register_local_unwind_libunwind_ops(struct thread *thread) {
+	register_null_unwind_libunwind_ops(thread);
 }
+#else
+void register_local_unwind_libunwind_ops(struct thread *thread);
+#endif
 
+#define unwind__get_entries(cb, arg,					\
+			    thread,					\
+			    data, max_stack)				\
+	thread->unwind_libunwind_ops->get_entries(cb,			\
+						  arg,			\
+						  thread,		\
+						  data,			\
+						  max_stack)
+
+#else
 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 unwind__get_arch(struct thread *thread __maybe_unused,
 				    struct map *map __maybe_unused) {}
+static inline void
+register_null_unwind_libunwind_ops(struct thread *thread __maybe_unused) {}
 #endif
 #else
 static inline int
@@ -47,14 +65,11 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
 	return 0;
 }
 
-static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
-{
-	return 0;
-}
-
 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 unwind__get_arch(struct thread *thread __maybe_unused,
 				    struct map *map __maybe_unused) {}
+static inline void
+register_null_unwind_libunwind_ops(struct thread *thread __maybe_unused) {}
 #endif /* HAVE_DWARF_UNWIND_SUPPORT */
 #endif /* __UNWIND_H */
Signature · 1 line
1.8.5.2
author
#23 lore raw

PATCH v2 8/9 perf callchain: Support x86 target platform

In reply to He Kuang

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

---
 .../arch/x86/include/libunwind/libunwind-arch.h    | 18 ++++++++++
 tools/perf/arch/x86/util/unwind-libunwind.c        | 42 ++++++++++++++++++++++
 tools/perf/util/Build                              |  6 ++++
 tools/perf/util/unwind-libunwind.c                 |  2 +-
 tools/perf/util/unwind-libunwind_common.c          |  7 ++--
 tools/perf/util/unwind.h                           |  5 +++
 6 files changed, 76 insertions(+), 4 deletions(-)
 create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h
tools/perf/arch/x86/include/libunwind/libunwind-arch.h new file +18 -0
new file mode 100644
index 0000000..265f14d
@@ -0,0 +1,18 @@
+#ifndef _LIBUNWIND_ARCH_H
+#define _LIBUNWIND_ARCH_H
+
+#include <libunwind-x86.h>
+#include <../perf_regs.h>
+#include <../../../../../../arch/x86/include/uapi/asm/perf_regs.h>
+
+#define LIBUNWIND_X86_32
+int libunwind__x86_reg_id(int regnum);
+
+#include <../../../x86/util/unwind-libunwind.c>
+
+#define LIBUNWIND__ARCH_REG_ID libunwind__x86_reg_id
+
+#define UNWT_PREFIX	UNW_PASTE(UNW_PASTE(_U, x86), _)
+#define UNWT_OBJ(fn)	UNW_PASTE(UNWT_PREFIX, fn)
+
+#endif /* _LIBUNWIND_ARCH_H */
tools/perf/arch/x86/util/unwind-libunwind.c +42 -0

51 lines not on this page · raw message

tools/perf/util/Build +6 -0
index 2e21529..2dd3939 100644
@@ -1,3 +1,5 @@
+include ../scripts/Makefile.include
+
 libperf-y += alias.o
 libperf-y += annotate.o
 libperf-y += build-id.o
@@ -99,6 +101,10 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o
 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 libperf-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
 libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind_common.o
+libperf-$(CONFIG_LIBUNWIND_X86)      += unwind-libunwind_x86_32.o
+
+$(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c
+	$(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c
 
 libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o
 
tools/perf/util/unwind-libunwind.c +1 -1
index 2a8d24e..1844431 100644
@@ -527,7 +527,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;
 
tools/perf/util/unwind-libunwind_common.c +4 -3
index 4bdd3b9..d0128f0 100644
@@ -82,10 +82,11 @@ void unwind__get_arch(struct thread *thread, struct map *map)
 		pr_debug("unwind: thread map is X86, 64bit is %d\n", is_64_bit);
 		if (!is_64_bit) {
 #ifdef HAVE_LIBUNWIND_X86_SUPPORT
-			pr_err("unwind: target platform=%s is not implemented\n",
-			       arch);
-#endif
+			register_unwind_libunwind_ops(
+				&_Ux86_unwind_libunwind_ops, thread);
+#else
 			register_null_unwind_libunwind_ops(thread);
+#endif
 		} else
 			use_local_unwind = 1;
 	} else {
tools/perf/util/unwind.h +5 -0
index e045600..8f7c4357 100644
@@ -54,6 +54,11 @@ static inline void unwind__get_arch(struct thread *thread __maybe_unused,
 static inline void
 register_null_unwind_libunwind_ops(struct thread *thread __maybe_unused) {}
 #endif
+
+#ifdef HAVE_LIBUNWIND_X86_SUPPORT
+extern struct unwind_libunwind_ops _Ux86_unwind_libunwind_ops;
+#endif
+
 #else
 static inline int
 unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
Signature · 1 line
1.8.5.2
author
#24 lore raw

PATCH v2 9/9 perf callchain: Support aarch64 cross-platform

In reply to He Kuang

Support aarch64 cross platform callchain unwind.

---
 .../perf/arch/arm64/include/libunwind/libunwind-arch.h | 18 ++++++++++++++++++
 tools/perf/arch/arm64/util/unwind-libunwind.c          |  5 ++++-
 tools/perf/config/Makefile                             | 12 ++++++++++++
 tools/perf/util/Build                                  |  4 ++++
 tools/perf/util/unwind-libunwind_common.c              | 12 ++++++++++++
 tools/perf/util/unwind.h                               |  3 +++
 6 files changed, 53 insertions(+), 1 deletion(-)
 create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h
tools/perf/arch/arm64/include/libunwind/libunwind-arch.h new file +18 -0
new file mode 100644
index 0000000..7bc8a00
@@ -0,0 +1,18 @@
+#ifndef _LIBUNWIND_ARCH_H
+#define _LIBUNWIND_ARCH_H
+
+#include <libunwind-aarch64.h>
+#include <../perf_regs.h>
+#include <../../../../../../arch/arm64/include/uapi/asm/perf_regs.h>
+
+#define LIBUNWIND_AARCH64
+int libunwind__aarch64_reg_id(int regnum);
+
+#include <../../../arm64/util/unwind-libunwind.c>
+
+#define LIBUNWIND__ARCH_REG_ID libunwind__aarch64_reg_id
+
+#define UNWT_PREFIX	UNW_PASTE(UNW_PASTE(_U, aarch64), _)
+#define UNWT_OBJ(fn)	UNW_PASTE(UNWT_PREFIX, fn)
+
+#endif /* _LIBUNWIND_ARCH_H */
tools/perf/arch/arm64/util/unwind-libunwind.c +4 -1
index a87afa9..5b557a5 100644
@@ -1,11 +1,14 @@
 
 #include <errno.h>
-#include <libunwind.h>
 #include "perf_regs.h"
 #include "../../util/unwind.h"
 #include "../../util/debug.h"
 
+#ifndef LIBUNWIND_AARCH64
 int libunwind__arch_reg_id(int regnum)
+#else
+int libunwind__aarch64_reg_id(int regnum)
+#endif
 {
 	switch (regnum) {
 	case UNW_AARCH64_X0:
tools/perf/config/Makefile +12 -0
index 16f14b1..c1bfc5e 100644
@@ -353,6 +353,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 -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
tools/perf/util/Build +4 -0
index 2dd3939..10e42ad 100644
@@ -102,10 +102,14 @@ libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 libperf-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind.o
 libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind_common.o
 libperf-$(CONFIG_LIBUNWIND_X86)      += unwind-libunwind_x86_32.o
+libperf-$(CONFIG_LIBUNWIND_AARCH64)  += unwind-libunwind_arm64.o
 
 $(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c
 	$(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c
 
+$(OUTPUT)util/unwind-libunwind_arm64.o: util/unwind-libunwind.c arch/arm64/util/unwind-libunwind.c
+	$(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/arm64/include/libunwind -c -o $@ util/unwind-libunwind.c
+
 libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o
 
 libperf-y += scripting-engines/
tools/perf/util/unwind-libunwind_common.c +12 -0
index d0128f0..fde42b2 100644
@@ -89,6 +89,18 @@ void unwind__get_arch(struct thread *thread, struct map *map)
 #endif
 		} else
 			use_local_unwind = 1;
+	} else if (!strcmp(arch, "aarch64") || !strncmp(arch, "arm", 3)) {
+		pr_debug("Thread map is ARM, 64bit is %d, dso=%s\n",
+			 is_64_bit, map->dso->name);
+		if (is_64_bit) {
+#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT
+			register_unwind_libunwind_ops(
+				&_Uaarch64_unwind_libunwind_ops, thread);
+#else
+			register_null_unwind_libunwind_ops(thread);
+#endif
+		} else
+			use_local_unwind = 1;
 	} else {
 		use_local_unwind = 1;
 	}
tools/perf/util/unwind.h +3 -0
index 8f7c4357..741a53f 100644
@@ -58,6 +58,9 @@ register_null_unwind_libunwind_ops(struct thread *thread __maybe_unused) {}
 #ifdef HAVE_LIBUNWIND_X86_SUPPORT
 extern struct unwind_libunwind_ops _Ux86_unwind_libunwind_ops;
 #endif
+#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT
+extern struct unwind_libunwind_ops _Uaarch64_unwind_libunwind_ops;
+#endif
 
 #else
 static inline int
Signature · 1 line
1.8.5.2