162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <linux/sched.h> 362306a36Sopenharmony_ci#include <linux/ftrace.h> 462306a36Sopenharmony_ci#include <asm/ptrace.h> 562306a36Sopenharmony_ci#include <asm/bitops.h> 662306a36Sopenharmony_ci#include <asm/stacktrace.h> 762306a36Sopenharmony_ci#include <asm/unwind.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ciunsigned long unwind_get_return_address(struct unwind_state *state) 1062306a36Sopenharmony_ci{ 1162306a36Sopenharmony_ci unsigned long addr; 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci if (unwind_done(state)) 1462306a36Sopenharmony_ci return 0; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci addr = READ_ONCE_NOCHECK(*state->sp); 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci return unwind_recover_ret_addr(state, addr, state->sp); 1962306a36Sopenharmony_ci} 2062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unwind_get_return_address); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciunsigned long *unwind_get_return_address_ptr(struct unwind_state *state) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci return NULL; 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cibool unwind_next_frame(struct unwind_state *state) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct stack_info *info = &state->stack_info; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (unwind_done(state)) 3262306a36Sopenharmony_ci return false; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci do { 3562306a36Sopenharmony_ci for (state->sp++; state->sp < info->end; state->sp++) { 3662306a36Sopenharmony_ci unsigned long addr = READ_ONCE_NOCHECK(*state->sp); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (__kernel_text_address(addr)) 3962306a36Sopenharmony_ci return true; 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci state->sp = PTR_ALIGN(info->next_sp, sizeof(long)); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci } while (!get_stack_info(state->sp, state->task, info, 4562306a36Sopenharmony_ci &state->stack_mask)); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return false; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unwind_next_frame); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_civoid __unwind_start(struct unwind_state *state, struct task_struct *task, 5262306a36Sopenharmony_ci struct pt_regs *regs, unsigned long *first_frame) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci memset(state, 0, sizeof(*state)); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci state->task = task; 5762306a36Sopenharmony_ci state->sp = PTR_ALIGN(first_frame, sizeof(long)); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci get_stack_info(first_frame, state->task, &state->stack_info, 6062306a36Sopenharmony_ci &state->stack_mask); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* 6362306a36Sopenharmony_ci * The caller can provide the address of the first frame directly 6462306a36Sopenharmony_ci * (first_frame) or indirectly (regs->sp) to indicate which stack frame 6562306a36Sopenharmony_ci * to start unwinding at. Skip ahead until we reach it. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci if (!unwind_done(state) && 6862306a36Sopenharmony_ci (!on_stack(&state->stack_info, first_frame, sizeof(long)) || 6962306a36Sopenharmony_ci !__kernel_text_address(*first_frame))) 7062306a36Sopenharmony_ci unwind_next_frame(state); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__unwind_start); 73