diff options
-rw-r--r-- | arch/ia64/kernel/kprobes.c | 49 |
1 files changed, 43 insertions, 6 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 41e80b42d3f3..5978823d5c63 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c | |||
@@ -41,8 +41,8 @@ extern void jprobe_inst_return(void); | |||
41 | #define KPROBE_HIT_ACTIVE 0x00000001 | 41 | #define KPROBE_HIT_ACTIVE 0x00000001 |
42 | #define KPROBE_HIT_SS 0x00000002 | 42 | #define KPROBE_HIT_SS 0x00000002 |
43 | 43 | ||
44 | static struct kprobe *current_kprobe; | 44 | static struct kprobe *current_kprobe, *kprobe_prev; |
45 | static unsigned long kprobe_status; | 45 | static unsigned long kprobe_status, kprobe_status_prev; |
46 | static struct pt_regs jprobe_saved_regs; | 46 | static struct pt_regs jprobe_saved_regs; |
47 | 47 | ||
48 | enum instruction_type {A, I, M, F, B, L, X, u}; | 48 | enum instruction_type {A, I, M, F, B, L, X, u}; |
@@ -273,6 +273,23 @@ static int valid_kprobe_addr(int template, int slot, unsigned long addr) | |||
273 | return 0; | 273 | return 0; |
274 | } | 274 | } |
275 | 275 | ||
276 | static inline void save_previous_kprobe(void) | ||
277 | { | ||
278 | kprobe_prev = current_kprobe; | ||
279 | kprobe_status_prev = kprobe_status; | ||
280 | } | ||
281 | |||
282 | static inline void restore_previous_kprobe(void) | ||
283 | { | ||
284 | current_kprobe = kprobe_prev; | ||
285 | kprobe_status = kprobe_status_prev; | ||
286 | } | ||
287 | |||
288 | static inline void set_current_kprobe(struct kprobe *p) | ||
289 | { | ||
290 | current_kprobe = p; | ||
291 | } | ||
292 | |||
276 | int arch_prepare_kprobe(struct kprobe *p) | 293 | int arch_prepare_kprobe(struct kprobe *p) |
277 | { | 294 | { |
278 | unsigned long addr = (unsigned long) p->addr; | 295 | unsigned long addr = (unsigned long) p->addr; |
@@ -436,8 +453,18 @@ static int pre_kprobes_handler(struct die_args *args) | |||
436 | unlock_kprobes(); | 453 | unlock_kprobes(); |
437 | goto no_kprobe; | 454 | goto no_kprobe; |
438 | } | 455 | } |
439 | arch_disarm_kprobe(p); | 456 | /* We have reentered the pre_kprobe_handler(), since |
440 | ret = 1; | 457 | * another probe was hit while within the handler. |
458 | * We here save the original kprobes variables and | ||
459 | * just single step on the instruction of the new probe | ||
460 | * without calling any user handlers. | ||
461 | */ | ||
462 | save_previous_kprobe(); | ||
463 | set_current_kprobe(p); | ||
464 | p->nmissed++; | ||
465 | prepare_ss(p, regs); | ||
466 | kprobe_status = KPROBE_REENTER; | ||
467 | return 1; | ||
441 | } else if (args->err == __IA64_BREAK_JPROBE) { | 468 | } else if (args->err == __IA64_BREAK_JPROBE) { |
442 | /* | 469 | /* |
443 | * jprobe instrumented function just completed | 470 | * jprobe instrumented function just completed |
@@ -460,7 +487,7 @@ static int pre_kprobes_handler(struct die_args *args) | |||
460 | } | 487 | } |
461 | 488 | ||
462 | kprobe_status = KPROBE_HIT_ACTIVE; | 489 | kprobe_status = KPROBE_HIT_ACTIVE; |
463 | current_kprobe = p; | 490 | set_current_kprobe(p); |
464 | 491 | ||
465 | if (p->pre_handler && p->pre_handler(p, regs)) | 492 | if (p->pre_handler && p->pre_handler(p, regs)) |
466 | /* | 493 | /* |
@@ -485,12 +512,22 @@ static int post_kprobes_handler(struct pt_regs *regs) | |||
485 | if (!kprobe_running()) | 512 | if (!kprobe_running()) |
486 | return 0; | 513 | return 0; |
487 | 514 | ||
488 | if (current_kprobe->post_handler) | 515 | if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { |
516 | kprobe_status = KPROBE_HIT_SSDONE; | ||
489 | current_kprobe->post_handler(current_kprobe, regs, 0); | 517 | current_kprobe->post_handler(current_kprobe, regs, 0); |
518 | } | ||
490 | 519 | ||
491 | resume_execution(current_kprobe, regs); | 520 | resume_execution(current_kprobe, regs); |
492 | 521 | ||
522 | /*Restore back the original saved kprobes variables and continue. */ | ||
523 | if (kprobe_status == KPROBE_REENTER) { | ||
524 | restore_previous_kprobe(); | ||
525 | goto out; | ||
526 | } | ||
527 | |||
493 | unlock_kprobes(); | 528 | unlock_kprobes(); |
529 | |||
530 | out: | ||
494 | preempt_enable_no_resched(); | 531 | preempt_enable_no_resched(); |
495 | return 1; | 532 | return 1; |
496 | } | 533 | } |