aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64/kernel/kprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc64/kernel/kprobes.c')
-rw-r--r--arch/ppc64/kernel/kprobes.c61
1 files changed, 51 insertions, 10 deletions
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c
index e950a2058a19..782ce3efa2c1 100644
--- a/arch/ppc64/kernel/kprobes.c
+++ b/arch/ppc64/kernel/kprobes.c
@@ -32,15 +32,14 @@
32#include <linux/ptrace.h> 32#include <linux/ptrace.h>
33#include <linux/spinlock.h> 33#include <linux/spinlock.h>
34#include <linux/preempt.h> 34#include <linux/preempt.h>
35#include <asm/cacheflush.h>
35#include <asm/kdebug.h> 36#include <asm/kdebug.h>
36#include <asm/sstep.h> 37#include <asm/sstep.h>
37 38
38/* kprobe_status settings */
39#define KPROBE_HIT_ACTIVE 0x00000001
40#define KPROBE_HIT_SS 0x00000002
41
42static struct kprobe *current_kprobe; 39static struct kprobe *current_kprobe;
43static 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;
44static struct pt_regs jprobe_saved_regs; 43static struct pt_regs jprobe_saved_regs;
45 44
46int arch_prepare_kprobe(struct kprobe *p) 45int arch_prepare_kprobe(struct kprobe *p)
@@ -61,16 +60,25 @@ int arch_prepare_kprobe(struct kprobe *p)
61void arch_copy_kprobe(struct kprobe *p) 60void arch_copy_kprobe(struct kprobe *p)
62{ 61{
63 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); 62 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
63 p->opcode = *p->addr;
64} 64}
65 65
66void arch_remove_kprobe(struct kprobe *p) 66void arch_arm_kprobe(struct kprobe *p)
67{ 67{
68 *p->addr = BREAKPOINT_INSTRUCTION;
69 flush_icache_range((unsigned long) p->addr,
70 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
68} 71}
69 72
70static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) 73void arch_disarm_kprobe(struct kprobe *p)
71{ 74{
72 *p->addr = p->opcode; 75 *p->addr = p->opcode;
73 regs->nip = (unsigned long)p->addr; 76 flush_icache_range((unsigned long) p->addr,
77 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
78}
79
80void arch_remove_kprobe(struct kprobe *p)
81{
74} 82}
75 83
76static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 84static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
@@ -83,6 +91,20 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
83 regs->nip = (unsigned long)&p->ainsn.insn; 91 regs->nip = (unsigned long)&p->ainsn.insn;
84} 92}
85 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
86static inline int kprobe_handler(struct pt_regs *regs) 108static inline int kprobe_handler(struct pt_regs *regs)
87{ 109{
88 struct kprobe *p; 110 struct kprobe *p;
@@ -101,8 +123,19 @@ static inline int kprobe_handler(struct pt_regs *regs)
101 unlock_kprobes(); 123 unlock_kprobes();
102 goto no_kprobe; 124 goto no_kprobe;
103 } 125 }
104 disarm_kprobe(p, regs); 126 /* We have reentered the kprobe_handler(), since
105 ret = 1; 127 * another probe was hit while within the handler.
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;
106 } else { 139 } else {
107 p = current_kprobe; 140 p = current_kprobe;
108 if (p->break_handler && p->break_handler(p, regs)) { 141 if (p->break_handler && p->break_handler(p, regs)) {
@@ -184,13 +217,21 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
184 if (!kprobe_running()) 217 if (!kprobe_running())
185 return 0; 218 return 0;
186 219
187 if (current_kprobe->post_handler) 220 if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) {
221 kprobe_status = KPROBE_HIT_SSDONE;
188 current_kprobe->post_handler(current_kprobe, regs, 0); 222 current_kprobe->post_handler(current_kprobe, regs, 0);
223 }
189 224
190 resume_execution(current_kprobe, regs); 225 resume_execution(current_kprobe, regs);
191 regs->msr |= kprobe_saved_msr; 226 regs->msr |= kprobe_saved_msr;
192 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 }
193 unlock_kprobes(); 233 unlock_kprobes();
234out:
194 preempt_enable_no_resched(); 235 preempt_enable_no_resched();
195 236
196 /* 237 /*