1a17ae4c3SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21bca09f7SHeiko Carstens /*
31bca09f7SHeiko Carstens * Stack dumping functions
41bca09f7SHeiko Carstens *
51bca09f7SHeiko Carstens * Copyright IBM Corp. 1999, 2013
61bca09f7SHeiko Carstens */
71bca09f7SHeiko Carstens
81bca09f7SHeiko Carstens #include <linux/kallsyms.h>
91bca09f7SHeiko Carstens #include <linux/hardirq.h>
101bca09f7SHeiko Carstens #include <linux/kprobes.h>
111bca09f7SHeiko Carstens #include <linux/utsname.h>
121bca09f7SHeiko Carstens #include <linux/export.h>
131bca09f7SHeiko Carstens #include <linux/kdebug.h>
141bca09f7SHeiko Carstens #include <linux/ptrace.h>
1510917b83SChristian Borntraeger #include <linux/mm.h>
161bca09f7SHeiko Carstens #include <linux/module.h>
171bca09f7SHeiko Carstens #include <linux/sched.h>
18b17b0153SIngo Molnar #include <linux/sched/debug.h>
1968db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
20*b9be1beeSHeiko Carstens #include <asm/asm-offsets.h>
211bca09f7SHeiko Carstens #include <asm/processor.h>
221bca09f7SHeiko Carstens #include <asm/debug.h>
230f20822aSHeiko Carstens #include <asm/dis.h>
241bca09f7SHeiko Carstens #include <asm/ipl.h>
2578c98f90SMartin Schwidefsky #include <asm/unwind.h>
261bca09f7SHeiko Carstens
stack_type_name(enum stack_type type)2778c98f90SMartin Schwidefsky const char *stack_type_name(enum stack_type type)
281bca09f7SHeiko Carstens {
2978c98f90SMartin Schwidefsky switch (type) {
3078c98f90SMartin Schwidefsky case STACK_TYPE_TASK:
3178c98f90SMartin Schwidefsky return "task";
3278c98f90SMartin Schwidefsky case STACK_TYPE_IRQ:
3378c98f90SMartin Schwidefsky return "irq";
3478c98f90SMartin Schwidefsky case STACK_TYPE_NODAT:
3578c98f90SMartin Schwidefsky return "nodat";
3678c98f90SMartin Schwidefsky case STACK_TYPE_RESTART:
3778c98f90SMartin Schwidefsky return "restart";
3878c98f90SMartin Schwidefsky default:
3978c98f90SMartin Schwidefsky return "unknown";
401bca09f7SHeiko Carstens }
411bca09f7SHeiko Carstens }
4206101546SVasily Gorbik EXPORT_SYMBOL_GPL(stack_type_name);
431bca09f7SHeiko Carstens
in_stack(unsigned long sp,struct stack_info * info,enum stack_type type,unsigned long stack)4478c98f90SMartin Schwidefsky static inline bool in_stack(unsigned long sp, struct stack_info *info,
45e6badee9SHeiko Carstens enum stack_type type, unsigned long stack)
461bca09f7SHeiko Carstens {
47e6badee9SHeiko Carstens if (sp < stack || sp >= stack + THREAD_SIZE)
4878c98f90SMartin Schwidefsky return false;
4978c98f90SMartin Schwidefsky info->type = type;
50e6badee9SHeiko Carstens info->begin = stack;
51e6badee9SHeiko Carstens info->end = stack + THREAD_SIZE;
5278c98f90SMartin Schwidefsky return true;
5378c98f90SMartin Schwidefsky }
5478c98f90SMartin Schwidefsky
in_task_stack(unsigned long sp,struct task_struct * task,struct stack_info * info)5578c98f90SMartin Schwidefsky static bool in_task_stack(unsigned long sp, struct task_struct *task,
5678c98f90SMartin Schwidefsky struct stack_info *info)
5778c98f90SMartin Schwidefsky {
58e6badee9SHeiko Carstens unsigned long stack = (unsigned long)task_stack_page(task);
5978c98f90SMartin Schwidefsky
60e6badee9SHeiko Carstens return in_stack(sp, info, STACK_TYPE_TASK, stack);
6178c98f90SMartin Schwidefsky }
6278c98f90SMartin Schwidefsky
in_irq_stack(unsigned long sp,struct stack_info * info)6378c98f90SMartin Schwidefsky static bool in_irq_stack(unsigned long sp, struct stack_info *info)
6478c98f90SMartin Schwidefsky {
65208da1d5SSven Schnelle unsigned long stack = get_lowcore()->async_stack - STACK_INIT_OFFSET;
661bca09f7SHeiko Carstens
67e6badee9SHeiko Carstens return in_stack(sp, info, STACK_TYPE_IRQ, stack);
68758d39ebSHeiko Carstens }
69758d39ebSHeiko Carstens
in_nodat_stack(unsigned long sp,struct stack_info * info)7078c98f90SMartin Schwidefsky static bool in_nodat_stack(unsigned long sp, struct stack_info *info)
71758d39ebSHeiko Carstens {
72208da1d5SSven Schnelle unsigned long stack = get_lowcore()->nodat_stack - STACK_INIT_OFFSET;
7378c98f90SMartin Schwidefsky
74e6badee9SHeiko Carstens return in_stack(sp, info, STACK_TYPE_NODAT, stack);
7578c98f90SMartin Schwidefsky }
7678c98f90SMartin Schwidefsky
in_mcck_stack(unsigned long sp,struct stack_info * info)7708edb968SVasily Gorbik static bool in_mcck_stack(unsigned long sp, struct stack_info *info)
7808edb968SVasily Gorbik {
79208da1d5SSven Schnelle unsigned long stack = get_lowcore()->mcck_stack - STACK_INIT_OFFSET;
8008edb968SVasily Gorbik
81e6badee9SHeiko Carstens return in_stack(sp, info, STACK_TYPE_MCCK, stack);
8208edb968SVasily Gorbik }
8308edb968SVasily Gorbik
in_restart_stack(unsigned long sp,struct stack_info * info)8478c98f90SMartin Schwidefsky static bool in_restart_stack(unsigned long sp, struct stack_info *info)
8578c98f90SMartin Schwidefsky {
86208da1d5SSven Schnelle unsigned long stack = get_lowcore()->restart_stack - STACK_INIT_OFFSET;
8778c98f90SMartin Schwidefsky
88e6badee9SHeiko Carstens return in_stack(sp, info, STACK_TYPE_RESTART, stack);
8978c98f90SMartin Schwidefsky }
9078c98f90SMartin Schwidefsky
get_stack_info(unsigned long sp,struct task_struct * task,struct stack_info * info,unsigned long * visit_mask)9178c98f90SMartin Schwidefsky int get_stack_info(unsigned long sp, struct task_struct *task,
9278c98f90SMartin Schwidefsky struct stack_info *info, unsigned long *visit_mask)
9378c98f90SMartin Schwidefsky {
9478c98f90SMartin Schwidefsky if (!sp)
9578c98f90SMartin Schwidefsky goto unknown;
9678c98f90SMartin Schwidefsky
97be2d11b2SMiroslav Benes /* Sanity check: ABI requires SP to be aligned 8 bytes. */
98be2d11b2SMiroslav Benes if (sp & 0x7)
99be2d11b2SMiroslav Benes goto unknown;
100be2d11b2SMiroslav Benes
10178c98f90SMartin Schwidefsky /* Check per-task stack */
10278c98f90SMartin Schwidefsky if (in_task_stack(sp, task, info))
10378c98f90SMartin Schwidefsky goto recursion_check;
10478c98f90SMartin Schwidefsky
10578c98f90SMartin Schwidefsky if (task != current)
10678c98f90SMartin Schwidefsky goto unknown;
10778c98f90SMartin Schwidefsky
10878c98f90SMartin Schwidefsky /* Check per-cpu stacks */
10978c98f90SMartin Schwidefsky if (!in_irq_stack(sp, info) &&
11078c98f90SMartin Schwidefsky !in_nodat_stack(sp, info) &&
11108edb968SVasily Gorbik !in_restart_stack(sp, info) &&
11208edb968SVasily Gorbik !in_mcck_stack(sp, info))
11378c98f90SMartin Schwidefsky goto unknown;
11478c98f90SMartin Schwidefsky
11578c98f90SMartin Schwidefsky recursion_check:
11678c98f90SMartin Schwidefsky /*
11778c98f90SMartin Schwidefsky * Make sure we don't iterate through any given stack more than once.
11878c98f90SMartin Schwidefsky * If it comes up a second time then there's something wrong going on:
11978c98f90SMartin Schwidefsky * just break out and report an unknown stack type.
12078c98f90SMartin Schwidefsky */
121fd0c7435SVasily Gorbik if (*visit_mask & (1UL << info->type))
12278c98f90SMartin Schwidefsky goto unknown;
12378c98f90SMartin Schwidefsky *visit_mask |= 1UL << info->type;
124758d39ebSHeiko Carstens return 0;
12578c98f90SMartin Schwidefsky unknown:
12678c98f90SMartin Schwidefsky info->type = STACK_TYPE_UNKNOWN;
12778c98f90SMartin Schwidefsky return -EINVAL;
128758d39ebSHeiko Carstens }
129758d39ebSHeiko Carstens
show_stack(struct task_struct * task,unsigned long * stack,const char * loglvl)1309cb8f069SDmitry Safonov void show_stack(struct task_struct *task, unsigned long *stack,
1318539c128SDmitry Safonov const char *loglvl)
132758d39ebSHeiko Carstens {
13378c98f90SMartin Schwidefsky struct unwind_state state;
1342b7b9817SHeiko Carstens
1358539c128SDmitry Safonov printk("%sCall Trace:\n", loglvl);
13678c98f90SMartin Schwidefsky unwind_for_each_frame(&state, task, NULL, (unsigned long) stack)
1378539c128SDmitry Safonov printk(state.reliable ? "%s [<%016lx>] %pSR \n" :
1388539c128SDmitry Safonov "%s([<%016lx>] %pSR)\n",
1398539c128SDmitry Safonov loglvl, state.ip, (void *) state.ip);
14078c98f90SMartin Schwidefsky debug_show_held_locks(task ? : current);
1411bca09f7SHeiko Carstens }
1421bca09f7SHeiko Carstens
show_last_breaking_event(struct pt_regs * regs)1431bca09f7SHeiko Carstens static void show_last_breaking_event(struct pt_regs *regs)
1441bca09f7SHeiko Carstens {
1451bca09f7SHeiko Carstens printk("Last Breaking-Event-Address:\n");
1467229ea86SIlya Leoshkevich printk(" [<%016lx>] ", regs->last_break);
1477229ea86SIlya Leoshkevich if (user_mode(regs)) {
1487229ea86SIlya Leoshkevich print_vma_addr(KERN_CONT, regs->last_break);
1497229ea86SIlya Leoshkevich pr_cont("\n");
1507229ea86SIlya Leoshkevich } else {
1517229ea86SIlya Leoshkevich pr_cont("%pSR\n", (void *)regs->last_break);
1527229ea86SIlya Leoshkevich }
1531bca09f7SHeiko Carstens }
1541bca09f7SHeiko Carstens
show_registers(struct pt_regs * regs)1551bca09f7SHeiko Carstens void show_registers(struct pt_regs *regs)
1561bca09f7SHeiko Carstens {
1571f021ea0SHeiko Carstens struct psw_bits *psw = &psw_bits(regs->psw);
1581bca09f7SHeiko Carstens char *mode;
1591bca09f7SHeiko Carstens
1601bca09f7SHeiko Carstens mode = user_mode(regs) ? "User" : "Krnl";
161e494990eSHeiko Carstens printk("%s PSW : %px %px", mode, (void *)regs->psw.mask, (void *)regs->psw.addr);
1629ea80662SHeiko Carstens if (!user_mode(regs))
163a7906345SHeiko Carstens pr_cont(" (%pSR)", (void *)regs->psw.addr);
164a7906345SHeiko Carstens pr_cont("\n");
1651bca09f7SHeiko Carstens printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
166a7525982SHeiko Carstens "P:%x AS:%x CC:%x PM:%x", psw->per, psw->dat, psw->io, psw->ext,
167a7525982SHeiko Carstens psw->key, psw->mcheck, psw->wait, psw->pstate, psw->as, psw->cc, psw->pm);
168a7906345SHeiko Carstens pr_cont(" RI:%x EA:%x\n", psw->ri, psw->eaba);
169a7906345SHeiko Carstens printk("%s GPRS: %016lx %016lx %016lx %016lx\n", mode,
1701bca09f7SHeiko Carstens regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
1715a79859aSHeiko Carstens printk(" %016lx %016lx %016lx %016lx\n",
1721bca09f7SHeiko Carstens regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
1735a79859aSHeiko Carstens printk(" %016lx %016lx %016lx %016lx\n",
1741bca09f7SHeiko Carstens regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
1755a79859aSHeiko Carstens printk(" %016lx %016lx %016lx %016lx\n",
1761bca09f7SHeiko Carstens regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
1771bca09f7SHeiko Carstens show_code(regs);
1781bca09f7SHeiko Carstens }
1791bca09f7SHeiko Carstens
show_regs(struct pt_regs * regs)1801bca09f7SHeiko Carstens void show_regs(struct pt_regs *regs)
1811bca09f7SHeiko Carstens {
182a43cb95dSTejun Heo show_regs_print_info(KERN_DEFAULT);
1831bca09f7SHeiko Carstens show_registers(regs);
1841bca09f7SHeiko Carstens /* Show stack backtrace if pt_regs is from kernel mode */
1851bca09f7SHeiko Carstens if (!user_mode(regs))
1869cb8f069SDmitry Safonov show_stack(NULL, (unsigned long *) regs->gprs[15], KERN_DEFAULT);
1871bca09f7SHeiko Carstens show_last_breaking_event(regs);
1881bca09f7SHeiko Carstens }
1891bca09f7SHeiko Carstens
1901bca09f7SHeiko Carstens static DEFINE_SPINLOCK(die_lock);
1911bca09f7SHeiko Carstens
die(struct pt_regs * regs,const char * str)1929fd5a04dSEric W. Biederman void __noreturn die(struct pt_regs *regs, const char *str)
1931bca09f7SHeiko Carstens {
1941bca09f7SHeiko Carstens static int die_counter;
1951bca09f7SHeiko Carstens
1961bca09f7SHeiko Carstens oops_enter();
1971bca09f7SHeiko Carstens lgr_info_log();
1981bca09f7SHeiko Carstens debug_stop_all();
1991bca09f7SHeiko Carstens console_verbose();
2001bca09f7SHeiko Carstens spin_lock_irq(&die_lock);
2011bca09f7SHeiko Carstens bust_spinlocks(1);
202413d4047SHeiko Carstens printk("%s: %04x ilc:%d [#%d]", str, regs->int_code & 0xffff,
203413d4047SHeiko Carstens regs->int_code >> 17, ++die_counter);
20447ece7feSHeiko Carstens pr_cont("SMP ");
20510917b83SChristian Borntraeger if (debug_pagealloc_enabled())
20647ece7feSHeiko Carstens pr_cont("DEBUG_PAGEALLOC");
20747ece7feSHeiko Carstens pr_cont("\n");
2081bca09f7SHeiko Carstens notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);
2091bca09f7SHeiko Carstens print_modules();
2101bca09f7SHeiko Carstens show_regs(regs);
2111bca09f7SHeiko Carstens bust_spinlocks(0);
2121bca09f7SHeiko Carstens add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
2131bca09f7SHeiko Carstens spin_unlock_irq(&die_lock);
2141bca09f7SHeiko Carstens if (in_interrupt())
2151bca09f7SHeiko Carstens panic("Fatal exception in interrupt");
2161bca09f7SHeiko Carstens if (panic_on_oops)
2171bca09f7SHeiko Carstens panic("Fatal exception: panic_on_oops");
2181bca09f7SHeiko Carstens oops_exit();
2190e25498fSEric W. Biederman make_task_dead(SIGSEGV);
2201bca09f7SHeiko Carstens }
221