~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/s390/kernel/stacktrace.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * arch/s390/kernel/stacktrace.c
 
3
 *
 
4
 * Stack trace management functions
 
5
 *
 
6
 *  Copyright (C) IBM Corp. 2006
 
7
 *  Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
 
8
 */
 
9
 
 
10
#include <linux/sched.h>
 
11
#include <linux/stacktrace.h>
 
12
#include <linux/kallsyms.h>
 
13
#include <linux/module.h>
 
14
 
 
15
static unsigned long save_context_stack(struct stack_trace *trace,
 
16
                                        unsigned long sp,
 
17
                                        unsigned long low,
 
18
                                        unsigned long high,
 
19
                                        int savesched)
 
20
{
 
21
        struct stack_frame *sf;
 
22
        struct pt_regs *regs;
 
23
        unsigned long addr;
 
24
 
 
25
        while(1) {
 
26
                sp &= PSW_ADDR_INSN;
 
27
                if (sp < low || sp > high)
 
28
                        return sp;
 
29
                sf = (struct stack_frame *)sp;
 
30
                while(1) {
 
31
                        addr = sf->gprs[8] & PSW_ADDR_INSN;
 
32
                        if (!trace->skip)
 
33
                                trace->entries[trace->nr_entries++] = addr;
 
34
                        else
 
35
                                trace->skip--;
 
36
                        if (trace->nr_entries >= trace->max_entries)
 
37
                                return sp;
 
38
                        low = sp;
 
39
                        sp = sf->back_chain & PSW_ADDR_INSN;
 
40
                        if (!sp)
 
41
                                break;
 
42
                        if (sp <= low || sp > high - sizeof(*sf))
 
43
                                return sp;
 
44
                        sf = (struct stack_frame *)sp;
 
45
                }
 
46
                /* Zero backchain detected, check for interrupt frame. */
 
47
                sp = (unsigned long)(sf + 1);
 
48
                if (sp <= low || sp > high - sizeof(*regs))
 
49
                        return sp;
 
50
                regs = (struct pt_regs *)sp;
 
51
                addr = regs->psw.addr & PSW_ADDR_INSN;
 
52
                if (savesched || !in_sched_functions(addr)) {
 
53
                        if (!trace->skip)
 
54
                                trace->entries[trace->nr_entries++] = addr;
 
55
                        else
 
56
                                trace->skip--;
 
57
                }
 
58
                if (trace->nr_entries >= trace->max_entries)
 
59
                        return sp;
 
60
                low = sp;
 
61
                sp = regs->gprs[15];
 
62
        }
 
63
}
 
64
 
 
65
void save_stack_trace(struct stack_trace *trace)
 
66
{
 
67
        register unsigned long sp asm ("15");
 
68
        unsigned long orig_sp, new_sp;
 
69
 
 
70
        orig_sp = sp & PSW_ADDR_INSN;
 
71
        new_sp = save_context_stack(trace, orig_sp,
 
72
                                    S390_lowcore.panic_stack - PAGE_SIZE,
 
73
                                    S390_lowcore.panic_stack, 1);
 
74
        if (new_sp != orig_sp)
 
75
                return;
 
76
        new_sp = save_context_stack(trace, new_sp,
 
77
                                    S390_lowcore.async_stack - ASYNC_SIZE,
 
78
                                    S390_lowcore.async_stack, 1);
 
79
        if (new_sp != orig_sp)
 
80
                return;
 
81
        save_context_stack(trace, new_sp,
 
82
                           S390_lowcore.thread_info,
 
83
                           S390_lowcore.thread_info + THREAD_SIZE, 1);
 
84
}
 
85
EXPORT_SYMBOL_GPL(save_stack_trace);
 
86
 
 
87
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
 
88
{
 
89
        unsigned long sp, low, high;
 
90
 
 
91
        sp = tsk->thread.ksp & PSW_ADDR_INSN;
 
92
        low = (unsigned long) task_stack_page(tsk);
 
93
        high = (unsigned long) task_pt_regs(tsk);
 
94
        save_context_stack(trace, sp, low, high, 0);
 
95
        if (trace->nr_entries < trace->max_entries)
 
96
                trace->entries[trace->nr_entries++] = ULONG_MAX;
 
97
}
 
98
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);