diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/oprofile/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/oprofile/backtrace.c | 79 | ||||
-rw-r--r-- | arch/s390/oprofile/init.c | 4 |
3 files changed, 84 insertions, 1 deletions
diff --git a/arch/s390/oprofile/Makefile b/arch/s390/oprofile/Makefile index ec349276258a..537b2d840e69 100644 --- a/arch/s390/oprofile/Makefile +++ b/arch/s390/oprofile/Makefile | |||
@@ -6,4 +6,4 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ | |||
6 | oprofilefs.o oprofile_stats.o \ | 6 | oprofilefs.o oprofile_stats.o \ |
7 | timer_int.o ) | 7 | timer_int.o ) |
8 | 8 | ||
9 | oprofile-y := $(DRIVER_OBJS) init.o | 9 | oprofile-y := $(DRIVER_OBJS) init.o backtrace.o |
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 | } | ||
diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index a65ead0e200a..7a995113b918 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c | |||
@@ -12,8 +12,12 @@ | |||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | 14 | ||
15 | |||
16 | extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth); | ||
17 | |||
15 | int __init oprofile_arch_init(struct oprofile_operations* ops) | 18 | int __init oprofile_arch_init(struct oprofile_operations* ops) |
16 | { | 19 | { |
20 | ops->backtrace = s390_backtrace; | ||
17 | return -ENODEV; | 21 | return -ENODEV; |
18 | } | 22 | } |
19 | 23 | ||