Merge remote-tracking branches 'regulator/topic/discharge', 'regulator/topic/fan53555...
[sfrench/cifs-2.6.git] / arch / s390 / oprofile / backtrace.c
1 /*
2  * S390 Version
3  *   Copyright IBM Corp. 2005
4  *   Author(s): Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
5  */
6
7 #include <linux/oprofile.h>
8
9 #include <asm/processor.h> /* for struct stack_frame */
10
11 static unsigned long
12 __show_trace(unsigned int *depth, unsigned long sp,
13              unsigned long low, unsigned long high)
14 {
15         struct stack_frame *sf;
16         struct pt_regs *regs;
17
18         while (*depth) {
19                 if (sp < low || sp > high - sizeof(*sf))
20                         return sp;
21                 sf = (struct stack_frame *) sp;
22                 (*depth)--;
23                 oprofile_add_trace(sf->gprs[8]);
24
25                 /* Follow the backchain.  */
26                 while (*depth) {
27                         low = sp;
28                         sp = sf->back_chain;
29                         if (!sp)
30                                 break;
31                         if (sp <= low || sp > high - sizeof(*sf))
32                                 return sp;
33                         sf = (struct stack_frame *) sp;
34                         (*depth)--;
35                         oprofile_add_trace(sf->gprs[8]);
36
37                 }
38
39                 if (*depth == 0)
40                         break;
41
42                 /* Zero backchain detected, check for interrupt frame.  */
43                 sp = (unsigned long) (sf + 1);
44                 if (sp <= low || sp > high - sizeof(*regs))
45                         return sp;
46                 regs = (struct pt_regs *) sp;
47                 (*depth)--;
48                 oprofile_add_trace(sf->gprs[8]);
49                 low = sp;
50                 sp = regs->gprs[15];
51         }
52         return sp;
53 }
54
55 void s390_backtrace(struct pt_regs * const regs, unsigned int depth)
56 {
57         unsigned long head, frame_size;
58         struct stack_frame* head_sf;
59
60         if (user_mode(regs))
61                 return;
62
63         frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
64         head = regs->gprs[15];
65         head_sf = (struct stack_frame*)head;
66
67         if (!head_sf->back_chain)
68                 return;
69
70         head = head_sf->back_chain;
71
72         head = __show_trace(&depth, head,
73                             S390_lowcore.async_stack + frame_size - ASYNC_SIZE,
74                             S390_lowcore.async_stack + frame_size);
75
76         __show_trace(&depth, head, S390_lowcore.thread_info,
77                      S390_lowcore.thread_info + THREAD_SIZE);
78 }