aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ptrace.c
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2008-12-11 07:49:59 -0500
committerIngo Molnar <mingo@elte.hu>2008-12-12 02:08:12 -0500
commitc2724775ce57c98b8af9694857b941dc61056516 (patch)
treec3936699317da3233bc31e92d68cb582ec17d193 /arch/x86/kernel/ptrace.c
parentb0884e25fe361f2ca228808fb5fd1b74cb04e711 (diff)
x86, bts: provide in-kernel branch-trace interface
Impact: cleanup Move the BTS bits from ptrace.c into ds.c. Signed-off-by: Markus Metzger <markus.t.metzger@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r--arch/x86/kernel/ptrace.c416
1 files changed, 105 insertions, 311 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index b2998fe1166b..45e9855da2d2 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -581,153 +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 */
587struct 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};
595static 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
622enum 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
632static 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
638static 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 */
650static 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
663static int ptrace_bts_read_record(struct task_struct *child, size_t index, 584static 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, &bts_end); 592 trace = ds_read_bts(child->bts);
672 if (error < 0) 593 if (!trace)
673 return error; 594 return -EPERM;
674
675 if (bts_end <= index)
676 return -EINVAL;
677 595
678 error = ds_get_bts_index(child->bts, &bts_index); 596 at = trace->ds.top - ((index + 1) * trace->ds.size);
679 if (error < 0) 597 if ((void *)at < trace->ds.begin)
680 return error; 598 at += (trace->ds.n * trace->ds.size);
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, 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
699static int ptrace_bts_drain(struct task_struct *child, 613static 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->bts, &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->bts, 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->bts); 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} 651}
732 652
733static int ptrace_bts_config(struct task_struct *child, 653static int ptrace_bts_config(struct task_struct *child,
@@ -735,136 +655,89 @@ static int ptrace_bts_config(struct task_struct *child,
735 const struct ptrace_bts_config __user *ucfg) 655 const struct ptrace_bts_config __user *ucfg)
736{ 656{
737 struct ptrace_bts_config cfg; 657 struct ptrace_bts_config cfg;
738 int error = 0; 658 unsigned int flags = 0;
739
740 error = -EOPNOTSUPP;
741 if (!bts_cfg.sizeof_bts)
742 goto errout;
743 659
744 error = -EIO;
745 if (cfg_size < sizeof(cfg)) 660 if (cfg_size < sizeof(cfg))
746 goto errout; 661 return -EIO;
747 662
748 error = -EFAULT;
749 if (copy_from_user(&cfg, ucfg, sizeof(cfg))) 663 if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
750 goto errout; 664 return -EFAULT;
751
752 error = -EINVAL;
753 if ((cfg.flags & PTRACE_BTS_O_SIGNAL) &&
754 !(cfg.flags & PTRACE_BTS_O_ALLOC))
755 goto errout;
756
757 if (cfg.flags & PTRACE_BTS_O_ALLOC) {
758 bts_ovfl_callback_t ovfl = NULL;
759 unsigned int sig = 0;
760
761 error = -EINVAL;
762 if (cfg.size < (10 * bts_cfg.sizeof_bts))
763 goto errout;
764 665
765 if (cfg.flags & PTRACE_BTS_O_SIGNAL) { 666 if (child->bts) {
766 if (!cfg.signal) 667 ds_release_bts(child->bts);
767 goto errout; 668 child->bts = NULL;
669 }
768 670
769 error = -EOPNOTSUPP; 671 if (cfg.flags & PTRACE_BTS_O_SIGNAL) {
770 goto errout; 672 if (!cfg.signal)
673 return -EINVAL;
771 674
772 sig = cfg.signal; 675 return -EOPNOTSUPP;
773 }
774 676
775 if (child->bts) { 677 child->thread.bts_ovfl_signal = cfg.signal;
776 (void)ds_release_bts(child->bts); 678 }
777 kfree(child->bts_buffer);
778 679
779 child->bts = NULL; 680 if ((cfg.flags & PTRACE_BTS_O_ALLOC) &&
780 child->bts_buffer = NULL; 681 (cfg.size != child->bts_size)) {
781 } 682 kfree(child->bts_buffer);
782 683
783 error = -ENOMEM; 684 child->bts_size = cfg.size;
784 child->bts_buffer = kzalloc(cfg.size, GFP_KERNEL); 685 child->bts_buffer = kzalloc(cfg.size, GFP_KERNEL);
785 if (!child->bts_buffer) 686 if (!child->bts_buffer) {
786 goto errout; 687 child->bts_size = 0;
787 688 return -ENOMEM;
788 child->bts = ds_request_bts(child, child->bts_buffer, cfg.size,
789 ovfl, /* th = */ (size_t)-1);
790 if (IS_ERR(child->bts)) {
791 error = PTR_ERR(child->bts);
792 kfree(child->bts_buffer);
793 child->bts = NULL;
794 child->bts_buffer = NULL;
795 goto errout;
796 } 689 }
797
798 child->thread.bts_ovfl_signal = sig;
799 } 690 }
800 691
801 error = -EINVAL;
802 if (!child->thread.ds_ctx && cfg.flags)
803 goto errout;
804
805 if (cfg.flags & PTRACE_BTS_O_TRACE) 692 if (cfg.flags & PTRACE_BTS_O_TRACE)
806 child->thread.debugctlmsr |= bts_cfg.debugctl_mask; 693 flags |= BTS_USER;
807 else
808 child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
809 694
810 if (cfg.flags & PTRACE_BTS_O_SCHED) 695 if (cfg.flags & PTRACE_BTS_O_SCHED)
811 set_tsk_thread_flag(child, TIF_BTS_TRACE_TS); 696 flags |= BTS_TIMESTAMPS;
812 else
813 clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
814 697
815 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);
816 703
817out: 704 kfree(child->bts_buffer);
818 if (child->thread.debugctlmsr) 705 child->bts = NULL;
819 set_tsk_thread_flag(child, TIF_DEBUGCTLMSR); 706 child->bts_buffer = NULL;
820 else 707 child->bts_size = 0;
821 clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
822 708
823 return error; 709 return error;
710 }
824 711
825errout: 712 return sizeof(cfg);
826 child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
827 clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
828 goto out;
829} 713}
830 714
831static int ptrace_bts_status(struct task_struct *child, 715static int ptrace_bts_status(struct task_struct *child,
832 long cfg_size, 716 long cfg_size,
833 struct ptrace_bts_config __user *ucfg) 717 struct ptrace_bts_config __user *ucfg)
834{ 718{
719 const struct bts_trace *trace;
835 struct ptrace_bts_config cfg; 720 struct ptrace_bts_config cfg;
836 size_t end;
837 const void *base, *max;
838 int error;
839 721
840 if (cfg_size < sizeof(cfg)) 722 if (cfg_size < sizeof(cfg))
841 return -EIO; 723 return -EIO;
842 724
843 error = ds_get_bts_end(child->bts, &end); 725 trace = ds_read_bts(child->bts);
844 if (error < 0) 726 if (!trace)
845 return error; 727 return -EPERM;
846
847 error = ds_access_bts(child->bts, /* index = */ 0, &base);
848 if (error < 0)
849 return error;
850
851 error = ds_access_bts(child->bts, /* index = */ end, &max);
852 if (error < 0)
853 return error;
854 728
855 memset(&cfg, 0, sizeof(cfg)); 729 memset(&cfg, 0, sizeof(cfg));
856 cfg.size = (max - base); 730 cfg.size = trace->ds.end - trace->ds.begin;
857 cfg.signal = child->thread.bts_ovfl_signal; 731 cfg.signal = child->thread.bts_ovfl_signal;
858 cfg.bts_size = sizeof(struct bts_struct); 732 cfg.bts_size = sizeof(struct bts_struct);
859 733
860 if (cfg.signal) 734 if (cfg.signal)
861 cfg.flags |= PTRACE_BTS_O_SIGNAL; 735 cfg.flags |= PTRACE_BTS_O_SIGNAL;
862 736
863 if (test_tsk_thread_flag(child, TIF_DEBUGCTLMSR) && 737 if (trace->ds.flags & BTS_USER)
864 child->thread.debugctlmsr & bts_cfg.debugctl_mask)
865 cfg.flags |= PTRACE_BTS_O_TRACE; 738 cfg.flags |= PTRACE_BTS_O_TRACE;
866 739
867 if (test_tsk_thread_flag(child, TIF_BTS_TRACE_TS)) 740 if (trace->ds.flags & BTS_TIMESTAMPS)
868 cfg.flags |= PTRACE_BTS_O_SCHED; 741 cfg.flags |= PTRACE_BTS_O_SCHED;
869 742
870 if (copy_to_user(ucfg, &cfg, sizeof(cfg))) 743 if (copy_to_user(ucfg, &cfg, sizeof(cfg)))
@@ -873,105 +746,28 @@ static int ptrace_bts_status(struct task_struct *child,
873 return sizeof(cfg); 746 return sizeof(cfg);
874} 747}
875 748
876static int ptrace_bts_write_record(struct task_struct *child, 749static int ptrace_bts_clear(struct task_struct *child)
877 const struct bts_struct *in)
878{ 750{
879 unsigned char bts_record[BTS_MAX_RECORD_SIZE]; 751 const struct bts_trace *trace;
880 752
881 if (BTS_MAX_RECORD_SIZE < bts_cfg.sizeof_bts) 753 trace = ds_read_bts(child->bts);
882 return -EOVERFLOW; 754 if (!trace)
755 return -EPERM;
883 756
884 memset(bts_record, 0, bts_cfg.sizeof_bts); 757 memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size);
885 switch (in->qualifier) {
886 case BTS_INVALID:
887 break;
888 758
889 case BTS_BRANCH: 759 return ds_reset_bts(child->bts);
890 bts_set(bts_record, bts_from, in->variant.lbr.from_ip);
891 bts_set(bts_record, bts_to, in->variant.lbr.to_ip);
892 break;
893
894 case BTS_TASK_ARRIVES:
895 case BTS_TASK_DEPARTS:
896 bts_set(bts_record, bts_from, bts_escape);
897 bts_set(bts_record, bts_qual, in->qualifier);
898 bts_set(bts_record, bts_jiffies, in->variant.jiffies);
899 break;
900
901 default:
902 return -EINVAL;
903 }
904
905 return ds_write_bts(child->bts, bts_record, bts_cfg.sizeof_bts);
906} 760}
907 761
908void ptrace_bts_take_timestamp(struct task_struct *tsk, 762static int ptrace_bts_size(struct task_struct *child)
909 enum bts_qualifier qualifier)
910{ 763{
911 struct bts_struct rec = { 764 const struct bts_trace *trace;
912 .qualifier = qualifier,
913 .variant.jiffies = jiffies_64
914 };
915
916 ptrace_bts_write_record(tsk, &rec);
917}
918
919static const struct bts_configuration bts_cfg_netburst = {
920 .sizeof_bts = sizeof(long) * 3,
921 .sizeof_field = sizeof(long),
922 .debugctl_mask = (1<<2)|(1<<3)|(1<<5)
923};
924 765
925static const struct bts_configuration bts_cfg_pentium_m = { 766 trace = ds_read_bts(child->bts);
926 .sizeof_bts = sizeof(long) * 3, 767 if (!trace)
927 .sizeof_field = sizeof(long), 768 return -EPERM;
928 .debugctl_mask = (1<<6)|(1<<7)
929};
930 769
931static const struct bts_configuration bts_cfg_core2 = { 770 return (trace->ds.top - trace->ds.begin) / trace->ds.size;
932 .sizeof_bts = 8 * 3,
933 .sizeof_field = 8,
934 .debugctl_mask = (1<<6)|(1<<7)|(1<<9)
935};
936
937static inline void bts_configure(const struct bts_configuration *cfg)
938{
939 bts_cfg = *cfg;
940}
941
942void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *c)
943{
944 switch (c->x86) {
945 case 0x6:
946 switch (c->x86_model) {
947 case 0 ... 0xC:
948 /* sorry, don't know about them */
949 break;
950 case 0xD:
951 case 0xE: /* Pentium M */
952 bts_configure(&bts_cfg_pentium_m);
953 break;
954 default: /* Core2, Atom, ... */
955 bts_configure(&bts_cfg_core2);
956 break;
957 }
958 break;
959 case 0xF:
960 switch (c->x86_model) {
961 case 0x0:
962 case 0x1:
963 case 0x2: /* Netburst */
964 bts_configure(&bts_cfg_netburst);
965 break;
966 default:
967 /* sorry, don't know about them */
968 break;
969 }
970 break;
971 default:
972 /* sorry, don't know about them */
973 break;
974 }
975} 771}
976#endif /* CONFIG_X86_PTRACE_BTS */ 772#endif /* CONFIG_X86_PTRACE_BTS */
977 773
@@ -988,15 +784,12 @@ void ptrace_disable(struct task_struct *child)
988#endif 784#endif
989#ifdef CONFIG_X86_PTRACE_BTS 785#ifdef CONFIG_X86_PTRACE_BTS
990 if (child->bts) { 786 if (child->bts) {
991 (void)ds_release_bts(child->bts); 787 ds_release_bts(child->bts);
788 child->bts = NULL;
789
992 kfree(child->bts_buffer); 790 kfree(child->bts_buffer);
993 child->bts_buffer = NULL; 791 child->bts_buffer = NULL;
994 792 child->bts_size = 0;
995 child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
996 if (!child->thread.debugctlmsr)
997 clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
998
999 clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
1000 } 793 }
1001#endif /* CONFIG_X86_PTRACE_BTS */ 794#endif /* CONFIG_X86_PTRACE_BTS */
1002} 795}
@@ -1129,16 +922,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
1129 (child, data, (struct ptrace_bts_config __user *)addr); 922 (child, data, (struct ptrace_bts_config __user *)addr);
1130 break; 923 break;
1131 924
1132 case PTRACE_BTS_SIZE: { 925 case PTRACE_BTS_SIZE:
1133 size_t size; 926 ret = ptrace_bts_size(child);
1134
1135 ret = ds_get_bts_index(child->bts, &size);
1136 if (ret == 0) {
1137 WARN_ON_ONCE(size != (int) size);
1138 ret = (int) size;
1139 }
1140 break; 927 break;
1141 }
1142 928
1143 case PTRACE_BTS_GET: 929 case PTRACE_BTS_GET:
1144 ret = ptrace_bts_read_record 930 ret = ptrace_bts_read_record
@@ -1146,7 +932,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
1146 break; 932 break;
1147 933
1148 case PTRACE_BTS_CLEAR: 934 case PTRACE_BTS_CLEAR:
1149 ret = ds_clear_bts(child->bts); 935 ret = ptrace_bts_clear(child);
1150 break; 936 break;
1151 937
1152 case PTRACE_BTS_DRAIN: 938 case PTRACE_BTS_DRAIN:
@@ -1409,6 +1195,14 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
1409 1195
1410 case PTRACE_GET_THREAD_AREA: 1196 case PTRACE_GET_THREAD_AREA:
1411 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 */
1412 return arch_ptrace(child, request, addr, data); 1206 return arch_ptrace(child, request, addr, data);
1413 1207
1414 default: 1208 default: