netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] Perf stack unwinding with pointer authentication
@ 2022-07-04 14:53 Andrew Kilroy
  2022-07-04 14:53 ` [PATCH 1/8] perf arm64: Send pointer auth masks to ring buffer Andrew Kilroy
                   ` (8 more replies)
  0 siblings, 9 replies; 15+ messages in thread
From: Andrew Kilroy @ 2022-07-04 14:53 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme
  Cc: Andrew Kilroy, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Namhyung Kim, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Tom Rix, linux-arm-kernel, netdev, bpf,
	llvm

This patch series addresses issues that perf has when attempting to show
userspace stacks in the presence of pointer authentication on arm64.

Depending on whether libunwind or libdw is used, perf incorrectly
displays the userspace stack in 'perf report --stdio'.  With libunwind,
only the leaf function is shown.

            |
            ---0x200000004005bf
               0x200000004005bf
               my_leaf_function

With libdw, only the leaf function is shown even though there are
callers in the application.

            |
            ---my_leaf_function


The reason perf cannot show the stack upon a perf report --stdio is
because the unwinders are given instruction pointers which contain a
pointer authentication code (PAC).  For the libraries to correctly
unwind, they need to know which bits of the instruction pointer to turn
off.

The kernel exposes the set of PAC bits via the NT_ARM_PAC_MASK regset.
It is expected that this may vary per-task in future. The kernel also
exposes which pointer authentication keys are enabled via the
NT_ARM_PAC_ENABLED_KEYS regset, and this can change dynamically. These
are per-task state which perf would need to sample.

It's not always feasible for perf to acquire these regsets via ptrace.
When sampling system-wide or with inherited events this may require a
large volume of ptrace requests, and by the time the perf tool processes
a sample for a task, that task might already have terminated.

Instead, these patches allow this state to be sampled into the perf
ringbuffer, where it can be consumed more easily by the perf tool.

The first patch changes the kernel to send the authentication PAC masks
to userspace perf via the perf ring buffer.  This is published in the
sample, using a new sample field PERF_SAMPLE_ARCH_1.

The subsequent patches are changes to userspace perf to

1) request the PERF_SAMPLE_ARCH_1
2) supply the instruction mask to libunwind
3) ensure perf can cope with an older kernel that does not know about
   the PERF_SAMPLE_ARCH_1 sample field.
4) checks if the version of libunwind has the capability to accept
   an instruction mask from perf and if so enable the feature.

These changes depend on a change to libunwind, that is yet to be
released, although the patch has been merged.

  https://github.com/libunwind/libunwind/pull/360


Andrew Kilroy (6):
  perf arm64: Send pointer auth masks to ring buffer
  perf evsel: Do not request ptrauth sample field if not supported
  perf tools: arm64: Read ptrauth data from kernel
  perf libunwind: Feature check for libunwind ptrauth callback
  perf libunwind: arm64 pointer authentication
  perf tools: Print ptrauth struct in perf report

German Gomez (2):
  perf test: Update arm64 tests to expect ptrauth masks
  perf test arm64: Test unwinding with PACs on gcc & clang compilers

 arch/arm64/include/asm/arch_sample_data.h     |  38 ++++++
 arch/arm64/kernel/Makefile                    |   2 +-
 arch/arm64/kernel/arch_sample_data.c          |  37 ++++++
 include/linux/perf_event.h                    |  24 ++++
 include/uapi/linux/perf_event.h               |   5 +-
 kernel/events/core.c                          |  35 ++++++
 tools/build/Makefile.feature                  |   2 +
 tools/build/feature/Makefile                  |   4 +
 tools/build/feature/test-all.c                |   5 +
 .../feature/test-libunwind-arm64-ptrauth.c    |  26 ++++
 tools/include/uapi/linux/perf_event.h         |   5 +-
 tools/perf/Makefile.config                    |  10 ++
 tools/perf/Makefile.perf                      |   1 +
 tools/perf/tests/Build                        |   1 +
 tools/perf/tests/arm_unwind_pac.c             | 113 ++++++++++++++++++
 tools/perf/tests/arm_unwind_pac.sh            |  57 +++++++++
 tools/perf/tests/attr/README                  |   1 +
 .../attr/test-record-graph-default-aarch64    |   3 +-
 tools/perf/tests/attr/test-record-graph-dwarf |   1 +
 .../attr/test-record-graph-dwarf-aarch64      |  13 ++
 .../tests/attr/test-record-graph-fp-aarch64   |   3 +-
 tools/perf/tests/builtin-test.c               |   1 +
 tools/perf/tests/sample-parsing.c             |   2 +-
 tools/perf/tests/tests.h                      |   1 +
 tools/perf/util/event.h                       |   8 ++
 tools/perf/util/evsel.c                       |  64 ++++++++++
 tools/perf/util/evsel.h                       |   1 +
 tools/perf/util/perf_event_attr_fprintf.c     |   2 +-
 tools/perf/util/session.c                     |  15 +++
 tools/perf/util/unwind-libunwind-local.c      |  12 ++
 30 files changed, 485 insertions(+), 7 deletions(-)
 create mode 100644 arch/arm64/include/asm/arch_sample_data.h
 create mode 100644 arch/arm64/kernel/arch_sample_data.c
 create mode 100644 tools/build/feature/test-libunwind-arm64-ptrauth.c
 create mode 100644 tools/perf/tests/arm_unwind_pac.c
 create mode 100755 tools/perf/tests/arm_unwind_pac.sh
 create mode 100644 tools/perf/tests/attr/test-record-graph-dwarf-aarch64

-- 
2.17.1


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

* [PATCH 1/8] perf arm64: Send pointer auth masks to ring buffer
  2022-07-04 14:53 [PATCH 0/8] Perf stack unwinding with pointer authentication Andrew Kilroy
@ 2022-07-04 14:53 ` Andrew Kilroy
  2022-08-10 13:23   ` Arnaldo Carvalho de Melo
  2022-07-04 14:53 ` [PATCH 2/8] perf evsel: Do not request ptrauth sample field if not supported Andrew Kilroy
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Andrew Kilroy @ 2022-07-04 14:53 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme
  Cc: Andrew Kilroy, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Namhyung Kim, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Tom Rix, linux-arm-kernel, netdev, bpf,
	llvm

Perf report cannot produce callgraphs using dwarf on arm64 where pointer
authentication is enabled.  This is because libunwind and libdw cannot
unmangle instruction pointers that have a pointer authentication code
(PAC) embedded in them.

libunwind and libdw need to be given an instruction mask which they can
use to arrive at the correct return address that does not contain the
PAC.

The bits in the return address that contain the PAC can differ by
process, so this patch adds a new sample field PERF_SAMPLE_ARCH_1
to allow the kernel to send the masks up to userspace perf.

This field can be used in a architecture specific fashion, but on
aarch64, it contains the ptrauth mask information.

Signed-off-by: Andrew Kilroy <andrew.kilroy@arm.com>
---
 arch/arm64/include/asm/arch_sample_data.h | 38 +++++++++++++++++++++++
 arch/arm64/kernel/Makefile                |  2 +-
 arch/arm64/kernel/arch_sample_data.c      | 37 ++++++++++++++++++++++
 include/linux/perf_event.h                | 24 ++++++++++++++
 include/uapi/linux/perf_event.h           |  5 ++-
 kernel/events/core.c                      | 35 +++++++++++++++++++++
 6 files changed, 139 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm64/include/asm/arch_sample_data.h
 create mode 100644 arch/arm64/kernel/arch_sample_data.c

diff --git a/arch/arm64/include/asm/arch_sample_data.h b/arch/arm64/include/asm/arch_sample_data.h
new file mode 100644
index 000000000000..83fda293b1fc
--- /dev/null
+++ b/arch/arm64/include/asm/arch_sample_data.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_ARCH_SAMPLE_DATA_H
+#define _ASM_ARCH_SAMPLE_DATA_H
+
+#include <linux/types.h>
+
+/*
+ * Structure holding masks to help userspace stack unwinding
+ * in the presence of arm64 pointer authentication.
+ */
+struct ptrauth_info {
+	/*
+	 * Bits 0, 1, 2, 3, 4 may be set to on, to indicate which keys are being used
+	 * The APIAKEY, APIBKEY, APDAKEY, APDBKEY, or the APGAKEY respectively.
+	 * Where all bits are off, pointer authentication is not in use for the
+	 * process.
+	 */
+	u64 enabled_keys;
+
+	/*
+	 * The on bits represent which bits in an instruction pointer
+	 * constitute the pointer authentication code.
+	 */
+	u64 insn_mask;
+
+	/*
+	 * The on bits represent which bits in a data pointer constitute the
+	 * pointer authentication code.
+	 */
+	u64 data_mask;
+};
+
+struct arch_sample_data {
+	struct ptrauth_info ptrauth;
+};
+
+#endif
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index fa7981d0d917..843c6e0e2393 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -44,7 +44,7 @@ obj-$(CONFIG_KUSER_HELPERS)		+= kuser32.o
 obj-$(CONFIG_FUNCTION_TRACER)		+= ftrace.o entry-ftrace.o
 obj-$(CONFIG_MODULES)			+= module.o
 obj-$(CONFIG_ARM64_MODULE_PLTS)		+= module-plts.o
-obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o perf_callchain.o
+obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o perf_callchain.o arch_sample_data.o
 obj-$(CONFIG_HW_PERF_EVENTS)		+= perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
 obj-$(CONFIG_CPU_PM)			+= sleep.o suspend.o
diff --git a/arch/arm64/kernel/arch_sample_data.c b/arch/arm64/kernel/arch_sample_data.c
new file mode 100644
index 000000000000..2d47e8db0dbe
--- /dev/null
+++ b/arch/arm64/kernel/arch_sample_data.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <asm/arch_sample_data.h>
+#include <linux/perf_event.h>
+
+inline void perf_output_sample_arch_1(struct perf_output_handle *handle,
+				      struct perf_event_header *header,
+				      struct perf_sample_data *data,
+				      struct perf_event *event)
+{
+	perf_output_put(handle, data->arch.ptrauth.enabled_keys);
+	perf_output_put(handle, data->arch.ptrauth.insn_mask);
+	perf_output_put(handle, data->arch.ptrauth.data_mask);
+}
+
+inline void perf_prepare_sample_arch_1(struct perf_event_header *header,
+				       struct perf_sample_data *data,
+				       struct perf_event *event,
+				       struct pt_regs *regs)
+{
+	struct task_struct *task = current;
+	int keys_result = ptrauth_get_enabled_keys(task);
+	u64 user_pac_mask = keys_result > 0 ? ptrauth_user_pac_mask() : 0;
+
+	data->arch.ptrauth.enabled_keys = keys_result > 0 ? keys_result : 0;
+	data->arch.ptrauth.insn_mask = user_pac_mask;
+	data->arch.ptrauth.data_mask = user_pac_mask;
+
+	header->size += (3 * sizeof(u64));
+}
+
+inline int perf_event_open_request_arch_1(void)
+{
+	return 0;
+}
+
+
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index da759560eec5..8a99942989ce 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -999,6 +999,29 @@ int perf_event_read_local(struct perf_event *event, u64 *value,
 extern u64 perf_event_read_value(struct perf_event *event,
 				 u64 *enabled, u64 *running);
 
+void perf_output_sample_arch_1(struct perf_output_handle *handle,
+			       struct perf_event_header *header,
+			       struct perf_sample_data *data,
+			       struct perf_event *event);
+
+void perf_prepare_sample_arch_1(struct perf_event_header *header,
+				struct perf_sample_data *data,
+				struct perf_event *event,
+				struct pt_regs *regs);
+
+int perf_event_open_request_arch_1(void);
+
+#if IS_ENABLED(CONFIG_ARM64)
+
+#define HAS_ARCH_SAMPLE_DATA
+#include <asm/arch_sample_data.h>
+
+#endif
+
+#ifndef HAS_ARCH_SAMPLE_DATA
+struct arch_sample_data {
+};
+#endif
 
 struct perf_sample_data {
 	/*
@@ -1041,6 +1064,7 @@ struct perf_sample_data {
 	u64				cgroup;
 	u64				data_page_size;
 	u64				code_page_size;
+	struct arch_sample_data		arch;
 } ____cacheline_aligned;
 
 /* default value for data source */
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index d37629dbad72..821bf5ff6a19 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -162,12 +162,15 @@ enum perf_event_sample_format {
 	PERF_SAMPLE_DATA_PAGE_SIZE		= 1U << 22,
 	PERF_SAMPLE_CODE_PAGE_SIZE		= 1U << 23,
 	PERF_SAMPLE_WEIGHT_STRUCT		= 1U << 24,
+	PERF_SAMPLE_ARCH_1			= 1U << 25,
 
-	PERF_SAMPLE_MAX = 1U << 25,		/* non-ABI */
+	PERF_SAMPLE_MAX = 1U << 26,		/* non-ABI */
 
 	__PERF_SAMPLE_CALLCHAIN_EARLY		= 1ULL << 63, /* non-ABI; internal use */
 };
 
+#define PERF_SAMPLE_ARM64_PTRAUTH PERF_SAMPLE_ARCH_1
+
 #define PERF_SAMPLE_WEIGHT_TYPE	(PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT)
 /*
  * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 80782cddb1da..89ab8120f4f0 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6957,6 +6957,29 @@ static inline bool perf_sample_save_hw_index(struct perf_event *event)
 	return event->attr.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX;
 }
 
+#ifndef HAS_ARCH_SAMPLE_DATA
+
+inline void perf_output_sample_arch_1(struct perf_output_handle *handle __maybe_unused,
+				      struct perf_event_header *header __maybe_unused,
+				      struct perf_sample_data *data __maybe_unused,
+				      struct perf_event *event __maybe_unused)
+{
+}
+
+inline void perf_prepare_sample_arch_1(struct perf_event_header *header __maybe_unused,
+				       struct perf_sample_data *data __maybe_unused,
+				       struct perf_event *event __maybe_unused,
+				       struct pt_regs *regs __maybe_unused)
+{
+}
+
+inline int perf_event_open_request_arch_1(void)
+{
+	return -EINVAL;
+}
+
+#endif
+
 void perf_output_sample(struct perf_output_handle *handle,
 			struct perf_event_header *header,
 			struct perf_sample_data *data,
@@ -7125,6 +7148,9 @@ void perf_output_sample(struct perf_output_handle *handle,
 			perf_aux_sample_output(event, handle, data);
 	}
 
+	if (sample_type & PERF_SAMPLE_ARCH_1)
+		perf_output_sample_arch_1(handle, header, data, event);
+
 	if (!event->attr.watermark) {
 		int wakeup_events = event->attr.wakeup_events;
 
@@ -7427,6 +7453,9 @@ void perf_prepare_sample(struct perf_event_header *header,
 	if (sample_type & PERF_SAMPLE_CODE_PAGE_SIZE)
 		data->code_page_size = perf_get_page_size(data->ip);
 
+	if (sample_type & PERF_SAMPLE_ARCH_1)
+		perf_prepare_sample_arch_1(header, data, event, regs);
+
 	if (sample_type & PERF_SAMPLE_AUX) {
 		u64 size;
 
@@ -12074,6 +12103,12 @@ SYSCALL_DEFINE5(perf_event_open,
 			return err;
 	}
 
+	if (attr.sample_type & PERF_SAMPLE_ARCH_1) {
+		err = perf_event_open_request_arch_1();
+		if (err)
+			return err;
+	}
+
 	/*
 	 * In cgroup mode, the pid argument is used to pass the fd
 	 * opened to the cgroup directory in cgroupfs. The cpu argument
-- 
2.17.1


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

* [PATCH 2/8] perf evsel: Do not request ptrauth sample field if not supported
  2022-07-04 14:53 [PATCH 0/8] Perf stack unwinding with pointer authentication Andrew Kilroy
  2022-07-04 14:53 ` [PATCH 1/8] perf arm64: Send pointer auth masks to ring buffer Andrew Kilroy
@ 2022-07-04 14:53 ` Andrew Kilroy
  2022-07-06 16:01   ` Vince Weaver
  2022-07-04 14:53 ` [PATCH 3/8] perf test: Update arm64 tests to expect ptrauth masks Andrew Kilroy
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 15+ messages in thread
From: Andrew Kilroy @ 2022-07-04 14:53 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme
  Cc: Andrew Kilroy, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Namhyung Kim, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Tom Rix, linux-arm-kernel, netdev, bpf,
	llvm

A subsequent patch alters perf to perf_event_open with the
PERF_SAMPLE_ARCH_1 bit on.

This patch deals with the case where the kernel does not know about the
PERF_SAMPLE_ARCH_1 bit, and does not know to send the pointer
authentication masks.  In this case the perf_event_open system call
returns -EINVAL (-22) and perf exits with an error.

This patch causes userspace process to re-attempt the perf_event_open
system call but without asking for the PERF_SAMPLE_ARCH_1 sample
field, allowing the perf_event_open system call to succeed.

The check is placed to disable PERF_SAMPLE_ARCH_1 as the first thing
to do in the try_fallback section of evsel__open_cpu() because it's the
most recent sample field added, so should probably be the first thing to
attempt to turn off.

Signed-off-by: Andrew Kilroy <andrew.kilroy@arm.com>
---
 tools/include/uapi/linux/perf_event.h     |  5 ++++-
 tools/perf/util/evsel.c                   | 19 +++++++++++++++++++
 tools/perf/util/evsel.h                   |  1 +
 tools/perf/util/perf_event_attr_fprintf.c |  2 +-
 4 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index d37629dbad72..821bf5ff6a19 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -162,12 +162,15 @@ enum perf_event_sample_format {
 	PERF_SAMPLE_DATA_PAGE_SIZE		= 1U << 22,
 	PERF_SAMPLE_CODE_PAGE_SIZE		= 1U << 23,
 	PERF_SAMPLE_WEIGHT_STRUCT		= 1U << 24,
+	PERF_SAMPLE_ARCH_1			= 1U << 25,
 
-	PERF_SAMPLE_MAX = 1U << 25,		/* non-ABI */
+	PERF_SAMPLE_MAX = 1U << 26,		/* non-ABI */
 
 	__PERF_SAMPLE_CALLCHAIN_EARLY		= 1ULL << 63, /* non-ABI; internal use */
 };
 
+#define PERF_SAMPLE_ARM64_PTRAUTH PERF_SAMPLE_ARCH_1
+
 #define PERF_SAMPLE_WEIGHT_TYPE	(PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT)
 /*
  * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index ce499c5da8d7..25d8f804f49a 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1830,6 +1830,8 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus,
 
 static void evsel__disable_missing_features(struct evsel *evsel)
 {
+	if (perf_missing_features.ptrauth)
+		evsel__reset_sample_bit(evsel, ARM64_PTRAUTH);
 	if (perf_missing_features.weight_struct) {
 		evsel__set_sample_bit(evsel, WEIGHT);
 		evsel__reset_sample_bit(evsel, WEIGHT_STRUCT);
@@ -1875,6 +1877,20 @@ int evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus,
 	return err;
 }
 
+static bool evsel__detect_ptrauth_masks_missing(struct evsel *evsel __maybe_unused)
+{
+#if defined(__aarch64__)
+	if (!perf_missing_features.ptrauth &&
+	    (evsel->core.attr.sample_type & PERF_SAMPLE_ARM64_PTRAUTH)) {
+		perf_missing_features.ptrauth = true;
+		pr_debug2_peo("switching off request for pointer authentication masks\n");
+		return true;
+	}
+#endif
+
+	return false;
+}
+
 bool evsel__detect_missing_features(struct evsel *evsel)
 {
 	/*
@@ -2114,6 +2130,9 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus,
 	return 0;
 
 try_fallback:
+	if (evsel__detect_ptrauth_masks_missing(evsel))
+		goto fallback_missing_features;
+
 	if (evsel__precise_ip_fallback(evsel))
 		goto retry_open;
 
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 73ea48e94079..9690c35088bf 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -188,6 +188,7 @@ struct perf_missing_features {
 	bool data_page_size;
 	bool code_page_size;
 	bool weight_struct;
+	bool ptrauth;
 };
 
 extern struct perf_missing_features perf_missing_features;
diff --git a/tools/perf/util/perf_event_attr_fprintf.c b/tools/perf/util/perf_event_attr_fprintf.c
index 98af3fa4ea35..d18d5f2c6891 100644
--- a/tools/perf/util/perf_event_attr_fprintf.c
+++ b/tools/perf/util/perf_event_attr_fprintf.c
@@ -36,7 +36,7 @@ static void __p_sample_type(char *buf, size_t size, u64 value)
 		bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC),
 		bit_name(WEIGHT), bit_name(PHYS_ADDR), bit_name(AUX),
 		bit_name(CGROUP), bit_name(DATA_PAGE_SIZE), bit_name(CODE_PAGE_SIZE),
-		bit_name(WEIGHT_STRUCT),
+		bit_name(WEIGHT_STRUCT), bit_name(ARCH_1),
 		{ .name = NULL, }
 	};
 #undef bit_name
-- 
2.17.1


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

* [PATCH 3/8] perf test: Update arm64 tests to expect ptrauth masks
  2022-07-04 14:53 [PATCH 0/8] Perf stack unwinding with pointer authentication Andrew Kilroy
  2022-07-04 14:53 ` [PATCH 1/8] perf arm64: Send pointer auth masks to ring buffer Andrew Kilroy
  2022-07-04 14:53 ` [PATCH 2/8] perf evsel: Do not request ptrauth sample field if not supported Andrew Kilroy
@ 2022-07-04 14:53 ` Andrew Kilroy
  2022-07-04 14:53 ` [PATCH 4/8] perf tools: arm64: Read ptrauth data from kernel Andrew Kilroy
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Andrew Kilroy @ 2022-07-04 14:53 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme
  Cc: German Gomez, Andrew Kilroy, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Martin KaFai Lau, Song Liu,
	Yonghong Song, John Fastabend, KP Singh, Tom Rix,
	linux-arm-kernel, netdev, bpf, llvm

From: German Gomez <german.gomez@arm.com>

We will request the pointer auth masks in a followup commit, so take the
opportunity to update the relevant tests.

Signed-off-by: German Gomez <german.gomez@arm.com>
Signed-off-by: Andrew Kilroy <andrew.kilroy@arm.com>
---
 tools/perf/tests/attr/README                        |  1 +
 .../tests/attr/test-record-graph-default-aarch64    |  3 ++-
 tools/perf/tests/attr/test-record-graph-dwarf       |  1 +
 .../perf/tests/attr/test-record-graph-dwarf-aarch64 | 13 +++++++++++++
 tools/perf/tests/attr/test-record-graph-fp-aarch64  |  3 ++-
 5 files changed, 19 insertions(+), 2 deletions(-)
 create mode 100644 tools/perf/tests/attr/test-record-graph-dwarf-aarch64

diff --git a/tools/perf/tests/attr/README b/tools/perf/tests/attr/README
index eb3f7d4bb324..9d7f4646920f 100644
--- a/tools/perf/tests/attr/README
+++ b/tools/perf/tests/attr/README
@@ -47,6 +47,7 @@ Following tests are defined (with perf commands):
   perf record -g kill                           (test-record-graph-default)
   perf record -g kill                           (test-record-graph-default-aarch64)
   perf record --call-graph dwarf kill		(test-record-graph-dwarf)
+  perf record --call-graph dwarf kill		(test-record-graph-dwarf-aarch64)
   perf record --call-graph fp kill              (test-record-graph-fp)
   perf record --call-graph fp kill              (test-record-graph-fp-aarch64)
   perf record --group -e cycles,instructions kill (test-record-group)
diff --git a/tools/perf/tests/attr/test-record-graph-default-aarch64 b/tools/perf/tests/attr/test-record-graph-default-aarch64
index e98d62efb6f7..948d41c162aa 100644
--- a/tools/perf/tests/attr/test-record-graph-default-aarch64
+++ b/tools/perf/tests/attr/test-record-graph-default-aarch64
@@ -5,5 +5,6 @@ ret     = 1
 arch    = aarch64
 
 [event:base-record]
-sample_type=4391
+# handle both with and without ARM64_PTRAUTH
+sample_type=4391|33558823
 sample_regs_user=1073741824
diff --git a/tools/perf/tests/attr/test-record-graph-dwarf b/tools/perf/tests/attr/test-record-graph-dwarf
index ae92061d611d..619bccd886c4 100644
--- a/tools/perf/tests/attr/test-record-graph-dwarf
+++ b/tools/perf/tests/attr/test-record-graph-dwarf
@@ -2,6 +2,7 @@
 command = record
 args    = --no-bpf-event --call-graph dwarf -- kill >/dev/null 2>&1
 ret     = 1
+arch    = !aarch64
 
 [event:base-record]
 sample_type=45359
diff --git a/tools/perf/tests/attr/test-record-graph-dwarf-aarch64 b/tools/perf/tests/attr/test-record-graph-dwarf-aarch64
new file mode 100644
index 000000000000..daec43b39e2e
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-graph-dwarf-aarch64
@@ -0,0 +1,13 @@
+[config]
+command = record
+args    = --no-bpf-event --call-graph dwarf -- kill >/dev/null 2>&1
+ret     = 1
+arch    = aarch64
+
+[event:base-record]
+# handle both with and without ARM64_PTRAUTH
+sample_type=45359|33599791
+exclude_callchain_user=1
+sample_stack_user=8192
+sample_regs_user=*
+mmap_data=1
diff --git a/tools/perf/tests/attr/test-record-graph-fp-aarch64 b/tools/perf/tests/attr/test-record-graph-fp-aarch64
index cbeea9971285..bc0880f71e8e 100644
--- a/tools/perf/tests/attr/test-record-graph-fp-aarch64
+++ b/tools/perf/tests/attr/test-record-graph-fp-aarch64
@@ -5,5 +5,6 @@ ret     = 1
 arch    = aarch64
 
 [event:base-record]
-sample_type=4391
+# handle both with and without ARM64_PTRAUTH
+sample_type=4391|33558823
 sample_regs_user=1073741824
-- 
2.17.1


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

* [PATCH 4/8] perf tools: arm64: Read ptrauth data from kernel
  2022-07-04 14:53 [PATCH 0/8] Perf stack unwinding with pointer authentication Andrew Kilroy
                   ` (2 preceding siblings ...)
  2022-07-04 14:53 ` [PATCH 3/8] perf test: Update arm64 tests to expect ptrauth masks Andrew Kilroy
@ 2022-07-04 14:53 ` Andrew Kilroy
  2022-07-04 14:53 ` [PATCH 5/8] perf libunwind: Feature check for libunwind ptrauth callback Andrew Kilroy
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Andrew Kilroy @ 2022-07-04 14:53 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme
  Cc: Andrew Kilroy, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Namhyung Kim, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Tom Rix, linux-arm-kernel, netdev, bpf,
	llvm

This patch alters the userspace perf program to request the
pointer authentication code masks using the PERF_SAMPLE_ARCH_1 sample
field and write the data to perf.data file.

A subsequent commit will make use of the masks in the data file to do
the unwinding.

Signed-off-by: Andrew Kilroy <andrew.kilroy@arm.com>
---
 tools/perf/tests/sample-parsing.c |  2 +-
 tools/perf/util/event.h           |  8 ++++++
 tools/perf/util/evsel.c           | 45 +++++++++++++++++++++++++++++++
 3 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 07f2411b0ad4..dd78ca279c01 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -381,7 +381,7 @@ static int test__sample_parsing(struct test_suite *test __maybe_unused, int subt
 	 * were added.  Please actually update the test rather than just change
 	 * the condition below.
 	 */
-	if (PERF_SAMPLE_MAX > PERF_SAMPLE_WEIGHT_STRUCT << 1) {
+	if (PERF_SAMPLE_MAX > PERF_SAMPLE_ARCH_1 << 1) {
 		pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n");
 		return -1;
 	}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index cdd72e05fd28..b99fc81dd37e 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -128,6 +128,13 @@ struct aux_sample {
 	void *data;
 };
 
+
+struct ptrauth_info {
+	u64 enabled_keys;  // arm64 ptrauth is in use if this is non-zero.
+	u64 insn_mask;
+	u64 data_mask;
+};
+
 struct perf_sample {
 	u64 ip;
 	u32 pid, tid;
@@ -163,6 +170,7 @@ struct perf_sample {
 	struct stack_dump user_stack;
 	struct sample_read read;
 	struct aux_sample aux_sample;
+	struct ptrauth_info ptrauth;
 };
 
 #define PERF_MEM_DATA_SRC_NONE \
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 25d8f804f49a..4627a68a7797 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -887,8 +887,22 @@ static void __evsel__config_callchain(struct evsel *evsel, struct record_opts *o
 				    "Falling back to framepointers.\n");
 	}
 
+#if defined(__aarch64__)
+	/*
+	 * We need to set ARM64_PTRAUTH in FP mode so that b9f6fbb3b2c2 ("perf arm64: Inject missing
+	 * frames when using 'perf record --call-graph=fp'") continues to work in the presence of
+	 * PACs.
+	 */
+	if (param->record_mode == CALLCHAIN_FP)
+		evsel__set_sample_bit(evsel, ARM64_PTRAUTH);
+
+#endif
+
 	if (param->record_mode == CALLCHAIN_DWARF) {
 		if (!function) {
+#if defined(__aarch64__)
+			evsel__set_sample_bit(evsel, ARM64_PTRAUTH);
+#endif
 			evsel__set_sample_bit(evsel, REGS_USER);
 			evsel__set_sample_bit(evsel, STACK_USER);
 			if (opts->sample_user_regs && DWARF_MINIMAL_REGS != PERF_REGS_MASK) {
@@ -2344,6 +2358,17 @@ u64 evsel__bitfield_swap_branch_flags(u64 value)
 	return new_val;
 }
 
+/*
+ * To return the normalised arch that is recorded in a perf.data file
+ */
+static const char *recorded_normalized_arch(struct evsel *evsel)
+{
+	if (evsel && evsel->evlist && evsel->evlist->env)
+		return perf_env__arch(evsel->evlist->env);
+	else
+		return NULL;
+}
+
 int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
 			struct perf_sample *data)
 {
@@ -2681,6 +2706,26 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
 		array = (void *)array + sz;
 	}
 
+	if (type & PERF_SAMPLE_ARCH_1) {
+		const char *normlzd_arch = recorded_normalized_arch(evsel);
+
+		if (normlzd_arch)
+			pr_debug4("PERF_SAMPLE_ARCH_1 is on, detected recorded arch as %s\n", normlzd_arch);
+		else
+			pr_debug4("PERF_SAMPLE_ARCH_1 is on, but arch not detected\n");
+
+		if (normlzd_arch && strcmp(normlzd_arch, "arm64") == 0) {
+			OVERFLOW_CHECK(array, 3 * sizeof(u64), max_size);
+
+			data->ptrauth.enabled_keys = *array;
+			array++;
+			data->ptrauth.insn_mask = *array;
+			array++;
+			data->ptrauth.data_mask = *array;
+			array++;
+		}
+	}
+
 	return 0;
 }
 
-- 
2.17.1


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

* [PATCH 5/8] perf libunwind: Feature check for libunwind ptrauth callback
  2022-07-04 14:53 [PATCH 0/8] Perf stack unwinding with pointer authentication Andrew Kilroy
                   ` (3 preceding siblings ...)
  2022-07-04 14:53 ` [PATCH 4/8] perf tools: arm64: Read ptrauth data from kernel Andrew Kilroy
@ 2022-07-04 14:53 ` Andrew Kilroy
  2022-07-04 14:53 ` [PATCH 6/8] perf libunwind: arm64 pointer authentication Andrew Kilroy
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Andrew Kilroy @ 2022-07-04 14:53 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme
  Cc: Andrew Kilroy, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Namhyung Kim, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Tom Rix, linux-arm-kernel, netdev, bpf,
	llvm

This patch prepares for a version of libunwind that is capable of
unwinding stacks with pointer authentication.

Without this change, anyone compiling perf would have to depend on a
very new version of libunwind that has the callback to supply it with
pointer authentication masks.

This patch detects if libunwind is recent enough, and if so, sets a
pre-processor flag that will be used in a subsequent commit to call
libunwind appropriately.

If libunwind is not recent enough, the pre-processor flag is not set.

Signed-off-by: Andrew Kilroy <andrew.kilroy@arm.com>
---
 tools/build/Makefile.feature                  |  2 ++
 tools/build/feature/Makefile                  |  4 +++
 tools/build/feature/test-all.c                |  5 ++++
 .../feature/test-libunwind-arm64-ptrauth.c    | 26 +++++++++++++++++++
 tools/perf/Makefile.config                    | 10 +++++++
 5 files changed, 47 insertions(+)
 create mode 100644 tools/build/feature/test-libunwind-arm64-ptrauth.c

diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 888a0421d43b..a894101342fc 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -90,6 +90,7 @@ FEATURE_TESTS_EXTRA :=                  \
          libunwind-x86_64               \
          libunwind-arm                  \
          libunwind-aarch64              \
+         libunwind-arm64-ptrauth        \
          libunwind-debug-frame          \
          libunwind-debug-frame-arm      \
          libunwind-debug-frame-aarch64  \
@@ -128,6 +129,7 @@ FEATURE_DISPLAY ?=              \
          libpython              \
          libcrypto              \
          libunwind              \
+         libunwind-arm64-ptrauth\
          libdw-dwarf-unwind     \
          zlib                   \
          lzma                   \
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index 7c2a17e23c30..ac23175d5bcb 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -45,6 +45,7 @@ FILES=                                          \
          test-libunwind-aarch64.bin             \
          test-libunwind-debug-frame-arm.bin     \
          test-libunwind-debug-frame-aarch64.bin \
+         test-libunwind-arm64-ptrauth.bin \
          test-pthread-attr-setaffinity-np.bin   \
          test-pthread-barrier.bin		\
          test-stackprotector-all.bin            \
@@ -193,6 +194,9 @@ $(OUTPUT)test-libunwind-debug-frame-arm.bin:
 $(OUTPUT)test-libunwind-debug-frame-aarch64.bin:
 	$(BUILD) -lelf -lunwind-aarch64
 
+$(OUTPUT)test-libunwind-arm64-ptrauth.bin:
+	$(BUILD) # -lunwind provided by $(FEATURE_CHECK_LDFLAGS-libunwind-arm64-ptrauth)
+
 $(OUTPUT)test-libaudit.bin:
 	$(BUILD) -laudit
 
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
index 5ffafb967b6e..86780c5c78e5 100644
--- a/tools/build/feature/test-all.c
+++ b/tools/build/feature/test-all.c
@@ -66,6 +66,10 @@
 # include "test-libunwind.c"
 #undef main
 
+#define main main_test_libunwind_arm64_ptrauth
+# include "test-libunwind-arm64-ptrauth.c"
+#undef main
+
 #define main main_test_libslang
 # include "test-libslang.c"
 #undef main
@@ -186,6 +190,7 @@ int main(int argc, char *argv[])
 	main_test_libelf_gelf_getnote();
 	main_test_libelf_getshdrstrndx();
 	main_test_libunwind();
+	main_test_libunwind_arm64_ptrauth();
 	main_test_libslang();
 	main_test_libbfd();
 	main_test_libbfd_buildid();
diff --git a/tools/build/feature/test-libunwind-arm64-ptrauth.c b/tools/build/feature/test-libunwind-arm64-ptrauth.c
new file mode 100644
index 000000000000..51650ceef90e
--- /dev/null
+++ b/tools/build/feature/test-libunwind-arm64-ptrauth.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <libunwind.h>
+
+static unw_word_t get_insn_mask(unw_addr_space_t addr_space, void *unwind_info_ptr)
+{
+	return 0;
+}
+
+// This feature test is intending to check if the version
+// of the available libunwind library is one that has the
+// ptrauth_insn_mask callback function.
+// If it doesn't this feature check should fail to compile.
+static unw_accessors_t accessors = {
+	.ptrauth_insn_mask = get_insn_mask,
+};
+
+int main(void)
+{
+	unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0);
+
+	if (addr_space)
+		return 0;
+
+	return 0;
+}
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 73e0762092fe..2578b1d1a502 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -133,6 +133,8 @@ FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
 FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
 FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
 FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
+FEATURE_CHECK_CFLAGS-libunwind-arm64-ptrauth = $(LIBUNWIND_CFLAGS)
+FEATURE_CHECK_LDFLAGS-libunwind-arm64-ptrauth = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
 
 FEATURE_CHECK_LDFLAGS-libunwind-arm += -lunwind -lunwind-arm
 FEATURE_CHECK_LDFLAGS-libunwind-aarch64 += -lunwind -lunwind-aarch64
@@ -677,6 +679,14 @@ ifndef NO_LIBUNWIND
     $(call detected,CONFIG_LOCAL_LIBUNWIND)
   endif
 
+  ifeq ($(have_libunwind), 1)
+    $(call feature_check,libunwind-arm64-ptrauth)
+    ifneq ($(feature-libunwind-arm64-ptrauth),1)
+      CFLAGS += -DNO_LIBUNWIND_ARM64_PTRAUTH
+      msg := $(warning libunwind cannot produce user stacks in the presence of pointer authentication.);
+    endif
+  endif
+
   ifneq ($(have_libunwind), 1)
     NO_LIBUNWIND := 1
   endif
-- 
2.17.1


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

* [PATCH 6/8] perf libunwind: arm64 pointer authentication
  2022-07-04 14:53 [PATCH 0/8] Perf stack unwinding with pointer authentication Andrew Kilroy
                   ` (4 preceding siblings ...)
  2022-07-04 14:53 ` [PATCH 5/8] perf libunwind: Feature check for libunwind ptrauth callback Andrew Kilroy
@ 2022-07-04 14:53 ` Andrew Kilroy
  2022-07-04 14:53 ` [PATCH 7/8] perf tools: Print ptrauth struct in perf report Andrew Kilroy
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Andrew Kilroy @ 2022-07-04 14:53 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme
  Cc: Andrew Kilroy, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Namhyung Kim, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Tom Rix, linux-arm-kernel, netdev, bpf,
	llvm

Make use of new changes in libunwind to decode a pointer which has a
pointer authentication code (PAC) in it.

Before this patch, perf is not able to produce stack traces where the
instruction addresses had PACs in them.

This commit has a dependency on a libunwind pull request:

  https://github.com/libunwind/libunwind/pull/360

Signed-off-by: Andrew Kilroy <andrew.kilroy@arm.com>
---
 tools/perf/util/unwind-libunwind-local.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index 6e5b8cce47bf..6983a3e76a71 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -652,6 +652,15 @@ static void display_error(int err)
 	}
 }
 
+#ifndef NO_LIBUNWIND_ARM64_PTRAUTH
+static unw_word_t get_insn_mask(unw_addr_space_t addr_space __maybe_unused, void *unwind_info_ptr)
+{
+	struct unwind_info *ui = unwind_info_ptr;
+	unw_word_t mask = ui->sample->ptrauth.insn_mask;
+	return mask;
+}
+#endif
+
 static unw_accessors_t accessors = {
 	.find_proc_info		= find_proc_info,
 	.put_unwind_info	= put_unwind_info,
@@ -661,6 +670,9 @@ static unw_accessors_t accessors = {
 	.access_fpreg		= access_fpreg,
 	.resume			= resume,
 	.get_proc_name		= get_proc_name,
+#ifndef NO_LIBUNWIND_ARM64_PTRAUTH
+	.ptrauth_insn_mask	= get_insn_mask,
+#endif
 };
 
 static int _unwind__prepare_access(struct maps *maps)
-- 
2.17.1


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

* [PATCH 7/8] perf tools: Print ptrauth struct in perf report
  2022-07-04 14:53 [PATCH 0/8] Perf stack unwinding with pointer authentication Andrew Kilroy
                   ` (5 preceding siblings ...)
  2022-07-04 14:53 ` [PATCH 6/8] perf libunwind: arm64 pointer authentication Andrew Kilroy
@ 2022-07-04 14:53 ` Andrew Kilroy
  2022-07-04 14:53 ` [PATCH 8/8] perf test arm64: Test unwinding with PACs on gcc & clang compilers Andrew Kilroy
  2022-09-07 15:00 ` [PATCH 0/8] Perf stack unwinding with pointer authentication James Clark
  8 siblings, 0 replies; 15+ messages in thread
From: Andrew Kilroy @ 2022-07-04 14:53 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme
  Cc: Andrew Kilroy, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Namhyung Kim, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Tom Rix, linux-arm-kernel, netdev, bpf,
	llvm

This patch prints a perf sample's ptrauth struct so that the PAC masks
can be seen.  To aid debugging.

Signed-off-by: Andrew Kilroy <andrew.kilroy@arm.com>
---
 tools/perf/util/session.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 37f833c3c81b..6b56e638d4dd 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1329,6 +1329,13 @@ char *get_page_size_name(u64 size, char *str)
 	return str;
 }
 
+static void ptrauth__printf(struct ptrauth_info *ptrauth)
+{
+	printf(" . ptrauth enabled keys:     0x%016"PRIx64"\n", ptrauth->enabled_keys);
+	printf(" . ptrauth instruction mask: 0x%016"PRIx64"\n", ptrauth->insn_mask);
+	printf(" . ptrauth data mask:        0x%016"PRIx64"\n", ptrauth->data_mask);
+}
+
 static void dump_sample(struct evsel *evsel, union perf_event *event,
 			struct perf_sample *sample, const char *arch)
 {
@@ -1385,6 +1392,14 @@ static void dump_sample(struct evsel *evsel, union perf_event *event,
 
 	if (sample_type & PERF_SAMPLE_READ)
 		sample_read__printf(sample, evsel->core.attr.read_format);
+
+	if (sample_type & PERF_SAMPLE_ARCH_1) {
+		const char *normlzd_arch = perf_env__arch(evsel->evlist->env);
+
+		if (normlzd_arch && strcmp(normlzd_arch, "arm64") == 0)
+			ptrauth__printf(&sample->ptrauth);
+	}
+
 }
 
 static void dump_read(struct evsel *evsel, union perf_event *event)
-- 
2.17.1


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

* [PATCH 8/8] perf test arm64: Test unwinding with PACs on gcc & clang compilers
  2022-07-04 14:53 [PATCH 0/8] Perf stack unwinding with pointer authentication Andrew Kilroy
                   ` (6 preceding siblings ...)
  2022-07-04 14:53 ` [PATCH 7/8] perf tools: Print ptrauth struct in perf report Andrew Kilroy
@ 2022-07-04 14:53 ` Andrew Kilroy
  2022-09-07 15:00 ` [PATCH 0/8] Perf stack unwinding with pointer authentication James Clark
  8 siblings, 0 replies; 15+ messages in thread
From: Andrew Kilroy @ 2022-07-04 14:53 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme
  Cc: German Gomez, Andrew Kilroy, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Martin KaFai Lau, Song Liu,
	Yonghong Song, John Fastabend, KP Singh, Tom Rix,
	linux-arm-kernel, netdev, bpf, llvm

From: German Gomez <german.gomez@arm.com>

Adds self test to test unwindings in the presence of PACs for different
versions of gcc and clang.

Example run:

| $ ./perf test 74
|  74: Arm64 unwinding with PAC support           :
|  74.1: gcc-9                                    : Ok
|  74.2: gcc-10                                   : Ok
|  74.3: gcc-11                                   : Ok
|  74.4: gcc-12                                   : Ok
|  74.5: clang-12                                 : Skip (not installed)
|  74.6: clang-13                                 : Skip (not installed)
|  74.7: clang-14                                 : Ok

Signed-off-by: German Gomez <german.gomez@arm.com>
Signed-off-by: Andrew Kilroy <andrew.kilroy@arm.com>
---
 tools/perf/Makefile.perf           |   1 +
 tools/perf/tests/Build             |   1 +
 tools/perf/tests/arm_unwind_pac.c  | 113 +++++++++++++++++++++++++++++
 tools/perf/tests/arm_unwind_pac.sh |  57 +++++++++++++++
 tools/perf/tests/builtin-test.c    |   1 +
 tools/perf/tests/tests.h           |   1 +
 6 files changed, 174 insertions(+)
 create mode 100644 tools/perf/tests/arm_unwind_pac.c
 create mode 100755 tools/perf/tests/arm_unwind_pac.sh

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 8f738e11356d..35d067534cf1 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -1008,6 +1008,7 @@ endif
 install-tests: all install-gtk
 	$(call QUIET_INSTALL, tests) \
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
+		$(INSTALL) tests/arm_unwind_pac.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
 		$(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
 		$(INSTALL) tests/pe-file.exe* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index af2b37ef7c70..a03c189c5e98 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -66,6 +66,7 @@ perf-y += expand-cgroup.o
 perf-y += perf-time-to-tsc.o
 perf-y += dlfilter-test.o
 perf-y += sigtrap.o
+perf-y += arm_unwind_pac.o
 
 $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
 	$(call rule_mkdir)
diff --git a/tools/perf/tests/arm_unwind_pac.c b/tools/perf/tests/arm_unwind_pac.c
new file mode 100644
index 000000000000..11b7e936a72d
--- /dev/null
+++ b/tools/perf/tests/arm_unwind_pac.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <subcmd/exec-cmd.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "pmu.h"
+#include "tests.h"
+#include "debug.h"
+
+#if defined(HAVE_LIBUNWIND_SUPPORT) && defined(__aarch64__)
+
+#define BUF_MAX 1024
+
+static bool test_command_exists(const char *cmd)
+{
+	char buf[BUF_MAX];
+
+	scnprintf(buf, BUF_MAX, "which %s", cmd);
+	return !system(buf);
+}
+
+static int run_dir(const char *d, const char *compiler, const char *compiler_argv)
+{
+	char buf[BUF_MAX];
+
+	if (!test_command_exists(compiler))
+		return TEST_SKIP;
+
+	scnprintf(buf, BUF_MAX, "%s/arm_unwind_pac.sh %s '%s'", d, compiler, compiler_argv);
+	return system(buf) ? TEST_FAIL : TEST_OK;
+}
+
+static int run(const char *compiler, const char *compiler_argv)
+{
+	struct stat st;
+	char exec_test_path[BUF_MAX];
+	char *exec_path;
+
+	/* Check development tree tests. */
+	if (!lstat("./tests", &st))
+		return run_dir("./tests", compiler, compiler_argv);
+
+	/* Otherwise, check installed path */
+	exec_path = get_argv_exec_path();
+	if (exec_path == NULL)
+		return -1;
+
+	snprintf(exec_test_path, BUF_MAX, "%s/tests", exec_path);
+	if (!lstat(exec_test_path, &st))
+		return run_dir(exec_test_path, compiler, compiler_argv);
+
+	return TEST_SKIP;
+}
+
+#define TEST_COMPILER(_test, compiler, args)					\
+	static int test__##_test(struct test_suite *test __maybe_unused,	\
+				 int subtest __maybe_unused)			\
+	{									\
+		return run(compiler, args);					\
+	}
+
+/*
+ * gcc compilers
+ */
+TEST_COMPILER(gcc8,	"gcc-8",	"-msign-return-address=all")
+TEST_COMPILER(gcc9,	"gcc-9",	"-mbranch-protection=pac-ret+leaf")
+TEST_COMPILER(gcc10,	"gcc-10",	"-mbranch-protection=pac-ret+leaf")
+TEST_COMPILER(gcc11,	"gcc-11",	"-mbranch-protection=pac-ret+leaf")
+TEST_COMPILER(gcc12,	"gcc-12",	"-mbranch-protection=pac-ret+leaf")
+
+/*
+ * clang compilers
+ */
+TEST_COMPILER(clang12,	"clang-12",	"-msign-return-address=all")
+TEST_COMPILER(clang13,	"clang-13",	"-msign-return-address=all")
+TEST_COMPILER(clang14,	"clang-14",	"-msign-return-address=all")
+
+static struct test_case pac_tests[] = {
+#define PAC_TEST_CASE(name, test) \
+	TEST_CASE_REASON(name, test, "not installed")
+
+	PAC_TEST_CASE("gcc-8",		gcc8),
+	PAC_TEST_CASE("gcc-9",		gcc9),
+	PAC_TEST_CASE("gcc-10",		gcc10),
+	PAC_TEST_CASE("gcc-11",		gcc11),
+	PAC_TEST_CASE("gcc-12",		gcc12),
+
+	PAC_TEST_CASE("clang-12",	clang12),
+	PAC_TEST_CASE("clang-13",	clang13),
+	PAC_TEST_CASE("clang-14",	clang14),
+
+#undef PAC_TEST_CASE
+	{ .name = NULL, }
+};
+
+struct test_suite suite__arm_unwind_pac = {
+	.desc = "Arm64 unwinding with PAC support",
+	.test_cases = pac_tests,
+};
+
+#else // HAVE_LIBUNWIND_SUPPORT && __aarch64__
+
+static int test__arm_unwind_pac(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
+{
+	return TEST_SKIP;
+}
+
+DEFINE_SUITE("Arm64 unwinding with PAC support", arm_unwind_pac);
+
+#endif // HAVE_LIBUNWIND_SUPPORT && __aarch64__
diff --git a/tools/perf/tests/arm_unwind_pac.sh b/tools/perf/tests/arm_unwind_pac.sh
new file mode 100755
index 000000000000..7491dc5f908b
--- /dev/null
+++ b/tools/perf/tests/arm_unwind_pac.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+COMPILER_CMD="$1"
+COMPILER_ARG="$2 -g -fno-omit-frame-pointer -fno-inline"
+
+echo "COMPILER_CMD=$COMPILER_CMD"
+echo "COMPILER_ARG=$COMPILER_ARG"
+
+TMPDIR=$(mktemp -d /tmp/__perf_test.XXXXX)
+
+clean_up() {
+	rm -rf $TMPDIR
+}
+
+trap clean_up exit term int
+
+cat << EOF > $TMPDIR/program.c
+void bar(void) {
+  for(;;);
+}
+void foo(void) {
+  bar();
+}
+int main(void) {
+  foo();
+  return 0;
+}
+EOF
+
+$COMPILER_CMD $COMPILER_ARG $TMPDIR/program.c -o $TMPDIR/program
+
+perf record --call-graph=dwarf -e cycles//u -o $TMPDIR/perf-dwarf.data -- $TMPDIR/program &
+PID=$!
+sleep 1
+kill $PID
+wait $PID
+
+perf record --call-graph=fp -e cycles//u -o $TMPDIR/perf-fp.data -- $TMPDIR/program &
+PID=$!
+sleep 1
+kill $PID
+wait $PID
+
+perf report --symbols=bar -i $TMPDIR/perf-dwarf.data --stdio > $TMPDIR/report-dwarf
+perf report --symbols=bar -i $TMPDIR/perf-fp.data --stdio > $TMPDIR/report-fp
+
+set -e
+set -x
+
+grep "main" $TMPDIR/report-dwarf
+grep "foo" $TMPDIR/report-dwarf
+grep "bar" $TMPDIR/report-dwarf
+
+grep "main" $TMPDIR/report-fp
+grep "foo" $TMPDIR/report-fp
+grep "bar" $TMPDIR/report-fp
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 81cf241cd109..e121cfd43b8d 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -108,6 +108,7 @@ static struct test_suite *generic_tests[] = {
 	&suite__perf_time_to_tsc,
 	&suite__dlfilter,
 	&suite__sigtrap,
+	&suite__arm_unwind_pac,
 	NULL,
 };
 
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 5bbb8f6a48fc..459e473a91cd 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -147,6 +147,7 @@ DECLARE_SUITE(expand_cgroup_events);
 DECLARE_SUITE(perf_time_to_tsc);
 DECLARE_SUITE(dlfilter);
 DECLARE_SUITE(sigtrap);
+DECLARE_SUITE(arm_unwind_pac);
 
 /*
  * PowerPC and S390 do not support creation of instruction breakpoints using the
-- 
2.17.1


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

* Re: [PATCH 2/8] perf evsel: Do not request ptrauth sample field if not supported
  2022-07-04 14:53 ` [PATCH 2/8] perf evsel: Do not request ptrauth sample field if not supported Andrew Kilroy
@ 2022-07-06 16:01   ` Vince Weaver
  2022-07-11  9:25     ` James Clark
  0 siblings, 1 reply; 15+ messages in thread
From: Vince Weaver @ 2022-07-06 16:01 UTC (permalink / raw)
  To: Andrew Kilroy
  Cc: linux-kernel, linux-perf-users, acme, Peter Zijlstra,
	Ingo Molnar, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Namhyung Kim, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Tom Rix, linux-arm-kernel, netdev, bpf,
	llvm

On Mon, 4 Jul 2022, Andrew Kilroy wrote:

> A subsequent patch alters perf to perf_event_open with the
> PERF_SAMPLE_ARCH_1 bit on.
> 
> This patch deals with the case where the kernel does not know about the
> PERF_SAMPLE_ARCH_1 bit, and does not know to send the pointer
> authentication masks.  In this case the perf_event_open system call
> returns -EINVAL (-22) and perf exits with an error.
> 
> This patch causes userspace process to re-attempt the perf_event_open
> system call but without asking for the PERF_SAMPLE_ARCH_1 sample
> field, allowing the perf_event_open system call to succeed.

So in this case you are leaking ARM64-specific info into the generic 
perf_event_open() call?  Is there any way the kernel could implement this 
without userspace having to deal with the issue?

There are a few recent ARM64 perf_event related patches that are pushing 
ARM specific interfaces into the generic code, with the apparent 
assumption that it will just be implemented in the userspace perf tool.  
However there are a number of outside-the-kernel codebases that also use 
perf_event_open() and it seems a bit onerous if all of them have to start 
adding a lot of extra ARM64-specific code, especially because as far as I 
can tell there haven't been any documentation patches included for the 
Makefile.

The other recent change that's annoying for userspace is the addition of 
the ARM-specific /proc/sys/kernel/perf_user_access that duplicates 
functionality found in /sys/devices/cpu/rdpmc

Vince Weaver
vincent.weaver@maine.edu

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

* Re: [PATCH 2/8] perf evsel: Do not request ptrauth sample field if not supported
  2022-07-06 16:01   ` Vince Weaver
@ 2022-07-11  9:25     ` James Clark
  2022-07-12 21:30       ` Vince Weaver
  0 siblings, 1 reply; 15+ messages in thread
From: James Clark @ 2022-07-11  9:25 UTC (permalink / raw)
  To: Vince Weaver, Andrew Kilroy
  Cc: linux-kernel, linux-perf-users, acme, Peter Zijlstra,
	Ingo Molnar, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Namhyung Kim, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Tom Rix, linux-arm-kernel, netdev, bpf,
	llvm



On 06/07/2022 17:01, Vince Weaver wrote:
> On Mon, 4 Jul 2022, Andrew Kilroy wrote:
> 
>> A subsequent patch alters perf to perf_event_open with the
>> PERF_SAMPLE_ARCH_1 bit on.
>>
>> This patch deals with the case where the kernel does not know about the
>> PERF_SAMPLE_ARCH_1 bit, and does not know to send the pointer
>> authentication masks.  In this case the perf_event_open system call
>> returns -EINVAL (-22) and perf exits with an error.
>>
>> This patch causes userspace process to re-attempt the perf_event_open
>> system call but without asking for the PERF_SAMPLE_ARCH_1 sample
>> field, allowing the perf_event_open system call to succeed.
> 
> So in this case you are leaking ARM64-specific info into the generic 
> perf_event_open() call?  Is there any way the kernel could implement this 
> without userspace having to deal with the issue?

Hi Vince,

The alternative to this change is just to call it "PERF_SAMPLE_POINTER_AUTH_MASK"
and then it's not Arm specific, it's just that only Arm implements it for now.
This is definitely an option.

But if no platform ever implements something similar then that bit is wasted.
The intention of adding "PERF_SAMPLE_ARCH_1" was to prevent wasting that bit.
But as you say, maybe making it arch specific isn't the right way either.

I wouldn't say the perf_event_open call is currently generic though, lots of
it already requires knowledge of the current platform, and searching for 'x86'
in the docs for it gives 10 matches.

> 
> There are a few recent ARM64 perf_event related patches that are pushing 
> ARM specific interfaces into the generic code, with the apparent 
> assumption that it will just be implemented in the userspace perf tool.  
> However there are a number of outside-the-kernel codebases that also use 
> perf_event_open() and it seems a bit onerous if all of them have to start 
> adding a lot of extra ARM64-specific code, especially because as far as I 

Because pointer auth is a hardware feature, other tools have no choice but
to implement this if they do Dwarf based stack unwinding. There is no way
around that. The pointers are stored mangled and they don't make sense
without masking them. GDB has already implemented support for it. If they
don't do Dwarf based stack unwinding then they can carry on as they are
and everything will still work.

> can tell there haven't been any documentation patches included for the 
> Makefile.

We plan to update the docs for the syscall, but it's in another repo, and
we'll wait for this change to be finalised first. I'm not sure what you
mean about the Makefile?

Thanks
James

> 
> The other recent change that's annoying for userspace is the addition of 
> the ARM-specific /proc/sys/kernel/perf_user_access that duplicates 
> functionality found in /sys/devices/cpu/rdpmc
> 
> Vince Weaver
> vincent.weaver@maine.edu

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

* Re: [PATCH 2/8] perf evsel: Do not request ptrauth sample field if not supported
  2022-07-11  9:25     ` James Clark
@ 2022-07-12 21:30       ` Vince Weaver
  0 siblings, 0 replies; 15+ messages in thread
From: Vince Weaver @ 2022-07-12 21:30 UTC (permalink / raw)
  To: James Clark
  Cc: Andrew Kilroy, linux-kernel, linux-perf-users, acme,
	Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Martin KaFai Lau, Song Liu,
	Yonghong Song, John Fastabend, KP Singh, Tom Rix,
	linux-arm-kernel, netdev, bpf, llvm

On Mon, 11 Jul 2022, James Clark wrote:
> On 06/07/2022 17:01, Vince Weaver wrote:
> > So in this case you are leaking ARM64-specific info into the generic 
> > perf_event_open() call?  Is there any way the kernel could implement this 
> > without userspace having to deal with the issue?
> 
> The alternative to this change is just to call it "PERF_SAMPLE_POINTER_AUTH_MASK"
> and then it's not Arm specific, it's just that only Arm implements it for now.
> This is definitely an option.
> 
> But if no platform ever implements something similar then that bit is wasted.
> The intention of adding "PERF_SAMPLE_ARCH_1" was to prevent wasting that bit.
> But as you say, maybe making it arch specific isn't the right way either.

I don't know what the current kernel policy is on this kind of thing, but 
in the past perf_event_open was meant to be a generic as possible.
Having architecture-specific magic bits is best avoided.
However I'm not the maintainer for this so really my opinion doesn't 
really matter.

I'm just speaking up as a userspace coder who is trying to write 
cross-platform tools, and having to maintain obscure arch-specific code 
paths in every single utility ends up being a huge pain.  And isn't the 
whole point of an operating system to abstract this away?

> > can tell there haven't been any documentation patches included for the 
> > Makefile.
> 
> We plan to update the docs for the syscall, but it's in another repo, and
> we'll wait for this change to be finalised first. I'm not sure what you
> mean about the Makefile?

sorry, that was a mis-type.  I meant "manpage" not Makefile.

Vince Weaver
vincent.weaver@maine.edu

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

* Re: [PATCH 1/8] perf arm64: Send pointer auth masks to ring buffer
  2022-07-04 14:53 ` [PATCH 1/8] perf arm64: Send pointer auth masks to ring buffer Andrew Kilroy
@ 2022-08-10 13:23   ` Arnaldo Carvalho de Melo
  2022-09-07 15:21     ` James Clark
  0 siblings, 1 reply; 15+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-10 13:23 UTC (permalink / raw)
  To: Andrew Kilroy
  Cc: linux-kernel, linux-perf-users, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Martin KaFai Lau, Song Liu,
	Yonghong Song, John Fastabend, KP Singh, Tom Rix,
	linux-arm-kernel, netdev, bpf, llvm

Em Mon, Jul 04, 2022 at 03:53:25PM +0100, Andrew Kilroy escreveu:
> Perf report cannot produce callgraphs using dwarf on arm64 where pointer
> authentication is enabled.  This is because libunwind and libdw cannot
> unmangle instruction pointers that have a pointer authentication code
> (PAC) embedded in them.
> 
> libunwind and libdw need to be given an instruction mask which they can
> use to arrive at the correct return address that does not contain the
> PAC.
> 
> The bits in the return address that contain the PAC can differ by
> process, so this patch adds a new sample field PERF_SAMPLE_ARCH_1
> to allow the kernel to send the masks up to userspace perf.
> 
> This field can be used in a architecture specific fashion, but on
> aarch64, it contains the ptrauth mask information.

I'm not seeing this kernel patch applied to tip/master or
torvalds/master, what is the status of that part? Then I can look at the
tooling part.

- Arnaldo
 
> Signed-off-by: Andrew Kilroy <andrew.kilroy@arm.com>
> ---
>  arch/arm64/include/asm/arch_sample_data.h | 38 +++++++++++++++++++++++
>  arch/arm64/kernel/Makefile                |  2 +-
>  arch/arm64/kernel/arch_sample_data.c      | 37 ++++++++++++++++++++++
>  include/linux/perf_event.h                | 24 ++++++++++++++
>  include/uapi/linux/perf_event.h           |  5 ++-
>  kernel/events/core.c                      | 35 +++++++++++++++++++++
>  6 files changed, 139 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm64/include/asm/arch_sample_data.h
>  create mode 100644 arch/arm64/kernel/arch_sample_data.c
> 
> diff --git a/arch/arm64/include/asm/arch_sample_data.h b/arch/arm64/include/asm/arch_sample_data.h
> new file mode 100644
> index 000000000000..83fda293b1fc
> --- /dev/null
> +++ b/arch/arm64/include/asm/arch_sample_data.h
> @@ -0,0 +1,38 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef _ASM_ARCH_SAMPLE_DATA_H
> +#define _ASM_ARCH_SAMPLE_DATA_H
> +
> +#include <linux/types.h>
> +
> +/*
> + * Structure holding masks to help userspace stack unwinding
> + * in the presence of arm64 pointer authentication.
> + */
> +struct ptrauth_info {
> +	/*
> +	 * Bits 0, 1, 2, 3, 4 may be set to on, to indicate which keys are being used
> +	 * The APIAKEY, APIBKEY, APDAKEY, APDBKEY, or the APGAKEY respectively.
> +	 * Where all bits are off, pointer authentication is not in use for the
> +	 * process.
> +	 */
> +	u64 enabled_keys;
> +
> +	/*
> +	 * The on bits represent which bits in an instruction pointer
> +	 * constitute the pointer authentication code.
> +	 */
> +	u64 insn_mask;
> +
> +	/*
> +	 * The on bits represent which bits in a data pointer constitute the
> +	 * pointer authentication code.
> +	 */
> +	u64 data_mask;
> +};
> +
> +struct arch_sample_data {
> +	struct ptrauth_info ptrauth;
> +};
> +
> +#endif
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index fa7981d0d917..843c6e0e2393 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -44,7 +44,7 @@ obj-$(CONFIG_KUSER_HELPERS)		+= kuser32.o
>  obj-$(CONFIG_FUNCTION_TRACER)		+= ftrace.o entry-ftrace.o
>  obj-$(CONFIG_MODULES)			+= module.o
>  obj-$(CONFIG_ARM64_MODULE_PLTS)		+= module-plts.o
> -obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o perf_callchain.o
> +obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o perf_callchain.o arch_sample_data.o
>  obj-$(CONFIG_HW_PERF_EVENTS)		+= perf_event.o
>  obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
>  obj-$(CONFIG_CPU_PM)			+= sleep.o suspend.o
> diff --git a/arch/arm64/kernel/arch_sample_data.c b/arch/arm64/kernel/arch_sample_data.c
> new file mode 100644
> index 000000000000..2d47e8db0dbe
> --- /dev/null
> +++ b/arch/arm64/kernel/arch_sample_data.c
> @@ -0,0 +1,37 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <asm/arch_sample_data.h>
> +#include <linux/perf_event.h>
> +
> +inline void perf_output_sample_arch_1(struct perf_output_handle *handle,
> +				      struct perf_event_header *header,
> +				      struct perf_sample_data *data,
> +				      struct perf_event *event)
> +{
> +	perf_output_put(handle, data->arch.ptrauth.enabled_keys);
> +	perf_output_put(handle, data->arch.ptrauth.insn_mask);
> +	perf_output_put(handle, data->arch.ptrauth.data_mask);
> +}
> +
> +inline void perf_prepare_sample_arch_1(struct perf_event_header *header,
> +				       struct perf_sample_data *data,
> +				       struct perf_event *event,
> +				       struct pt_regs *regs)
> +{
> +	struct task_struct *task = current;
> +	int keys_result = ptrauth_get_enabled_keys(task);
> +	u64 user_pac_mask = keys_result > 0 ? ptrauth_user_pac_mask() : 0;
> +
> +	data->arch.ptrauth.enabled_keys = keys_result > 0 ? keys_result : 0;
> +	data->arch.ptrauth.insn_mask = user_pac_mask;
> +	data->arch.ptrauth.data_mask = user_pac_mask;
> +
> +	header->size += (3 * sizeof(u64));
> +}
> +
> +inline int perf_event_open_request_arch_1(void)
> +{
> +	return 0;
> +}
> +
> +
> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
> index da759560eec5..8a99942989ce 100644
> --- a/include/linux/perf_event.h
> +++ b/include/linux/perf_event.h
> @@ -999,6 +999,29 @@ int perf_event_read_local(struct perf_event *event, u64 *value,
>  extern u64 perf_event_read_value(struct perf_event *event,
>  				 u64 *enabled, u64 *running);
>  
> +void perf_output_sample_arch_1(struct perf_output_handle *handle,
> +			       struct perf_event_header *header,
> +			       struct perf_sample_data *data,
> +			       struct perf_event *event);
> +
> +void perf_prepare_sample_arch_1(struct perf_event_header *header,
> +				struct perf_sample_data *data,
> +				struct perf_event *event,
> +				struct pt_regs *regs);
> +
> +int perf_event_open_request_arch_1(void);
> +
> +#if IS_ENABLED(CONFIG_ARM64)
> +
> +#define HAS_ARCH_SAMPLE_DATA
> +#include <asm/arch_sample_data.h>
> +
> +#endif
> +
> +#ifndef HAS_ARCH_SAMPLE_DATA
> +struct arch_sample_data {
> +};
> +#endif
>  
>  struct perf_sample_data {
>  	/*
> @@ -1041,6 +1064,7 @@ struct perf_sample_data {
>  	u64				cgroup;
>  	u64				data_page_size;
>  	u64				code_page_size;
> +	struct arch_sample_data		arch;
>  } ____cacheline_aligned;
>  
>  /* default value for data source */
> diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
> index d37629dbad72..821bf5ff6a19 100644
> --- a/include/uapi/linux/perf_event.h
> +++ b/include/uapi/linux/perf_event.h
> @@ -162,12 +162,15 @@ enum perf_event_sample_format {
>  	PERF_SAMPLE_DATA_PAGE_SIZE		= 1U << 22,
>  	PERF_SAMPLE_CODE_PAGE_SIZE		= 1U << 23,
>  	PERF_SAMPLE_WEIGHT_STRUCT		= 1U << 24,
> +	PERF_SAMPLE_ARCH_1			= 1U << 25,
>  
> -	PERF_SAMPLE_MAX = 1U << 25,		/* non-ABI */
> +	PERF_SAMPLE_MAX = 1U << 26,		/* non-ABI */
>  
>  	__PERF_SAMPLE_CALLCHAIN_EARLY		= 1ULL << 63, /* non-ABI; internal use */
>  };
>  
> +#define PERF_SAMPLE_ARM64_PTRAUTH PERF_SAMPLE_ARCH_1
> +
>  #define PERF_SAMPLE_WEIGHT_TYPE	(PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT)
>  /*
>   * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index 80782cddb1da..89ab8120f4f0 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -6957,6 +6957,29 @@ static inline bool perf_sample_save_hw_index(struct perf_event *event)
>  	return event->attr.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX;
>  }
>  
> +#ifndef HAS_ARCH_SAMPLE_DATA
> +
> +inline void perf_output_sample_arch_1(struct perf_output_handle *handle __maybe_unused,
> +				      struct perf_event_header *header __maybe_unused,
> +				      struct perf_sample_data *data __maybe_unused,
> +				      struct perf_event *event __maybe_unused)
> +{
> +}
> +
> +inline void perf_prepare_sample_arch_1(struct perf_event_header *header __maybe_unused,
> +				       struct perf_sample_data *data __maybe_unused,
> +				       struct perf_event *event __maybe_unused,
> +				       struct pt_regs *regs __maybe_unused)
> +{
> +}
> +
> +inline int perf_event_open_request_arch_1(void)
> +{
> +	return -EINVAL;
> +}
> +
> +#endif
> +
>  void perf_output_sample(struct perf_output_handle *handle,
>  			struct perf_event_header *header,
>  			struct perf_sample_data *data,
> @@ -7125,6 +7148,9 @@ void perf_output_sample(struct perf_output_handle *handle,
>  			perf_aux_sample_output(event, handle, data);
>  	}
>  
> +	if (sample_type & PERF_SAMPLE_ARCH_1)
> +		perf_output_sample_arch_1(handle, header, data, event);
> +
>  	if (!event->attr.watermark) {
>  		int wakeup_events = event->attr.wakeup_events;
>  
> @@ -7427,6 +7453,9 @@ void perf_prepare_sample(struct perf_event_header *header,
>  	if (sample_type & PERF_SAMPLE_CODE_PAGE_SIZE)
>  		data->code_page_size = perf_get_page_size(data->ip);
>  
> +	if (sample_type & PERF_SAMPLE_ARCH_1)
> +		perf_prepare_sample_arch_1(header, data, event, regs);
> +
>  	if (sample_type & PERF_SAMPLE_AUX) {
>  		u64 size;
>  
> @@ -12074,6 +12103,12 @@ SYSCALL_DEFINE5(perf_event_open,
>  			return err;
>  	}
>  
> +	if (attr.sample_type & PERF_SAMPLE_ARCH_1) {
> +		err = perf_event_open_request_arch_1();
> +		if (err)
> +			return err;
> +	}
> +
>  	/*
>  	 * In cgroup mode, the pid argument is used to pass the fd
>  	 * opened to the cgroup directory in cgroupfs. The cpu argument
> -- 
> 2.17.1

-- 

- Arnaldo

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

* Re: [PATCH 0/8] Perf stack unwinding with pointer authentication
  2022-07-04 14:53 [PATCH 0/8] Perf stack unwinding with pointer authentication Andrew Kilroy
                   ` (7 preceding siblings ...)
  2022-07-04 14:53 ` [PATCH 8/8] perf test arm64: Test unwinding with PACs on gcc & clang compilers Andrew Kilroy
@ 2022-09-07 15:00 ` James Clark
  8 siblings, 0 replies; 15+ messages in thread
From: James Clark @ 2022-09-07 15:00 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme, peterz
  Cc: Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
	KP Singh, Tom Rix, linux-arm-kernel, netdev, bpf, llvm,
	Andrew Kilroy



On 04/07/2022 15:53, Andrew Kilroy wrote:
> This patch series addresses issues that perf has when attempting to show
> userspace stacks in the presence of pointer authentication on arm64.
> 
> Depending on whether libunwind or libdw is used, perf incorrectly
> displays the userspace stack in 'perf report --stdio'.  With libunwind,
> only the leaf function is shown.
> 
>             |
>             ---0x200000004005bf
>                0x200000004005bf
>                my_leaf_function
> 
> With libdw, only the leaf function is shown even though there are
> callers in the application.
> 
>             |
>             ---my_leaf_function
> 
> 
> The reason perf cannot show the stack upon a perf report --stdio is
> because the unwinders are given instruction pointers which contain a
> pointer authentication code (PAC).  For the libraries to correctly
> unwind, they need to know which bits of the instruction pointer to turn
> off.
> 
> The kernel exposes the set of PAC bits via the NT_ARM_PAC_MASK regset.
> It is expected that this may vary per-task in future. The kernel also
> exposes which pointer authentication keys are enabled via the
> NT_ARM_PAC_ENABLED_KEYS regset, and this can change dynamically. These
> are per-task state which perf would need to sample.
> 
> It's not always feasible for perf to acquire these regsets via ptrace.
> When sampling system-wide or with inherited events this may require a
> large volume of ptrace requests, and by the time the perf tool processes
> a sample for a task, that task might already have terminated.
> 
> Instead, these patches allow this state to be sampled into the perf
> ringbuffer, where it can be consumed more easily by the perf tool.
> 
> The first patch changes the kernel to send the authentication PAC masks
> to userspace perf via the perf ring buffer.  This is published in the
> sample, using a new sample field PERF_SAMPLE_ARCH_1.
> 
> The subsequent patches are changes to userspace perf to
> 
> 1) request the PERF_SAMPLE_ARCH_1
> 2) supply the instruction mask to libunwind
> 3) ensure perf can cope with an older kernel that does not know about
>    the PERF_SAMPLE_ARCH_1 sample field.
> 4) checks if the version of libunwind has the capability to accept
>    an instruction mask from perf and if so enable the feature.
> 
> These changes depend on a change to libunwind, that is yet to be
> released, although the patch has been merged.
> 
>   https://github.com/libunwind/libunwind/pull/360
> 

For the whole set:

Reviewed-by: James Clark <james.clark@arm.com>

I checked that the new test passes on an AWS Graviton 3 instance and
with a build of mainline libunwind. I also checked that the PAC masks on
the samples look sensible.

The tests also still pass when run on N1SDP which doesn't have pointer
authentication.

> 
> Andrew Kilroy (6):
>   perf arm64: Send pointer auth masks to ring buffer
>   perf evsel: Do not request ptrauth sample field if not supported
>   perf tools: arm64: Read ptrauth data from kernel
>   perf libunwind: Feature check for libunwind ptrauth callback
>   perf libunwind: arm64 pointer authentication
>   perf tools: Print ptrauth struct in perf report
> 
> German Gomez (2):
>   perf test: Update arm64 tests to expect ptrauth masks
>   perf test arm64: Test unwinding with PACs on gcc & clang compilers
> 
>  arch/arm64/include/asm/arch_sample_data.h     |  38 ++++++
>  arch/arm64/kernel/Makefile                    |   2 +-
>  arch/arm64/kernel/arch_sample_data.c          |  37 ++++++
>  include/linux/perf_event.h                    |  24 ++++
>  include/uapi/linux/perf_event.h               |   5 +-
>  kernel/events/core.c                          |  35 ++++++
>  tools/build/Makefile.feature                  |   2 +
>  tools/build/feature/Makefile                  |   4 +
>  tools/build/feature/test-all.c                |   5 +
>  .../feature/test-libunwind-arm64-ptrauth.c    |  26 ++++
>  tools/include/uapi/linux/perf_event.h         |   5 +-
>  tools/perf/Makefile.config                    |  10 ++
>  tools/perf/Makefile.perf                      |   1 +
>  tools/perf/tests/Build                        |   1 +
>  tools/perf/tests/arm_unwind_pac.c             | 113 ++++++++++++++++++
>  tools/perf/tests/arm_unwind_pac.sh            |  57 +++++++++
>  tools/perf/tests/attr/README                  |   1 +
>  .../attr/test-record-graph-default-aarch64    |   3 +-
>  tools/perf/tests/attr/test-record-graph-dwarf |   1 +
>  .../attr/test-record-graph-dwarf-aarch64      |  13 ++
>  .../tests/attr/test-record-graph-fp-aarch64   |   3 +-
>  tools/perf/tests/builtin-test.c               |   1 +
>  tools/perf/tests/sample-parsing.c             |   2 +-
>  tools/perf/tests/tests.h                      |   1 +
>  tools/perf/util/event.h                       |   8 ++
>  tools/perf/util/evsel.c                       |  64 ++++++++++
>  tools/perf/util/evsel.h                       |   1 +
>  tools/perf/util/perf_event_attr_fprintf.c     |   2 +-
>  tools/perf/util/session.c                     |  15 +++
>  tools/perf/util/unwind-libunwind-local.c      |  12 ++
>  30 files changed, 485 insertions(+), 7 deletions(-)
>  create mode 100644 arch/arm64/include/asm/arch_sample_data.h
>  create mode 100644 arch/arm64/kernel/arch_sample_data.c
>  create mode 100644 tools/build/feature/test-libunwind-arm64-ptrauth.c
>  create mode 100644 tools/perf/tests/arm_unwind_pac.c
>  create mode 100755 tools/perf/tests/arm_unwind_pac.sh
>  create mode 100644 tools/perf/tests/attr/test-record-graph-dwarf-aarch64
> 

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

* Re: [PATCH 1/8] perf arm64: Send pointer auth masks to ring buffer
  2022-08-10 13:23   ` Arnaldo Carvalho de Melo
@ 2022-09-07 15:21     ` James Clark
  0 siblings, 0 replies; 15+ messages in thread
From: James Clark @ 2022-09-07 15:21 UTC (permalink / raw)
  To: peterz, Arnaldo Carvalho de Melo
  Cc: linux-kernel, linux-perf-users, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Martin KaFai Lau, Song Liu,
	Yonghong Song, John Fastabend, KP Singh, Tom Rix,
	linux-arm-kernel, netdev, bpf, llvm, Arnaldo Carvalho de Melo,
	Andrew Kilroy



On 10/08/2022 14:23, Arnaldo Carvalho de Melo wrote:
> Em Mon, Jul 04, 2022 at 03:53:25PM +0100, Andrew Kilroy escreveu:
>> Perf report cannot produce callgraphs using dwarf on arm64 where pointer
>> authentication is enabled.  This is because libunwind and libdw cannot
>> unmangle instruction pointers that have a pointer authentication code
>> (PAC) embedded in them.
>>
>> libunwind and libdw need to be given an instruction mask which they can
>> use to arrive at the correct return address that does not contain the
>> PAC.
>>
>> The bits in the return address that contain the PAC can differ by
>> process, so this patch adds a new sample field PERF_SAMPLE_ARCH_1
>> to allow the kernel to send the masks up to userspace perf.
>>
>> This field can be used in a architecture specific fashion, but on
>> aarch64, it contains the ptrauth mask information.
> 
> I'm not seeing this kernel patch applied to tip/master or
> torvalds/master, what is the status of that part? Then I can look at the
> tooling part.
> 

Hi Peter,

I just left my review tag for the whole set, is it ok by you to apply
the first commit?

I'm not 100% sure of the process because it has some kernel/events
changes and arch/arm64 in the same commit. And I'm also not sure if
there is consensus about the new PERF_SAMPLE_ARCH_1 bit. There was a
comment from Vince Weaver but I don't agree that perf_event_open should
or can ever be completely generic so it's not a huge issue for me. And
there weren't any other comments against adding it.

Thanks
James

> - Arnaldo
>  
>> Signed-off-by: Andrew Kilroy <andrew.kilroy@arm.com>
>> ---
>>  arch/arm64/include/asm/arch_sample_data.h | 38 +++++++++++++++++++++++
>>  arch/arm64/kernel/Makefile                |  2 +-
>>  arch/arm64/kernel/arch_sample_data.c      | 37 ++++++++++++++++++++++
>>  include/linux/perf_event.h                | 24 ++++++++++++++
>>  include/uapi/linux/perf_event.h           |  5 ++-
>>  kernel/events/core.c                      | 35 +++++++++++++++++++++
>>  6 files changed, 139 insertions(+), 2 deletions(-)
>>  create mode 100644 arch/arm64/include/asm/arch_sample_data.h
>>  create mode 100644 arch/arm64/kernel/arch_sample_data.c
>>
>> diff --git a/arch/arm64/include/asm/arch_sample_data.h b/arch/arm64/include/asm/arch_sample_data.h
>> new file mode 100644
>> index 000000000000..83fda293b1fc
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/arch_sample_data.h
>> @@ -0,0 +1,38 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +
>> +#ifndef _ASM_ARCH_SAMPLE_DATA_H
>> +#define _ASM_ARCH_SAMPLE_DATA_H
>> +
>> +#include <linux/types.h>
>> +
>> +/*
>> + * Structure holding masks to help userspace stack unwinding
>> + * in the presence of arm64 pointer authentication.
>> + */
>> +struct ptrauth_info {
>> +	/*
>> +	 * Bits 0, 1, 2, 3, 4 may be set to on, to indicate which keys are being used
>> +	 * The APIAKEY, APIBKEY, APDAKEY, APDBKEY, or the APGAKEY respectively.
>> +	 * Where all bits are off, pointer authentication is not in use for the
>> +	 * process.
>> +	 */
>> +	u64 enabled_keys;
>> +
>> +	/*
>> +	 * The on bits represent which bits in an instruction pointer
>> +	 * constitute the pointer authentication code.
>> +	 */
>> +	u64 insn_mask;
>> +
>> +	/*
>> +	 * The on bits represent which bits in a data pointer constitute the
>> +	 * pointer authentication code.
>> +	 */
>> +	u64 data_mask;
>> +};
>> +
>> +struct arch_sample_data {
>> +	struct ptrauth_info ptrauth;
>> +};
>> +
>> +#endif
>> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
>> index fa7981d0d917..843c6e0e2393 100644
>> --- a/arch/arm64/kernel/Makefile
>> +++ b/arch/arm64/kernel/Makefile
>> @@ -44,7 +44,7 @@ obj-$(CONFIG_KUSER_HELPERS)		+= kuser32.o
>>  obj-$(CONFIG_FUNCTION_TRACER)		+= ftrace.o entry-ftrace.o
>>  obj-$(CONFIG_MODULES)			+= module.o
>>  obj-$(CONFIG_ARM64_MODULE_PLTS)		+= module-plts.o
>> -obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o perf_callchain.o
>> +obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o perf_callchain.o arch_sample_data.o
>>  obj-$(CONFIG_HW_PERF_EVENTS)		+= perf_event.o
>>  obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
>>  obj-$(CONFIG_CPU_PM)			+= sleep.o suspend.o
>> diff --git a/arch/arm64/kernel/arch_sample_data.c b/arch/arm64/kernel/arch_sample_data.c
>> new file mode 100644
>> index 000000000000..2d47e8db0dbe
>> --- /dev/null
>> +++ b/arch/arm64/kernel/arch_sample_data.c
>> @@ -0,0 +1,37 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +#include <asm/arch_sample_data.h>
>> +#include <linux/perf_event.h>
>> +
>> +inline void perf_output_sample_arch_1(struct perf_output_handle *handle,
>> +				      struct perf_event_header *header,
>> +				      struct perf_sample_data *data,
>> +				      struct perf_event *event)
>> +{
>> +	perf_output_put(handle, data->arch.ptrauth.enabled_keys);
>> +	perf_output_put(handle, data->arch.ptrauth.insn_mask);
>> +	perf_output_put(handle, data->arch.ptrauth.data_mask);
>> +}
>> +
>> +inline void perf_prepare_sample_arch_1(struct perf_event_header *header,
>> +				       struct perf_sample_data *data,
>> +				       struct perf_event *event,
>> +				       struct pt_regs *regs)
>> +{
>> +	struct task_struct *task = current;
>> +	int keys_result = ptrauth_get_enabled_keys(task);
>> +	u64 user_pac_mask = keys_result > 0 ? ptrauth_user_pac_mask() : 0;
>> +
>> +	data->arch.ptrauth.enabled_keys = keys_result > 0 ? keys_result : 0;
>> +	data->arch.ptrauth.insn_mask = user_pac_mask;
>> +	data->arch.ptrauth.data_mask = user_pac_mask;
>> +
>> +	header->size += (3 * sizeof(u64));
>> +}
>> +
>> +inline int perf_event_open_request_arch_1(void)
>> +{
>> +	return 0;
>> +}
>> +
>> +
>> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
>> index da759560eec5..8a99942989ce 100644
>> --- a/include/linux/perf_event.h
>> +++ b/include/linux/perf_event.h
>> @@ -999,6 +999,29 @@ int perf_event_read_local(struct perf_event *event, u64 *value,
>>  extern u64 perf_event_read_value(struct perf_event *event,
>>  				 u64 *enabled, u64 *running);
>>  
>> +void perf_output_sample_arch_1(struct perf_output_handle *handle,
>> +			       struct perf_event_header *header,
>> +			       struct perf_sample_data *data,
>> +			       struct perf_event *event);
>> +
>> +void perf_prepare_sample_arch_1(struct perf_event_header *header,
>> +				struct perf_sample_data *data,
>> +				struct perf_event *event,
>> +				struct pt_regs *regs);
>> +
>> +int perf_event_open_request_arch_1(void);
>> +
>> +#if IS_ENABLED(CONFIG_ARM64)
>> +
>> +#define HAS_ARCH_SAMPLE_DATA
>> +#include <asm/arch_sample_data.h>
>> +
>> +#endif
>> +
>> +#ifndef HAS_ARCH_SAMPLE_DATA
>> +struct arch_sample_data {
>> +};
>> +#endif
>>  
>>  struct perf_sample_data {
>>  	/*
>> @@ -1041,6 +1064,7 @@ struct perf_sample_data {
>>  	u64				cgroup;
>>  	u64				data_page_size;
>>  	u64				code_page_size;
>> +	struct arch_sample_data		arch;
>>  } ____cacheline_aligned;
>>  
>>  /* default value for data source */
>> diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
>> index d37629dbad72..821bf5ff6a19 100644
>> --- a/include/uapi/linux/perf_event.h
>> +++ b/include/uapi/linux/perf_event.h
>> @@ -162,12 +162,15 @@ enum perf_event_sample_format {
>>  	PERF_SAMPLE_DATA_PAGE_SIZE		= 1U << 22,
>>  	PERF_SAMPLE_CODE_PAGE_SIZE		= 1U << 23,
>>  	PERF_SAMPLE_WEIGHT_STRUCT		= 1U << 24,
>> +	PERF_SAMPLE_ARCH_1			= 1U << 25,
>>  
>> -	PERF_SAMPLE_MAX = 1U << 25,		/* non-ABI */
>> +	PERF_SAMPLE_MAX = 1U << 26,		/* non-ABI */
>>  
>>  	__PERF_SAMPLE_CALLCHAIN_EARLY		= 1ULL << 63, /* non-ABI; internal use */
>>  };
>>  
>> +#define PERF_SAMPLE_ARM64_PTRAUTH PERF_SAMPLE_ARCH_1
>> +
>>  #define PERF_SAMPLE_WEIGHT_TYPE	(PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT)
>>  /*
>>   * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
>> diff --git a/kernel/events/core.c b/kernel/events/core.c
>> index 80782cddb1da..89ab8120f4f0 100644
>> --- a/kernel/events/core.c
>> +++ b/kernel/events/core.c
>> @@ -6957,6 +6957,29 @@ static inline bool perf_sample_save_hw_index(struct perf_event *event)
>>  	return event->attr.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX;
>>  }
>>  
>> +#ifndef HAS_ARCH_SAMPLE_DATA
>> +
>> +inline void perf_output_sample_arch_1(struct perf_output_handle *handle __maybe_unused,
>> +				      struct perf_event_header *header __maybe_unused,
>> +				      struct perf_sample_data *data __maybe_unused,
>> +				      struct perf_event *event __maybe_unused)
>> +{
>> +}
>> +
>> +inline void perf_prepare_sample_arch_1(struct perf_event_header *header __maybe_unused,
>> +				       struct perf_sample_data *data __maybe_unused,
>> +				       struct perf_event *event __maybe_unused,
>> +				       struct pt_regs *regs __maybe_unused)
>> +{
>> +}
>> +
>> +inline int perf_event_open_request_arch_1(void)
>> +{
>> +	return -EINVAL;
>> +}
>> +
>> +#endif
>> +
>>  void perf_output_sample(struct perf_output_handle *handle,
>>  			struct perf_event_header *header,
>>  			struct perf_sample_data *data,
>> @@ -7125,6 +7148,9 @@ void perf_output_sample(struct perf_output_handle *handle,
>>  			perf_aux_sample_output(event, handle, data);
>>  	}
>>  
>> +	if (sample_type & PERF_SAMPLE_ARCH_1)
>> +		perf_output_sample_arch_1(handle, header, data, event);
>> +
>>  	if (!event->attr.watermark) {
>>  		int wakeup_events = event->attr.wakeup_events;
>>  
>> @@ -7427,6 +7453,9 @@ void perf_prepare_sample(struct perf_event_header *header,
>>  	if (sample_type & PERF_SAMPLE_CODE_PAGE_SIZE)
>>  		data->code_page_size = perf_get_page_size(data->ip);
>>  
>> +	if (sample_type & PERF_SAMPLE_ARCH_1)
>> +		perf_prepare_sample_arch_1(header, data, event, regs);
>> +
>>  	if (sample_type & PERF_SAMPLE_AUX) {
>>  		u64 size;
>>  
>> @@ -12074,6 +12103,12 @@ SYSCALL_DEFINE5(perf_event_open,
>>  			return err;
>>  	}
>>  
>> +	if (attr.sample_type & PERF_SAMPLE_ARCH_1) {
>> +		err = perf_event_open_request_arch_1();
>> +		if (err)
>> +			return err;
>> +	}
>> +
>>  	/*
>>  	 * In cgroup mode, the pid argument is used to pass the fd
>>  	 * opened to the cgroup directory in cgroupfs. The cpu argument
>> -- 
>> 2.17.1
> 

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

end of thread, other threads:[~2022-09-07 15:21 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-04 14:53 [PATCH 0/8] Perf stack unwinding with pointer authentication Andrew Kilroy
2022-07-04 14:53 ` [PATCH 1/8] perf arm64: Send pointer auth masks to ring buffer Andrew Kilroy
2022-08-10 13:23   ` Arnaldo Carvalho de Melo
2022-09-07 15:21     ` James Clark
2022-07-04 14:53 ` [PATCH 2/8] perf evsel: Do not request ptrauth sample field if not supported Andrew Kilroy
2022-07-06 16:01   ` Vince Weaver
2022-07-11  9:25     ` James Clark
2022-07-12 21:30       ` Vince Weaver
2022-07-04 14:53 ` [PATCH 3/8] perf test: Update arm64 tests to expect ptrauth masks Andrew Kilroy
2022-07-04 14:53 ` [PATCH 4/8] perf tools: arm64: Read ptrauth data from kernel Andrew Kilroy
2022-07-04 14:53 ` [PATCH 5/8] perf libunwind: Feature check for libunwind ptrauth callback Andrew Kilroy
2022-07-04 14:53 ` [PATCH 6/8] perf libunwind: arm64 pointer authentication Andrew Kilroy
2022-07-04 14:53 ` [PATCH 7/8] perf tools: Print ptrauth struct in perf report Andrew Kilroy
2022-07-04 14:53 ` [PATCH 8/8] perf test arm64: Test unwinding with PACs on gcc & clang compilers Andrew Kilroy
2022-09-07 15:00 ` [PATCH 0/8] Perf stack unwinding with pointer authentication James Clark

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).