18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2012 ARM Ltd. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#ifndef __ASM_STACKTRACE_H 68c2ecf20Sopenharmony_ci#define __ASM_STACKTRACE_H 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/percpu.h> 98c2ecf20Sopenharmony_ci#include <linux/sched.h> 108c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h> 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <asm/memory.h> 148c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 158c2ecf20Sopenharmony_ci#include <asm/sdei.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cienum stack_type { 188c2ecf20Sopenharmony_ci STACK_TYPE_UNKNOWN, 198c2ecf20Sopenharmony_ci STACK_TYPE_TASK, 208c2ecf20Sopenharmony_ci STACK_TYPE_IRQ, 218c2ecf20Sopenharmony_ci STACK_TYPE_OVERFLOW, 228c2ecf20Sopenharmony_ci STACK_TYPE_SDEI_NORMAL, 238c2ecf20Sopenharmony_ci STACK_TYPE_SDEI_CRITICAL, 248c2ecf20Sopenharmony_ci __NR_STACK_TYPES 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct stack_info { 288c2ecf20Sopenharmony_ci unsigned long low; 298c2ecf20Sopenharmony_ci unsigned long high; 308c2ecf20Sopenharmony_ci enum stack_type type; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * A snapshot of a frame record or fp/lr register values, along with some 358c2ecf20Sopenharmony_ci * accounting information necessary for robust unwinding. 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * @fp: The fp value in the frame record (or the real fp) 388c2ecf20Sopenharmony_ci * @pc: The fp value in the frame record (or the real lr) 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * @stacks_done: Stacks which have been entirely unwound, for which it is no 418c2ecf20Sopenharmony_ci * longer valid to unwind to. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * @prev_fp: The fp that pointed to this frame record, or a synthetic value 448c2ecf20Sopenharmony_ci * of 0. This is used to ensure that within a stack, each 458c2ecf20Sopenharmony_ci * subsequent frame record is at an increasing address. 468c2ecf20Sopenharmony_ci * @prev_type: The type of stack this frame record was on, or a synthetic 478c2ecf20Sopenharmony_ci * value of STACK_TYPE_UNKNOWN. This is used to detect a 488c2ecf20Sopenharmony_ci * transition from one stack to another. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * @graph: When FUNCTION_GRAPH_TRACER is selected, holds the index of a 518c2ecf20Sopenharmony_ci * replacement lr value in the ftrace graph stack. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_cistruct stackframe { 548c2ecf20Sopenharmony_ci unsigned long fp; 558c2ecf20Sopenharmony_ci unsigned long pc; 568c2ecf20Sopenharmony_ci DECLARE_BITMAP(stacks_done, __NR_STACK_TYPES); 578c2ecf20Sopenharmony_ci unsigned long prev_fp; 588c2ecf20Sopenharmony_ci enum stack_type prev_type; 598c2ecf20Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER 608c2ecf20Sopenharmony_ci int graph; 618c2ecf20Sopenharmony_ci#endif 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ciextern int unwind_frame(struct task_struct *tsk, struct stackframe *frame); 658c2ecf20Sopenharmony_ciextern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, 668c2ecf20Sopenharmony_ci bool (*fn)(void *, unsigned long), void *data); 678c2ecf20Sopenharmony_ciextern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk, 688c2ecf20Sopenharmony_ci const char *loglvl); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ciDECLARE_PER_CPU(unsigned long *, irq_stack_ptr); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic inline bool on_stack(unsigned long sp, unsigned long low, 738c2ecf20Sopenharmony_ci unsigned long high, enum stack_type type, 748c2ecf20Sopenharmony_ci struct stack_info *info) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci if (!low) 778c2ecf20Sopenharmony_ci return false; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (sp < low || sp >= high) 808c2ecf20Sopenharmony_ci return false; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (info) { 838c2ecf20Sopenharmony_ci info->low = low; 848c2ecf20Sopenharmony_ci info->high = high; 858c2ecf20Sopenharmony_ci info->type = type; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci return true; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic inline bool on_irq_stack(unsigned long sp, 918c2ecf20Sopenharmony_ci struct stack_info *info) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci unsigned long low = (unsigned long)raw_cpu_read(irq_stack_ptr); 948c2ecf20Sopenharmony_ci unsigned long high = low + IRQ_STACK_SIZE; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return on_stack(sp, low, high, STACK_TYPE_IRQ, info); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic inline bool on_task_stack(const struct task_struct *tsk, 1008c2ecf20Sopenharmony_ci unsigned long sp, 1018c2ecf20Sopenharmony_ci struct stack_info *info) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci unsigned long low = (unsigned long)task_stack_page(tsk); 1048c2ecf20Sopenharmony_ci unsigned long high = low + THREAD_SIZE; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return on_stack(sp, low, high, STACK_TYPE_TASK, info); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#ifdef CONFIG_VMAP_STACK 1108c2ecf20Sopenharmony_ciDECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic inline bool on_overflow_stack(unsigned long sp, 1138c2ecf20Sopenharmony_ci struct stack_info *info) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci unsigned long low = (unsigned long)raw_cpu_ptr(overflow_stack); 1168c2ecf20Sopenharmony_ci unsigned long high = low + OVERFLOW_STACK_SIZE; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return on_stack(sp, low, high, STACK_TYPE_OVERFLOW, info); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci#else 1218c2ecf20Sopenharmony_cistatic inline bool on_overflow_stack(unsigned long sp, 1228c2ecf20Sopenharmony_ci struct stack_info *info) { return false; } 1238c2ecf20Sopenharmony_ci#endif 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* 1278c2ecf20Sopenharmony_ci * We can only safely access per-cpu stacks from current in a non-preemptible 1288c2ecf20Sopenharmony_ci * context. 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_cistatic inline bool on_accessible_stack(const struct task_struct *tsk, 1318c2ecf20Sopenharmony_ci unsigned long sp, 1328c2ecf20Sopenharmony_ci struct stack_info *info) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci if (info) 1358c2ecf20Sopenharmony_ci info->type = STACK_TYPE_UNKNOWN; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (on_task_stack(tsk, sp, info)) 1388c2ecf20Sopenharmony_ci return true; 1398c2ecf20Sopenharmony_ci if (tsk != current || preemptible()) 1408c2ecf20Sopenharmony_ci return false; 1418c2ecf20Sopenharmony_ci if (on_irq_stack(sp, info)) 1428c2ecf20Sopenharmony_ci return true; 1438c2ecf20Sopenharmony_ci if (on_overflow_stack(sp, info)) 1448c2ecf20Sopenharmony_ci return true; 1458c2ecf20Sopenharmony_ci if (on_sdei_stack(sp, info)) 1468c2ecf20Sopenharmony_ci return true; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return false; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic inline void start_backtrace(struct stackframe *frame, 1528c2ecf20Sopenharmony_ci unsigned long fp, unsigned long pc) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci frame->fp = fp; 1558c2ecf20Sopenharmony_ci frame->pc = pc; 1568c2ecf20Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER 1578c2ecf20Sopenharmony_ci frame->graph = 0; 1588c2ecf20Sopenharmony_ci#endif 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* 1618c2ecf20Sopenharmony_ci * Prime the first unwind. 1628c2ecf20Sopenharmony_ci * 1638c2ecf20Sopenharmony_ci * In unwind_frame() we'll check that the FP points to a valid stack, 1648c2ecf20Sopenharmony_ci * which can't be STACK_TYPE_UNKNOWN, and the first unwind will be 1658c2ecf20Sopenharmony_ci * treated as a transition to whichever stack that happens to be. The 1668c2ecf20Sopenharmony_ci * prev_fp value won't be used, but we set it to 0 such that it is 1678c2ecf20Sopenharmony_ci * definitely not an accessible stack address. 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_ci bitmap_zero(frame->stacks_done, __NR_STACK_TYPES); 1708c2ecf20Sopenharmony_ci frame->prev_fp = 0; 1718c2ecf20Sopenharmony_ci frame->prev_type = STACK_TYPE_UNKNOWN; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#endif /* __ASM_STACKTRACE_H */ 175