aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2011-01-05 06:47:20 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2011-01-05 06:47:24 -0500
commitb9599798f953084774da926caa8bafd7e244948e (patch)
tree90d1df0f902e9947319c83641109a6a2560b671c
parentba640a591574036ab22cd32b47897340b0605342 (diff)
[S390] kprobes: activation and deactivation
Replace set_current_kprobe/reset_current_kprobe/save_previous_kprobe/ restore_previous_kprobe with a simpler scheme push_kprobe/pop_kprobe. The mini kprobes stack can store up to two active kprobes. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/kernel/kprobes.c59
1 files changed, 27 insertions, 32 deletions
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index fcbc25836879..f68eaaaa8062 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -214,25 +214,29 @@ static void __kprobes disable_singlestep(struct kprobe_ctlblk *kcb,
214 regs->psw.addr = ip | PSW_ADDR_AMODE; 214 regs->psw.addr = ip | PSW_ADDR_AMODE;
215} 215}
216 216
217 217/*
218static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) 218 * Activate a kprobe by storing its pointer to current_kprobe. The
219 * previous kprobe is stored in kcb->prev_kprobe. A stack of up to
220 * two kprobes can be active, see KPROBE_REENTER.
221 */
222static void __kprobes push_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p)
219{ 223{
220 kcb->prev_kprobe.kp = kprobe_running(); 224 kcb->prev_kprobe.kp = __get_cpu_var(current_kprobe);
221 kcb->prev_kprobe.status = kcb->kprobe_status; 225 kcb->prev_kprobe.status = kcb->kprobe_status;
226 __get_cpu_var(current_kprobe) = p;
222} 227}
223 228
224static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) 229/*
230 * Deactivate a kprobe by backing up to the previous state. If the
231 * current state is KPROBE_REENTER prev_kprobe.kp will be non-NULL,
232 * for any other state prev_kprobe.kp will be NULL.
233 */
234static void __kprobes pop_kprobe(struct kprobe_ctlblk *kcb)
225{ 235{
226 __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; 236 __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
227 kcb->kprobe_status = kcb->prev_kprobe.status; 237 kcb->kprobe_status = kcb->prev_kprobe.status;
228} 238}
229 239
230static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
231 struct kprobe_ctlblk *kcb)
232{
233 __get_cpu_var(current_kprobe) = p;
234}
235
236void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, 240void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
237 struct pt_regs *regs) 241 struct pt_regs *regs)
238{ 242{
@@ -261,14 +265,16 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
261 if (kprobe_running()) { 265 if (kprobe_running()) {
262 p = get_kprobe(addr); 266 p = get_kprobe(addr);
263 if (p) { 267 if (p) {
264 /* We have reentered the kprobe_handler(), since 268 /*
265 * another probe was hit while within the handler. 269 * We have hit a kprobe while another is still
266 * We here save the original kprobes variables and 270 * active. This can happen in the pre and post
267 * just single step on the instruction of the new probe 271 * handler. Single step the instruction of the
268 * without calling any user handlers. 272 * new probe but do not call any handler function
273 * of this secondary kprobe.
274 * push_kprobe and pop_kprobe saves and restores
275 * the currently active kprobe.
269 */ 276 */
270 save_previous_kprobe(kcb); 277 push_kprobe(kcb, p);
271 set_current_kprobe(p, regs, kcb);
272 kprobes_inc_nmissed_count(p); 278 kprobes_inc_nmissed_count(p);
273 enable_singlestep(kcb, regs, 279 enable_singlestep(kcb, regs,
274 (unsigned long) p->ainsn.insn); 280 (unsigned long) p->ainsn.insn);
@@ -294,7 +300,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
294 goto no_kprobe; 300 goto no_kprobe;
295 301
296 kcb->kprobe_status = KPROBE_HIT_ACTIVE; 302 kcb->kprobe_status = KPROBE_HIT_ACTIVE;
297 set_current_kprobe(p, regs, kcb); 303 push_kprobe(kcb, p);
298 if (p->pre_handler && p->pre_handler(p, regs)) 304 if (p->pre_handler && p->pre_handler(p, regs))
299 /* handler has already set things up, so skip ss setup */ 305 /* handler has already set things up, so skip ss setup */
300 return 1; 306 return 1;
@@ -395,7 +401,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
395 401
396 regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE; 402 regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE;
397 403
398 reset_current_kprobe(); 404 pop_kprobe(get_kprobe_ctlblk());
399 kretprobe_hash_unlock(current, &flags); 405 kretprobe_hash_unlock(current, &flags);
400 preempt_enable_no_resched(); 406 preempt_enable_no_resched();
401 407
@@ -457,14 +463,7 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
457 } 463 }
458 464
459 resume_execution(cur, regs); 465 resume_execution(cur, regs);
460 466 pop_kprobe(kcb);
461 /*Restore back the original saved kprobes variables and continue. */
462 if (kcb->kprobe_status == KPROBE_REENTER) {
463 restore_previous_kprobe(kcb);
464 goto out;
465 }
466 reset_current_kprobe();
467out:
468 preempt_enable_no_resched(); 467 preempt_enable_no_resched();
469 468
470 /* 469 /*
@@ -499,11 +498,7 @@ static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
499 * normal page fault. 498 * normal page fault.
500 */ 499 */
501 disable_singlestep(kcb, regs, (unsigned long) cur->addr); 500 disable_singlestep(kcb, regs, (unsigned long) cur->addr);
502 if (kcb->kprobe_status == KPROBE_REENTER) 501 pop_kprobe(kcb);
503 restore_previous_kprobe(kcb);
504 else {
505 reset_current_kprobe();
506 }
507 preempt_enable_no_resched(); 502 preempt_enable_no_resched();
508 break; 503 break;
509 case KPROBE_HIT_ACTIVE: 504 case KPROBE_HIT_ACTIVE: