Commit 9afe33ada275f2413dfeae27cc58fbb27474ac72
Committed by
Linus Torvalds
1 parent
29a5551341
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
ptrace/x86: introduce ptrace_register_breakpoint()
No functional changes, preparation. Extract the "register breakpoint" code from ptrace_get_debugreg() into the new/generic helper, ptrace_register_breakpoint(). It will have more users. The patch also adds another simple helper, ptrace_fill_bp_fields(), to factor out the arch_bp_generic_fields() logic in register/modify. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jan Kratochvil <jan.kratochvil@redhat.com> Cc: Michael Neuling <mikey@neuling.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Paul Mundt <lethal@linux-sh.org> Cc: Will Deacon <will.deacon@arm.com> Cc: Prasad <prasad@linux.vnet.ibm.com> Cc: Russell King <linux@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 50 additions and 36 deletions Side-by-side Diff
arch/x86/kernel/ptrace.c
... | ... | @@ -601,23 +601,49 @@ |
601 | 601 | return dr7; |
602 | 602 | } |
603 | 603 | |
604 | -static int | |
605 | -ptrace_modify_breakpoint(struct perf_event *bp, int len, int type, | |
606 | - struct task_struct *tsk, int disabled) | |
604 | +static int ptrace_fill_bp_fields(struct perf_event_attr *attr, | |
605 | + int len, int type, bool disabled) | |
607 | 606 | { |
608 | - int err; | |
609 | - int gen_len, gen_type; | |
607 | + int err, bp_len, bp_type; | |
608 | + | |
609 | + err = arch_bp_generic_fields(len, type, &bp_len, &bp_type); | |
610 | + if (!err) { | |
611 | + attr->bp_len = bp_len; | |
612 | + attr->bp_type = bp_type; | |
613 | + attr->disabled = disabled; | |
614 | + } | |
615 | + | |
616 | + return err; | |
617 | +} | |
618 | + | |
619 | +static struct perf_event * | |
620 | +ptrace_register_breakpoint(struct task_struct *tsk, int len, int type, | |
621 | + unsigned long addr, bool disabled) | |
622 | +{ | |
610 | 623 | struct perf_event_attr attr; |
624 | + int err; | |
611 | 625 | |
612 | - err = arch_bp_generic_fields(len, type, &gen_len, &gen_type); | |
626 | + ptrace_breakpoint_init(&attr); | |
627 | + attr.bp_addr = addr; | |
628 | + | |
629 | + err = ptrace_fill_bp_fields(&attr, len, type, disabled); | |
613 | 630 | if (err) |
614 | - return err; | |
631 | + return ERR_PTR(err); | |
615 | 632 | |
616 | - attr = bp->attr; | |
617 | - attr.bp_len = gen_len; | |
618 | - attr.bp_type = gen_type; | |
619 | - attr.disabled = disabled; | |
633 | + return register_user_hw_breakpoint(&attr, ptrace_triggered, | |
634 | + NULL, tsk); | |
635 | +} | |
620 | 636 | |
637 | +static int ptrace_modify_breakpoint(struct perf_event *bp, int len, int type, | |
638 | + int disabled) | |
639 | +{ | |
640 | + struct perf_event_attr attr = bp->attr; | |
641 | + int err; | |
642 | + | |
643 | + err = ptrace_fill_bp_fields(&attr, len, type, disabled); | |
644 | + if (err) | |
645 | + return err; | |
646 | + | |
621 | 647 | return modify_user_hw_breakpoint(bp, &attr); |
622 | 648 | } |
623 | 649 | |
... | ... | @@ -653,7 +679,7 @@ |
653 | 679 | break; |
654 | 680 | } |
655 | 681 | |
656 | - rc = ptrace_modify_breakpoint(bp, len, type, tsk, disabled); | |
682 | + rc = ptrace_modify_breakpoint(bp, len, type, disabled); | |
657 | 683 | if (rc) |
658 | 684 | break; |
659 | 685 | } |
660 | 686 | |
661 | 687 | |
662 | 688 | |
... | ... | @@ -693,26 +719,14 @@ |
693 | 719 | static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, |
694 | 720 | unsigned long addr) |
695 | 721 | { |
696 | - struct perf_event *bp; | |
697 | 722 | struct thread_struct *t = &tsk->thread; |
698 | - struct perf_event_attr attr; | |
723 | + struct perf_event *bp = t->ptrace_bps[nr]; | |
699 | 724 | int err = 0; |
700 | 725 | |
701 | - if (!t->ptrace_bps[nr]) { | |
702 | - ptrace_breakpoint_init(&attr); | |
726 | + if (!bp) { | |
703 | 727 | /* |
704 | - * Put stub len and type to register (reserve) an inactive but | |
705 | - * correct bp | |
706 | - */ | |
707 | - attr.bp_addr = addr; | |
708 | - attr.bp_len = HW_BREAKPOINT_LEN_1; | |
709 | - attr.bp_type = HW_BREAKPOINT_W; | |
710 | - attr.disabled = 1; | |
711 | - | |
712 | - bp = register_user_hw_breakpoint(&attr, ptrace_triggered, | |
713 | - NULL, tsk); | |
714 | - | |
715 | - /* | |
728 | + * Put stub len and type to create an inactive but correct bp. | |
729 | + * | |
716 | 730 | * CHECKME: the previous code returned -EIO if the addr wasn't |
717 | 731 | * a valid task virtual addr. The new one will return -EINVAL in |
718 | 732 | * this case. |
719 | 733 | |
720 | 734 | |
721 | 735 | |
722 | 736 | |
... | ... | @@ -721,20 +735,20 @@ |
721 | 735 | * writing for the user. And anyway this is the previous |
722 | 736 | * behaviour. |
723 | 737 | */ |
724 | - if (IS_ERR(bp)) { | |
738 | + bp = ptrace_register_breakpoint(tsk, | |
739 | + X86_BREAKPOINT_LEN_1, X86_BREAKPOINT_WRITE, | |
740 | + addr, true); | |
741 | + if (IS_ERR(bp)) | |
725 | 742 | err = PTR_ERR(bp); |
726 | - goto out; | |
727 | - } | |
728 | - | |
729 | - t->ptrace_bps[nr] = bp; | |
743 | + else | |
744 | + t->ptrace_bps[nr] = bp; | |
730 | 745 | } else { |
731 | - bp = t->ptrace_bps[nr]; | |
746 | + struct perf_event_attr attr = bp->attr; | |
732 | 747 | |
733 | - attr = bp->attr; | |
734 | 748 | attr.bp_addr = addr; |
735 | 749 | err = modify_user_hw_breakpoint(bp, &attr); |
736 | 750 | } |
737 | -out: | |
751 | + | |
738 | 752 | return err; |
739 | 753 | } |
740 | 754 |