aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/kprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/kprobes.c')
-rw-r--r--arch/sparc64/kernel/kprobes.c62
1 files changed, 49 insertions, 13 deletions
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index d67195ba3fa..bdac631cf01 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -65,19 +65,40 @@ void arch_remove_kprobe(struct kprobe *p)
65{ 65{
66} 66}
67 67
68/* kprobe_status settings */
69#define KPROBE_HIT_ACTIVE 0x00000001
70#define KPROBE_HIT_SS 0x00000002
71
72static struct kprobe *current_kprobe; 68static struct kprobe *current_kprobe;
73static unsigned long current_kprobe_orig_tnpc; 69static unsigned long current_kprobe_orig_tnpc;
74static unsigned long current_kprobe_orig_tstate_pil; 70static unsigned long current_kprobe_orig_tstate_pil;
75static unsigned int kprobe_status; 71static unsigned int kprobe_status;
72static struct kprobe *kprobe_prev;
73static unsigned long kprobe_orig_tnpc_prev;
74static unsigned long kprobe_orig_tstate_pil_prev;
75static unsigned int kprobe_status_prev;
76 76
77static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 77static inline void save_previous_kprobe(void)
78{
79 kprobe_status_prev = kprobe_status;
80 kprobe_orig_tnpc_prev = current_kprobe_orig_tnpc;
81 kprobe_orig_tstate_pil_prev = current_kprobe_orig_tstate_pil;
82 kprobe_prev = current_kprobe;
83}
84
85static inline void restore_previous_kprobe(void)
86{
87 kprobe_status = kprobe_status_prev;
88 current_kprobe_orig_tnpc = kprobe_orig_tnpc_prev;
89 current_kprobe_orig_tstate_pil = kprobe_orig_tstate_pil_prev;
90 current_kprobe = kprobe_prev;
91}
92
93static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs)
78{ 94{
79 current_kprobe_orig_tnpc = regs->tnpc; 95 current_kprobe_orig_tnpc = regs->tnpc;
80 current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL); 96 current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL);
97 current_kprobe = p;
98}
99
100static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
101{
81 regs->tstate |= TSTATE_PIL; 102 regs->tstate |= TSTATE_PIL;
82 103
83 /*single step inline, if it a breakpoint instruction*/ 104 /*single step inline, if it a breakpoint instruction*/
@@ -110,12 +131,18 @@ static int kprobe_handler(struct pt_regs *regs)
110 unlock_kprobes(); 131 unlock_kprobes();
111 goto no_kprobe; 132 goto no_kprobe;
112 } 133 }
113 arch_disarm_kprobe(p); 134 /* We have reentered the kprobe_handler(), since
114 regs->tpc = (unsigned long) p->addr; 135 * another probe was hit while within the handler.
115 regs->tnpc = current_kprobe_orig_tnpc; 136 * We here save the original kprobes variables and
116 regs->tstate = ((regs->tstate & ~TSTATE_PIL) | 137 * just single step on the instruction of the new probe
117 current_kprobe_orig_tstate_pil); 138 * without calling any user handlers.
118 ret = 1; 139 */
140 save_previous_kprobe();
141 set_current_kprobe(p, regs);
142 p->nmissed++;
143 kprobe_status = KPROBE_REENTER;
144 prepare_singlestep(p, regs);
145 return 1;
119 } else { 146 } else {
120 p = current_kprobe; 147 p = current_kprobe;
121 if (p->break_handler && p->break_handler(p, regs)) 148 if (p->break_handler && p->break_handler(p, regs))
@@ -143,8 +170,8 @@ static int kprobe_handler(struct pt_regs *regs)
143 goto no_kprobe; 170 goto no_kprobe;
144 } 171 }
145 172
173 set_current_kprobe(p, regs);
146 kprobe_status = KPROBE_HIT_ACTIVE; 174 kprobe_status = KPROBE_HIT_ACTIVE;
147 current_kprobe = p;
148 if (p->pre_handler && p->pre_handler(p, regs)) 175 if (p->pre_handler && p->pre_handler(p, regs))
149 return 1; 176 return 1;
150 177
@@ -250,12 +277,20 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
250 if (!kprobe_running()) 277 if (!kprobe_running())
251 return 0; 278 return 0;
252 279
253 if (current_kprobe->post_handler) 280 if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) {
281 kprobe_status = KPROBE_HIT_SSDONE;
254 current_kprobe->post_handler(current_kprobe, regs, 0); 282 current_kprobe->post_handler(current_kprobe, regs, 0);
283 }
255 284
256 resume_execution(current_kprobe, regs); 285 resume_execution(current_kprobe, regs);
257 286
287 /*Restore back the original saved kprobes variables and continue. */
288 if (kprobe_status == KPROBE_REENTER) {
289 restore_previous_kprobe();
290 goto out;
291 }
258 unlock_kprobes(); 292 unlock_kprobes();
293out:
259 preempt_enable_no_resched(); 294 preempt_enable_no_resched();
260 295
261 return 1; 296 return 1;
@@ -397,3 +432,4 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
397 } 432 }
398 return 0; 433 return 0;
399} 434}
435