diff options
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r-- | arch/x86/kernel/ptrace.c | 398 |
1 files changed, 109 insertions, 289 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 06180dff5b2e..45e9855da2d2 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -581,158 +581,73 @@ static int ioperm_get(struct task_struct *target, | |||
581 | } | 581 | } |
582 | 582 | ||
583 | #ifdef CONFIG_X86_PTRACE_BTS | 583 | #ifdef CONFIG_X86_PTRACE_BTS |
584 | /* | ||
585 | * The configuration for a particular BTS hardware implementation. | ||
586 | */ | ||
587 | struct bts_configuration { | ||
588 | /* the size of a BTS record in bytes; at most BTS_MAX_RECORD_SIZE */ | ||
589 | unsigned char sizeof_bts; | ||
590 | /* the size of a field in the BTS record in bytes */ | ||
591 | unsigned char sizeof_field; | ||
592 | /* a bitmask to enable/disable BTS in DEBUGCTL MSR */ | ||
593 | unsigned long debugctl_mask; | ||
594 | }; | ||
595 | static struct bts_configuration bts_cfg; | ||
596 | |||
597 | #define BTS_MAX_RECORD_SIZE (8 * 3) | ||
598 | |||
599 | |||
600 | /* | ||
601 | * Branch Trace Store (BTS) uses the following format. Different | ||
602 | * architectures vary in the size of those fields. | ||
603 | * - source linear address | ||
604 | * - destination linear address | ||
605 | * - flags | ||
606 | * | ||
607 | * Later architectures use 64bit pointers throughout, whereas earlier | ||
608 | * architectures use 32bit pointers in 32bit mode. | ||
609 | * | ||
610 | * We compute the base address for the first 8 fields based on: | ||
611 | * - the field size stored in the DS configuration | ||
612 | * - the relative field position | ||
613 | * | ||
614 | * In order to store additional information in the BTS buffer, we use | ||
615 | * a special source address to indicate that the record requires | ||
616 | * special interpretation. | ||
617 | * | ||
618 | * Netburst indicated via a bit in the flags field whether the branch | ||
619 | * was predicted; this is ignored. | ||
620 | */ | ||
621 | |||
622 | enum bts_field { | ||
623 | bts_from = 0, | ||
624 | bts_to, | ||
625 | bts_flags, | ||
626 | |||
627 | bts_escape = (unsigned long)-1, | ||
628 | bts_qual = bts_to, | ||
629 | bts_jiffies = bts_flags | ||
630 | }; | ||
631 | |||
632 | static inline unsigned long bts_get(const char *base, enum bts_field field) | ||
633 | { | ||
634 | base += (bts_cfg.sizeof_field * field); | ||
635 | return *(unsigned long *)base; | ||
636 | } | ||
637 | |||
638 | static inline void bts_set(char *base, enum bts_field field, unsigned long val) | ||
639 | { | ||
640 | base += (bts_cfg.sizeof_field * field);; | ||
641 | (*(unsigned long *)base) = val; | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * Translate a BTS record from the raw format into the bts_struct format | ||
646 | * | ||
647 | * out (out): bts_struct interpretation | ||
648 | * raw: raw BTS record | ||
649 | */ | ||
650 | static void ptrace_bts_translate_record(struct bts_struct *out, const void *raw) | ||
651 | { | ||
652 | memset(out, 0, sizeof(*out)); | ||
653 | if (bts_get(raw, bts_from) == bts_escape) { | ||
654 | out->qualifier = bts_get(raw, bts_qual); | ||
655 | out->variant.jiffies = bts_get(raw, bts_jiffies); | ||
656 | } else { | ||
657 | out->qualifier = BTS_BRANCH; | ||
658 | out->variant.lbr.from_ip = bts_get(raw, bts_from); | ||
659 | out->variant.lbr.to_ip = bts_get(raw, bts_to); | ||
660 | } | ||
661 | } | ||
662 | |||
663 | static int ptrace_bts_read_record(struct task_struct *child, size_t index, | 584 | static int ptrace_bts_read_record(struct task_struct *child, size_t index, |
664 | struct bts_struct __user *out) | 585 | struct bts_struct __user *out) |
665 | { | 586 | { |
666 | struct bts_struct ret; | 587 | const struct bts_trace *trace; |
667 | const void *bts_record; | 588 | struct bts_struct bts; |
668 | size_t bts_index, bts_end; | 589 | const unsigned char *at; |
669 | int error; | 590 | int error; |
670 | 591 | ||
671 | error = ds_get_bts_end(child, &bts_end); | 592 | trace = ds_read_bts(child->bts); |
672 | if (error < 0) | 593 | if (!trace) |
673 | return error; | 594 | return -EPERM; |
674 | 595 | ||
675 | if (bts_end <= index) | 596 | at = trace->ds.top - ((index + 1) * trace->ds.size); |
676 | return -EINVAL; | 597 | if ((void *)at < trace->ds.begin) |
677 | 598 | at += (trace->ds.n * trace->ds.size); | |
678 | error = ds_get_bts_index(child, &bts_index); | ||
679 | if (error < 0) | ||
680 | return error; | ||
681 | 599 | ||
682 | /* translate the ptrace bts index into the ds bts index */ | 600 | if (!trace->read) |
683 | bts_index += bts_end - (index + 1); | 601 | return -EOPNOTSUPP; |
684 | if (bts_end <= bts_index) | ||
685 | bts_index -= bts_end; | ||
686 | 602 | ||
687 | error = ds_access_bts(child, bts_index, &bts_record); | 603 | error = trace->read(child->bts, at, &bts); |
688 | if (error < 0) | 604 | if (error < 0) |
689 | return error; | 605 | return error; |
690 | 606 | ||
691 | ptrace_bts_translate_record(&ret, bts_record); | 607 | if (copy_to_user(out, &bts, sizeof(bts))) |
692 | |||
693 | if (copy_to_user(out, &ret, sizeof(ret))) | ||
694 | return -EFAULT; | 608 | return -EFAULT; |
695 | 609 | ||
696 | return sizeof(ret); | 610 | return sizeof(bts); |
697 | } | 611 | } |
698 | 612 | ||
699 | static int ptrace_bts_drain(struct task_struct *child, | 613 | static int ptrace_bts_drain(struct task_struct *child, |
700 | long size, | 614 | long size, |
701 | struct bts_struct __user *out) | 615 | struct bts_struct __user *out) |
702 | { | 616 | { |
703 | struct bts_struct ret; | 617 | const struct bts_trace *trace; |
704 | const unsigned char *raw; | 618 | const unsigned char *at; |
705 | size_t end, i; | 619 | int error, drained = 0; |
706 | int error; | ||
707 | 620 | ||
708 | error = ds_get_bts_index(child, &end); | 621 | trace = ds_read_bts(child->bts); |
709 | if (error < 0) | 622 | if (!trace) |
710 | return error; | 623 | return -EPERM; |
711 | 624 | ||
712 | if (size < (end * sizeof(struct bts_struct))) | 625 | if (!trace->read) |
626 | return -EOPNOTSUPP; | ||
627 | |||
628 | if (size < (trace->ds.top - trace->ds.begin)) | ||
713 | return -EIO; | 629 | return -EIO; |
714 | 630 | ||
715 | error = ds_access_bts(child, 0, (const void **)&raw); | 631 | for (at = trace->ds.begin; (void *)at < trace->ds.top; |
716 | if (error < 0) | 632 | out++, drained++, at += trace->ds.size) { |
717 | return error; | 633 | struct bts_struct bts; |
634 | int error; | ||
718 | 635 | ||
719 | for (i = 0; i < end; i++, out++, raw += bts_cfg.sizeof_bts) { | 636 | error = trace->read(child->bts, at, &bts); |
720 | ptrace_bts_translate_record(&ret, raw); | 637 | if (error < 0) |
638 | return error; | ||
721 | 639 | ||
722 | if (copy_to_user(out, &ret, sizeof(ret))) | 640 | if (copy_to_user(out, &bts, sizeof(bts))) |
723 | return -EFAULT; | 641 | return -EFAULT; |
724 | } | 642 | } |
725 | 643 | ||
726 | error = ds_clear_bts(child); | 644 | memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size); |
645 | |||
646 | error = ds_reset_bts(child->bts); | ||
727 | if (error < 0) | 647 | if (error < 0) |
728 | return error; | 648 | return error; |
729 | 649 | ||
730 | return end; | 650 | return drained; |
731 | } | ||
732 | |||
733 | static void ptrace_bts_ovfl(struct task_struct *child) | ||
734 | { | ||
735 | send_sig(child->thread.bts_ovfl_signal, child, 0); | ||
736 | } | 651 | } |
737 | 652 | ||
738 | static int ptrace_bts_config(struct task_struct *child, | 653 | static int ptrace_bts_config(struct task_struct *child, |
@@ -740,114 +655,89 @@ static int ptrace_bts_config(struct task_struct *child, | |||
740 | const struct ptrace_bts_config __user *ucfg) | 655 | const struct ptrace_bts_config __user *ucfg) |
741 | { | 656 | { |
742 | struct ptrace_bts_config cfg; | 657 | struct ptrace_bts_config cfg; |
743 | int error = 0; | 658 | unsigned int flags = 0; |
744 | |||
745 | error = -EOPNOTSUPP; | ||
746 | if (!bts_cfg.sizeof_bts) | ||
747 | goto errout; | ||
748 | 659 | ||
749 | error = -EIO; | ||
750 | if (cfg_size < sizeof(cfg)) | 660 | if (cfg_size < sizeof(cfg)) |
751 | goto errout; | 661 | return -EIO; |
752 | 662 | ||
753 | error = -EFAULT; | ||
754 | if (copy_from_user(&cfg, ucfg, sizeof(cfg))) | 663 | if (copy_from_user(&cfg, ucfg, sizeof(cfg))) |
755 | goto errout; | 664 | return -EFAULT; |
756 | |||
757 | error = -EINVAL; | ||
758 | if ((cfg.flags & PTRACE_BTS_O_SIGNAL) && | ||
759 | !(cfg.flags & PTRACE_BTS_O_ALLOC)) | ||
760 | goto errout; | ||
761 | 665 | ||
762 | if (cfg.flags & PTRACE_BTS_O_ALLOC) { | 666 | if (child->bts) { |
763 | ds_ovfl_callback_t ovfl = NULL; | 667 | ds_release_bts(child->bts); |
764 | unsigned int sig = 0; | 668 | child->bts = NULL; |
669 | } | ||
765 | 670 | ||
766 | /* we ignore the error in case we were not tracing child */ | 671 | if (cfg.flags & PTRACE_BTS_O_SIGNAL) { |
767 | (void)ds_release_bts(child); | 672 | if (!cfg.signal) |
673 | return -EINVAL; | ||
768 | 674 | ||
769 | if (cfg.flags & PTRACE_BTS_O_SIGNAL) { | 675 | return -EOPNOTSUPP; |
770 | if (!cfg.signal) | ||
771 | goto errout; | ||
772 | 676 | ||
773 | sig = cfg.signal; | 677 | child->thread.bts_ovfl_signal = cfg.signal; |
774 | ovfl = ptrace_bts_ovfl; | 678 | } |
775 | } | ||
776 | 679 | ||
777 | error = ds_request_bts(child, /* base = */ NULL, cfg.size, ovfl); | 680 | if ((cfg.flags & PTRACE_BTS_O_ALLOC) && |
778 | if (error < 0) | 681 | (cfg.size != child->bts_size)) { |
779 | goto errout; | 682 | kfree(child->bts_buffer); |
780 | 683 | ||
781 | child->thread.bts_ovfl_signal = sig; | 684 | child->bts_size = cfg.size; |
685 | child->bts_buffer = kzalloc(cfg.size, GFP_KERNEL); | ||
686 | if (!child->bts_buffer) { | ||
687 | child->bts_size = 0; | ||
688 | return -ENOMEM; | ||
689 | } | ||
782 | } | 690 | } |
783 | 691 | ||
784 | error = -EINVAL; | ||
785 | if (!child->thread.ds_ctx && cfg.flags) | ||
786 | goto errout; | ||
787 | |||
788 | if (cfg.flags & PTRACE_BTS_O_TRACE) | 692 | if (cfg.flags & PTRACE_BTS_O_TRACE) |
789 | child->thread.debugctlmsr |= bts_cfg.debugctl_mask; | 693 | flags |= BTS_USER; |
790 | else | ||
791 | child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask; | ||
792 | 694 | ||
793 | if (cfg.flags & PTRACE_BTS_O_SCHED) | 695 | if (cfg.flags & PTRACE_BTS_O_SCHED) |
794 | set_tsk_thread_flag(child, TIF_BTS_TRACE_TS); | 696 | flags |= BTS_TIMESTAMPS; |
795 | else | ||
796 | clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); | ||
797 | 697 | ||
798 | error = sizeof(cfg); | 698 | child->bts = ds_request_bts(child, child->bts_buffer, child->bts_size, |
699 | /* ovfl = */ NULL, /* th = */ (size_t)-1, | ||
700 | flags); | ||
701 | if (IS_ERR(child->bts)) { | ||
702 | int error = PTR_ERR(child->bts); | ||
799 | 703 | ||
800 | out: | 704 | kfree(child->bts_buffer); |
801 | if (child->thread.debugctlmsr) | 705 | child->bts = NULL; |
802 | set_tsk_thread_flag(child, TIF_DEBUGCTLMSR); | 706 | child->bts_buffer = NULL; |
803 | else | 707 | child->bts_size = 0; |
804 | clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); | ||
805 | 708 | ||
806 | return error; | 709 | return error; |
710 | } | ||
807 | 711 | ||
808 | errout: | 712 | return sizeof(cfg); |
809 | child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask; | ||
810 | clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); | ||
811 | goto out; | ||
812 | } | 713 | } |
813 | 714 | ||
814 | static int ptrace_bts_status(struct task_struct *child, | 715 | static int ptrace_bts_status(struct task_struct *child, |
815 | long cfg_size, | 716 | long cfg_size, |
816 | struct ptrace_bts_config __user *ucfg) | 717 | struct ptrace_bts_config __user *ucfg) |
817 | { | 718 | { |
719 | const struct bts_trace *trace; | ||
818 | struct ptrace_bts_config cfg; | 720 | struct ptrace_bts_config cfg; |
819 | size_t end; | ||
820 | const void *base, *max; | ||
821 | int error; | ||
822 | 721 | ||
823 | if (cfg_size < sizeof(cfg)) | 722 | if (cfg_size < sizeof(cfg)) |
824 | return -EIO; | 723 | return -EIO; |
825 | 724 | ||
826 | error = ds_get_bts_end(child, &end); | 725 | trace = ds_read_bts(child->bts); |
827 | if (error < 0) | 726 | if (!trace) |
828 | return error; | 727 | return -EPERM; |
829 | |||
830 | error = ds_access_bts(child, /* index = */ 0, &base); | ||
831 | if (error < 0) | ||
832 | return error; | ||
833 | |||
834 | error = ds_access_bts(child, /* index = */ end, &max); | ||
835 | if (error < 0) | ||
836 | return error; | ||
837 | 728 | ||
838 | memset(&cfg, 0, sizeof(cfg)); | 729 | memset(&cfg, 0, sizeof(cfg)); |
839 | cfg.size = (max - base); | 730 | cfg.size = trace->ds.end - trace->ds.begin; |
840 | cfg.signal = child->thread.bts_ovfl_signal; | 731 | cfg.signal = child->thread.bts_ovfl_signal; |
841 | cfg.bts_size = sizeof(struct bts_struct); | 732 | cfg.bts_size = sizeof(struct bts_struct); |
842 | 733 | ||
843 | if (cfg.signal) | 734 | if (cfg.signal) |
844 | cfg.flags |= PTRACE_BTS_O_SIGNAL; | 735 | cfg.flags |= PTRACE_BTS_O_SIGNAL; |
845 | 736 | ||
846 | if (test_tsk_thread_flag(child, TIF_DEBUGCTLMSR) && | 737 | if (trace->ds.flags & BTS_USER) |
847 | child->thread.debugctlmsr & bts_cfg.debugctl_mask) | ||
848 | cfg.flags |= PTRACE_BTS_O_TRACE; | 738 | cfg.flags |= PTRACE_BTS_O_TRACE; |
849 | 739 | ||
850 | if (test_tsk_thread_flag(child, TIF_BTS_TRACE_TS)) | 740 | if (trace->ds.flags & BTS_TIMESTAMPS) |
851 | cfg.flags |= PTRACE_BTS_O_SCHED; | 741 | cfg.flags |= PTRACE_BTS_O_SCHED; |
852 | 742 | ||
853 | if (copy_to_user(ucfg, &cfg, sizeof(cfg))) | 743 | if (copy_to_user(ucfg, &cfg, sizeof(cfg))) |
@@ -856,107 +746,28 @@ static int ptrace_bts_status(struct task_struct *child, | |||
856 | return sizeof(cfg); | 746 | return sizeof(cfg); |
857 | } | 747 | } |
858 | 748 | ||
859 | static int ptrace_bts_write_record(struct task_struct *child, | 749 | static int ptrace_bts_clear(struct task_struct *child) |
860 | const struct bts_struct *in) | ||
861 | { | 750 | { |
862 | unsigned char bts_record[BTS_MAX_RECORD_SIZE]; | 751 | const struct bts_trace *trace; |
863 | 752 | ||
864 | BUG_ON(BTS_MAX_RECORD_SIZE < bts_cfg.sizeof_bts); | 753 | trace = ds_read_bts(child->bts); |
754 | if (!trace) | ||
755 | return -EPERM; | ||
865 | 756 | ||
866 | memset(bts_record, 0, bts_cfg.sizeof_bts); | 757 | memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size); |
867 | switch (in->qualifier) { | ||
868 | case BTS_INVALID: | ||
869 | break; | ||
870 | |||
871 | case BTS_BRANCH: | ||
872 | bts_set(bts_record, bts_from, in->variant.lbr.from_ip); | ||
873 | bts_set(bts_record, bts_to, in->variant.lbr.to_ip); | ||
874 | break; | ||
875 | |||
876 | case BTS_TASK_ARRIVES: | ||
877 | case BTS_TASK_DEPARTS: | ||
878 | bts_set(bts_record, bts_from, bts_escape); | ||
879 | bts_set(bts_record, bts_qual, in->qualifier); | ||
880 | bts_set(bts_record, bts_jiffies, in->variant.jiffies); | ||
881 | break; | ||
882 | |||
883 | default: | ||
884 | return -EINVAL; | ||
885 | } | ||
886 | 758 | ||
887 | /* The writing task will be the switched-to task on a context | 759 | return ds_reset_bts(child->bts); |
888 | * switch. It needs to write into the switched-from task's BTS | ||
889 | * buffer. */ | ||
890 | return ds_unchecked_write_bts(child, bts_record, bts_cfg.sizeof_bts); | ||
891 | } | 760 | } |
892 | 761 | ||
893 | void ptrace_bts_take_timestamp(struct task_struct *tsk, | 762 | static int ptrace_bts_size(struct task_struct *child) |
894 | enum bts_qualifier qualifier) | ||
895 | { | 763 | { |
896 | struct bts_struct rec = { | 764 | const struct bts_trace *trace; |
897 | .qualifier = qualifier, | ||
898 | .variant.jiffies = jiffies_64 | ||
899 | }; | ||
900 | |||
901 | ptrace_bts_write_record(tsk, &rec); | ||
902 | } | ||
903 | 765 | ||
904 | static const struct bts_configuration bts_cfg_netburst = { | 766 | trace = ds_read_bts(child->bts); |
905 | .sizeof_bts = sizeof(long) * 3, | 767 | if (!trace) |
906 | .sizeof_field = sizeof(long), | 768 | return -EPERM; |
907 | .debugctl_mask = (1<<2)|(1<<3)|(1<<5) | ||
908 | }; | ||
909 | 769 | ||
910 | static const struct bts_configuration bts_cfg_pentium_m = { | 770 | return (trace->ds.top - trace->ds.begin) / trace->ds.size; |
911 | .sizeof_bts = sizeof(long) * 3, | ||
912 | .sizeof_field = sizeof(long), | ||
913 | .debugctl_mask = (1<<6)|(1<<7) | ||
914 | }; | ||
915 | |||
916 | static const struct bts_configuration bts_cfg_core2 = { | ||
917 | .sizeof_bts = 8 * 3, | ||
918 | .sizeof_field = 8, | ||
919 | .debugctl_mask = (1<<6)|(1<<7)|(1<<9) | ||
920 | }; | ||
921 | |||
922 | static inline void bts_configure(const struct bts_configuration *cfg) | ||
923 | { | ||
924 | bts_cfg = *cfg; | ||
925 | } | ||
926 | |||
927 | void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *c) | ||
928 | { | ||
929 | switch (c->x86) { | ||
930 | case 0x6: | ||
931 | switch (c->x86_model) { | ||
932 | case 0 ... 0xC: | ||
933 | /* sorry, don't know about them */ | ||
934 | break; | ||
935 | case 0xD: | ||
936 | case 0xE: /* Pentium M */ | ||
937 | bts_configure(&bts_cfg_pentium_m); | ||
938 | break; | ||
939 | default: /* Core2, Atom, ... */ | ||
940 | bts_configure(&bts_cfg_core2); | ||
941 | break; | ||
942 | } | ||
943 | break; | ||
944 | case 0xF: | ||
945 | switch (c->x86_model) { | ||
946 | case 0x0: | ||
947 | case 0x1: | ||
948 | case 0x2: /* Netburst */ | ||
949 | bts_configure(&bts_cfg_netburst); | ||
950 | break; | ||
951 | default: | ||
952 | /* sorry, don't know about them */ | ||
953 | break; | ||
954 | } | ||
955 | break; | ||
956 | default: | ||
957 | /* sorry, don't know about them */ | ||
958 | break; | ||
959 | } | ||
960 | } | 771 | } |
961 | #endif /* CONFIG_X86_PTRACE_BTS */ | 772 | #endif /* CONFIG_X86_PTRACE_BTS */ |
962 | 773 | ||
@@ -972,13 +783,14 @@ void ptrace_disable(struct task_struct *child) | |||
972 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | 783 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); |
973 | #endif | 784 | #endif |
974 | #ifdef CONFIG_X86_PTRACE_BTS | 785 | #ifdef CONFIG_X86_PTRACE_BTS |
975 | (void)ds_release_bts(child); | 786 | if (child->bts) { |
976 | 787 | ds_release_bts(child->bts); | |
977 | child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask; | 788 | child->bts = NULL; |
978 | if (!child->thread.debugctlmsr) | ||
979 | clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); | ||
980 | 789 | ||
981 | clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); | 790 | kfree(child->bts_buffer); |
791 | child->bts_buffer = NULL; | ||
792 | child->bts_size = 0; | ||
793 | } | ||
982 | #endif /* CONFIG_X86_PTRACE_BTS */ | 794 | #endif /* CONFIG_X86_PTRACE_BTS */ |
983 | } | 795 | } |
984 | 796 | ||
@@ -1111,7 +923,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
1111 | break; | 923 | break; |
1112 | 924 | ||
1113 | case PTRACE_BTS_SIZE: | 925 | case PTRACE_BTS_SIZE: |
1114 | ret = ds_get_bts_index(child, /* pos = */ NULL); | 926 | ret = ptrace_bts_size(child); |
1115 | break; | 927 | break; |
1116 | 928 | ||
1117 | case PTRACE_BTS_GET: | 929 | case PTRACE_BTS_GET: |
@@ -1120,7 +932,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
1120 | break; | 932 | break; |
1121 | 933 | ||
1122 | case PTRACE_BTS_CLEAR: | 934 | case PTRACE_BTS_CLEAR: |
1123 | ret = ds_clear_bts(child); | 935 | ret = ptrace_bts_clear(child); |
1124 | break; | 936 | break; |
1125 | 937 | ||
1126 | case PTRACE_BTS_DRAIN: | 938 | case PTRACE_BTS_DRAIN: |
@@ -1383,6 +1195,14 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
1383 | 1195 | ||
1384 | case PTRACE_GET_THREAD_AREA: | 1196 | case PTRACE_GET_THREAD_AREA: |
1385 | case PTRACE_SET_THREAD_AREA: | 1197 | case PTRACE_SET_THREAD_AREA: |
1198 | #ifdef CONFIG_X86_PTRACE_BTS | ||
1199 | case PTRACE_BTS_CONFIG: | ||
1200 | case PTRACE_BTS_STATUS: | ||
1201 | case PTRACE_BTS_SIZE: | ||
1202 | case PTRACE_BTS_GET: | ||
1203 | case PTRACE_BTS_CLEAR: | ||
1204 | case PTRACE_BTS_DRAIN: | ||
1205 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
1386 | return arch_ptrace(child, request, addr, data); | 1206 | return arch_ptrace(child, request, addr, data); |
1387 | 1207 | ||
1388 | default: | 1208 | default: |