Commit | Line | Data |
---|---|---|
5bdc9b44 HC |
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 | ||
4d284cac | 14 | static unsigned long save_context_stack(struct stack_trace *trace, |
4d284cac HC |
15 | unsigned long sp, |
16 | unsigned long low, | |
17 | unsigned long high) | |
5bdc9b44 HC |
18 | { |
19 | struct stack_frame *sf; | |
20 | struct pt_regs *regs; | |
21 | unsigned long addr; | |
22 | ||
23 | while(1) { | |
24 | sp &= PSW_ADDR_INSN; | |
25 | if (sp < low || sp > high) | |
26 | return sp; | |
27 | sf = (struct stack_frame *)sp; | |
28 | while(1) { | |
29 | addr = sf->gprs[8] & PSW_ADDR_INSN; | |
e90a2857 | 30 | if (!trace->skip) |
5bdc9b44 HC |
31 | trace->entries[trace->nr_entries++] = addr; |
32 | else | |
e90a2857 | 33 | trace->skip--; |
5bdc9b44 HC |
34 | if (trace->nr_entries >= trace->max_entries) |
35 | return sp; | |
36 | low = sp; | |
37 | sp = sf->back_chain & PSW_ADDR_INSN; | |
38 | if (!sp) | |
39 | break; | |
40 | if (sp <= low || sp > high - sizeof(*sf)) | |
41 | return sp; | |
42 | sf = (struct stack_frame *)sp; | |
43 | } | |
44 | /* Zero backchain detected, check for interrupt frame. */ | |
45 | sp = (unsigned long)(sf + 1); | |
46 | if (sp <= low || sp > high - sizeof(*regs)) | |
47 | return sp; | |
48 | regs = (struct pt_regs *)sp; | |
49 | addr = regs->psw.addr & PSW_ADDR_INSN; | |
e90a2857 | 50 | if (!trace->skip) |
5bdc9b44 HC |
51 | trace->entries[trace->nr_entries++] = addr; |
52 | else | |
e90a2857 | 53 | trace->skip--; |
5bdc9b44 HC |
54 | if (trace->nr_entries >= trace->max_entries) |
55 | return sp; | |
56 | low = sp; | |
57 | sp = regs->gprs[15]; | |
58 | } | |
59 | } | |
60 | ||
ab1b6f03 | 61 | void save_stack_trace(struct stack_trace *trace) |
5bdc9b44 HC |
62 | { |
63 | register unsigned long sp asm ("15"); | |
75e9de18 | 64 | unsigned long orig_sp, new_sp; |
5bdc9b44 | 65 | |
75e9de18 | 66 | orig_sp = sp & PSW_ADDR_INSN; |
e90a2857 HC |
67 | new_sp = save_context_stack(trace, orig_sp, |
68 | S390_lowcore.panic_stack - PAGE_SIZE, | |
69 | S390_lowcore.panic_stack); | |
ab1b6f03 | 70 | if (new_sp != orig_sp) |
5bdc9b44 | 71 | return; |
e90a2857 HC |
72 | new_sp = save_context_stack(trace, new_sp, |
73 | S390_lowcore.async_stack - ASYNC_SIZE, | |
74 | S390_lowcore.async_stack); | |
ab1b6f03 | 75 | if (new_sp != orig_sp) |
5bdc9b44 | 76 | return; |
e90a2857 | 77 | save_context_stack(trace, new_sp, |
ab1b6f03 CH |
78 | S390_lowcore.thread_info, |
79 | S390_lowcore.thread_info + THREAD_SIZE); | |
5bdc9b44 | 80 | } |