diff options
author | Markus Metzger <markus.t.metzger@intel.com> | 2008-11-25 03:01:25 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-11-25 11:31:11 -0500 |
commit | ca0002a179bfa532d009a9272d619732872c49bd (patch) | |
tree | 9a9ca02164dfb2c13afaa38ab67f3f15d8dd5ce8 /arch/x86/kernel/ptrace.c | |
parent | 7d55718b0c19ba611241c330f688ee824e9bab79 (diff) |
x86, bts: base in-kernel ds interface on handles
Impact: generalize the DS code to shared buffers
Change the in-kernel ds.h interface to identify the tracer via a
handle returned on ds_request_~().
Tracers used to be identified via their task_struct.
The changes are required to allow DS to be shared between different
tasks, which is needed for perfmon2 and for ftrace.
For ptrace, the handle is stored in the traced task's task_struct.
This should probably go into a (arch-specific) ptrace context some
time.
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.c | 73 |
1 files changed, 40 insertions, 33 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 06180dff5b2e..76adf5b640ff 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -668,14 +668,14 @@ static int ptrace_bts_read_record(struct task_struct *child, size_t index, | |||
668 | size_t bts_index, bts_end; | 668 | size_t bts_index, bts_end; |
669 | int error; | 669 | int error; |
670 | 670 | ||
671 | error = ds_get_bts_end(child, &bts_end); | 671 | error = ds_get_bts_end(child->bts, &bts_end); |
672 | if (error < 0) | 672 | if (error < 0) |
673 | return error; | 673 | return error; |
674 | 674 | ||
675 | if (bts_end <= index) | 675 | if (bts_end <= index) |
676 | return -EINVAL; | 676 | return -EINVAL; |
677 | 677 | ||
678 | error = ds_get_bts_index(child, &bts_index); | 678 | error = ds_get_bts_index(child->bts, &bts_index); |
679 | if (error < 0) | 679 | if (error < 0) |
680 | return error; | 680 | return error; |
681 | 681 | ||
@@ -684,7 +684,7 @@ static int ptrace_bts_read_record(struct task_struct *child, size_t index, | |||
684 | if (bts_end <= bts_index) | 684 | if (bts_end <= bts_index) |
685 | bts_index -= bts_end; | 685 | bts_index -= bts_end; |
686 | 686 | ||
687 | error = ds_access_bts(child, bts_index, &bts_record); | 687 | error = ds_access_bts(child->bts, bts_index, &bts_record); |
688 | if (error < 0) | 688 | if (error < 0) |
689 | return error; | 689 | return error; |
690 | 690 | ||
@@ -705,14 +705,14 @@ static int ptrace_bts_drain(struct task_struct *child, | |||
705 | size_t end, i; | 705 | size_t end, i; |
706 | int error; | 706 | int error; |
707 | 707 | ||
708 | error = ds_get_bts_index(child, &end); | 708 | error = ds_get_bts_index(child->bts, &end); |
709 | if (error < 0) | 709 | if (error < 0) |
710 | return error; | 710 | return error; |
711 | 711 | ||
712 | if (size < (end * sizeof(struct bts_struct))) | 712 | if (size < (end * sizeof(struct bts_struct))) |
713 | return -EIO; | 713 | return -EIO; |
714 | 714 | ||
715 | error = ds_access_bts(child, 0, (const void **)&raw); | 715 | error = ds_access_bts(child->bts, 0, (const void **)&raw); |
716 | if (error < 0) | 716 | if (error < 0) |
717 | return error; | 717 | return error; |
718 | 718 | ||
@@ -723,18 +723,13 @@ static int ptrace_bts_drain(struct task_struct *child, | |||
723 | return -EFAULT; | 723 | return -EFAULT; |
724 | } | 724 | } |
725 | 725 | ||
726 | error = ds_clear_bts(child); | 726 | error = ds_clear_bts(child->bts); |
727 | if (error < 0) | 727 | if (error < 0) |
728 | return error; | 728 | return error; |
729 | 729 | ||
730 | return end; | 730 | return end; |
731 | } | 731 | } |
732 | 732 | ||
733 | static void ptrace_bts_ovfl(struct task_struct *child) | ||
734 | { | ||
735 | send_sig(child->thread.bts_ovfl_signal, child, 0); | ||
736 | } | ||
737 | |||
738 | static int ptrace_bts_config(struct task_struct *child, | 733 | static int ptrace_bts_config(struct task_struct *child, |
739 | long cfg_size, | 734 | long cfg_size, |
740 | const struct ptrace_bts_config __user *ucfg) | 735 | const struct ptrace_bts_config __user *ucfg) |
@@ -760,23 +755,29 @@ static int ptrace_bts_config(struct task_struct *child, | |||
760 | goto errout; | 755 | goto errout; |
761 | 756 | ||
762 | if (cfg.flags & PTRACE_BTS_O_ALLOC) { | 757 | if (cfg.flags & PTRACE_BTS_O_ALLOC) { |
763 | ds_ovfl_callback_t ovfl = NULL; | 758 | bts_ovfl_callback_t ovfl = NULL; |
764 | unsigned int sig = 0; | 759 | unsigned int sig = 0; |
765 | 760 | ||
766 | /* we ignore the error in case we were not tracing child */ | ||
767 | (void)ds_release_bts(child); | ||
768 | |||
769 | if (cfg.flags & PTRACE_BTS_O_SIGNAL) { | 761 | if (cfg.flags & PTRACE_BTS_O_SIGNAL) { |
770 | if (!cfg.signal) | 762 | if (!cfg.signal) |
771 | goto errout; | 763 | goto errout; |
772 | 764 | ||
765 | error = -EOPNOTSUPP; | ||
766 | goto errout; | ||
767 | |||
773 | sig = cfg.signal; | 768 | sig = cfg.signal; |
774 | ovfl = ptrace_bts_ovfl; | ||
775 | } | 769 | } |
776 | 770 | ||
777 | error = ds_request_bts(child, /* base = */ NULL, cfg.size, ovfl); | 771 | if (child->bts) |
778 | if (error < 0) | 772 | (void)ds_release_bts(child->bts); |
773 | |||
774 | child->bts = ds_request_bts(child, /* base = */ NULL, cfg.size, | ||
775 | ovfl, /* th = */ (size_t)-1); | ||
776 | if (IS_ERR(child->bts)) { | ||
777 | error = PTR_ERR(child->bts); | ||
778 | child->bts = NULL; | ||
779 | goto errout; | 779 | goto errout; |
780 | } | ||
780 | 781 | ||
781 | child->thread.bts_ovfl_signal = sig; | 782 | child->thread.bts_ovfl_signal = sig; |
782 | } | 783 | } |
@@ -823,15 +824,15 @@ static int ptrace_bts_status(struct task_struct *child, | |||
823 | if (cfg_size < sizeof(cfg)) | 824 | if (cfg_size < sizeof(cfg)) |
824 | return -EIO; | 825 | return -EIO; |
825 | 826 | ||
826 | error = ds_get_bts_end(child, &end); | 827 | error = ds_get_bts_end(child->bts, &end); |
827 | if (error < 0) | 828 | if (error < 0) |
828 | return error; | 829 | return error; |
829 | 830 | ||
830 | error = ds_access_bts(child, /* index = */ 0, &base); | 831 | error = ds_access_bts(child->bts, /* index = */ 0, &base); |
831 | if (error < 0) | 832 | if (error < 0) |
832 | return error; | 833 | return error; |
833 | 834 | ||
834 | error = ds_access_bts(child, /* index = */ end, &max); | 835 | error = ds_access_bts(child->bts, /* index = */ end, &max); |
835 | if (error < 0) | 836 | if (error < 0) |
836 | return error; | 837 | return error; |
837 | 838 | ||
@@ -884,10 +885,7 @@ static int ptrace_bts_write_record(struct task_struct *child, | |||
884 | return -EINVAL; | 885 | return -EINVAL; |
885 | } | 886 | } |
886 | 887 | ||
887 | /* The writing task will be the switched-to task on a context | 888 | return ds_write_bts(child->bts, bts_record, bts_cfg.sizeof_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 | } | 889 | } |
892 | 890 | ||
893 | void ptrace_bts_take_timestamp(struct task_struct *tsk, | 891 | void ptrace_bts_take_timestamp(struct task_struct *tsk, |
@@ -972,13 +970,15 @@ void ptrace_disable(struct task_struct *child) | |||
972 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | 970 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); |
973 | #endif | 971 | #endif |
974 | #ifdef CONFIG_X86_PTRACE_BTS | 972 | #ifdef CONFIG_X86_PTRACE_BTS |
975 | (void)ds_release_bts(child); | 973 | if (child->bts) { |
974 | (void)ds_release_bts(child->bts); | ||
976 | 975 | ||
977 | child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask; | 976 | child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask; |
978 | if (!child->thread.debugctlmsr) | 977 | if (!child->thread.debugctlmsr) |
979 | clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); | 978 | clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); |
980 | 979 | ||
981 | clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); | 980 | clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); |
981 | } | ||
982 | #endif /* CONFIG_X86_PTRACE_BTS */ | 982 | #endif /* CONFIG_X86_PTRACE_BTS */ |
983 | } | 983 | } |
984 | 984 | ||
@@ -1110,9 +1110,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
1110 | (child, data, (struct ptrace_bts_config __user *)addr); | 1110 | (child, data, (struct ptrace_bts_config __user *)addr); |
1111 | break; | 1111 | break; |
1112 | 1112 | ||
1113 | case PTRACE_BTS_SIZE: | 1113 | case PTRACE_BTS_SIZE: { |
1114 | ret = ds_get_bts_index(child, /* pos = */ NULL); | 1114 | size_t size; |
1115 | |||
1116 | ret = ds_get_bts_index(child->bts, &size); | ||
1117 | if (ret == 0) { | ||
1118 | BUG_ON(size != (int) size); | ||
1119 | ret = (int) size; | ||
1120 | } | ||
1115 | break; | 1121 | break; |
1122 | } | ||
1116 | 1123 | ||
1117 | case PTRACE_BTS_GET: | 1124 | case PTRACE_BTS_GET: |
1118 | ret = ptrace_bts_read_record | 1125 | ret = ptrace_bts_read_record |
@@ -1120,7 +1127,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
1120 | break; | 1127 | break; |
1121 | 1128 | ||
1122 | case PTRACE_BTS_CLEAR: | 1129 | case PTRACE_BTS_CLEAR: |
1123 | ret = ds_clear_bts(child); | 1130 | ret = ds_clear_bts(child->bts); |
1124 | break; | 1131 | break; |
1125 | 1132 | ||
1126 | case PTRACE_BTS_DRAIN: | 1133 | case PTRACE_BTS_DRAIN: |