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 32*dc4e0021SAndy Lutomirski if (type == STACK_TYPE_EXCEPTION) 33*dc4e0021SAndy Lutomirski return "#DF"; 34*dc4e0021SAndy Lutomirski 353d02a9c4SJosh Poimboeuf return NULL; 36198d208dSSteven Rostedt } 37198d208dSSteven Rostedt 38cb76c939SJosh Poimboeuf static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info) 39198d208dSSteven Rostedt { 40a754fe2bSThomas Gleixner unsigned long *begin = (unsigned long *)this_cpu_read(hardirq_stack_ptr); 41cb76c939SJosh Poimboeuf unsigned long *end = begin + (THREAD_SIZE / sizeof(long)); 42198d208dSSteven Rostedt 435fe599e0SJosh Poimboeuf /* 445fe599e0SJosh Poimboeuf * This is a software stack, so 'end' can be a valid stack pointer. 455fe599e0SJosh Poimboeuf * It just means the stack is empty. 465fe599e0SJosh Poimboeuf */ 47fa332154SAndy Lutomirski if (stack < begin || stack > end) 48cb76c939SJosh Poimboeuf return false; 49cb76c939SJosh Poimboeuf 50cb76c939SJosh Poimboeuf info->type = STACK_TYPE_IRQ; 51cb76c939SJosh Poimboeuf info->begin = begin; 52cb76c939SJosh Poimboeuf info->end = end; 53cb76c939SJosh Poimboeuf 54cb76c939SJosh Poimboeuf /* 55cb76c939SJosh Poimboeuf * See irq_32.c -- the next stack pointer is stored at the beginning of 56cb76c939SJosh Poimboeuf * the stack. 57cb76c939SJosh Poimboeuf */ 58cb76c939SJosh Poimboeuf info->next_sp = (unsigned long *)*begin; 59cb76c939SJosh Poimboeuf 60cb76c939SJosh Poimboeuf return true; 61198d208dSSteven Rostedt } 62198d208dSSteven Rostedt 63cb76c939SJosh Poimboeuf static bool in_softirq_stack(unsigned long *stack, struct stack_info *info) 64198d208dSSteven Rostedt { 65a754fe2bSThomas Gleixner unsigned long *begin = (unsigned long *)this_cpu_read(softirq_stack_ptr); 66cb76c939SJosh Poimboeuf unsigned long *end = begin + (THREAD_SIZE / sizeof(long)); 67198d208dSSteven Rostedt 685fe599e0SJosh Poimboeuf /* 695fe599e0SJosh Poimboeuf * This is a software stack, so 'end' can be a valid stack pointer. 705fe599e0SJosh Poimboeuf * It just means the stack is empty. 715fe599e0SJosh Poimboeuf */ 72fa332154SAndy Lutomirski if (stack < begin || stack > end) 73cb76c939SJosh Poimboeuf return false; 74cb76c939SJosh Poimboeuf 75cb76c939SJosh Poimboeuf info->type = STACK_TYPE_SOFTIRQ; 76cb76c939SJosh Poimboeuf info->begin = begin; 77cb76c939SJosh Poimboeuf info->end = end; 78cb76c939SJosh Poimboeuf 79cb76c939SJosh Poimboeuf /* 80cb76c939SJosh Poimboeuf * The next stack pointer is stored at the beginning of the stack. 81cb76c939SJosh Poimboeuf * See irq_32.c. 82cb76c939SJosh Poimboeuf */ 83cb76c939SJosh Poimboeuf info->next_sp = (unsigned long *)*begin; 84cb76c939SJosh Poimboeuf 85cb76c939SJosh Poimboeuf return true; 86cb76c939SJosh Poimboeuf } 87cb76c939SJosh Poimboeuf 88*dc4e0021SAndy Lutomirski static bool in_doublefault_stack(unsigned long *stack, struct stack_info *info) 89*dc4e0021SAndy Lutomirski { 90*dc4e0021SAndy Lutomirski #ifdef CONFIG_DOUBLEFAULT 91*dc4e0021SAndy Lutomirski struct cpu_entry_area *cea = get_cpu_entry_area(raw_smp_processor_id()); 92*dc4e0021SAndy Lutomirski struct doublefault_stack *ss = &cea->doublefault_stack; 93*dc4e0021SAndy Lutomirski 94*dc4e0021SAndy Lutomirski void *begin = ss->stack; 95*dc4e0021SAndy Lutomirski void *end = begin + sizeof(ss->stack); 96*dc4e0021SAndy Lutomirski 97*dc4e0021SAndy Lutomirski if ((void *)stack < begin || (void *)stack >= end) 98*dc4e0021SAndy Lutomirski return false; 99*dc4e0021SAndy Lutomirski 100*dc4e0021SAndy Lutomirski info->type = STACK_TYPE_EXCEPTION; 101*dc4e0021SAndy Lutomirski info->begin = begin; 102*dc4e0021SAndy Lutomirski info->end = end; 103*dc4e0021SAndy Lutomirski info->next_sp = (unsigned long *)this_cpu_read(cpu_tss_rw.x86_tss.sp); 104*dc4e0021SAndy Lutomirski 105*dc4e0021SAndy Lutomirski return true; 106*dc4e0021SAndy Lutomirski #else 107*dc4e0021SAndy Lutomirski return false; 108*dc4e0021SAndy Lutomirski #endif 109*dc4e0021SAndy Lutomirski } 110*dc4e0021SAndy Lutomirski 111*dc4e0021SAndy Lutomirski 112cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task, 113cb76c939SJosh Poimboeuf struct stack_info *info, unsigned long *visit_mask) 114cb76c939SJosh Poimboeuf { 115cb76c939SJosh Poimboeuf if (!stack) 116cb76c939SJosh Poimboeuf goto unknown; 117cb76c939SJosh Poimboeuf 118cb76c939SJosh Poimboeuf task = task ? : current; 119cb76c939SJosh Poimboeuf 120cb76c939SJosh Poimboeuf if (in_task_stack(stack, task, info)) 121fcd709efSJosh Poimboeuf goto recursion_check; 122cb76c939SJosh Poimboeuf 123cb76c939SJosh Poimboeuf if (task != current) 124cb76c939SJosh Poimboeuf goto unknown; 125cb76c939SJosh Poimboeuf 1264fe2d8b1SDave Hansen if (in_entry_stack(stack, info)) 12733a2f1a6SAndy Lutomirski goto recursion_check; 12833a2f1a6SAndy Lutomirski 129cb76c939SJosh Poimboeuf if (in_hardirq_stack(stack, info)) 130fcd709efSJosh Poimboeuf goto recursion_check; 131cb76c939SJosh Poimboeuf 132cb76c939SJosh Poimboeuf if (in_softirq_stack(stack, info)) 133fcd709efSJosh Poimboeuf goto recursion_check; 134fcd709efSJosh Poimboeuf 135*dc4e0021SAndy Lutomirski if (in_doublefault_stack(stack, info)) 136*dc4e0021SAndy Lutomirski goto recursion_check; 137*dc4e0021SAndy Lutomirski 138fcd709efSJosh Poimboeuf goto unknown; 139fcd709efSJosh Poimboeuf 140fcd709efSJosh Poimboeuf recursion_check: 141fcd709efSJosh Poimboeuf /* 142fcd709efSJosh Poimboeuf * Make sure we don't iterate through any given stack more than once. 143fcd709efSJosh Poimboeuf * If it comes up a second time then there's something wrong going on: 144fcd709efSJosh Poimboeuf * just break out and report an unknown stack type. 145fcd709efSJosh Poimboeuf */ 146fcd709efSJosh Poimboeuf if (visit_mask) { 1470d2b8579SJosh Poimboeuf if (*visit_mask & (1UL << info->type)) { 1480d2b8579SJosh Poimboeuf printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type); 149fcd709efSJosh Poimboeuf goto unknown; 1500d2b8579SJosh Poimboeuf } 151fcd709efSJosh Poimboeuf *visit_mask |= 1UL << info->type; 152fcd709efSJosh Poimboeuf } 153fcd709efSJosh Poimboeuf 154cb76c939SJosh Poimboeuf return 0; 155cb76c939SJosh Poimboeuf 156cb76c939SJosh Poimboeuf unknown: 157cb76c939SJosh Poimboeuf info->type = STACK_TYPE_UNKNOWN; 158cb76c939SJosh Poimboeuf return -EINVAL; 159198d208dSSteven Rostedt } 160