diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-01-05 06:47:20 -0500 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2011-01-05 06:47:24 -0500 |
commit | b9599798f953084774da926caa8bafd7e244948e (patch) | |
tree | 90d1df0f902e9947319c83641109a6a2560b671c | |
parent | ba640a591574036ab22cd32b47897340b0605342 (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.c | 59 |
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 | /* | |
218 | static 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 | */ | ||
222 | static 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 | ||
224 | static 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 | */ | ||
234 | static 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 | ||
230 | static 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 | |||
236 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, | 240 | void __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(); | ||
467 | out: | ||
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: |