All of lore.kernel.org
 help / color / mirror / Atom feed
From: Oleg Nesterov <oleg@redhat.com>
To: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
	Roland McGrath <roland@redhat.com>,
	linux-kernel@vger.kernel.org
Subject: Re: [RFC] semantics of singlestepping vs. tracer exiting
Date: Mon, 3 Sep 2012 19:02:15 +0200	[thread overview]
Message-ID: <20120903170215.GA13266@redhat.com> (raw)
In-Reply-To: <20120903160538.GA10114@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 586 bytes --]

On 09/03, Oleg Nesterov wrote:
>
> This is another reason to move enable/disable step into ptrace_stop().
> And in fact I had the patches a loong ago, but we need to cleanup
> the usage of PT_SINGLESTEP/PT_BLOCKSTEP first. The tracer should
> simply set/clear these PT_ flags and resume the tracee which should
> check them and do user_*_single_step() in response.

Found these patches, see the attachments.... And this also fixes the
problems with DEBUGCTLMSR_BTF.

The patches should be re-diffed, but I need to recall why I didn't
send them, perhaps I noticed some problem...

Oleg.

[-- Attachment #2: 1_use_PT_STEP.patch --]
[-- Type: text/plain, Size: 2773 bytes --]

[PATCH 1/3] ptrace_resume: set/clear PT_SINGLESTEP/PT_BLOCKSTEP

Contrary to the comment in ptrace.h, PT_SINGLESTEP is only used on
arch/xtensa, and PT_BLOCKSTEP is not used at all.

Change the arch independent ptrace_resume() to set/clear these bits
before user_enable_*_step/user_disable_single_step() and remove this
this code from arch/xtensa/kernel/ptrace.c.

Also change ptrace_init_task() to prevent the copying of these bits.

This doesn't make any difference on xtensa, and other arches do not
use these flags so far.

But, thereafter we can check task->ptrace & PT_*STEP to figure out if
this tracer wants the stepping and unlike TIF_SINGLESTEP it is always
correct in this sense and it is not arch dependent.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---

 include/linux/ptrace.h      |    4 ++--
 kernel/ptrace.c             |    3 +++
 arch/xtensa/kernel/ptrace.c |    2 --
 3 files changed, 5 insertions(+), 4 deletions(-)

--- ptrace/include/linux/ptrace.h~1_use_PT_STEP	2011-06-28 17:50:27.000000000 +0200
+++ ptrace/include/linux/ptrace.h	2011-07-03 21:55:17.000000000 +0200
@@ -104,7 +104,6 @@
 
 #define PT_TRACE_MASK	0x000003f4
 
-/* single stepping state bits (used on ARM and PA-RISC) */
 #define PT_SINGLESTEP_BIT	31
 #define PT_SINGLESTEP		(1<<PT_SINGLESTEP_BIT)
 #define PT_BLOCKSTEP_BIT	30
@@ -220,7 +219,8 @@ static inline void ptrace_init_task(stru
 	child->parent = child->real_parent;
 	child->ptrace = 0;
 	if (unlikely(ptrace) && (current->ptrace & PT_PTRACED)) {
-		child->ptrace = current->ptrace;
+		child->ptrace = current->ptrace &
+				~(PT_SINGLESTEP | PT_BLOCKSTEP);
 		__ptrace_link(child, current->parent);
 	}
 
--- ptrace/kernel/ptrace.c~1_use_PT_STEP	2011-06-28 17:50:27.000000000 +0200
+++ ptrace/kernel/ptrace.c	2011-07-03 21:55:17.000000000 +0200
@@ -599,13 +599,16 @@ static int ptrace_resume(struct task_str
 		clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
 #endif
 
+	child->ptrace &= ~(PT_SINGLESTEP | PT_BLOCKSTEP);
 	if (is_singleblock(request)) {
 		if (unlikely(!arch_has_block_step()))
 			return -EIO;
+		child->ptrace |= PT_BLOCKSTEP;
 		user_enable_block_step(child);
 	} else if (is_singlestep(request) || is_sysemu_singlestep(request)) {
 		if (unlikely(!arch_has_single_step()))
 			return -EIO;
+		child->ptrace |= PT_SINGLESTEP;
 		user_enable_single_step(child);
 	} else {
 		user_disable_single_step(child);
--- ptrace/arch/xtensa/kernel/ptrace.c~1_use_PT_STEP	2011-04-06 21:33:43.000000000 +0200
+++ ptrace/arch/xtensa/kernel/ptrace.c	2011-07-03 20:30:57.000000000 +0200
@@ -33,12 +33,10 @@
 
 void user_enable_single_step(struct task_struct *child)
 {
-	child->ptrace |= PT_SINGLESTEP;
 }
 
 void user_disable_single_step(struct task_struct *child)
 {
-	child->ptrace &= ~PT_SINGLESTEP;
 }
 
 /*

[-- Attachment #3: 2_ptrace_finish_resume.patch --]
[-- Type: text/plain, Size: 2980 bytes --]

[PATCH 2/3] ptrace: shift user_*_step() from ptrace_resume() to ptrace_stop() path

Ignoring the buggy PTRACE_KILL, ptrace_resume() calls user_*_step()
when the tracee sleeps in ptrace_stop(). Now that ptrace_resume()
sets PT_SINGLE* flags, we can reassign user_*_step() from the tracer
to the tracee.

Introduce ptrace_finish_stop(), it is called by ptrace_stop() after
schedule(). Move user_*_step() call sites from ptrace_resume() to
ptrace_finish_stop().

This way:

	- we can remove user_disable_single_step() from detach paths.
	
	  This is the main motivation, we can implement asynchronous
	  detach.

	- this makes the detach-on-exit more correct, we do not leak
	  TIF_SINGLESTEP if the tracer dies.

	- user_enable_*_step(tsk) can be implemented more efficiently
	  if tsk == current, we can avoid access_process_vm().

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---

 include/linux/ptrace.h |    1 +
 kernel/signal.c        |    1 +
 kernel/ptrace.c        |   16 ++++++++++++----
 3 files changed, 14 insertions(+), 4 deletions(-)

--- ptrace/include/linux/ptrace.h~2_ptrace_finish_resume	2011-07-03 21:55:17.000000000 +0200
+++ ptrace/include/linux/ptrace.h	2011-07-03 21:55:37.000000000 +0200
@@ -112,6 +112,7 @@
 #include <linux/compiler.h>		/* For unlikely.  */
 #include <linux/sched.h>		/* For struct task_struct.  */
 
+extern void ptrace_finish_stop(void);
 
 extern long arch_ptrace(struct task_struct *child, long request,
 			unsigned long addr, unsigned long data);
--- ptrace/kernel/signal.c~2_ptrace_finish_resume	2011-07-03 21:55:17.000000000 +0200
+++ ptrace/kernel/signal.c	2011-07-03 21:55:37.000000000 +0200
@@ -1879,6 +1879,7 @@ static void ptrace_stop(int exit_code, i
 	 */
 	try_to_freeze();
 
+	ptrace_finish_stop();
 	/*
 	 * We are back.  Now reacquire the siglock before touching
 	 * last_siginfo, so that we are sure to have synchronized with
--- ptrace/kernel/ptrace.c~2_ptrace_finish_resume	2011-07-03 21:55:17.000000000 +0200
+++ ptrace/kernel/ptrace.c	2011-07-03 21:55:37.000000000 +0200
@@ -581,6 +581,18 @@ static int ptrace_setsiginfo(struct task
 #define is_sysemu_singlestep(request)	0
 #endif
 
+void ptrace_finish_stop(void)
+{
+	struct task_struct *task = current;
+
+	if (task->ptrace & PT_BLOCKSTEP)
+		user_enable_block_step(task);
+	else if (task->ptrace & PT_SINGLESTEP)
+		user_enable_single_step(task);
+	else
+		user_disable_single_step(task);
+}
+
 static int ptrace_resume(struct task_struct *child, long request,
 			 unsigned long data)
 {
@@ -604,14 +616,10 @@ static int ptrace_resume(struct task_str
 		if (unlikely(!arch_has_block_step()))
 			return -EIO;
 		child->ptrace |= PT_BLOCKSTEP;
-		user_enable_block_step(child);
 	} else if (is_singlestep(request) || is_sysemu_singlestep(request)) {
 		if (unlikely(!arch_has_single_step()))
 			return -EIO;
 		child->ptrace |= PT_SINGLESTEP;
-		user_enable_single_step(child);
-	} else {
-		user_disable_single_step(child);
 	}
 
 	child->exit_code = data;

[-- Attachment #4: 3_detach_dont_disable_step.patch --]
[-- Type: text/plain, Size: 593 bytes --]

[PATCH 3/3] x86: remove ptrace_disable()->user_disable_single_step()

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---

 arch/x86/kernel/ptrace.c |    1 -
 1 file changed, 1 deletion(-)

--- ptrace/arch/x86/kernel/ptrace.c~3_detach_dont_disable_step	2011-06-07 19:20:02.000000000 +0200
+++ ptrace/arch/x86/kernel/ptrace.c	2011-07-03 21:56:42.000000000 +0200
@@ -807,7 +807,6 @@ static int ioperm_get(struct task_struct
  */
 void ptrace_disable(struct task_struct *child)
 {
-	user_disable_single_step(child);
 #ifdef TIF_SYSCALL_EMU
 	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
 #endif

  reply	other threads:[~2012-09-03 16:59 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20120903001436.GG23464@ZenIV.linux.org.uk>
2012-09-03 16:05 ` [RFC] semantics of singlestepping vs. tracer exiting Oleg Nesterov
2012-09-03 17:02   ` Oleg Nesterov [this message]
2012-09-03 17:31   ` Al Viro
2012-09-04 15:39     ` Oleg Nesterov
2012-09-04 16:08       ` Al Viro
2012-09-04 16:58         ` Oleg Nesterov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120903170215.GA13266@redhat.com \
    --to=oleg@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=roland@redhat.com \
    --cc=torvalds@linux-foundation.org \
    --cc=viro@ZenIV.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.