1 // SPDX-License-Identifier: GPL-2.0
2 #include "arm64-frame-pointer-unwind-support.h"
5 #include "perf_regs.h" // SMPL_REG_MASK
8 #define perf_event_arm_regs perf_event_arm64_regs
9 #include "../../arch/arm64/include/uapi/asm/perf_regs.h"
10 #undef perf_event_arm_regs
17 static bool get_leaf_frame_caller_enabled(struct perf_sample
*sample
)
19 return callchain_param
.record_mode
== CALLCHAIN_FP
&& sample
->user_regs
.regs
20 && sample
->user_regs
.mask
& SMPL_REG_MASK(PERF_REG_ARM64_LR
);
23 static int add_entry(struct unwind_entry
*entry
, void *arg
)
25 struct entries
*entries
= arg
;
27 entries
->stack
[entries
->length
++] = entry
->ip
;
31 u64
get_leaf_frame_caller_aarch64(struct perf_sample
*sample
, struct thread
*thread
, int usr_idx
)
34 struct entries entries
= {};
35 struct regs_dump old_regs
= sample
->user_regs
;
37 if (!get_leaf_frame_caller_enabled(sample
))
41 * If PC and SP are not recorded, get the value of PC from the stack
42 * and set its mask. SP is not used when doing the unwinding but it
43 * still needs to be set to prevent failures.
46 if (!(sample
->user_regs
.mask
& SMPL_REG_MASK(PERF_REG_ARM64_PC
))) {
47 sample
->user_regs
.cache_mask
|= SMPL_REG_MASK(PERF_REG_ARM64_PC
);
48 sample
->user_regs
.cache_regs
[PERF_REG_ARM64_PC
] = sample
->callchain
->ips
[usr_idx
+1];
51 if (!(sample
->user_regs
.mask
& SMPL_REG_MASK(PERF_REG_ARM64_SP
))) {
52 sample
->user_regs
.cache_mask
|= SMPL_REG_MASK(PERF_REG_ARM64_SP
);
53 sample
->user_regs
.cache_regs
[PERF_REG_ARM64_SP
] = 0;
56 ret
= unwind__get_entries(add_entry
, &entries
, thread
, sample
, 2, true);
57 sample
->user_regs
= old_regs
;
59 if (ret
|| entries
.length
!= 2)
62 return callchain_param
.order
== ORDER_CALLER
? entries
.stack
[0] : entries
.stack
[1];