Commit | Line | Data |
---|---|---|
a53c8fab | 1 | /* |
d0f4c16f | 2 | * S390 Version |
a53c8fab | 3 | * Copyright IBM Corp. 2005 |
d0f4c16f AK |
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) { | |
d0f4c16f AK |
19 | if (sp < low || sp > high - sizeof(*sf)) |
20 | return sp; | |
21 | sf = (struct stack_frame *) sp; | |
22 | (*depth)--; | |
9cb1ccec | 23 | oprofile_add_trace(sf->gprs[8]); |
d0f4c16f AK |
24 | |
25 | /* Follow the backchain. */ | |
26 | while (*depth) { | |
27 | low = sp; | |
9cb1ccec | 28 | sp = sf->back_chain; |
d0f4c16f AK |
29 | if (!sp) |
30 | break; | |
31 | if (sp <= low || sp > high - sizeof(*sf)) | |
32 | return sp; | |
33 | sf = (struct stack_frame *) sp; | |
34 | (*depth)--; | |
9cb1ccec | 35 | oprofile_add_trace(sf->gprs[8]); |
d0f4c16f AK |
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)--; | |
9cb1ccec | 48 | oprofile_add_trace(sf->gprs[8]); |
d0f4c16f AK |
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 | { | |
232f5dd7 | 57 | unsigned long head, frame_size; |
d0f4c16f AK |
58 | struct stack_frame* head_sf; |
59 | ||
7d256175 | 60 | if (user_mode(regs)) |
d0f4c16f AK |
61 | return; |
62 | ||
232f5dd7 | 63 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); |
d0f4c16f AK |
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 | ||
232f5dd7 HC |
72 | head = __show_trace(&depth, head, |
73 | S390_lowcore.async_stack + frame_size - ASYNC_SIZE, | |
74 | S390_lowcore.async_stack + frame_size); | |
d0f4c16f AK |
75 | |
76 | __show_trace(&depth, head, S390_lowcore.thread_info, | |
77 | S390_lowcore.thread_info + THREAD_SIZE); | |
78 | } |