1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 22bc5f927SAlexander van Heukelum /* 32bc5f927SAlexander van Heukelum * Copyright (C) 1991, 1992 Linus Torvalds 42bc5f927SAlexander van Heukelum * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs 52bc5f927SAlexander van Heukelum */ 6b17b0153SIngo Molnar #include <linux/sched/debug.h> 72bc5f927SAlexander van Heukelum #include <linux/kallsyms.h> 82bc5f927SAlexander van Heukelum #include <linux/kprobes.h> 92bc5f927SAlexander van Heukelum #include <linux/uaccess.h> 102bc5f927SAlexander van Heukelum #include <linux/hardirq.h> 112bc5f927SAlexander van Heukelum #include <linux/kdebug.h> 12186f4360SPaul Gortmaker #include <linux/export.h> 132bc5f927SAlexander van Heukelum #include <linux/ptrace.h> 142bc5f927SAlexander van Heukelum #include <linux/kexec.h> 15b8030906SIngo Molnar #include <linux/sysfs.h> 162bc5f927SAlexander van Heukelum #include <linux/bug.h> 172bc5f927SAlexander van Heukelum #include <linux/nmi.h> 182bc5f927SAlexander van Heukelum 192bc5f927SAlexander van Heukelum #include <asm/stacktrace.h> 202bc5f927SAlexander van Heukelum 213d02a9c4SJosh Poimboeuf const char *stack_type_name(enum stack_type type) 22198d208dSSteven Rostedt { 233d02a9c4SJosh Poimboeuf if (type == STACK_TYPE_IRQ) 243d02a9c4SJosh Poimboeuf return "IRQ"; 253d02a9c4SJosh Poimboeuf 263d02a9c4SJosh Poimboeuf if (type == STACK_TYPE_SOFTIRQ) 273d02a9c4SJosh Poimboeuf return "SOFTIRQ"; 283d02a9c4SJosh Poimboeuf 294fe2d8b1SDave Hansen if (type == STACK_TYPE_ENTRY) 304fe2d8b1SDave Hansen return "ENTRY_TRAMPOLINE"; 3133a2f1a6SAndy Lutomirski 323d02a9c4SJosh Poimboeuf return NULL; 33198d208dSSteven Rostedt } 34198d208dSSteven Rostedt 35cb76c939SJosh Poimboeuf static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info) 36198d208dSSteven Rostedt { 37cb76c939SJosh Poimboeuf unsigned long *begin = (unsigned long *)this_cpu_read(hardirq_stack); 38cb76c939SJosh Poimboeuf unsigned long *end = begin + (THREAD_SIZE / sizeof(long)); 39198d208dSSteven Rostedt 405fe599e0SJosh Poimboeuf /* 415fe599e0SJosh Poimboeuf * This is a software stack, so 'end' can be a valid stack pointer. 425fe599e0SJosh Poimboeuf * It just means the stack is empty. 435fe599e0SJosh Poimboeuf */ 44*fa332154SAndy Lutomirski if (stack < begin || stack > end) 45cb76c939SJosh Poimboeuf return false; 46cb76c939SJosh Poimboeuf 47cb76c939SJosh Poimboeuf info->type = STACK_TYPE_IRQ; 48cb76c939SJosh Poimboeuf info->begin = begin; 49cb76c939SJosh Poimboeuf info->end = end; 50cb76c939SJosh Poimboeuf 51cb76c939SJosh Poimboeuf /* 52cb76c939SJosh Poimboeuf * See irq_32.c -- the next stack pointer is stored at the beginning of 53cb76c939SJosh Poimboeuf * the stack. 54cb76c939SJosh Poimboeuf */ 55cb76c939SJosh Poimboeuf info->next_sp = (unsigned long *)*begin; 56cb76c939SJosh Poimboeuf 57cb76c939SJosh Poimboeuf return true; 58198d208dSSteven Rostedt } 59198d208dSSteven Rostedt 60cb76c939SJosh Poimboeuf static bool in_softirq_stack(unsigned long *stack, struct stack_info *info) 61198d208dSSteven Rostedt { 62cb76c939SJosh Poimboeuf unsigned long *begin = (unsigned long *)this_cpu_read(softirq_stack); 63cb76c939SJosh Poimboeuf unsigned long *end = begin + (THREAD_SIZE / sizeof(long)); 64198d208dSSteven Rostedt 655fe599e0SJosh Poimboeuf /* 665fe599e0SJosh Poimboeuf * This is a software stack, so 'end' can be a valid stack pointer. 675fe599e0SJosh Poimboeuf * It just means the stack is empty. 685fe599e0SJosh Poimboeuf */ 69*fa332154SAndy Lutomirski if (stack < begin || stack > end) 70cb76c939SJosh Poimboeuf return false; 71cb76c939SJosh Poimboeuf 72cb76c939SJosh Poimboeuf info->type = STACK_TYPE_SOFTIRQ; 73cb76c939SJosh Poimboeuf info->begin = begin; 74cb76c939SJosh Poimboeuf info->end = end; 75cb76c939SJosh Poimboeuf 76cb76c939SJosh Poimboeuf /* 77cb76c939SJosh Poimboeuf * The next stack pointer is stored at the beginning of the stack. 78cb76c939SJosh Poimboeuf * See irq_32.c. 79cb76c939SJosh Poimboeuf */ 80cb76c939SJosh Poimboeuf info->next_sp = (unsigned long *)*begin; 81cb76c939SJosh Poimboeuf 82cb76c939SJosh Poimboeuf return true; 83cb76c939SJosh Poimboeuf } 84cb76c939SJosh Poimboeuf 85cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task, 86cb76c939SJosh Poimboeuf struct stack_info *info, unsigned long *visit_mask) 87cb76c939SJosh Poimboeuf { 88cb76c939SJosh Poimboeuf if (!stack) 89cb76c939SJosh Poimboeuf goto unknown; 90cb76c939SJosh Poimboeuf 91cb76c939SJosh Poimboeuf task = task ? : current; 92cb76c939SJosh Poimboeuf 93cb76c939SJosh Poimboeuf if (in_task_stack(stack, task, info)) 94fcd709efSJosh Poimboeuf goto recursion_check; 95cb76c939SJosh Poimboeuf 96cb76c939SJosh Poimboeuf if (task != current) 97cb76c939SJosh Poimboeuf goto unknown; 98cb76c939SJosh Poimboeuf 994fe2d8b1SDave Hansen if (in_entry_stack(stack, info)) 10033a2f1a6SAndy Lutomirski goto recursion_check; 10133a2f1a6SAndy Lutomirski 102cb76c939SJosh Poimboeuf if (in_hardirq_stack(stack, info)) 103fcd709efSJosh Poimboeuf goto recursion_check; 104cb76c939SJosh Poimboeuf 105cb76c939SJosh Poimboeuf if (in_softirq_stack(stack, info)) 106fcd709efSJosh Poimboeuf goto recursion_check; 107fcd709efSJosh Poimboeuf 108fcd709efSJosh Poimboeuf goto unknown; 109fcd709efSJosh Poimboeuf 110fcd709efSJosh Poimboeuf recursion_check: 111fcd709efSJosh Poimboeuf /* 112fcd709efSJosh Poimboeuf * Make sure we don't iterate through any given stack more than once. 113fcd709efSJosh Poimboeuf * If it comes up a second time then there's something wrong going on: 114fcd709efSJosh Poimboeuf * just break out and report an unknown stack type. 115fcd709efSJosh Poimboeuf */ 116fcd709efSJosh Poimboeuf if (visit_mask) { 1170d2b8579SJosh Poimboeuf if (*visit_mask & (1UL << info->type)) { 1180d2b8579SJosh Poimboeuf printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type); 119fcd709efSJosh Poimboeuf goto unknown; 1200d2b8579SJosh Poimboeuf } 121fcd709efSJosh Poimboeuf *visit_mask |= 1UL << info->type; 122fcd709efSJosh Poimboeuf } 123fcd709efSJosh Poimboeuf 124cb76c939SJosh Poimboeuf return 0; 125cb76c939SJosh Poimboeuf 126cb76c939SJosh Poimboeuf unknown: 127cb76c939SJosh Poimboeuf info->type = STACK_TYPE_UNKNOWN; 128cb76c939SJosh Poimboeuf return -EINVAL; 129198d208dSSteven Rostedt } 130