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 32dc4e0021SAndy Lutomirski if (type == STACK_TYPE_EXCEPTION) 33dc4e0021SAndy Lutomirski return "#DF"; 34dc4e0021SAndy 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 { 40*d7b6d709SThomas Gleixner unsigned long *begin = (unsigned long *)this_cpu_read(pcpu_hot.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 { 65*d7b6d709SThomas Gleixner unsigned long *begin = (unsigned long *)this_cpu_read(pcpu_hot.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 88dc4e0021SAndy Lutomirski static bool in_doublefault_stack(unsigned long *stack, struct stack_info *info) 89dc4e0021SAndy Lutomirski { 90dc4e0021SAndy Lutomirski struct cpu_entry_area *cea = get_cpu_entry_area(raw_smp_processor_id()); 91dc4e0021SAndy Lutomirski struct doublefault_stack *ss = &cea->doublefault_stack; 92dc4e0021SAndy Lutomirski 93dc4e0021SAndy Lutomirski void *begin = ss->stack; 94dc4e0021SAndy Lutomirski void *end = begin + sizeof(ss->stack); 95dc4e0021SAndy Lutomirski 96dc4e0021SAndy Lutomirski if ((void *)stack < begin || (void *)stack >= end) 97dc4e0021SAndy Lutomirski return false; 98dc4e0021SAndy Lutomirski 99dc4e0021SAndy Lutomirski info->type = STACK_TYPE_EXCEPTION; 100dc4e0021SAndy Lutomirski info->begin = begin; 101dc4e0021SAndy Lutomirski info->end = end; 102dc4e0021SAndy Lutomirski info->next_sp = (unsigned long *)this_cpu_read(cpu_tss_rw.x86_tss.sp); 103dc4e0021SAndy Lutomirski 104dc4e0021SAndy Lutomirski return true; 105dc4e0021SAndy Lutomirski } 106dc4e0021SAndy Lutomirski 107dc4e0021SAndy Lutomirski 108cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task, 109cb76c939SJosh Poimboeuf struct stack_info *info, unsigned long *visit_mask) 110cb76c939SJosh Poimboeuf { 111cb76c939SJosh Poimboeuf if (!stack) 112cb76c939SJosh Poimboeuf goto unknown; 113cb76c939SJosh Poimboeuf 114cb76c939SJosh Poimboeuf task = task ? : current; 115cb76c939SJosh Poimboeuf 116cb76c939SJosh Poimboeuf if (in_task_stack(stack, task, info)) 117fcd709efSJosh Poimboeuf goto recursion_check; 118cb76c939SJosh Poimboeuf 119cb76c939SJosh Poimboeuf if (task != current) 120cb76c939SJosh Poimboeuf goto unknown; 121cb76c939SJosh Poimboeuf 1224fe2d8b1SDave Hansen if (in_entry_stack(stack, info)) 12333a2f1a6SAndy Lutomirski goto recursion_check; 12433a2f1a6SAndy Lutomirski 125cb76c939SJosh Poimboeuf if (in_hardirq_stack(stack, info)) 126fcd709efSJosh Poimboeuf goto recursion_check; 127cb76c939SJosh Poimboeuf 128cb76c939SJosh Poimboeuf if (in_softirq_stack(stack, info)) 129fcd709efSJosh Poimboeuf goto recursion_check; 130fcd709efSJosh Poimboeuf 131dc4e0021SAndy Lutomirski if (in_doublefault_stack(stack, info)) 132dc4e0021SAndy Lutomirski goto recursion_check; 133dc4e0021SAndy Lutomirski 134fcd709efSJosh Poimboeuf goto unknown; 135fcd709efSJosh Poimboeuf 136fcd709efSJosh Poimboeuf recursion_check: 137fcd709efSJosh Poimboeuf /* 138fcd709efSJosh Poimboeuf * Make sure we don't iterate through any given stack more than once. 139fcd709efSJosh Poimboeuf * If it comes up a second time then there's something wrong going on: 140fcd709efSJosh Poimboeuf * just break out and report an unknown stack type. 141fcd709efSJosh Poimboeuf */ 142fcd709efSJosh Poimboeuf if (visit_mask) { 1430d2b8579SJosh Poimboeuf if (*visit_mask & (1UL << info->type)) { 1440d2b8579SJosh Poimboeuf printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type); 145fcd709efSJosh Poimboeuf goto unknown; 1460d2b8579SJosh Poimboeuf } 147fcd709efSJosh Poimboeuf *visit_mask |= 1UL << info->type; 148fcd709efSJosh Poimboeuf } 149fcd709efSJosh Poimboeuf 150cb76c939SJosh Poimboeuf return 0; 151cb76c939SJosh Poimboeuf 152cb76c939SJosh Poimboeuf unknown: 153cb76c939SJosh Poimboeuf info->type = STACK_TYPE_UNKNOWN; 154cb76c939SJosh Poimboeuf return -EINVAL; 155198d208dSSteven Rostedt } 156