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 | } |
