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) { | |
19 | sp = sp & PSW_ADDR_INSN; | |
20 | if (sp < low || sp > high - sizeof(*sf)) | |
21 | return sp; | |
22 | sf = (struct stack_frame *) sp; | |
23 | (*depth)--; | |
24 | oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN); | |
25 | ||
26 | /* Follow the backchain. */ | |
27 | while (*depth) { | |
28 | low = sp; | |
29 | sp = sf->back_chain & PSW_ADDR_INSN; | |
30 | if (!sp) | |
31 | break; | |
32 | if (sp <= low || sp > high - sizeof(*sf)) | |
33 | return sp; | |
34 | sf = (struct stack_frame *) sp; | |
35 | (*depth)--; | |
36 | oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN); | |
37 | ||
38 | } | |
39 | ||
40 | if (*depth == 0) | |
41 | break; | |
42 | ||
43 | /* Zero backchain detected, check for interrupt frame. */ | |
44 | sp = (unsigned long) (sf + 1); | |
45 | if (sp <= low || sp > high - sizeof(*regs)) | |
46 | return sp; | |
47 | regs = (struct pt_regs *) sp; | |
48 | (*depth)--; | |
49 | oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN); | |
50 | low = sp; | |
51 | sp = regs->gprs[15]; | |
52 | } | |
53 | return sp; | |
54 | } | |
55 | ||
56 | void s390_backtrace(struct pt_regs * const regs, unsigned int depth) | |
57 | { | |
58 | unsigned long head; | |
59 | struct stack_frame* head_sf; | |
60 | ||
7d256175 | 61 | if (user_mode(regs)) |
d0f4c16f AK |
62 | return; |
63 | ||
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, S390_lowcore.async_stack - ASYNC_SIZE, | |
73 | S390_lowcore.async_stack); | |
74 | ||
75 | __show_trace(&depth, head, S390_lowcore.thread_info, | |
76 | S390_lowcore.thread_info + THREAD_SIZE); | |
77 | } |