linux/arch/x86/kernel/dumpstack_32.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  Copyright (C) 1991, 1992  Linus Torvalds
   4 *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
   5 */
   6#include <linux/sched/debug.h>
   7#include <linux/kallsyms.h>
   8#include <linux/kprobes.h>
   9#include <linux/uaccess.h>
  10#include <linux/hardirq.h>
  11#include <linux/kdebug.h>
  12#include <linux/export.h>
  13#include <linux/ptrace.h>
  14#include <linux/kexec.h>
  15#include <linux/sysfs.h>
  16#include <linux/bug.h>
  17#include <linux/nmi.h>
  18
  19#include <asm/stacktrace.h>
  20
  21const char *stack_type_name(enum stack_type type)
  22{
  23        if (type == STACK_TYPE_IRQ)
  24                return "IRQ";
  25
  26        if (type == STACK_TYPE_SOFTIRQ)
  27                return "SOFTIRQ";
  28
  29        if (type == STACK_TYPE_ENTRY)
  30                return "ENTRY_TRAMPOLINE";
  31
  32        return NULL;
  33}
  34
  35static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info)
  36{
  37        unsigned long *begin = (unsigned long *)this_cpu_read(hardirq_stack);
  38        unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
  39
  40        /*
  41         * This is a software stack, so 'end' can be a valid stack pointer.
  42         * It just means the stack is empty.
  43         */
  44        if (stack <= begin || stack > end)
  45                return false;
  46
  47        info->type      = STACK_TYPE_IRQ;
  48        info->begin     = begin;
  49        info->end       = end;
  50
  51        /*
  52         * See irq_32.c -- the next stack pointer is stored at the beginning of
  53         * the stack.
  54         */
  55        info->next_sp   = (unsigned long *)*begin;
  56
  57        return true;
  58}
  59
  60static bool in_softirq_stack(unsigned long *stack, struct stack_info *info)
  61{
  62        unsigned long *begin = (unsigned long *)this_cpu_read(softirq_stack);
  63        unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
  64
  65        /*
  66         * This is a software stack, so 'end' can be a valid stack pointer.
  67         * It just means the stack is empty.
  68         */
  69        if (stack <= begin || stack > end)
  70                return false;
  71
  72        info->type      = STACK_TYPE_SOFTIRQ;
  73        info->begin     = begin;
  74        info->end       = end;
  75
  76        /*
  77         * The next stack pointer is stored at the beginning of the stack.
  78         * See irq_32.c.
  79         */
  80        info->next_sp   = (unsigned long *)*begin;
  81
  82        return true;
  83}
  84
  85int get_stack_info(unsigned long *stack, struct task_struct *task,
  86                   struct stack_info *info, unsigned long *visit_mask)
  87{
  88        if (!stack)
  89                goto unknown;
  90
  91        task = task ? : current;
  92
  93        if (in_task_stack(stack, task, info))
  94                goto recursion_check;
  95
  96        if (task != current)
  97                goto unknown;
  98
  99        if (in_entry_stack(stack, info))
 100                goto recursion_check;
 101
 102        if (in_hardirq_stack(stack, info))
 103                goto recursion_check;
 104
 105        if (in_softirq_stack(stack, info))
 106                goto recursion_check;
 107
 108        goto unknown;
 109
 110recursion_check:
 111        /*
 112         * Make sure we don't iterate through any given stack more than once.
 113         * If it comes up a second time then there's something wrong going on:
 114         * just break out and report an unknown stack type.
 115         */
 116        if (visit_mask) {
 117                if (*visit_mask & (1UL << info->type)) {
 118                        printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
 119                        goto unknown;
 120                }
 121                *visit_mask |= 1UL << info->type;
 122        }
 123
 124        return 0;
 125
 126unknown:
 127        info->type = STACK_TYPE_UNKNOWN;
 128        return -EINVAL;
 129}
 130