88 lines · 2.2 KB · C
RawDownload
/* * arch/s390/kernel/stacktrace.c * * Stack trace management functions * *  Copyright (C) IBM Corp. 2006 *  Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> */ #include <linux/sched.h>#include <linux/stacktrace.h>#include <linux/kallsyms.h> static unsigned long save_context_stack(struct stack_trace *trace,					unsigned int *skip,					unsigned long sp,					unsigned long low,					unsigned long high){	struct stack_frame *sf;	struct pt_regs *regs;	unsigned long addr; 	while(1) {		sp &= PSW_ADDR_INSN;		if (sp < low || sp > high)			return sp;		sf = (struct stack_frame *)sp;		while(1) {			addr = sf->gprs[8] & PSW_ADDR_INSN;			if (!(*skip))				trace->entries[trace->nr_entries++] = addr;			else				(*skip)--;			if (trace->nr_entries >= trace->max_entries)				return sp;			low = sp;			sp = sf->back_chain & PSW_ADDR_INSN;			if (!sp)				break;			if (sp <= low || sp > high - sizeof(*sf))				return sp;			sf = (struct stack_frame *)sp;		}		/* Zero backchain detected, check for interrupt frame. */		sp = (unsigned long)(sf + 1);		if (sp <= low || sp > high - sizeof(*regs))			return sp;		regs = (struct pt_regs *)sp;		addr = regs->psw.addr & PSW_ADDR_INSN;		if (!(*skip))			trace->entries[trace->nr_entries++] = addr;		else			(*skip)--;		if (trace->nr_entries >= trace->max_entries)			return sp;		low = sp;		sp = regs->gprs[15];	}} void save_stack_trace(struct stack_trace *trace, struct task_struct *task){	register unsigned long sp asm ("15");	unsigned long orig_sp, new_sp; 	orig_sp = sp & PSW_ADDR_INSN; 	new_sp = save_context_stack(trace, &trace->skip, orig_sp,				S390_lowcore.panic_stack - PAGE_SIZE,				S390_lowcore.panic_stack);	if ((new_sp != orig_sp) && !trace->all_contexts)		return;	new_sp = save_context_stack(trace, &trace->skip, new_sp,				S390_lowcore.async_stack - ASYNC_SIZE,				S390_lowcore.async_stack);	if ((new_sp != orig_sp) && !trace->all_contexts)		return;	if (task)		save_context_stack(trace, &trace->skip, new_sp,				   (unsigned long) task_stack_page(task),				   (unsigned long) task_stack_page(task) + THREAD_SIZE);	else		save_context_stack(trace, &trace->skip, new_sp,				   S390_lowcore.thread_info,				   S390_lowcore.thread_info + THREAD_SIZE);	return;}