// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const char * const exception_stack_names[] = { [ ESTACK_DF ] = "#DF", [ ESTACK_NMI ] = "NMI", [ ESTACK_DB2 ] = "#DB2", [ ESTACK_DB1 ] = "#DB1", [ ESTACK_DB ] = "#DB", [ ESTACK_MCE ] = "#MC", }; const char *stack_type_name(enum stack_type type) { BUILD_BUG_ON(N_EXCEPTION_STACKS != 6); if (type == STACK_TYPE_IRQ) return "IRQ"; if (type == STACK_TYPE_ENTRY) { /* * On 64-bit, we have a generic entry stack that we * use for all the kernel entry points, including * SYSENTER. */ return "ENTRY_TRAMPOLINE"; } if (type >= STACK_TYPE_EXCEPTION && type <= STACK_TYPE_EXCEPTION_LAST) return exception_stack_names[type - STACK_TYPE_EXCEPTION]; return NULL; } struct estack_layout { unsigned int begin; unsigned int end; }; #define ESTACK_ENTRY(x) { \ .begin = offsetof(struct cea_exception_stacks, x## _stack), \ .end = offsetof(struct cea_exception_stacks, x## _stack_guard) \ } static const struct estack_layout layout[] = { [ ESTACK_DF ] = ESTACK_ENTRY(DF), [ ESTACK_NMI ] = ESTACK_ENTRY(NMI), [ ESTACK_DB2 ] = { .begin = 0, .end = 0}, [ ESTACK_DB1 ] = ESTACK_ENTRY(DB1), [ ESTACK_DB ] = ESTACK_ENTRY(DB), [ ESTACK_MCE ] = ESTACK_ENTRY(MCE), }; static bool in_exception_stack(unsigned long *stack, struct stack_info *info) { unsigned long estacks, begin, end, stk = (unsigned long)stack; struct pt_regs *regs; unsigned int k; BUILD_BUG_ON(N_EXCEPTION_STACKS != 6); estacks = (unsigned long)__this_cpu_read(cea_exception_stacks); for (k = 0; k < N_EXCEPTION_STACKS; k++) { begin = estacks + layout[k].begin; end = estacks + layout[k].end; regs = (struct pt_regs *)end - 1; if (stk < begin || stk >= end) continue; info->type = STACK_TYPE_EXCEPTION + k; info->begin = (unsigned long *)begin; info->end = (unsigned long *)end; info->next_sp = (unsigned long *)regs->sp; return true; } return false; } static bool in_irq_stack(unsigned long *stack, struct stack_info *info) { unsigned long *end = (unsigned long *)this_cpu_read(irq_stack_ptr); unsigned long *begin = end - (IRQ_STACK_SIZE / sizeof(long)); /* * This is a software stack, so 'end' can be a valid stack pointer. * It just means the stack is empty. */ if (stack < begin || stack >= end) return false; info->type = STACK_TYPE_IRQ; info->begin = begin; info->end = end; /* * The next stack pointer is the first thing pushed by the entry code * after switching to the irq stack. */ info->next_sp = (unsigned long *)*(end - 1); return true; } int get_stack_info(unsigned long *stack, struct task_struct *task, struct stack_info *info, unsigned long *visit_mask) { if (!stack) goto unknown; task = task ? : current; if (in_task_stack(stack, task, info)) goto recursion_check; if (task != current) goto unknown; if (in_exception_stack(stack, info)) goto recursion_check; if (in_irq_stack(stack, info)) goto recursion_check; if (in_entry_stack(stack, info)) goto recursion_check; goto unknown; recursion_check: /* * Make sure we don't iterate through any given stack more than once. * If it comes up a second time then there's something wrong going on: * just break out and report an unknown stack type. */ if (visit_mask) { if (*visit_mask & (1UL << info->type)) { printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type); goto unknown; } *visit_mask |= 1UL << info->type; } return 0; unknown: info->type = STACK_TYPE_UNKNOWN; return -EINVAL; }