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 196fcbede3SAlexander van Heukelum #include <asm/stacktrace.h> 206fcbede3SAlexander van Heukelum 219c003907SJosh Poimboeuf static char *exception_stack_names[N_EXCEPTION_STACKS] = { 226fcbede3SAlexander van Heukelum [ DOUBLEFAULT_STACK-1 ] = "#DF", 239c003907SJosh Poimboeuf [ NMI_STACK-1 ] = "NMI", 249c003907SJosh Poimboeuf [ DEBUG_STACK-1 ] = "#DB", 256fcbede3SAlexander van Heukelum [ MCE_STACK-1 ] = "#MC", 269c003907SJosh Poimboeuf }; 279c003907SJosh Poimboeuf 289c003907SJosh Poimboeuf static unsigned long exception_stack_sizes[N_EXCEPTION_STACKS] = { 299c003907SJosh Poimboeuf [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STKSZ, 309c003907SJosh Poimboeuf [DEBUG_STACK - 1] = DEBUG_STKSZ 316fcbede3SAlexander van Heukelum }; 320406ca6dSFrederic Weisbecker 333d02a9c4SJosh Poimboeuf const char *stack_type_name(enum stack_type type) 340406ca6dSFrederic Weisbecker { 35cb76c939SJosh Poimboeuf BUILD_BUG_ON(N_EXCEPTION_STACKS != 4); 36cb76c939SJosh Poimboeuf 373d02a9c4SJosh Poimboeuf if (type == STACK_TYPE_IRQ) 383d02a9c4SJosh Poimboeuf return "IRQ"; 393d02a9c4SJosh Poimboeuf 4033a2f1a6SAndy Lutomirski if (type == STACK_TYPE_SYSENTER) 4133a2f1a6SAndy Lutomirski return "SYSENTER"; 4233a2f1a6SAndy Lutomirski 433d02a9c4SJosh Poimboeuf if (type >= STACK_TYPE_EXCEPTION && type <= STACK_TYPE_EXCEPTION_LAST) 443d02a9c4SJosh Poimboeuf return exception_stack_names[type - STACK_TYPE_EXCEPTION]; 453d02a9c4SJosh Poimboeuf 463d02a9c4SJosh Poimboeuf return NULL; 47cb76c939SJosh Poimboeuf } 48cb76c939SJosh Poimboeuf 49fcd709efSJosh Poimboeuf static bool in_exception_stack(unsigned long *stack, struct stack_info *info) 50cb76c939SJosh Poimboeuf { 51cb76c939SJosh Poimboeuf unsigned long *begin, *end; 52cb76c939SJosh Poimboeuf struct pt_regs *regs; 536fcbede3SAlexander van Heukelum unsigned k; 546fcbede3SAlexander van Heukelum 559c003907SJosh Poimboeuf BUILD_BUG_ON(N_EXCEPTION_STACKS != 4); 569c003907SJosh Poimboeuf 576fcbede3SAlexander van Heukelum for (k = 0; k < N_EXCEPTION_STACKS; k++) { 58cb76c939SJosh Poimboeuf end = (unsigned long *)raw_cpu_ptr(&orig_ist)->ist[k]; 59cb76c939SJosh Poimboeuf begin = end - (exception_stack_sizes[k] / sizeof(long)); 60cb76c939SJosh Poimboeuf regs = (struct pt_regs *)end - 1; 619c003907SJosh Poimboeuf 625a3cf869SJosh Poimboeuf if (stack <= begin || stack >= end) 636fcbede3SAlexander van Heukelum continue; 649c003907SJosh Poimboeuf 65cb76c939SJosh Poimboeuf info->type = STACK_TYPE_EXCEPTION + k; 66cb76c939SJosh Poimboeuf info->begin = begin; 67cb76c939SJosh Poimboeuf info->end = end; 68cb76c939SJosh Poimboeuf info->next_sp = (unsigned long *)regs->sp; 69cb76c939SJosh Poimboeuf 70cb76c939SJosh Poimboeuf return true; 716fcbede3SAlexander van Heukelum } 729c003907SJosh Poimboeuf 73cb76c939SJosh Poimboeuf return false; 746fcbede3SAlexander van Heukelum } 756fcbede3SAlexander van Heukelum 76cb76c939SJosh Poimboeuf static bool in_irq_stack(unsigned long *stack, struct stack_info *info) 77af2d8289SFrederic Weisbecker { 78cb76c939SJosh Poimboeuf unsigned long *end = (unsigned long *)this_cpu_read(irq_stack_ptr); 79cb76c939SJosh Poimboeuf unsigned long *begin = end - (IRQ_STACK_SIZE / sizeof(long)); 80cb76c939SJosh Poimboeuf 815fe599e0SJosh Poimboeuf /* 825fe599e0SJosh Poimboeuf * This is a software stack, so 'end' can be a valid stack pointer. 835fe599e0SJosh Poimboeuf * It just means the stack is empty. 845fe599e0SJosh Poimboeuf */ 855a3cf869SJosh Poimboeuf if (stack <= begin || stack > end) 86cb76c939SJosh Poimboeuf return false; 87cb76c939SJosh Poimboeuf 88cb76c939SJosh Poimboeuf info->type = STACK_TYPE_IRQ; 89cb76c939SJosh Poimboeuf info->begin = begin; 90cb76c939SJosh Poimboeuf info->end = end; 91cb76c939SJosh Poimboeuf 92cb76c939SJosh Poimboeuf /* 93cb76c939SJosh Poimboeuf * The next stack pointer is the first thing pushed by the entry code 94cb76c939SJosh Poimboeuf * after switching to the irq stack. 95cb76c939SJosh Poimboeuf */ 96cb76c939SJosh Poimboeuf info->next_sp = (unsigned long *)*(end - 1); 97cb76c939SJosh Poimboeuf 98cb76c939SJosh Poimboeuf return true; 99af2d8289SFrederic Weisbecker } 100af2d8289SFrederic Weisbecker 101cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task, 102cb76c939SJosh Poimboeuf struct stack_info *info, unsigned long *visit_mask) 1032223f6f6SSteven Rostedt { 104cb76c939SJosh Poimboeuf if (!stack) 105cb76c939SJosh Poimboeuf goto unknown; 1062223f6f6SSteven Rostedt 107cb76c939SJosh Poimboeuf task = task ? : current; 1082223f6f6SSteven Rostedt 109cb76c939SJosh Poimboeuf if (in_task_stack(stack, task, info)) 110fcd709efSJosh Poimboeuf goto recursion_check; 1112223f6f6SSteven Rostedt 112cb76c939SJosh Poimboeuf if (task != current) 113cb76c939SJosh Poimboeuf goto unknown; 1142223f6f6SSteven Rostedt 115fcd709efSJosh Poimboeuf if (in_exception_stack(stack, info)) 116fcd709efSJosh Poimboeuf goto recursion_check; 1172223f6f6SSteven Rostedt 118cb76c939SJosh Poimboeuf if (in_irq_stack(stack, info)) 119fcd709efSJosh Poimboeuf goto recursion_check; 120fcd709efSJosh Poimboeuf 12133a2f1a6SAndy Lutomirski if (in_sysenter_stack(stack, info)) 12233a2f1a6SAndy Lutomirski goto recursion_check; 12333a2f1a6SAndy Lutomirski 124fcd709efSJosh Poimboeuf goto unknown; 125fcd709efSJosh Poimboeuf 126fcd709efSJosh Poimboeuf recursion_check: 127fcd709efSJosh Poimboeuf /* 128fcd709efSJosh Poimboeuf * Make sure we don't iterate through any given stack more than once. 129fcd709efSJosh Poimboeuf * If it comes up a second time then there's something wrong going on: 130fcd709efSJosh Poimboeuf * just break out and report an unknown stack type. 131fcd709efSJosh Poimboeuf */ 132fcd709efSJosh Poimboeuf if (visit_mask) { 1330d2b8579SJosh Poimboeuf if (*visit_mask & (1UL << info->type)) { 1340d2b8579SJosh Poimboeuf printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type); 135fcd709efSJosh Poimboeuf goto unknown; 1360d2b8579SJosh Poimboeuf } 137fcd709efSJosh Poimboeuf *visit_mask |= 1UL << info->type; 138fcd709efSJosh Poimboeuf } 1392223f6f6SSteven Rostedt 140cb76c939SJosh Poimboeuf return 0; 141cb76c939SJosh Poimboeuf 142cb76c939SJosh Poimboeuf unknown: 143cb76c939SJosh Poimboeuf info->type = STACK_TYPE_UNKNOWN; 144cb76c939SJosh Poimboeuf return -EINVAL; 1452223f6f6SSteven Rostedt } 1462223f6f6SSteven Rostedt 14757da8b96SJan Beulich void show_regs(struct pt_regs *regs) 1486fcbede3SAlexander van Heukelum { 1496fcbede3SAlexander van Heukelum int i; 1506fcbede3SAlexander van Heukelum 151a43cb95dSTejun Heo show_regs_print_info(KERN_DEFAULT); 1526fcbede3SAlexander van Heukelum __show_regs(regs, 1); 1536fcbede3SAlexander van Heukelum 1546fcbede3SAlexander van Heukelum /* 1556fcbede3SAlexander van Heukelum * When in-kernel, we also print out the stack and code at the 1566fcbede3SAlexander van Heukelum * time of the fault.. 1576fcbede3SAlexander van Heukelum */ 1586fcbede3SAlexander van Heukelum if (!user_mode(regs)) { 1596fcbede3SAlexander van Heukelum unsigned int code_prologue = code_bytes * 43 / 64; 1606fcbede3SAlexander van Heukelum unsigned int code_len = code_bytes; 1616fcbede3SAlexander van Heukelum unsigned char c; 1626fcbede3SAlexander van Heukelum u8 *ip; 1636fcbede3SAlexander van Heukelum 1640ee1dd9fSJosh Poimboeuf show_trace_log_lvl(current, regs, NULL, KERN_DEFAULT); 1656fcbede3SAlexander van Heukelum 166b0f4c4b3SPrarit Bhargava printk(KERN_DEFAULT "Code: "); 1676fcbede3SAlexander van Heukelum 1686fcbede3SAlexander van Heukelum ip = (u8 *)regs->ip - code_prologue; 1696fcbede3SAlexander van Heukelum if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { 1708a541665SAlexander van Heukelum /* try starting at IP */ 1716fcbede3SAlexander van Heukelum ip = (u8 *)regs->ip; 1726fcbede3SAlexander van Heukelum code_len = code_len - code_prologue + 1; 1736fcbede3SAlexander van Heukelum } 1746fcbede3SAlexander van Heukelum for (i = 0; i < code_len; i++, ip++) { 1756fcbede3SAlexander van Heukelum if (ip < (u8 *)PAGE_OFFSET || 1766fcbede3SAlexander van Heukelum probe_kernel_address(ip, c)) { 177c767a54bSJoe Perches pr_cont(" Bad RIP value."); 1786fcbede3SAlexander van Heukelum break; 1796fcbede3SAlexander van Heukelum } 1806fcbede3SAlexander van Heukelum if (ip == (u8 *)regs->ip) 181c767a54bSJoe Perches pr_cont("<%02x> ", c); 1826fcbede3SAlexander van Heukelum else 183c767a54bSJoe Perches pr_cont("%02x ", c); 1846fcbede3SAlexander van Heukelum } 1856fcbede3SAlexander van Heukelum } 186c767a54bSJoe Perches pr_cont("\n"); 1876fcbede3SAlexander van Heukelum } 188