linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Ptrace updates [0/5]
@ 2003-02-06 22:39 Daniel Jacobowitz
  2003-02-06 22:40 ` Ptrace updates: has_stopped_jobs [1/5] Daniel Jacobowitz
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Daniel Jacobowitz @ 2003-02-06 22:39 UTC (permalink / raw)
  To: linux-kernel, torvalds

It's been a while since the last set of ptrace patches; here's what I've
queued up.  They'll follow in individual messages, or they're available by
BitKeeper (details below).

These are all small changes; there may be some more interesting ones in a
couple of weeks, after GDB support for NPTL is more mature.  Overview:
  - Two new traceable events, end-of-vfork and process exit.
  - Ptrace calls to get and set the siginfo struct associated with a signal.
  - Two separate signal handling fixes for the fork-tracing and CLONE_PTRACE
    support.
  - A bugfix to prevent zombie processes when debugging LinuxThreads.



Linus, please do a

	bk pull http://ptrace.bkbits.net/for-linus-2.5

This will update the following files:

 include/linux/ptrace.h |    6 ++++++
 include/linux/sched.h  |    3 +++
 kernel/exit.c          |   30 ++++++++++++++++++++++++++----
 kernel/fork.c          |    8 +++++---
 kernel/ptrace.c        |   36 +++++++++++++++++++++++++++++++++++-
 kernel/signal.c        |    8 +++++++-
 6 files changed, 82 insertions(+), 9 deletions(-)

through these ChangeSets:

<drow@nevyn.them.org> (03/02/06 1.961)
   Signal handling bugs for thread exit + ptrace

<drow@nevyn.them.org> (03/02/06 1.960)
   Add PTRACE_O_TRACEVFORKDONE and PTRACE_O_TRACEEXIT facilities.

<drow@nevyn.them.org> (03/02/04 1.959)
   Use force_sig_specific to send SIGSTOP to newly-created CLONE_PTRACE processes.

<drow@nevyn.them.org> (03/01/18 1.958)
   Add PTRACE_GETSIGINFO and PTRACE_SETSIGINFO
   
   These new ptrace commands allow a debugger to control signals more precisely;
   for instance, store a signal and deliver it later, as if it had come from the
   original outside process or in response to the same faulting memory access.

<drow@nevyn.them.org> (03/01/18 1.957)
   Tweak has_stopped_jobs for use with debugging


-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Ptrace updates: has_stopped_jobs [1/5]
  2003-02-06 22:39 Ptrace updates [0/5] Daniel Jacobowitz
@ 2003-02-06 22:40 ` Daniel Jacobowitz
  2003-02-06 22:41 ` Ptrace updates: PTRACE_GETSIGINFO [2/5] Daniel Jacobowitz
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Daniel Jacobowitz @ 2003-02-06 22:40 UTC (permalink / raw)
  To: linux-kernel, torvalds

I posted this patch a couple of weeks ago, here it is again.  The basic
problem it's solving is this: suppose you have GDB debugging an application,
using the new PTRACE_EVENT_FORK.  The application forks.  There can be a
point where GDB resumes the parent, which gets scheduled, and exits, before
GDB gets a chance to resume the child.  has_stopped_jobs causes the kernel
to decide the still-stopped-in-GDB child (which will be an orphaned pgrp) is
going to be lost, so it sends a SIGHUP and SIGCONT to it, confusing GDB
terribly.  Normally those signals wouldn't be sent.


The longer explanation:

POSIX has this terribly useful thing to say:

# If the exit of the process causes a process group to become orphaned, and if
# any member of the newly-orphaned process group is stopped, then a SIGHUP
# signal followed by a SIGCONT signal shall be sent to each process in the
# newly-orphaned process group.

The Rationale is at least a little chattier.  See

http://www.opengroup.org/onlinepubs/007904975/functions/exit.html#tag_03_131  
if you want to read it.

Basically, this is so that a stopped process group won't unintentionally
stay stopped when its shell no longer has a connection to it.  For whatever
that's worth.

I think this patch is well within the spirit of that definition.  If a
process is stopped, but there is a debugger attached to it and the stopping
signal is not one that would normally stop the process, then don't count it
as a stopped job.  Without this, when you continue past a fork() call and
the parent quickly exits, the child will get an unaccountable SIGHUP.

It's not perfect, of course - the application might be SIG_IGN'ing SIGTSTP,
but stopped in the debugger for it anyway.  It's not worth being that
complicated here, though.


# --------------------------------------------
# 03/01/18	drow@nevyn.them.org	1.957
# Tweak has_stopped_jobs for use with debugging
# --------------------------------------------

diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Thu Feb  6 16:57:39 2003
+++ b/kernel/exit.c	Thu Feb  6 16:57:39 2003
@@ -203,6 +203,17 @@
 	for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) {
 		if (p->state != TASK_STOPPED)
 			continue;
+
+		/* If p is stopped by a debugger on a signal that won't
+		   stop it, then don't count p as stopped.  This isn't
+		   perfect but it's a good approximation.  */
+		if (unlikely (p->ptrace)
+		    && p->exit_code != SIGSTOP
+		    && p->exit_code != SIGTSTP
+		    && p->exit_code != SIGTTOU
+		    && p->exit_code != SIGTTIN)
+			continue;
+
 		retval = 1;
 		break;
 	}

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Ptrace updates: PTRACE_GETSIGINFO [2/5]
  2003-02-06 22:39 Ptrace updates [0/5] Daniel Jacobowitz
  2003-02-06 22:40 ` Ptrace updates: has_stopped_jobs [1/5] Daniel Jacobowitz
@ 2003-02-06 22:41 ` Daniel Jacobowitz
  2003-02-06 22:42 ` Ptrace updates: CLONE_PTRACE should use force_sig_specific [3/5] Daniel Jacobowitz
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Daniel Jacobowitz @ 2003-02-06 22:41 UTC (permalink / raw)
  To: linux-kernel, torvalds

This patch adds PTRACE_GETSIGINFO and PTRACE_SETSIGINFO, as suggested by
someone on linux-kernel (discussion between Andi Kleen and Roland McGrath, I
think).  You can use these to query the information about a signal or forge
it, which is useful if (for instance) a debugger needs to queue a signal
for later delivery.

This implements the feature for all architectures which use the generic
get_signal_to_deliver.  Doing it for the rest is straightforward.

# --------------------------------------------
# 03/01/18	drow@nevyn.them.org	1.958
# Add PTRACE_GETSIGINFO and PTRACE_SETSIGINFO
# 
# These new ptrace commands allow a debugger to control signals more precisely;
# for instance, store a signal and deliver it later, as if it had come from the
# original outside process or in response to the same faulting memory access.
# --------------------------------------------

diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h
--- a/include/linux/ptrace.h	Thu Feb  6 16:57:36 2003
+++ b/include/linux/ptrace.h	Thu Feb  6 16:57:36 2003
@@ -26,6 +26,8 @@
 /* 0x4200-0x4300 are reserved for architecture-independent additions.  */
 #define PTRACE_SETOPTIONS	0x4200
 #define PTRACE_GETEVENTMSG	0x4201
+#define PTRACE_GETSIGINFO	0x4202
+#define PTRACE_SETSIGINFO	0x4203
 
 /* options set using PTRACE_SETOPTIONS */
 #define PTRACE_O_TRACESYSGOOD	0x00000001
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Thu Feb  6 16:57:36 2003
+++ b/include/linux/sched.h	Thu Feb  6 16:57:36 2003
@@ -400,6 +400,7 @@
 	struct backing_dev_info *backing_dev_info;
 
 	unsigned long ptrace_message;
+	siginfo_t *last_siginfo; /* For ptrace use.  */
 };
 
 extern void __put_task_struct(struct task_struct *tsk);
diff -Nru a/kernel/ptrace.c b/kernel/ptrace.c
--- a/kernel/ptrace.c	Thu Feb  6 16:57:36 2003
+++ b/kernel/ptrace.c	Thu Feb  6 16:57:36 2003
@@ -286,6 +286,23 @@
 	return 0;
 }
 
+static int ptrace_getsiginfo(struct task_struct *child, long data)
+{
+	if (child->last_siginfo == NULL)
+		return -EINVAL;
+	return copy_siginfo_to_user ((siginfo_t *) data, child->last_siginfo);
+}
+
+static int ptrace_setsiginfo(struct task_struct *child, long data)
+{
+	if (child->last_siginfo == NULL)
+		return -EINVAL;
+	if (copy_from_user (child->last_siginfo, (siginfo_t *) data,
+			    sizeof (siginfo_t)) != 0)
+		return -EFAULT;
+	return 0;
+}
+
 int ptrace_request(struct task_struct *child, long request,
 		   long addr, long data)
 {
@@ -300,6 +317,12 @@
 		break;
 	case PTRACE_GETEVENTMSG:
 		ret = put_user(child->ptrace_message, (unsigned long *) data);
+		break;
+	case PTRACE_GETSIGINFO:
+		ret = ptrace_getsiginfo(child, data);
+		break;
+	case PTRACE_SETSIGINFO:
+		ret = ptrace_setsiginfo(child, data);
 		break;
 	default:
 		break;
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Thu Feb  6 16:57:36 2003
+++ b/kernel/signal.c	Thu Feb  6 16:57:36 2003
@@ -1244,10 +1244,13 @@
 		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
 			/* Let the debugger run.  */
 			current->exit_code = signr;
+			current->last_siginfo = info;
 			set_current_state(TASK_STOPPED);
 			notify_parent(current, SIGCHLD);
 			schedule();
 
+			current->last_siginfo = NULL;
+
 			/* We're back.  Did the debugger cancel the sig?  */
 			signr = current->exit_code;
 			if (signr == 0)
@@ -1258,7 +1261,10 @@
 			if (signr == SIGSTOP)
 				continue;
 
-			/* Update the siginfo structure.  Is this good?  */
+			/* Update the siginfo structure if the signal has
+			   changed.  If the debugger wanted something
+			   specific in the siginfo structure then it should
+			   have updated *info via PTRACE_SETSIGINFO.  */
 			if (signr != info->si_signo) {
 				info->si_signo = signr;
 				info->si_errno = 0;

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Ptrace updates: CLONE_PTRACE should use force_sig_specific [3/5]
  2003-02-06 22:39 Ptrace updates [0/5] Daniel Jacobowitz
  2003-02-06 22:40 ` Ptrace updates: has_stopped_jobs [1/5] Daniel Jacobowitz
  2003-02-06 22:41 ` Ptrace updates: PTRACE_GETSIGINFO [2/5] Daniel Jacobowitz
@ 2003-02-06 22:42 ` Daniel Jacobowitz
  2003-02-06 22:42 ` Ptrace updates: event tracing for vfork finish and process exit [4/5] Daniel Jacobowitz
  2003-02-06 22:43 ` Ptrace updates: Prevent zombies when debugging LinuxThreads apps [5/5] Daniel Jacobowitz
  4 siblings, 0 replies; 6+ messages in thread
From: Daniel Jacobowitz @ 2003-02-06 22:42 UTC (permalink / raw)
  To: linux-kernel, torvalds

Right now, CLONE_PTRACE uses send_sig(SIGSTOP, p, 1).  If you use
CLONE_THREAD | CLONE_PTRACE, though, this SIGSTOP gets broadcast to the
entire thread group.  That's not what was intended; we only want the one
new thread to stop.  Fixed like so.

# --------------------------------------------
# 03/02/04	drow@nevyn.them.org	1.959
# Use force_sig_specific to send SIGSTOP to newly-created CLONE_PTRACE processes.
# --------------------------------------------

diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Thu Feb  6 16:57:32 2003
+++ b/kernel/fork.c	Thu Feb  6 16:57:32 2003
@@ -1036,7 +1036,7 @@
 		}
 
 		if (p->ptrace & PT_PTRACED)
-			send_sig(SIGSTOP, p, 1);
+			force_sig_specific(SIGSTOP, p);
 
 		wake_up_forked_process(p);		/* do this last */
 		++total_forks;

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Ptrace updates: event tracing for vfork finish and process exit [4/5]
  2003-02-06 22:39 Ptrace updates [0/5] Daniel Jacobowitz
                   ` (2 preceding siblings ...)
  2003-02-06 22:42 ` Ptrace updates: CLONE_PTRACE should use force_sig_specific [3/5] Daniel Jacobowitz
@ 2003-02-06 22:42 ` Daniel Jacobowitz
  2003-02-06 22:43 ` Ptrace updates: Prevent zombies when debugging LinuxThreads apps [5/5] Daniel Jacobowitz
  4 siblings, 0 replies; 6+ messages in thread
From: Daniel Jacobowitz @ 2003-02-06 22:42 UTC (permalink / raw)
  To: linux-kernel, torvalds

This patch adds two new event hooks to ptrace:

  PTRACE_EVENT_EXIT, which triggers in do_exit().  This is useful to quickly
  find out where a program is making an exit syscall from, etc. - it
  triggers before the mm is released, so we can still get backtraces et
  cetera.

  PTRACE_EVENT_VFORK_DONE triggers in do_fork() after the vfork completion,
  i.e. when the child is done with the mm.  This is a safe way to figure out
  when we can re-insert breakpoints in the parent without the child hitting
  them.  It's the only safe way, in fact.

# --------------------------------------------
# 03/02/06	drow@nevyn.them.org	1.960
# Add PTRACE_O_TRACEVFORKDONE and PTRACE_O_TRACEEXIT facilities.
# --------------------------------------------

diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h
--- a/include/linux/ptrace.h	Thu Feb  6 16:57:29 2003
+++ b/include/linux/ptrace.h	Thu Feb  6 16:57:29 2003
@@ -35,12 +35,16 @@
 #define PTRACE_O_TRACEVFORK	0x00000004
 #define PTRACE_O_TRACECLONE	0x00000008
 #define PTRACE_O_TRACEEXEC	0x00000010
+#define PTRACE_O_TRACEVFORKDONE	0x00000020
+#define PTRACE_O_TRACEEXIT	0x00000040
 
 /* Wait extended result codes for the above trace options.  */
 #define PTRACE_EVENT_FORK	1
 #define PTRACE_EVENT_VFORK	2
 #define PTRACE_EVENT_CLONE	3
 #define PTRACE_EVENT_EXEC	4
+#define PTRACE_EVENT_VFORK_DONE	5
+#define PTRACE_EVENT_EXIT	6
 
 #include <asm/ptrace.h>
 #include <linux/sched.h>
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Thu Feb  6 16:57:29 2003
+++ b/include/linux/sched.h	Thu Feb  6 16:57:29 2003
@@ -441,6 +441,8 @@
 #define PT_TRACE_VFORK	0x00000020
 #define PT_TRACE_CLONE	0x00000040
 #define PT_TRACE_EXEC	0x00000080
+#define PT_TRACE_VFORK_DONE	0x00000100
+#define PT_TRACE_EXIT	0x00000200
 
 #if CONFIG_SMP
 extern void set_cpus_allowed(task_t *p, unsigned long new_mask);
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Thu Feb  6 16:57:29 2003
+++ b/kernel/exit.c	Thu Feb  6 16:57:29 2003
@@ -653,6 +653,9 @@
 
 	profile_exit_task(tsk);
  
+	if (unlikely(current->ptrace & PT_TRACE_EXIT))
+		ptrace_notify((PTRACE_EVENT_EXIT << 8) | SIGTRAP);
+
 fake_volatile:
 	acct_process(code);
 	__exit_mm(tsk);
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Thu Feb  6 16:57:29 2003
+++ b/kernel/fork.c	Thu Feb  6 16:57:29 2003
@@ -1046,9 +1046,11 @@
 			ptrace_notify ((trace << 8) | SIGTRAP);
 		}
 
-		if (clone_flags & CLONE_VFORK)
+		if (clone_flags & CLONE_VFORK) {
 			wait_for_completion(&vfork);
-		else
+			if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))
+				ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
+		} else
 			/*
 			 * Let the child process run first, to avoid most of the
 			 * COW overhead when the child exec()s afterwards.
diff -Nru a/kernel/ptrace.c b/kernel/ptrace.c
--- a/kernel/ptrace.c	Thu Feb  6 16:57:29 2003
+++ b/kernel/ptrace.c	Thu Feb  6 16:57:29 2003
@@ -277,9 +277,20 @@
 	else
 		child->ptrace &= ~PT_TRACE_EXEC;
 
+	if (data & PTRACE_O_TRACEVFORKDONE)
+		child->ptrace |= PT_TRACE_VFORK_DONE;
+	else
+		child->ptrace &= ~PT_TRACE_VFORK_DONE;
+
+	if (data & PTRACE_O_TRACEEXIT)
+		child->ptrace |= PT_TRACE_EXIT;
+	else
+		child->ptrace &= ~PT_TRACE_EXIT;
+
 	if ((data & (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK
 		    | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE
-		    | PTRACE_O_TRACEEXEC))
+		    | PTRACE_O_TRACEEXEC | PTRACE_O_TRACEEXIT
+		    | PTRACE_O_TRACEVFORKDONE))
 	    != data)
 		return -EINVAL;
 

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Ptrace updates: Prevent zombies when debugging LinuxThreads apps [5/5]
  2003-02-06 22:39 Ptrace updates [0/5] Daniel Jacobowitz
                   ` (3 preceding siblings ...)
  2003-02-06 22:42 ` Ptrace updates: event tracing for vfork finish and process exit [4/5] Daniel Jacobowitz
@ 2003-02-06 22:43 ` Daniel Jacobowitz
  4 siblings, 0 replies; 6+ messages in thread
From: Daniel Jacobowitz @ 2003-02-06 22:43 UTC (permalink / raw)
  To: linux-kernel, torvalds

This is a pretty old patch; the first version of it that I saw came from
Mark Kettenis about two and a half years ago, and Alan said he'd look at it
for the next 2.2 kernel at the time.  It got lost somewhere along the line.

The problem is that we check current->parent->self_exec_domain in
exit_notify, where we should be checking current->real_parent instead. 
Then, when that's fixed, we hardcode a SIGCHLD in sys_wait4 where we should
be using p->exit_signal.

Without both fixes, when debugging a LinuxThreads application, the manager
thread receives SIGCHLDs instead of SIGRTMIN+1's every time a thread exits;
and it never reaps them, so they stick around as zombies until the whole
process exits and init gets a chance to reap them.

# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/02/06	drow@nevyn.them.org	1.961
# Signal handling bugs for thread exit + ptrace
# --------------------------------------------

diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Thu Feb  6 16:57:26 2003
+++ b/kernel/exit.c	Thu Feb  6 16:57:26 2003
@@ -586,7 +586,7 @@
 	 * is about to become orphaned.
 	 */
 	 
-	t = current->parent;
+	t = current->real_parent;
 	
 	if ((t->pgrp != current->pgrp) &&
 	    (t->session == current->session) &&
@@ -619,8 +619,16 @@
 		current->exit_signal = SIGCHLD;
 
 
-	if (current->exit_signal != -1)
-		do_notify_parent(current, current->exit_signal);
+	/* If something other than our normal parent is ptracing us, then
+	 * send it a SIGCHLD instead of honoring exit_signal.  exit_signal
+	 * only has special meaning to our real parent.
+	 */
+	if (current->exit_signal != -1) {
+		if (current->parent == current->real_parent)
+			do_notify_parent(current, current->exit_signal);
+		else
+			do_notify_parent(current, SIGCHLD);
+	}
 
 	current->state = TASK_ZOMBIE;
 	/*
@@ -877,7 +885,7 @@
 				if (p->real_parent != p->parent) {
 					write_lock_irq(&tasklist_lock);
 					__ptrace_unlink(p);
-					do_notify_parent(p, SIGCHLD);
+					do_notify_parent(p, p->exit_signal);
 					p->state = TASK_ZOMBIE;
 					write_unlock_irq(&tasklist_lock);
 				} else

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2003-02-06 22:35 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-02-06 22:39 Ptrace updates [0/5] Daniel Jacobowitz
2003-02-06 22:40 ` Ptrace updates: has_stopped_jobs [1/5] Daniel Jacobowitz
2003-02-06 22:41 ` Ptrace updates: PTRACE_GETSIGINFO [2/5] Daniel Jacobowitz
2003-02-06 22:42 ` Ptrace updates: CLONE_PTRACE should use force_sig_specific [3/5] Daniel Jacobowitz
2003-02-06 22:42 ` Ptrace updates: event tracing for vfork finish and process exit [4/5] Daniel Jacobowitz
2003-02-06 22:43 ` Ptrace updates: Prevent zombies when debugging LinuxThreads apps [5/5] Daniel Jacobowitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).