Commit | Line | Data |
---|---|---|
d0f4c16f AK |
1 | /** |
2 | * arch/s390/oprofile/backtrace.c | |
3 | * | |
4 | * S390 Version | |
5 | * Copyright (C) 2005 IBM Corporation, IBM Deutschland Entwicklung GmbH. | |
6 | * Author(s): Andreas Krebbel <Andreas.Krebbel@de.ibm.com> | |
7 | */ | |
8 | ||
9 | #include <linux/oprofile.h> | |
10 | ||
11 | #include <asm/processor.h> /* for struct stack_frame */ | |
12 | ||
13 | static unsigned long | |
14 | __show_trace(unsigned int *depth, unsigned long sp, | |
15 | unsigned long low, unsigned long high) | |
16 | { | |
17 | struct stack_frame *sf; | |
18 | struct pt_regs *regs; | |
19 | ||
20 | while (*depth) { | |
21 | sp = sp & PSW_ADDR_INSN; | |
22 | if (sp < low || sp > high - sizeof(*sf)) | |
23 | return sp; | |
24 | sf = (struct stack_frame *) sp; | |
25 | (*depth)--; | |
26 | oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN); | |
27 | ||
28 | /* Follow the backchain. */ | |
29 | while (*depth) { | |
30 | low = sp; | |
31 | sp = sf->back_chain & PSW_ADDR_INSN; | |
32 | if (!sp) | |
33 | break; | |
34 | if (sp <= low || sp > high - sizeof(*sf)) | |
35 | return sp; | |
36 | sf = (struct stack_frame *) sp; | |
37 | (*depth)--; | |
38 | oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN); | |
39 | ||
40 | } | |
41 | ||
42 | if (*depth == 0) | |
43 | break; | |
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 | (*depth)--; | |
51 | oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN); | |
52 | low = sp; | |
53 | sp = regs->gprs[15]; | |
54 | } | |
55 | return sp; | |
56 | } | |
57 | ||
58 | void s390_backtrace(struct pt_regs * const regs, unsigned int depth) | |
59 | { | |
60 | unsigned long head; | |
61 | struct stack_frame* head_sf; | |
62 | ||
63 | if (user_mode (regs)) | |
64 | return; | |
65 | ||
66 | head = regs->gprs[15]; | |
67 | head_sf = (struct stack_frame*)head; | |
68 | ||
69 | if (!head_sf->back_chain) | |
70 | return; | |
71 | ||
72 | head = head_sf->back_chain; | |
73 | ||
74 | head = __show_trace(&depth, head, S390_lowcore.async_stack - ASYNC_SIZE, | |
75 | S390_lowcore.async_stack); | |
76 | ||
77 | __show_trace(&depth, head, S390_lowcore.thread_info, | |
78 | S390_lowcore.thread_info + THREAD_SIZE); | |
79 | } |