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@xxxxxxx> --- 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