diff options
author | Andreas Krebbel <krebbel1@de.ibm.com> | 2006-01-06 03:19:16 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:33:50 -0500 |
commit | d0f4c16febf258ba8c0f917ac3ba935fc5459566 (patch) | |
tree | 069f60a74c4bed5c4e599f9ffa337d96454b78f6 /arch/s390/oprofile/backtrace.c | |
parent | 1c01b8a5963aec60488c1c97d67cffd8b5275e3f (diff) |
[PATCH] s390: add oprofile callgraph support
Signed-off-by: Andreas Krebbel <krebbel1@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/s390/oprofile/backtrace.c')
-rw-r--r-- | arch/s390/oprofile/backtrace.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/arch/s390/oprofile/backtrace.c b/arch/s390/oprofile/backtrace.c new file mode 100644 index 000000000000..bc4b84a35cad --- /dev/null +++ b/arch/s390/oprofile/backtrace.c | |||
@@ -0,0 +1,79 @@ | |||
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 | } | ||