diff mbox series

[4/8] perf tools: arm64: Read ptrauth data from kernel

Message ID 20220704145333.22557-5-andrew.kilroy@arm.com (mailing list archive)
State New, archived
Headers show
Series Perf stack unwinding with pointer authentication | expand

Commit Message

Andrew Kilroy July 4, 2022, 2:53 p.m. UTC
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 mbox series

Patch

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;
 }