1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 26fcbede3SAlexander van Heukelum /* 36fcbede3SAlexander van Heukelum * Copyright (C) 1991, 1992 Linus Torvalds 46fcbede3SAlexander van Heukelum * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs 56fcbede3SAlexander van Heukelum */ 6b17b0153SIngo Molnar #include <linux/sched/debug.h> 76fcbede3SAlexander van Heukelum #include <linux/kallsyms.h> 86fcbede3SAlexander van Heukelum #include <linux/kprobes.h> 96fcbede3SAlexander van Heukelum #include <linux/uaccess.h> 106fcbede3SAlexander van Heukelum #include <linux/hardirq.h> 116fcbede3SAlexander van Heukelum #include <linux/kdebug.h> 12186f4360SPaul Gortmaker #include <linux/export.h> 136fcbede3SAlexander van Heukelum #include <linux/ptrace.h> 146fcbede3SAlexander van Heukelum #include <linux/kexec.h> 15b8030906SIngo Molnar #include <linux/sysfs.h> 166fcbede3SAlexander van Heukelum #include <linux/bug.h> 176fcbede3SAlexander van Heukelum #include <linux/nmi.h> 186fcbede3SAlexander van Heukelum 19afcd21daSThomas Gleixner #include <asm/cpu_entry_area.h> 206fcbede3SAlexander van Heukelum #include <asm/stacktrace.h> 216fcbede3SAlexander van Heukelum 222a594d4cSThomas Gleixner static const char * const exception_stack_names[] = { 238f34c5b5SThomas Gleixner [ ESTACK_DF ] = "#DF", 248f34c5b5SThomas Gleixner [ ESTACK_NMI ] = "NMI", 258f34c5b5SThomas Gleixner [ ESTACK_DB ] = "#DB", 268f34c5b5SThomas Gleixner [ ESTACK_MCE ] = "#MC", 2702772fb9SJoerg Roedel [ ESTACK_VC ] = "#VC", 2802772fb9SJoerg Roedel [ ESTACK_VC2 ] = "#VC2", 299c003907SJosh Poimboeuf }; 309c003907SJosh Poimboeuf 313d02a9c4SJosh Poimboeuf const char *stack_type_name(enum stack_type type) 320406ca6dSFrederic Weisbecker { 3302772fb9SJoerg Roedel BUILD_BUG_ON(N_EXCEPTION_STACKS != 6); 34cb76c939SJosh Poimboeuf 353d02a9c4SJosh Poimboeuf if (type == STACK_TYPE_IRQ) 363d02a9c4SJosh Poimboeuf return "IRQ"; 373d02a9c4SJosh Poimboeuf 384fe2d8b1SDave Hansen if (type == STACK_TYPE_ENTRY) { 394fe2d8b1SDave Hansen /* 404fe2d8b1SDave Hansen * On 64-bit, we have a generic entry stack that we 414fe2d8b1SDave Hansen * use for all the kernel entry points, including 424fe2d8b1SDave Hansen * SYSENTER. 434fe2d8b1SDave Hansen */ 444fe2d8b1SDave Hansen return "ENTRY_TRAMPOLINE"; 454fe2d8b1SDave Hansen } 4633a2f1a6SAndy Lutomirski 473d02a9c4SJosh Poimboeuf if (type >= STACK_TYPE_EXCEPTION && type <= STACK_TYPE_EXCEPTION_LAST) 483d02a9c4SJosh Poimboeuf return exception_stack_names[type - STACK_TYPE_EXCEPTION]; 493d02a9c4SJosh Poimboeuf 503d02a9c4SJosh Poimboeuf return NULL; 51cb76c939SJosh Poimboeuf } 52cb76c939SJosh Poimboeuf 53c450c8f5SThomas Gleixner /** 54c450c8f5SThomas Gleixner * struct estack_pages - Page descriptor for exception stacks 55c450c8f5SThomas Gleixner * @offs: Offset from the start of the exception stack area 56c450c8f5SThomas Gleixner * @size: Size of the exception stack 57c450c8f5SThomas Gleixner * @type: Type to store in the stack_info struct 58c450c8f5SThomas Gleixner */ 59c450c8f5SThomas Gleixner struct estack_pages { 60c450c8f5SThomas Gleixner u32 offs; 61c450c8f5SThomas Gleixner u16 size; 62c450c8f5SThomas Gleixner u16 type; 63afcd21daSThomas Gleixner }; 64afcd21daSThomas Gleixner 65c450c8f5SThomas Gleixner #define EPAGERANGE(st) \ 66c450c8f5SThomas Gleixner [PFN_DOWN(CEA_ESTACK_OFFS(st)) ... \ 67c450c8f5SThomas Gleixner PFN_DOWN(CEA_ESTACK_OFFS(st) + CEA_ESTACK_SIZE(st) - 1)] = { \ 68c450c8f5SThomas Gleixner .offs = CEA_ESTACK_OFFS(st), \ 69c450c8f5SThomas Gleixner .size = CEA_ESTACK_SIZE(st), \ 70c450c8f5SThomas Gleixner .type = STACK_TYPE_EXCEPTION + ESTACK_ ##st, } 71afcd21daSThomas Gleixner 72c450c8f5SThomas Gleixner /* 73c450c8f5SThomas Gleixner * Array of exception stack page descriptors. If the stack is larger than 74c450c8f5SThomas Gleixner * PAGE_SIZE, all pages covering a particular stack will have the same 75c450c8f5SThomas Gleixner * info. The guard pages including the not mapped DB2 stack are zeroed 76c450c8f5SThomas Gleixner * out. 77c450c8f5SThomas Gleixner */ 78c450c8f5SThomas Gleixner static const 79c450c8f5SThomas Gleixner struct estack_pages estack_pages[CEA_ESTACK_PAGES] ____cacheline_aligned = { 80c450c8f5SThomas Gleixner EPAGERANGE(DF), 81c450c8f5SThomas Gleixner EPAGERANGE(NMI), 82c450c8f5SThomas Gleixner EPAGERANGE(DB), 83c450c8f5SThomas Gleixner EPAGERANGE(MCE), 8402772fb9SJoerg Roedel EPAGERANGE(VC), 8502772fb9SJoerg Roedel EPAGERANGE(VC2), 86afcd21daSThomas Gleixner }; 87afcd21daSThomas Gleixner 88fcd709efSJosh Poimboeuf static bool in_exception_stack(unsigned long *stack, struct stack_info *info) 89cb76c939SJosh Poimboeuf { 90c450c8f5SThomas Gleixner unsigned long begin, end, stk = (unsigned long)stack; 91c450c8f5SThomas Gleixner const struct estack_pages *ep; 92cb76c939SJosh Poimboeuf struct pt_regs *regs; 93afcd21daSThomas Gleixner unsigned int k; 946fcbede3SAlexander van Heukelum 9502772fb9SJoerg Roedel BUILD_BUG_ON(N_EXCEPTION_STACKS != 6); 969c003907SJosh Poimboeuf 97c450c8f5SThomas Gleixner begin = (unsigned long)__this_cpu_read(cea_exception_stacks); 98e361362bSThomas Gleixner /* 99e361362bSThomas Gleixner * Handle the case where stack trace is collected _before_ 100e361362bSThomas Gleixner * cea_exception_stacks had been initialized. 101e361362bSThomas Gleixner */ 102e361362bSThomas Gleixner if (!begin) 103e361362bSThomas Gleixner return false; 104e361362bSThomas Gleixner 105c450c8f5SThomas Gleixner end = begin + sizeof(struct cea_exception_stacks); 106c450c8f5SThomas Gleixner /* Bail if @stack is outside the exception stack area. */ 107c450c8f5SThomas Gleixner if (stk < begin || stk >= end) 108c450c8f5SThomas Gleixner return false; 109afcd21daSThomas Gleixner 110c450c8f5SThomas Gleixner /* Calc page offset from start of exception stacks */ 111c450c8f5SThomas Gleixner k = (stk - begin) >> PAGE_SHIFT; 112c450c8f5SThomas Gleixner /* Lookup the page descriptor */ 113c450c8f5SThomas Gleixner ep = &estack_pages[k]; 114c450c8f5SThomas Gleixner /* Guard page? */ 115c450c8f5SThomas Gleixner if (!ep->size) 116c450c8f5SThomas Gleixner return false; 117c450c8f5SThomas Gleixner 118c450c8f5SThomas Gleixner begin += (unsigned long)ep->offs; 119c450c8f5SThomas Gleixner end = begin + (unsigned long)ep->size; 120cb76c939SJosh Poimboeuf regs = (struct pt_regs *)end - 1; 1219c003907SJosh Poimboeuf 122c450c8f5SThomas Gleixner info->type = ep->type; 123afcd21daSThomas Gleixner info->begin = (unsigned long *)begin; 124afcd21daSThomas Gleixner info->end = (unsigned long *)end; 125cb76c939SJosh Poimboeuf info->next_sp = (unsigned long *)regs->sp; 126cb76c939SJosh Poimboeuf return true; 1276fcbede3SAlexander van Heukelum } 1289c003907SJosh Poimboeuf 129cb76c939SJosh Poimboeuf static bool in_irq_stack(unsigned long *stack, struct stack_info *info) 130af2d8289SFrederic Weisbecker { 131758a2e31SThomas Gleixner unsigned long *end = (unsigned long *)this_cpu_read(hardirq_stack_ptr); 132cb76c939SJosh Poimboeuf unsigned long *begin = end - (IRQ_STACK_SIZE / sizeof(long)); 133cb76c939SJosh Poimboeuf 1345fe599e0SJosh Poimboeuf /* 1355fe599e0SJosh Poimboeuf * This is a software stack, so 'end' can be a valid stack pointer. 1365fe599e0SJosh Poimboeuf * It just means the stack is empty. 1375fe599e0SJosh Poimboeuf */ 138fa332154SAndy Lutomirski if (stack < begin || stack >= end) 139cb76c939SJosh Poimboeuf return false; 140cb76c939SJosh Poimboeuf 141cb76c939SJosh Poimboeuf info->type = STACK_TYPE_IRQ; 142cb76c939SJosh Poimboeuf info->begin = begin; 143cb76c939SJosh Poimboeuf info->end = end; 144cb76c939SJosh Poimboeuf 145cb76c939SJosh Poimboeuf /* 146cb76c939SJosh Poimboeuf * The next stack pointer is the first thing pushed by the entry code 147cb76c939SJosh Poimboeuf * after switching to the irq stack. 148cb76c939SJosh Poimboeuf */ 149cb76c939SJosh Poimboeuf info->next_sp = (unsigned long *)*(end - 1); 150cb76c939SJosh Poimboeuf 151cb76c939SJosh Poimboeuf return true; 152af2d8289SFrederic Weisbecker } 153af2d8289SFrederic Weisbecker 154cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task, 155cb76c939SJosh Poimboeuf struct stack_info *info, unsigned long *visit_mask) 1562223f6f6SSteven Rostedt { 157cb76c939SJosh Poimboeuf if (!stack) 158cb76c939SJosh Poimboeuf goto unknown; 1592223f6f6SSteven Rostedt 160cb76c939SJosh Poimboeuf task = task ? : current; 1612223f6f6SSteven Rostedt 162cb76c939SJosh Poimboeuf if (in_task_stack(stack, task, info)) 163fcd709efSJosh Poimboeuf goto recursion_check; 1642223f6f6SSteven Rostedt 165cb76c939SJosh Poimboeuf if (task != current) 166cb76c939SJosh Poimboeuf goto unknown; 1672223f6f6SSteven Rostedt 168fcd709efSJosh Poimboeuf if (in_exception_stack(stack, info)) 169fcd709efSJosh Poimboeuf goto recursion_check; 1702223f6f6SSteven Rostedt 171cb76c939SJosh Poimboeuf if (in_irq_stack(stack, info)) 172fcd709efSJosh Poimboeuf goto recursion_check; 173fcd709efSJosh Poimboeuf 1744fe2d8b1SDave Hansen if (in_entry_stack(stack, info)) 17533a2f1a6SAndy Lutomirski goto recursion_check; 17633a2f1a6SAndy Lutomirski 177fcd709efSJosh Poimboeuf goto unknown; 178fcd709efSJosh Poimboeuf 179fcd709efSJosh Poimboeuf recursion_check: 180fcd709efSJosh Poimboeuf /* 181fcd709efSJosh Poimboeuf * Make sure we don't iterate through any given stack more than once. 182fcd709efSJosh Poimboeuf * If it comes up a second time then there's something wrong going on: 183fcd709efSJosh Poimboeuf * just break out and report an unknown stack type. 184fcd709efSJosh Poimboeuf */ 185fcd709efSJosh Poimboeuf if (visit_mask) { 1860d2b8579SJosh Poimboeuf if (*visit_mask & (1UL << info->type)) { 187b08418b5SJosh Poimboeuf if (task == current) 1880d2b8579SJosh Poimboeuf printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type); 189fcd709efSJosh Poimboeuf goto unknown; 1900d2b8579SJosh Poimboeuf } 191fcd709efSJosh Poimboeuf *visit_mask |= 1UL << info->type; 192fcd709efSJosh Poimboeuf } 1932223f6f6SSteven Rostedt 194cb76c939SJosh Poimboeuf return 0; 195cb76c939SJosh Poimboeuf 196cb76c939SJosh Poimboeuf unknown: 197cb76c939SJosh Poimboeuf info->type = STACK_TYPE_UNKNOWN; 198cb76c939SJosh Poimboeuf return -EINVAL; 1992223f6f6SSteven Rostedt } 200