linux/arch/arm64/include/asm/stacktrace.h
<<
>>
Prefs
   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#include <linux/types.h>
  12#include <linux/llist.h>
  13
  14#include <asm/memory.h>
  15#include <asm/ptrace.h>
  16#include <asm/sdei.h>
  17
  18enum stack_type {
  19        STACK_TYPE_UNKNOWN,
  20        STACK_TYPE_TASK,
  21        STACK_TYPE_IRQ,
  22        STACK_TYPE_OVERFLOW,
  23        STACK_TYPE_SDEI_NORMAL,
  24        STACK_TYPE_SDEI_CRITICAL,
  25        __NR_STACK_TYPES
  26};
  27
  28struct stack_info {
  29        unsigned long low;
  30        unsigned long high;
  31        enum stack_type type;
  32};
  33
  34extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
  35                           const char *loglvl);
  36
  37DECLARE_PER_CPU(unsigned long *, irq_stack_ptr);
  38
  39static inline bool on_stack(unsigned long sp, unsigned long size,
  40                            unsigned long low, unsigned long high,
  41                            enum stack_type type, struct stack_info *info)
  42{
  43        if (!low)
  44                return false;
  45
  46        if (sp < low || sp + size < sp || sp + size > high)
  47                return false;
  48
  49        if (info) {
  50                info->low = low;
  51                info->high = high;
  52                info->type = type;
  53        }
  54        return true;
  55}
  56
  57static inline bool on_irq_stack(unsigned long sp, unsigned long size,
  58                                struct stack_info *info)
  59{
  60        unsigned long low = (unsigned long)raw_cpu_read(irq_stack_ptr);
  61        unsigned long high = low + IRQ_STACK_SIZE;
  62
  63        return on_stack(sp, size, low, high, STACK_TYPE_IRQ, info);
  64}
  65
  66static inline bool on_task_stack(const struct task_struct *tsk,
  67                                 unsigned long sp, unsigned long size,
  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        return on_stack(sp, size, low, high, STACK_TYPE_TASK, info);
  74}
  75
  76#ifdef CONFIG_VMAP_STACK
  77DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
  78
  79static inline bool on_overflow_stack(unsigned long sp, unsigned long size,
  80                                struct stack_info *info)
  81{
  82        unsigned long low = (unsigned long)raw_cpu_ptr(overflow_stack);
  83        unsigned long high = low + OVERFLOW_STACK_SIZE;
  84
  85        return on_stack(sp, size, low, high, STACK_TYPE_OVERFLOW, info);
  86}
  87#else
  88static inline bool on_overflow_stack(unsigned long sp, unsigned long size,
  89                        struct stack_info *info) { return false; }
  90#endif
  91
  92
  93/*
  94 * We can only safely access per-cpu stacks from current in a non-preemptible
  95 * context.
  96 */
  97static inline bool on_accessible_stack(const struct task_struct *tsk,
  98                                       unsigned long sp, unsigned long size,
  99                                       struct stack_info *info)
 100{
 101        if (info)
 102                info->type = STACK_TYPE_UNKNOWN;
 103
 104        if (on_task_stack(tsk, sp, size, info))
 105                return true;
 106        if (tsk != current || preemptible())
 107                return false;
 108        if (on_irq_stack(sp, size, info))
 109                return true;
 110        if (on_overflow_stack(sp, size, info))
 111                return true;
 112        if (on_sdei_stack(sp, size, info))
 113                return true;
 114
 115        return false;
 116}
 117
 118#endif  /* __ASM_STACKTRACE_H */
 119