162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include "arm64-frame-pointer-unwind-support.h" 362306a36Sopenharmony_ci#include "callchain.h" 462306a36Sopenharmony_ci#include "event.h" 562306a36Sopenharmony_ci#include "perf_regs.h" // SMPL_REG_MASK 662306a36Sopenharmony_ci#include "unwind.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define perf_event_arm_regs perf_event_arm64_regs 962306a36Sopenharmony_ci#include "../../arch/arm64/include/uapi/asm/perf_regs.h" 1062306a36Sopenharmony_ci#undef perf_event_arm_regs 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistruct entries { 1362306a36Sopenharmony_ci u64 stack[2]; 1462306a36Sopenharmony_ci size_t length; 1562306a36Sopenharmony_ci}; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic bool get_leaf_frame_caller_enabled(struct perf_sample *sample) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci return callchain_param.record_mode == CALLCHAIN_FP && sample->user_regs.regs 2062306a36Sopenharmony_ci && sample->user_regs.mask & SMPL_REG_MASK(PERF_REG_ARM64_LR); 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int add_entry(struct unwind_entry *entry, void *arg) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct entries *entries = arg; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci entries->stack[entries->length++] = entry->ip; 2862306a36Sopenharmony_ci return 0; 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciu64 get_leaf_frame_caller_aarch64(struct perf_sample *sample, struct thread *thread, int usr_idx) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci int ret; 3462306a36Sopenharmony_ci struct entries entries = {}; 3562306a36Sopenharmony_ci struct regs_dump old_regs = sample->user_regs; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (!get_leaf_frame_caller_enabled(sample)) 3862306a36Sopenharmony_ci return 0; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* 4162306a36Sopenharmony_ci * If PC and SP are not recorded, get the value of PC from the stack 4262306a36Sopenharmony_ci * and set its mask. SP is not used when doing the unwinding but it 4362306a36Sopenharmony_ci * still needs to be set to prevent failures. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (!(sample->user_regs.mask & SMPL_REG_MASK(PERF_REG_ARM64_PC))) { 4762306a36Sopenharmony_ci sample->user_regs.cache_mask |= SMPL_REG_MASK(PERF_REG_ARM64_PC); 4862306a36Sopenharmony_ci sample->user_regs.cache_regs[PERF_REG_ARM64_PC] = sample->callchain->ips[usr_idx+1]; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (!(sample->user_regs.mask & SMPL_REG_MASK(PERF_REG_ARM64_SP))) { 5262306a36Sopenharmony_ci sample->user_regs.cache_mask |= SMPL_REG_MASK(PERF_REG_ARM64_SP); 5362306a36Sopenharmony_ci sample->user_regs.cache_regs[PERF_REG_ARM64_SP] = 0; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci ret = unwind__get_entries(add_entry, &entries, thread, sample, 2, true); 5762306a36Sopenharmony_ci sample->user_regs = old_regs; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (ret || entries.length != 2) 6062306a36Sopenharmony_ci return ret; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return callchain_param.order == ORDER_CALLER ? entries.stack[0] : entries.stack[1]; 6362306a36Sopenharmony_ci} 64