stacktrace.c 2.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * 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>

14 15 16 17 18
static unsigned long save_context_stack(struct stack_trace *trace,
					unsigned int *skip,
					unsigned long sp,
					unsigned long low,
					unsigned long high)
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
{
	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];
	}
}

62
void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
63 64
{
	register unsigned long sp asm ("15");
C
Christian Borntraeger 已提交
65
	unsigned long orig_sp, new_sp;
66

C
Christian Borntraeger 已提交
67
	orig_sp = sp & PSW_ADDR_INSN;
68

C
Christian Borntraeger 已提交
69
	new_sp = save_context_stack(trace, &trace->skip, orig_sp,
70 71
				S390_lowcore.panic_stack - PAGE_SIZE,
				S390_lowcore.panic_stack);
C
Christian Borntraeger 已提交
72
	if ((new_sp != orig_sp) && !trace->all_contexts)
73
		return;
C
Christian Borntraeger 已提交
74
	new_sp = save_context_stack(trace, &trace->skip, new_sp,
75 76
				S390_lowcore.async_stack - ASYNC_SIZE,
				S390_lowcore.async_stack);
C
Christian Borntraeger 已提交
77
	if ((new_sp != orig_sp) && !trace->all_contexts)
78 79
		return;
	if (task)
C
Christian Borntraeger 已提交
80
		save_context_stack(trace, &trace->skip, new_sp,
81 82 83
				   (unsigned long) task_stack_page(task),
				   (unsigned long) task_stack_page(task) + THREAD_SIZE);
	else
C
Christian Borntraeger 已提交
84
		save_context_stack(trace, &trace->skip, new_sp,
85
				   S390_lowcore.thread_info,
86 87 88
				   S390_lowcore.thread_info + THREAD_SIZE);
	return;
}