diff options
Diffstat (limited to 'arch/s390/kernel/ftrace.c')
-rw-r--r-- | arch/s390/kernel/ftrace.c | 61 |
1 files changed, 45 insertions, 16 deletions
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 82c19899574f..6c79f1b44fe7 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c | |||
@@ -57,6 +57,44 @@ | |||
57 | 57 | ||
58 | unsigned long ftrace_plt; | 58 | unsigned long ftrace_plt; |
59 | 59 | ||
60 | static inline void ftrace_generate_orig_insn(struct ftrace_insn *insn) | ||
61 | { | ||
62 | #ifdef CC_USING_HOTPATCH | ||
63 | /* brcl 0,0 */ | ||
64 | insn->opc = 0xc004; | ||
65 | insn->disp = 0; | ||
66 | #else | ||
67 | /* stg r14,8(r15) */ | ||
68 | insn->opc = 0xe3e0; | ||
69 | insn->disp = 0xf0080024; | ||
70 | #endif | ||
71 | } | ||
72 | |||
73 | static inline int is_kprobe_on_ftrace(struct ftrace_insn *insn) | ||
74 | { | ||
75 | #ifdef CONFIG_KPROBES | ||
76 | if (insn->opc == BREAKPOINT_INSTRUCTION) | ||
77 | return 1; | ||
78 | #endif | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static inline void ftrace_generate_kprobe_nop_insn(struct ftrace_insn *insn) | ||
83 | { | ||
84 | #ifdef CONFIG_KPROBES | ||
85 | insn->opc = BREAKPOINT_INSTRUCTION; | ||
86 | insn->disp = KPROBE_ON_FTRACE_NOP; | ||
87 | #endif | ||
88 | } | ||
89 | |||
90 | static inline void ftrace_generate_kprobe_call_insn(struct ftrace_insn *insn) | ||
91 | { | ||
92 | #ifdef CONFIG_KPROBES | ||
93 | insn->opc = BREAKPOINT_INSTRUCTION; | ||
94 | insn->disp = KPROBE_ON_FTRACE_CALL; | ||
95 | #endif | ||
96 | } | ||
97 | |||
60 | int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, | 98 | int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, |
61 | unsigned long addr) | 99 | unsigned long addr) |
62 | { | 100 | { |
@@ -72,16 +110,9 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, | |||
72 | return -EFAULT; | 110 | return -EFAULT; |
73 | if (addr == MCOUNT_ADDR) { | 111 | if (addr == MCOUNT_ADDR) { |
74 | /* Initial code replacement */ | 112 | /* Initial code replacement */ |
75 | #ifdef CC_USING_HOTPATCH | 113 | ftrace_generate_orig_insn(&orig); |
76 | /* We expect to see brcl 0,0 */ | ||
77 | ftrace_generate_nop_insn(&orig); | ||
78 | #else | ||
79 | /* We expect to see stg r14,8(r15) */ | ||
80 | orig.opc = 0xe3e0; | ||
81 | orig.disp = 0xf0080024; | ||
82 | #endif | ||
83 | ftrace_generate_nop_insn(&new); | 114 | ftrace_generate_nop_insn(&new); |
84 | } else if (old.opc == BREAKPOINT_INSTRUCTION) { | 115 | } else if (is_kprobe_on_ftrace(&old)) { |
85 | /* | 116 | /* |
86 | * If we find a breakpoint instruction, a kprobe has been | 117 | * If we find a breakpoint instruction, a kprobe has been |
87 | * placed at the beginning of the function. We write the | 118 | * placed at the beginning of the function. We write the |
@@ -89,9 +120,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, | |||
89 | * bytes of the original instruction so that the kprobes | 120 | * bytes of the original instruction so that the kprobes |
90 | * handler can execute a nop, if it reaches this breakpoint. | 121 | * handler can execute a nop, if it reaches this breakpoint. |
91 | */ | 122 | */ |
92 | new.opc = orig.opc = BREAKPOINT_INSTRUCTION; | 123 | ftrace_generate_kprobe_call_insn(&orig); |
93 | orig.disp = KPROBE_ON_FTRACE_CALL; | 124 | ftrace_generate_kprobe_nop_insn(&new); |
94 | new.disp = KPROBE_ON_FTRACE_NOP; | ||
95 | } else { | 125 | } else { |
96 | /* Replace ftrace call with a nop. */ | 126 | /* Replace ftrace call with a nop. */ |
97 | ftrace_generate_call_insn(&orig, rec->ip); | 127 | ftrace_generate_call_insn(&orig, rec->ip); |
@@ -111,7 +141,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
111 | 141 | ||
112 | if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) | 142 | if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) |
113 | return -EFAULT; | 143 | return -EFAULT; |
114 | if (old.opc == BREAKPOINT_INSTRUCTION) { | 144 | if (is_kprobe_on_ftrace(&old)) { |
115 | /* | 145 | /* |
116 | * If we find a breakpoint instruction, a kprobe has been | 146 | * If we find a breakpoint instruction, a kprobe has been |
117 | * placed at the beginning of the function. We write the | 147 | * placed at the beginning of the function. We write the |
@@ -119,9 +149,8 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
119 | * bytes of the original instruction so that the kprobes | 149 | * bytes of the original instruction so that the kprobes |
120 | * handler can execute a brasl if it reaches this breakpoint. | 150 | * handler can execute a brasl if it reaches this breakpoint. |
121 | */ | 151 | */ |
122 | new.opc = orig.opc = BREAKPOINT_INSTRUCTION; | 152 | ftrace_generate_kprobe_nop_insn(&orig); |
123 | orig.disp = KPROBE_ON_FTRACE_NOP; | 153 | ftrace_generate_kprobe_call_insn(&new); |
124 | new.disp = KPROBE_ON_FTRACE_CALL; | ||
125 | } else { | 154 | } else { |
126 | /* Replace nop with an ftrace call. */ | 155 | /* Replace nop with an ftrace call. */ |
127 | ftrace_generate_nop_insn(&orig); | 156 | ftrace_generate_nop_insn(&orig); |