File Index
Files and directories
Sign in
FILE

dumpstack.c

File preview with syntax highlighting.

linux-6.19.14/arch/s390/kernel/dumpstack.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Stack dumping functions
  4 *
  5 *  Copyright IBM Corp. 1999, 2013
  6 */
  7
  8#include <linux/kallsyms.h>
  9#include <linux/hardirq.h>
 10#include <linux/kprobes.h>
 11#include <linux/utsname.h>
 12#include <linux/export.h>
 13#include <linux/kdebug.h>
 14#include <linux/ptrace.h>
 15#include <linux/mm.h>
 16#include <linux/module.h>
 17#include <linux/sched.h>
 18#include <linux/sched/debug.h>
 19#include <linux/sched/task_stack.h>
 20#include <asm/asm-offsets.h>
 21#include <asm/processor.h>
 22#include <asm/debug.h>
 23#include <asm/dis.h>
 24#include <asm/ipl.h>
 25#include <asm/unwind.h>
 26
 27const char *stack_type_name(enum stack_type type)
 28{
 29	switch (type) {
 30	case STACK_TYPE_TASK:
 31		return "task";
 32	case STACK_TYPE_IRQ:
 33		return "irq";
 34	case STACK_TYPE_NODAT:
 35		return "nodat";
 36	case STACK_TYPE_RESTART:
 37		return "restart";
 38	default:
 39		return "unknown";
 40	}
 41}
 42EXPORT_SYMBOL_GPL(stack_type_name);
 43
 44static inline bool in_stack(unsigned long sp, struct stack_info *info,
 45			    enum stack_type type, unsigned long stack)
 46{
 47	if (sp < stack || sp >= stack + THREAD_SIZE)
 48		return false;
 49	info->type = type;
 50	info->begin = stack;
 51	info->end = stack + THREAD_SIZE;
 52	return true;
 53}
 54
 55static bool in_task_stack(unsigned long sp, struct task_struct *task,
 56			  struct stack_info *info)
 57{
 58	unsigned long stack = (unsigned long)task_stack_page(task);
 59
 60	return in_stack(sp, info, STACK_TYPE_TASK, stack);
 61}
 62
 63static bool in_irq_stack(unsigned long sp, struct stack_info *info)
 64{
 65	unsigned long stack = get_lowcore()->async_stack - STACK_INIT_OFFSET;
 66
 67	return in_stack(sp, info, STACK_TYPE_IRQ, stack);
 68}
 69
 70static bool in_nodat_stack(unsigned long sp, struct stack_info *info)
 71{
 72	unsigned long stack = get_lowcore()->nodat_stack - STACK_INIT_OFFSET;
 73
 74	return in_stack(sp, info, STACK_TYPE_NODAT, stack);
 75}
 76
 77static bool in_mcck_stack(unsigned long sp, struct stack_info *info)
 78{
 79	unsigned long stack = get_lowcore()->mcck_stack - STACK_INIT_OFFSET;
 80
 81	return in_stack(sp, info, STACK_TYPE_MCCK, stack);
 82}
 83
 84static bool in_restart_stack(unsigned long sp, struct stack_info *info)
 85{
 86	unsigned long stack = get_lowcore()->restart_stack - STACK_INIT_OFFSET;
 87
 88	return in_stack(sp, info, STACK_TYPE_RESTART, stack);
 89}
 90
 91int get_stack_info(unsigned long sp, struct task_struct *task,
 92		   struct stack_info *info, unsigned long *visit_mask)
 93{
 94	if (!sp)
 95		goto unknown;
 96
 97	/* Sanity check: ABI requires SP to be aligned 8 bytes. */
 98	if (sp & 0x7)
 99		goto unknown;
100
101	/* Check per-task stack */
102	if (in_task_stack(sp, task, info))
103		goto recursion_check;
104
105	if (task != current)
106		goto unknown;
107
108	/* Check per-cpu stacks */
109	if (!in_irq_stack(sp, info) &&
110	    !in_nodat_stack(sp, info) &&
111	    !in_restart_stack(sp, info) &&
112	    !in_mcck_stack(sp, info))
113		goto unknown;
114
115recursion_check:
116	/*
117	 * Make sure we don't iterate through any given stack more than once.
118	 * If it comes up a second time then there's something wrong going on:
119	 * just break out and report an unknown stack type.
120	 */
121	if (*visit_mask & (1UL << info->type))
122		goto unknown;
123	*visit_mask |= 1UL << info->type;
124	return 0;
125unknown:
126	info->type = STACK_TYPE_UNKNOWN;
127	return -EINVAL;
128}
129
130void show_stack(struct task_struct *task, unsigned long *stack,
131		       const char *loglvl)
132{
133	struct unwind_state state;
134
135	printk("%sCall Trace:\n", loglvl);
136	unwind_for_each_frame(&state, task, NULL, (unsigned long) stack)
137		printk(state.reliable ? "%s [<%016lx>] %pSR \n" :
138					"%s([<%016lx>] %pSR)\n",
139		       loglvl, state.ip, (void *) state.ip);
140	debug_show_held_locks(task ? : current);
141}
142
143static void show_last_breaking_event(struct pt_regs *regs)
144{
145	printk("Last Breaking-Event-Address:\n");
146	printk(" [<%016lx>] ", regs->last_break);
147	if (user_mode(regs)) {
148		print_vma_addr(KERN_CONT, regs->last_break);
149		pr_cont("\n");
150	} else {
151		pr_cont("%pSR\n", (void *)regs->last_break);
152	}
153}
154
155void show_registers(struct pt_regs *regs)
156{
157	struct psw_bits *psw = &psw_bits(regs->psw);
158	unsigned long pswaddr;
159	char *mode;
160
161	pswaddr = regs->psw.addr;
162	if (test_pt_regs_flag(regs, PIF_PSW_ADDR_ADJUSTED))
163		pswaddr = __forward_psw(regs->psw, regs->int_code >> 16);
164	mode = user_mode(regs) ? "User" : "Krnl";
165	printk("%s PSW : %px %px", mode, (void *)regs->psw.mask, (void *)pswaddr);
166	if (!user_mode(regs))
167		pr_cont(" (%pSR)", (void *)pswaddr);
168	pr_cont("\n");
169	printk("           R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
170	       "P:%x AS:%x CC:%x PM:%x", psw->per, psw->dat, psw->io, psw->ext,
171	       psw->key, psw->mcheck, psw->wait, psw->pstate, psw->as, psw->cc, psw->pm);
172	pr_cont(" RI:%x EA:%x\n", psw->ri, psw->eaba);
173	printk("%s GPRS: %016lx %016lx %016lx %016lx\n", mode,
174	       regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
175	printk("           %016lx %016lx %016lx %016lx\n",
176	       regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
177	printk("           %016lx %016lx %016lx %016lx\n",
178	       regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
179	printk("           %016lx %016lx %016lx %016lx\n",
180	       regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
181	show_code(regs);
182}
183
184void show_regs(struct pt_regs *regs)
185{
186	show_regs_print_info(KERN_DEFAULT);
187	show_registers(regs);
188	/* Show stack backtrace if pt_regs is from kernel mode */
189	if (!user_mode(regs))
190		show_stack(NULL, (unsigned long *) regs->gprs[15], KERN_DEFAULT);
191	show_last_breaking_event(regs);
192}
193
194static DEFINE_SPINLOCK(die_lock);
195
196void __noreturn die(struct pt_regs *regs, const char *str)
197{
198	static int die_counter;
199
200	oops_enter();
201	lgr_info_log();
202	debug_stop_all();
203	console_verbose();
204	spin_lock_irq(&die_lock);
205	bust_spinlocks(1);
206	printk("%s: %04x ilc:%d [#%d]", str, regs->int_code & 0xffff,
207	       regs->int_code >> 17, ++die_counter);
208	pr_cont("SMP ");
209	if (debug_pagealloc_enabled())
210		pr_cont("DEBUG_PAGEALLOC");
211	pr_cont("\n");
212	notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);
213	print_modules();
214	show_regs(regs);
215	bust_spinlocks(0);
216	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
217	spin_unlock_irq(&die_lock);
218	if (in_interrupt())
219		panic("Fatal exception in interrupt");
220	if (panic_on_oops)
221		panic("Fatal exception: panic_on_oops");
222	oops_exit();
223	make_task_dead(SIGSEGV);
224}
~/ Read-only file preview.