diff options
author | Markus Metzger <markus.t.metzger@intel.com> | 2008-12-19 09:10:24 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-12-20 03:15:46 -0500 |
commit | bf53de907dfdaac178c92d774aae7370d7b97d20 (patch) | |
tree | 738a07a8b4b22f7bb8ec2029c9ea9c635db6c62a /arch/x86 | |
parent | 30cd324e9787ccc9a5ede59742d5409857550692 (diff) |
x86, bts: add fork and exit handling
Impact: introduce new ptrace facility
Add arch_ptrace_untrace() function that is called when the tracer
detaches (either voluntarily or when the tracing task dies);
ptrace_disable() is only called on a voluntary detach.
Add ptrace_fork() and arch_ptrace_fork(). They are called when a
traced task is forked.
Clear DS and BTS related fields on fork.
Release DS resources and reclaim memory in ptrace_untrace(). This
releases resources already when the tracing task dies. We used to do
that when the traced task dies.
Signed-off-by: Markus Metzger <markus.t.metzger@intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/include/asm/ds.h | 9 | ||||
-rw-r--r-- | arch/x86/include/asm/ptrace.h | 7 | ||||
-rw-r--r-- | arch/x86/kernel/ds.c | 11 | ||||
-rw-r--r-- | arch/x86/kernel/process_32.c | 20 | ||||
-rw-r--r-- | arch/x86/kernel/process_64.c | 20 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 50 |
6 files changed, 85 insertions, 32 deletions
diff --git a/arch/x86/include/asm/ds.h b/arch/x86/include/asm/ds.h index ee0ea3a96c11..a8f672ba100c 100644 --- a/arch/x86/include/asm/ds.h +++ b/arch/x86/include/asm/ds.h | |||
@@ -252,12 +252,21 @@ extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *); | |||
252 | */ | 252 | */ |
253 | extern void ds_switch_to(struct task_struct *prev, struct task_struct *next); | 253 | extern void ds_switch_to(struct task_struct *prev, struct task_struct *next); |
254 | 254 | ||
255 | /* | ||
256 | * Task clone/init and cleanup work | ||
257 | */ | ||
258 | extern void ds_copy_thread(struct task_struct *tsk, struct task_struct *father); | ||
259 | extern void ds_exit_thread(struct task_struct *tsk); | ||
260 | |||
255 | #else /* CONFIG_X86_DS */ | 261 | #else /* CONFIG_X86_DS */ |
256 | 262 | ||
257 | struct cpuinfo_x86; | 263 | struct cpuinfo_x86; |
258 | static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {} | 264 | static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {} |
259 | static inline void ds_switch_to(struct task_struct *prev, | 265 | static inline void ds_switch_to(struct task_struct *prev, |
260 | struct task_struct *next) {} | 266 | struct task_struct *next) {} |
267 | static inline void ds_copy_thread(struct task_struct *tsk, | ||
268 | struct task_struct *father) {} | ||
269 | static inline void ds_exit_thread(struct task_struct *tsk) {} | ||
261 | 270 | ||
262 | #endif /* CONFIG_X86_DS */ | 271 | #endif /* CONFIG_X86_DS */ |
263 | #endif /* _ASM_X86_DS_H */ | 272 | #endif /* _ASM_X86_DS_H */ |
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index fbf744215911..6d34d954c228 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h | |||
@@ -235,6 +235,13 @@ extern int do_get_thread_area(struct task_struct *p, int idx, | |||
235 | extern int do_set_thread_area(struct task_struct *p, int idx, | 235 | extern int do_set_thread_area(struct task_struct *p, int idx, |
236 | struct user_desc __user *info, int can_allocate); | 236 | struct user_desc __user *info, int can_allocate); |
237 | 237 | ||
238 | extern void x86_ptrace_untrace(struct task_struct *); | ||
239 | extern void x86_ptrace_fork(struct task_struct *child, | ||
240 | unsigned long clone_flags); | ||
241 | |||
242 | #define arch_ptrace_untrace(tsk) x86_ptrace_untrace(tsk) | ||
243 | #define arch_ptrace_fork(child, flags) x86_ptrace_fork(child, flags) | ||
244 | |||
238 | #endif /* __KERNEL__ */ | 245 | #endif /* __KERNEL__ */ |
239 | 246 | ||
240 | #endif /* !__ASSEMBLY__ */ | 247 | #endif /* !__ASSEMBLY__ */ |
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c index 98d271e60e08..da91701a2348 100644 --- a/arch/x86/kernel/ds.c +++ b/arch/x86/kernel/ds.c | |||
@@ -1017,3 +1017,14 @@ void ds_switch_to(struct task_struct *prev, struct task_struct *next) | |||
1017 | 1017 | ||
1018 | update_debugctlmsr(next->thread.debugctlmsr); | 1018 | update_debugctlmsr(next->thread.debugctlmsr); |
1019 | } | 1019 | } |
1020 | |||
1021 | void ds_copy_thread(struct task_struct *tsk, struct task_struct *father) | ||
1022 | { | ||
1023 | clear_tsk_thread_flag(tsk, TIF_DS_AREA_MSR); | ||
1024 | tsk->thread.ds_ctx = NULL; | ||
1025 | } | ||
1026 | |||
1027 | void ds_exit_thread(struct task_struct *tsk) | ||
1028 | { | ||
1029 | WARN_ON(tsk->thread.ds_ctx); | ||
1030 | } | ||
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 605eff9a8ac0..3ba155d24884 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <asm/idle.h> | 60 | #include <asm/idle.h> |
61 | #include <asm/syscalls.h> | 61 | #include <asm/syscalls.h> |
62 | #include <asm/smp.h> | 62 | #include <asm/smp.h> |
63 | #include <asm/ds.h> | ||
63 | 64 | ||
64 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 65 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
65 | 66 | ||
@@ -251,17 +252,8 @@ void exit_thread(void) | |||
251 | tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; | 252 | tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; |
252 | put_cpu(); | 253 | put_cpu(); |
253 | } | 254 | } |
254 | #ifdef CONFIG_X86_DS | 255 | |
255 | /* Free any BTS tracers that have not been properly released. */ | 256 | ds_exit_thread(current); |
256 | if (unlikely(current->bts)) { | ||
257 | ds_release_bts(current->bts); | ||
258 | current->bts = NULL; | ||
259 | |||
260 | kfree(current->bts_buffer); | ||
261 | current->bts_buffer = NULL; | ||
262 | current->bts_size = 0; | ||
263 | } | ||
264 | #endif /* CONFIG_X86_DS */ | ||
265 | } | 257 | } |
266 | 258 | ||
267 | void flush_thread(void) | 259 | void flush_thread(void) |
@@ -343,6 +335,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
343 | kfree(p->thread.io_bitmap_ptr); | 335 | kfree(p->thread.io_bitmap_ptr); |
344 | p->thread.io_bitmap_max = 0; | 336 | p->thread.io_bitmap_max = 0; |
345 | } | 337 | } |
338 | |||
339 | ds_copy_thread(p, current); | ||
340 | |||
341 | clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR); | ||
342 | p->thread.debugctlmsr = 0; | ||
343 | |||
346 | return err; | 344 | return err; |
347 | } | 345 | } |
348 | 346 | ||
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 1cfd2a4bf853..416fb9282f4f 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <asm/ia32.h> | 53 | #include <asm/ia32.h> |
54 | #include <asm/idle.h> | 54 | #include <asm/idle.h> |
55 | #include <asm/syscalls.h> | 55 | #include <asm/syscalls.h> |
56 | #include <asm/ds.h> | ||
56 | 57 | ||
57 | asmlinkage extern void ret_from_fork(void); | 58 | asmlinkage extern void ret_from_fork(void); |
58 | 59 | ||
@@ -236,17 +237,8 @@ void exit_thread(void) | |||
236 | t->io_bitmap_max = 0; | 237 | t->io_bitmap_max = 0; |
237 | put_cpu(); | 238 | put_cpu(); |
238 | } | 239 | } |
239 | #ifdef CONFIG_X86_DS | 240 | |
240 | /* Free any BTS tracers that have not been properly released. */ | 241 | ds_exit_thread(current); |
241 | if (unlikely(current->bts)) { | ||
242 | ds_release_bts(current->bts); | ||
243 | current->bts = NULL; | ||
244 | |||
245 | kfree(current->bts_buffer); | ||
246 | current->bts_buffer = NULL; | ||
247 | current->bts_size = 0; | ||
248 | } | ||
249 | #endif /* CONFIG_X86_DS */ | ||
250 | } | 242 | } |
251 | 243 | ||
252 | void flush_thread(void) | 244 | void flush_thread(void) |
@@ -376,6 +368,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
376 | if (err) | 368 | if (err) |
377 | goto out; | 369 | goto out; |
378 | } | 370 | } |
371 | |||
372 | ds_copy_thread(p, me); | ||
373 | |||
374 | clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR); | ||
375 | p->thread.debugctlmsr = 0; | ||
376 | |||
379 | err = 0; | 377 | err = 0; |
380 | out: | 378 | out: |
381 | if (err && p->thread.io_bitmap_ptr) { | 379 | if (err && p->thread.io_bitmap_ptr) { |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 45e9855da2d2..6ad2bb607650 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -769,8 +769,47 @@ static int ptrace_bts_size(struct task_struct *child) | |||
769 | 769 | ||
770 | return (trace->ds.top - trace->ds.begin) / trace->ds.size; | 770 | return (trace->ds.top - trace->ds.begin) / trace->ds.size; |
771 | } | 771 | } |
772 | |||
773 | static void ptrace_bts_fork(struct task_struct *tsk) | ||
774 | { | ||
775 | tsk->bts = NULL; | ||
776 | tsk->bts_buffer = NULL; | ||
777 | tsk->bts_size = 0; | ||
778 | tsk->thread.bts_ovfl_signal = 0; | ||
779 | } | ||
780 | |||
781 | static void ptrace_bts_untrace(struct task_struct *child) | ||
782 | { | ||
783 | if (unlikely(child->bts)) { | ||
784 | ds_release_bts(child->bts); | ||
785 | child->bts = NULL; | ||
786 | |||
787 | kfree(child->bts_buffer); | ||
788 | child->bts_buffer = NULL; | ||
789 | child->bts_size = 0; | ||
790 | } | ||
791 | } | ||
792 | |||
793 | static void ptrace_bts_detach(struct task_struct *child) | ||
794 | { | ||
795 | ptrace_bts_untrace(child); | ||
796 | } | ||
797 | #else | ||
798 | static inline void ptrace_bts_fork(struct task_struct *tsk) {} | ||
799 | static inline void ptrace_bts_detach(struct task_struct *child) {} | ||
800 | static inline void ptrace_bts_untrace(struct task_struct *child) {} | ||
772 | #endif /* CONFIG_X86_PTRACE_BTS */ | 801 | #endif /* CONFIG_X86_PTRACE_BTS */ |
773 | 802 | ||
803 | void x86_ptrace_fork(struct task_struct *child, unsigned long clone_flags) | ||
804 | { | ||
805 | ptrace_bts_fork(child); | ||
806 | } | ||
807 | |||
808 | void x86_ptrace_untrace(struct task_struct *child) | ||
809 | { | ||
810 | ptrace_bts_untrace(child); | ||
811 | } | ||
812 | |||
774 | /* | 813 | /* |
775 | * Called by kernel/ptrace.c when detaching.. | 814 | * Called by kernel/ptrace.c when detaching.. |
776 | * | 815 | * |
@@ -782,16 +821,7 @@ void ptrace_disable(struct task_struct *child) | |||
782 | #ifdef TIF_SYSCALL_EMU | 821 | #ifdef TIF_SYSCALL_EMU |
783 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | 822 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); |
784 | #endif | 823 | #endif |
785 | #ifdef CONFIG_X86_PTRACE_BTS | 824 | ptrace_bts_detach(child); |
786 | if (child->bts) { | ||
787 | ds_release_bts(child->bts); | ||
788 | child->bts = NULL; | ||
789 | |||
790 | kfree(child->bts_buffer); | ||
791 | child->bts_buffer = NULL; | ||
792 | child->bts_size = 0; | ||
793 | } | ||
794 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
795 | } | 825 | } |
796 | 826 | ||
797 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION | 827 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION |