at v5.2 2.8 kB view raw
1/* SPDX-License-Identifier: GPL-2.0-only */ 2/* 3 * Copyright (C) 2012 ARM Ltd. 4 */ 5#ifndef __ASM_STACKTRACE_H 6#define __ASM_STACKTRACE_H 7 8#include <linux/percpu.h> 9#include <linux/sched.h> 10#include <linux/sched/task_stack.h> 11 12#include <asm/memory.h> 13#include <asm/ptrace.h> 14#include <asm/sdei.h> 15 16struct stackframe { 17 unsigned long fp; 18 unsigned long pc; 19#ifdef CONFIG_FUNCTION_GRAPH_TRACER 20 int graph; 21#endif 22}; 23 24enum stack_type { 25 STACK_TYPE_UNKNOWN, 26 STACK_TYPE_TASK, 27 STACK_TYPE_IRQ, 28 STACK_TYPE_OVERFLOW, 29 STACK_TYPE_SDEI_NORMAL, 30 STACK_TYPE_SDEI_CRITICAL, 31}; 32 33struct stack_info { 34 unsigned long low; 35 unsigned long high; 36 enum stack_type type; 37}; 38 39extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame); 40extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, 41 int (*fn)(struct stackframe *, void *), void *data); 42extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk); 43 44DECLARE_PER_CPU(unsigned long *, irq_stack_ptr); 45 46static inline bool on_irq_stack(unsigned long sp, 47 struct stack_info *info) 48{ 49 unsigned long low = (unsigned long)raw_cpu_read(irq_stack_ptr); 50 unsigned long high = low + IRQ_STACK_SIZE; 51 52 if (!low) 53 return false; 54 55 if (sp < low || sp >= high) 56 return false; 57 58 if (info) { 59 info->low = low; 60 info->high = high; 61 info->type = STACK_TYPE_IRQ; 62 } 63 64 return true; 65} 66 67static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp, 68 struct stack_info *info) 69{ 70 unsigned long low = (unsigned long)task_stack_page(tsk); 71 unsigned long high = low + THREAD_SIZE; 72 73 if (sp < low || sp >= high) 74 return false; 75 76 if (info) { 77 info->low = low; 78 info->high = high; 79 info->type = STACK_TYPE_TASK; 80 } 81 82 return true; 83} 84 85#ifdef CONFIG_VMAP_STACK 86DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack); 87 88static inline bool on_overflow_stack(unsigned long sp, 89 struct stack_info *info) 90{ 91 unsigned long low = (unsigned long)raw_cpu_ptr(overflow_stack); 92 unsigned long high = low + OVERFLOW_STACK_SIZE; 93 94 if (sp < low || sp >= high) 95 return false; 96 97 if (info) { 98 info->low = low; 99 info->high = high; 100 info->type = STACK_TYPE_OVERFLOW; 101 } 102 103 return true; 104} 105#else 106static inline bool on_overflow_stack(unsigned long sp, 107 struct stack_info *info) { return false; } 108#endif 109 110 111/* 112 * We can only safely access per-cpu stacks from current in a non-preemptible 113 * context. 114 */ 115static inline bool on_accessible_stack(struct task_struct *tsk, 116 unsigned long sp, 117 struct stack_info *info) 118{ 119 if (on_task_stack(tsk, sp, info)) 120 return true; 121 if (tsk != current || preemptible()) 122 return false; 123 if (on_irq_stack(sp, info)) 124 return true; 125 if (on_overflow_stack(sp, info)) 126 return true; 127 if (on_sdei_stack(sp, info)) 128 return true; 129 130 return false; 131} 132 133#endif /* __ASM_STACKTRACE_H */