aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc64/kernel')
-rw-r--r--arch/ppc64/kernel/kprobes.c46
1 files changed, 38 insertions, 8 deletions
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c
index 8c0920a6d03e..782ce3efa2c1 100644
--- a/arch/ppc64/kernel/kprobes.c
+++ b/arch/ppc64/kernel/kprobes.c
@@ -36,12 +36,10 @@
36#include <asm/kdebug.h> 36#include <asm/kdebug.h>
37#include <asm/sstep.h> 37#include <asm/sstep.h>
38 38
39/* kprobe_status settings */
40#define KPROBE_HIT_ACTIVE 0x00000001
41#define KPROBE_HIT_SS 0x00000002
42
43static struct kprobe *current_kprobe; 39static struct kprobe *current_kprobe;
44static unsigned long kprobe_status, kprobe_saved_msr; 40static unsigned long kprobe_status, kprobe_saved_msr;
41static struct kprobe *kprobe_prev;
42static unsigned long kprobe_status_prev, kprobe_saved_msr_prev;
45static struct pt_regs jprobe_saved_regs; 43static struct pt_regs jprobe_saved_regs;
46 44
47int arch_prepare_kprobe(struct kprobe *p) 45int arch_prepare_kprobe(struct kprobe *p)
@@ -93,6 +91,20 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
93 regs->nip = (unsigned long)&p->ainsn.insn; 91 regs->nip = (unsigned long)&p->ainsn.insn;
94} 92}
95 93
94static inline void save_previous_kprobe(void)
95{
96 kprobe_prev = current_kprobe;
97 kprobe_status_prev = kprobe_status;
98 kprobe_saved_msr_prev = kprobe_saved_msr;
99}
100
101static inline void restore_previous_kprobe(void)
102{
103 current_kprobe = kprobe_prev;
104 kprobe_status = kprobe_status_prev;
105 kprobe_saved_msr = kprobe_saved_msr_prev;
106}
107
96static inline int kprobe_handler(struct pt_regs *regs) 108static inline int kprobe_handler(struct pt_regs *regs)
97{ 109{
98 struct kprobe *p; 110 struct kprobe *p;
@@ -111,9 +123,19 @@ static inline int kprobe_handler(struct pt_regs *regs)
111 unlock_kprobes(); 123 unlock_kprobes();
112 goto no_kprobe; 124 goto no_kprobe;
113 } 125 }
114 arch_disarm_kprobe(p); 126 /* We have reentered the kprobe_handler(), since
115 regs->nip = (unsigned long)p->addr; 127 * another probe was hit while within the handler.
116 ret = 1; 128 * We here save the original kprobes variables and
129 * just single step on the instruction of the new probe
130 * without calling any user handlers.
131 */
132 save_previous_kprobe();
133 current_kprobe = p;
134 kprobe_saved_msr = regs->msr;
135 p->nmissed++;
136 prepare_singlestep(p, regs);
137 kprobe_status = KPROBE_REENTER;
138 return 1;
117 } else { 139 } else {
118 p = current_kprobe; 140 p = current_kprobe;
119 if (p->break_handler && p->break_handler(p, regs)) { 141 if (p->break_handler && p->break_handler(p, regs)) {
@@ -195,13 +217,21 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
195 if (!kprobe_running()) 217 if (!kprobe_running())
196 return 0; 218 return 0;
197 219
198 if (current_kprobe->post_handler) 220 if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) {
221 kprobe_status = KPROBE_HIT_SSDONE;
199 current_kprobe->post_handler(current_kprobe, regs, 0); 222 current_kprobe->post_handler(current_kprobe, regs, 0);
223 }
200 224
201 resume_execution(current_kprobe, regs); 225 resume_execution(current_kprobe, regs);
202 regs->msr |= kprobe_saved_msr; 226 regs->msr |= kprobe_saved_msr;
203 227
228 /*Restore back the original saved kprobes variables and continue. */
229 if (kprobe_status == KPROBE_REENTER) {
230 restore_previous_kprobe();
231 goto out;
232 }
204 unlock_kprobes(); 233 unlock_kprobes();
234out:
205 preempt_enable_no_resched(); 235 preempt_enable_no_resched();
206 236
207 /* 237 /*