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", 252a594d4cSThomas Gleixner [ ESTACK_DB2 ] = "#DB2", 262a594d4cSThomas Gleixner [ ESTACK_DB1 ] = "#DB1", 278f34c5b5SThomas Gleixner [ ESTACK_DB ] = "#DB", 288f34c5b5SThomas Gleixner [ ESTACK_MCE ] = "#MC", 299c003907SJosh Poimboeuf }; 309c003907SJosh Poimboeuf 313d02a9c4SJosh Poimboeuf const char *stack_type_name(enum stack_type type) 320406ca6dSFrederic Weisbecker { 332a594d4cSThomas Gleixner 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(DB1), 83c450c8f5SThomas Gleixner EPAGERANGE(DB), 84c450c8f5SThomas Gleixner EPAGERANGE(MCE), 85afcd21daSThomas Gleixner }; 86afcd21daSThomas Gleixner 87fcd709efSJosh Poimboeuf static bool in_exception_stack(unsigned long *stack, struct stack_info *info) 88cb76c939SJosh Poimboeuf { 89c450c8f5SThomas Gleixner unsigned long begin, end, stk = (unsigned long)stack; 90c450c8f5SThomas Gleixner const struct estack_pages *ep; 91cb76c939SJosh Poimboeuf struct pt_regs *regs; 92afcd21daSThomas Gleixner unsigned int k; 936fcbede3SAlexander van Heukelum 942a594d4cSThomas Gleixner BUILD_BUG_ON(N_EXCEPTION_STACKS != 6); 959c003907SJosh Poimboeuf 96c450c8f5SThomas Gleixner begin = (unsigned long)__this_cpu_read(cea_exception_stacks); 97e361362bSThomas Gleixner /* 98e361362bSThomas Gleixner * Handle the case where stack trace is collected _before_ 99e361362bSThomas Gleixner * cea_exception_stacks had been initialized. 100e361362bSThomas Gleixner */ 101e361362bSThomas Gleixner if (!begin) 102e361362bSThomas Gleixner return false; 103e361362bSThomas Gleixner 104c450c8f5SThomas Gleixner end = begin + sizeof(struct cea_exception_stacks); 105c450c8f5SThomas Gleixner /* Bail if @stack is outside the exception stack area. */ 106c450c8f5SThomas Gleixner if (stk < begin || stk >= end) 107c450c8f5SThomas Gleixner return false; 108afcd21daSThomas Gleixner 109c450c8f5SThomas Gleixner /* Calc page offset from start of exception stacks */ 110c450c8f5SThomas Gleixner k = (stk - begin) >> PAGE_SHIFT; 111c450c8f5SThomas Gleixner /* Lookup the page descriptor */ 112c450c8f5SThomas Gleixner ep = &estack_pages[k]; 113c450c8f5SThomas Gleixner /* Guard page? */ 114c450c8f5SThomas Gleixner if (!ep->size) 115c450c8f5SThomas Gleixner return false; 116c450c8f5SThomas Gleixner 117c450c8f5SThomas Gleixner begin += (unsigned long)ep->offs; 118c450c8f5SThomas Gleixner end = begin + (unsigned long)ep->size; 119cb76c939SJosh Poimboeuf regs = (struct pt_regs *)end - 1; 1209c003907SJosh Poimboeuf 121c450c8f5SThomas Gleixner info->type = ep->type; 122afcd21daSThomas Gleixner info->begin = (unsigned long *)begin; 123afcd21daSThomas Gleixner info->end = (unsigned long *)end; 124cb76c939SJosh Poimboeuf info->next_sp = (unsigned long *)regs->sp; 125cb76c939SJosh Poimboeuf return true; 1266fcbede3SAlexander van Heukelum } 1279c003907SJosh Poimboeuf 128cb76c939SJosh Poimboeuf static bool in_irq_stack(unsigned long *stack, struct stack_info *info) 129af2d8289SFrederic Weisbecker { 130758a2e31SThomas Gleixner unsigned long *end = (unsigned long *)this_cpu_read(hardirq_stack_ptr); 131cb76c939SJosh Poimboeuf unsigned long *begin = end - (IRQ_STACK_SIZE / sizeof(long)); 132cb76c939SJosh Poimboeuf 1335fe599e0SJosh Poimboeuf /* 1345fe599e0SJosh Poimboeuf * This is a software stack, so 'end' can be a valid stack pointer. 1355fe599e0SJosh Poimboeuf * It just means the stack is empty. 1365fe599e0SJosh Poimboeuf */ 137fa332154SAndy Lutomirski if (stack < begin || stack >= end) 138cb76c939SJosh Poimboeuf return false; 139cb76c939SJosh Poimboeuf 140cb76c939SJosh Poimboeuf info->type = STACK_TYPE_IRQ; 141cb76c939SJosh Poimboeuf info->begin = begin; 142cb76c939SJosh Poimboeuf info->end = end; 143cb76c939SJosh Poimboeuf 144cb76c939SJosh Poimboeuf /* 145cb76c939SJosh Poimboeuf * The next stack pointer is the first thing pushed by the entry code 146cb76c939SJosh Poimboeuf * after switching to the irq stack. 147cb76c939SJosh Poimboeuf */ 148cb76c939SJosh Poimboeuf info->next_sp = (unsigned long *)*(end - 1); 149cb76c939SJosh Poimboeuf 150cb76c939SJosh Poimboeuf return true; 151af2d8289SFrederic Weisbecker } 152af2d8289SFrederic Weisbecker 153cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task, 154cb76c939SJosh Poimboeuf struct stack_info *info, unsigned long *visit_mask) 1552223f6f6SSteven Rostedt { 156cb76c939SJosh Poimboeuf if (!stack) 157cb76c939SJosh Poimboeuf goto unknown; 1582223f6f6SSteven Rostedt 159cb76c939SJosh Poimboeuf task = task ? : current; 1602223f6f6SSteven Rostedt 161cb76c939SJosh Poimboeuf if (in_task_stack(stack, task, info)) 162fcd709efSJosh Poimboeuf goto recursion_check; 1632223f6f6SSteven Rostedt 164cb76c939SJosh Poimboeuf if (task != current) 165cb76c939SJosh Poimboeuf goto unknown; 1662223f6f6SSteven Rostedt 167fcd709efSJosh Poimboeuf if (in_exception_stack(stack, info)) 168fcd709efSJosh Poimboeuf goto recursion_check; 1692223f6f6SSteven Rostedt 170cb76c939SJosh Poimboeuf if (in_irq_stack(stack, info)) 171fcd709efSJosh Poimboeuf goto recursion_check; 172fcd709efSJosh Poimboeuf 1734fe2d8b1SDave Hansen if (in_entry_stack(stack, info)) 17433a2f1a6SAndy Lutomirski goto recursion_check; 17533a2f1a6SAndy Lutomirski 176fcd709efSJosh Poimboeuf goto unknown; 177fcd709efSJosh Poimboeuf 178fcd709efSJosh Poimboeuf recursion_check: 179fcd709efSJosh Poimboeuf /* 180fcd709efSJosh Poimboeuf * Make sure we don't iterate through any given stack more than once. 181fcd709efSJosh Poimboeuf * If it comes up a second time then there's something wrong going on: 182fcd709efSJosh Poimboeuf * just break out and report an unknown stack type. 183fcd709efSJosh Poimboeuf */ 184fcd709efSJosh Poimboeuf if (visit_mask) { 1850d2b8579SJosh Poimboeuf if (*visit_mask & (1UL << info->type)) { 1860d2b8579SJosh Poimboeuf printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type); 187fcd709efSJosh Poimboeuf goto unknown; 1880d2b8579SJosh Poimboeuf } 189fcd709efSJosh Poimboeuf *visit_mask |= 1UL << info->type; 190fcd709efSJosh Poimboeuf } 1912223f6f6SSteven Rostedt 192cb76c939SJosh Poimboeuf return 0; 193cb76c939SJosh Poimboeuf 194cb76c939SJosh Poimboeuf unknown: 195cb76c939SJosh Poimboeuf info->type = STACK_TYPE_UNKNOWN; 196cb76c939SJosh Poimboeuf return -EINVAL; 1972223f6f6SSteven Rostedt } 198