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