Re: [ptrace] please review follow fork/exec changes

2012-02-15 Thread Konstantin Belousov
On Mon, Feb 13, 2012 at 02:50:45PM -0800, Dmitry Mikulin wrote:
 It seems that now wait4(2) can be called from the real (non-debugger)
 parent first and result in the call to proc_reap(), isn't it ? We would
 then just reparent the child back to the caller, still leaving the
 zombie and confusing debugger.
 When either gdb or the real parent gets to proc_reap() the process 
 wouldn't
 get destroyed, it'll get caught by the following clause:
  if (p-p_oppid  (t = pfind(p-p_oppid)) != NULL) {
 
 and the real parent with get the child back into the children's list while
 gdb will get it into the orphan list. The second time around when
 proc_reap() is entered, p-p_oppid will be 0 and the process will get
 really reaped. Does it make sense? And proc_reparent() attempts to keep 
 the
 orphan list clean and not have the same entries and the list of siblings.
 Right, this is what I figured. But I asked about some further implication
 of this change:
 
 if real parent spuriosly calls wait4(2) on the child pid after the child
 exited, but before the debugger called the wait4(), then exactly the
 code you noted above will be run. This results in the child being fully
 returned to the original parent.
 
 Next, the wait4() call from debugger gets an error, and zombie will be
 kept around until parent calls wait4() for this pid once more.
 
 Am I missed something ?
 
 In this case the process will move from gdb's child list to gdb's orphan 
 list when the real parent does a wait4(). Next time around the wait loop in 
 gdb it'll be caught by the orphan's proc_reap().

I do not see how the next debugger loop could find this process at all,
since the first wait4() call reparented it to the original parent.


pgpYsbd4CxqpH.pgp
Description: PGP signature


Re: [ptrace] please review follow fork/exec changes

2012-02-15 Thread Konstantin Belousov
On Wed, Feb 15, 2012 at 09:22:10AM -0800, Dmitry Mikulin wrote:
 
 
 On 02/15/2012 08:32 AM, Konstantin Belousov wrote:
 On Mon, Feb 13, 2012 at 02:50:45PM -0800, Dmitry Mikulin wrote:
 It seems that now wait4(2) can be called from the real (non-debugger)
 parent first and result in the call to proc_reap(), isn't it ? We would
 then just reparent the child back to the caller, still leaving the
 zombie and confusing debugger.
 When either gdb or the real parent gets to proc_reap() the process
 wouldn't
 get destroyed, it'll get caught by the following clause:
  if (p-p_oppid   (t = pfind(p-p_oppid)) != NULL) {
 
 and the real parent with get the child back into the children's list 
 while
 gdb will get it into the orphan list. The second time around when
 proc_reap() is entered, p-p_oppid will be 0 and the process will get
 really reaped. Does it make sense? And proc_reparent() attempts to keep
 the
 orphan list clean and not have the same entries and the list of 
 siblings.
 Right, this is what I figured. But I asked about some further implication
 of this change:
 
 if real parent spuriosly calls wait4(2) on the child pid after the child
 exited, but before the debugger called the wait4(), then exactly the
 code you noted above will be run. This results in the child being fully
 returned to the original parent.
 
 Next, the wait4() call from debugger gets an error, and zombie will be
 kept around until parent calls wait4() for this pid once more.
 
 Am I missed something ?
 In this case the process will move from gdb's child list to gdb's orphan
 list when the real parent does a wait4(). Next time around the wait loop 
 in
 gdb it'll be caught by the orphan's proc_reap().
 I do not see how the next debugger loop could find this process at all,
 since the first wait4() call reparented it to the original parent.
 
 Not the debugger loop, the kern_wait() loop. The child get re-parented to 
 the original parent but moves to the orphan list of the debugger process.

Either the debugger loop which calls wait4/waitpid, or the kern_wait loop
resulting from the debugger calling wait*.

Could you, please, describe, how the patched kernel moves the wait'ed
zombie to the orphan list of the debugger ?
For me, it seems that there is another bug, the child appears both on
the childdren list, and on the orphan list of the real parent.


pgpeVg6zOwT6c.pgp
Description: PGP signature


Re: [ptrace] please review follow fork/exec changes

2012-02-15 Thread Dmitry Mikulin



On 02/15/2012 08:32 AM, Konstantin Belousov wrote:

On Mon, Feb 13, 2012 at 02:50:45PM -0800, Dmitry Mikulin wrote:

It seems that now wait4(2) can be called from the real (non-debugger)
parent first and result in the call to proc_reap(), isn't it ? We would
then just reparent the child back to the caller, still leaving the
zombie and confusing debugger.

When either gdb or the real parent gets to proc_reap() the process
wouldn't
get destroyed, it'll get caught by the following clause:
 if (p-p_oppid   (t = pfind(p-p_oppid)) != NULL) {

and the real parent with get the child back into the children's list while
gdb will get it into the orphan list. The second time around when
proc_reap() is entered, p-p_oppid will be 0 and the process will get
really reaped. Does it make sense? And proc_reparent() attempts to keep
the
orphan list clean and not have the same entries and the list of siblings.

Right, this is what I figured. But I asked about some further implication
of this change:

if real parent spuriosly calls wait4(2) on the child pid after the child
exited, but before the debugger called the wait4(), then exactly the
code you noted above will be run. This results in the child being fully
returned to the original parent.

Next, the wait4() call from debugger gets an error, and zombie will be
kept around until parent calls wait4() for this pid once more.

Am I missed something ?

In this case the process will move from gdb's child list to gdb's orphan
list when the real parent does a wait4(). Next time around the wait loop in
gdb it'll be caught by the orphan's proc_reap().

I do not see how the next debugger loop could find this process at all,
since the first wait4() call reparented it to the original parent.


Not the debugger loop, the kern_wait() loop. The child get re-parented to the 
original parent but moves to the orphan list of the debugger process.

___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-02-15 Thread Konstantin Belousov
On Wed, Feb 15, 2012 at 09:54:44AM -0800, Dmitry Mikulin wrote:
 
 
 On 02/15/2012 09:40 AM, Konstantin Belousov wrote:
 On Wed, Feb 15, 2012 at 09:22:10AM -0800, Dmitry Mikulin wrote:
 
 On 02/15/2012 08:32 AM, Konstantin Belousov wrote:
 On Mon, Feb 13, 2012 at 02:50:45PM -0800, Dmitry Mikulin wrote:
 It seems that now wait4(2) can be called from the real (non-debugger)
 parent first and result in the call to proc_reap(), isn't it ? We 
 would
 then just reparent the child back to the caller, still leaving the
 zombie and confusing debugger.
 When either gdb or the real parent gets to proc_reap() the process
 wouldn't
 get destroyed, it'll get caught by the following clause:
  if (p-p_oppid(t = pfind(p-p_oppid)) != NULL) {
 
 and the real parent with get the child back into the children's list
 while
 gdb will get it into the orphan list. The second time around when
 proc_reap() is entered, p-p_oppid will be 0 and the process will get
 really reaped. Does it make sense? And proc_reparent() attempts to 
 keep
 the
 orphan list clean and not have the same entries and the list of
 siblings.
 Right, this is what I figured. But I asked about some further 
 implication
 of this change:
 
 if real parent spuriosly calls wait4(2) on the child pid after the 
 child
 exited, but before the debugger called the wait4(), then exactly the
 code you noted above will be run. This results in the child being fully
 returned to the original parent.
 
 Next, the wait4() call from debugger gets an error, and zombie will be
 kept around until parent calls wait4() for this pid once more.
 
 Am I missed something ?
 In this case the process will move from gdb's child list to gdb's orphan
 list when the real parent does a wait4(). Next time around the wait loop
 in
 gdb it'll be caught by the orphan's proc_reap().
 I do not see how the next debugger loop could find this process at all,
 since the first wait4() call reparented it to the original parent.
 Not the debugger loop, the kern_wait() loop. The child get re-parented to
 the original parent but moves to the orphan list of the debugger process.
 Either the debugger loop which calls wait4/waitpid, or the kern_wait loop
 resulting from the debugger calling wait*.
 
 Could you, please, describe, how the patched kernel moves the wait'ed
 zombie to the orphan list of the debugger ?
 For me, it seems that there is another bug, the child appears both on
 the childdren list, and on the orphan list of the real parent.
 
 
 The first attempt to reap the child will get into the
 if (p-p_oppid  (t = pfind(p-p_oppid)) != NULL) {
 clause, which will re-parent it to the real parent. The child will not be 
 destroyed at this point.
 
 The following loop in proc_reparent() will make sure that the child does 
 not stay in both lists:
 LIST_FOREACH(p, parent-p_orphans, p_orphan) {
 if (p == child) {
 LIST_REMOVE(child, p_orphan);
 break;
 }
 }
 
 Since the child parent is gdb and it's still being traced, the following 
 will move it to gdb's orphan list:
 
 if (child-p_flag  P_TRACED)
 LIST_INSERT_HEAD(child-p_pptr-p_orphans, child, p_orphan);
No, the child parent at this point is no longer the gdb, it is the original
parent. And since P_TRACED is set, the process is inserted also in the
orphans list of the original parent.

This all happens during the first execution of wait4/waitpid from the
real parent, in the proc_reparent.

 
 After this the real parent will get the exit status.
 

 The next pass through the kern_wait() loop called from gdb will catch the 
 child in its orphan list and will reap it this time for real since 
 p-p_oppid will be set to 0 in the previous attempt to reap it. Gdb gets 
 the exit code, the child is destroyed.
 
No, the child has no longer any assotiation with the debugger process,
since the block in the
if (p-p_oppid  (t = pfind(p-p_oppid)) != NULL) {
statement destroyed it.


pgpGeU7C26Grj.pgp
Description: PGP signature


Re: [ptrace] please review follow fork/exec changes

2012-02-15 Thread Dmitry Mikulin



On 02/15/2012 09:40 AM, Konstantin Belousov wrote:

On Wed, Feb 15, 2012 at 09:22:10AM -0800, Dmitry Mikulin wrote:


On 02/15/2012 08:32 AM, Konstantin Belousov wrote:

On Mon, Feb 13, 2012 at 02:50:45PM -0800, Dmitry Mikulin wrote:

It seems that now wait4(2) can be called from the real (non-debugger)
parent first and result in the call to proc_reap(), isn't it ? We would
then just reparent the child back to the caller, still leaving the
zombie and confusing debugger.

When either gdb or the real parent gets to proc_reap() the process
wouldn't
get destroyed, it'll get caught by the following clause:
 if (p-p_oppid(t = pfind(p-p_oppid)) != NULL) {

and the real parent with get the child back into the children's list
while
gdb will get it into the orphan list. The second time around when
proc_reap() is entered, p-p_oppid will be 0 and the process will get
really reaped. Does it make sense? And proc_reparent() attempts to keep
the
orphan list clean and not have the same entries and the list of
siblings.

Right, this is what I figured. But I asked about some further implication
of this change:

if real parent spuriosly calls wait4(2) on the child pid after the child
exited, but before the debugger called the wait4(), then exactly the
code you noted above will be run. This results in the child being fully
returned to the original parent.

Next, the wait4() call from debugger gets an error, and zombie will be
kept around until parent calls wait4() for this pid once more.

Am I missed something ?

In this case the process will move from gdb's child list to gdb's orphan
list when the real parent does a wait4(). Next time around the wait loop
in
gdb it'll be caught by the orphan's proc_reap().

I do not see how the next debugger loop could find this process at all,
since the first wait4() call reparented it to the original parent.

Not the debugger loop, the kern_wait() loop. The child get re-parented to
the original parent but moves to the orphan list of the debugger process.

Either the debugger loop which calls wait4/waitpid, or the kern_wait loop
resulting from the debugger calling wait*.

Could you, please, describe, how the patched kernel moves the wait'ed
zombie to the orphan list of the debugger ?
For me, it seems that there is another bug, the child appears both on
the childdren list, and on the orphan list of the real parent.



The first attempt to reap the child will get into the
if (p-p_oppid  (t = pfind(p-p_oppid)) != NULL) {
clause, which will re-parent it to the real parent. The child will not be 
destroyed at this point.

The following loop in proc_reparent() will make sure that the child does not 
stay in both lists:
LIST_FOREACH(p, parent-p_orphans, p_orphan) {
if (p == child) {
LIST_REMOVE(child, p_orphan);
break;
}
}

Since the child parent is gdb and it's still being traced, the following will 
move it to gdb's orphan list:

if (child-p_flag  P_TRACED)
LIST_INSERT_HEAD(child-p_pptr-p_orphans, child, p_orphan);

After this the real parent will get the exit status.

The next pass through the kern_wait() loop called from gdb will catch the child in 
its orphan list and will reap it this time for real since p-p_oppid will be 
set to 0 in the previous attempt to reap it. Gdb gets the exit code, the child is 
destroyed.


___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-02-15 Thread Dmitry Mikulin

I'm not sure we are on the same page. Let's do it from the very beginning.

The real parent calls wait4() and enters kern_wait() while the child is in a 
zombie state. The child is in the gdb's children list and the real parent's 
orphan list.

We enter proc_reap() because the child is caught by the orphan list of the real 
parent.
We are at
if (p-p_oppid  (t = pfind(p-p_oppid)) != NULL) {
doing proc_reparent() to the real parent of the child.
The child is in the real parent's orphan list and will be removed from it by 
proc_reparent and added to the orphan list of gdb.

After we're done re-parenting, the child is in the children list of the real 
parent and in the orphan list of gdb.
On the way out of proc_reap we clear p-p_oppid and wait4() returns the exit 
code to the real parent.

The child is not yet destroyed and is being waited for by gdb since it's on 
gdb's orphan list. We enter proc_reap() through gdb's wait4() and kern_wait().
We don't enter the following this time
if (p-p_oppid  (t = pfind(p-p_oppid)) != NULL) {
and go to the actual destruction of the process.

___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-02-13 Thread Konstantin Belousov
I looked at the orphan.patch.

Am I right that the orphans are the real childs of the process which
are temporarily reparented to the debugger ? Whatever they are, a comment
should be added to proc.h describing what does it mean.

Please provide me with a test case that demonstrates the issue
solved by the change.

The new LIST_FOREACH(q-p_orphans) body is copy/pasted, together
with the comments, from the LIST_FOREACH(q-p_children). Can the
common code be moved into some function ?

Shouldn't there be some assertion in proc_reparent() for the case when
we remove child from the orphans list, that the child is no longer
debugged ?

Why in proc_reparent(), in the case of P_TRACED child, you do
PROC_UNLOC/PROC_LOCK ?

It seems that now wait4(2) can be called from the real (non-debugger)
parent first and result in the call to proc_reap(), isn't it ? We would
then just reparent the child back to the caller, still leaving the
zombie and confusing debugger.


pgpZfjlKmTwOb.pgp
Description: PGP signature


Re: [ptrace] please review follow fork/exec changes

2012-02-13 Thread Dmitry Mikulin



On 02/13/2012 07:28 AM, Konstantin Belousov wrote:

I looked at the orphan.patch.

Am I right that the orphans are the real childs of the process which
are temporarily reparented to the debugger ? Whatever they are, a comment
should be added to proc.h describing what does it mean.


Done.




Please provide me with a test case that demonstrates the issue
solved by the change.


ftp://ftp.springdaemons.com/soft/I attached 2 source files that compile into 
separate binaries. scescx should be able
The problem I'm trying to solve is to allow a parent to collect it's child exit 
status while we're following its child. Gdb detaches from the parent upon 
successful switch-over from parent to child. At this point due to re-parenting 
the parent loses the child to gdb and if it's in a wait() it'll get a return 
status that it has no children to wait for.



The new LIST_FOREACH(q-p_orphans) body is copy/pasted, together
with the comments, from the LIST_FOREACH(q-p_children). Can the
common code be moved into some function ?


Moved the common code into a function. Didn't have time to test though.



Shouldn't there be some assertion in proc_reparent() for the case when
we remove child from the orphans list, that the child is no longer
debugged ?


Hmm... Not sure I understand...



Why in proc_reparent(), in the case of P_TRACED child, you do
PROC_UNLOC/PROC_LOCK ?


No idea how it ended up like that... I'll clean it up.



It seems that now wait4(2) can be called from the real (non-debugger)
parent first and result in the call to proc_reap(), isn't it ? We would
then just reparent the child back to the caller, still leaving the
zombie and confusing debugger.

When either gdb or the real parent gets to proc_reap() the process wouldn't get 
destroyed, it'll get caught by the following clause:
if (p-p_oppid  (t = pfind(p-p_oppid)) != NULL) {

and the real parent with get the child back into the children's list while gdb 
will get it into the orphan list. The second time around when proc_reap() is 
entered, p-p_oppid will be 0 and the process will get really reaped. Does it 
make sense? And proc_reparent() attempts to keep the orphan list clean and not 
have the same entries and the list of siblings.

The idea is to keep the real parent alive ling enough  to collect the statuc of 
the child running under gdb.

Index: sys/proc.h
===
--- sys/proc.h	(revision 231328)
+++ sys/proc.h	(working copy)
@@ -507,8 +507,6 @@ struct proc {
 /* The following fields are all zeroed upon creation in fork. */
 #define	p_startzero	p_oppid
 	pid_t		p_oppid;	/* (c + e) Save ppid in ptrace. XXX */
-	int		p_dbg_child;	/* (c + e) # of debugged children in
-			ptrace. */
 	struct vmspace	*p_vmspace;	/* (b) Address space. */
 	u_int		p_swtick;	/* (c) Tick when swapped in or out. */
 	struct itimerval p_realtimer;	/* (c) Alarm timer. */
@@ -576,6 +574,11 @@ struct proc {
 	   after fork. */
 	uint64_t	p_prev_runtime;	/* (c) Resource usage accounting. */
 	struct racct	*p_racct;	/* (b) Resource accounting. */
+	/* An orphan is process that has beed re-parented to the debugger
+	   as a result of attaching to it. Need to keep track of tham to
+	   be able to collect the exit status of what used to be children. */
+	LIST_ENTRY(proc) p_orphan;	/* (e) List of orphan processes. */
+	LIST_HEAD(, proc) p_orphans;	/* (e) Pointer to list of orphans. */
 };
 
 #define	p_session	p_pgrp-pg_session
@@ -867,7 +870,7 @@ void	procinit(void);
 void	proc_linkup0(struct proc *p, struct thread *td);
 void	proc_linkup(struct proc *p, struct thread *td);
 void	proc_reap(struct thread *td, struct proc *p, int *status, int options,
-	struct rusage *rusage);
+	struct rusage *rusage, int child);
 void	proc_reparent(struct proc *child, struct proc *newparent);
 struct	pstats *pstats_alloc(void);
 void	pstats_fork(struct pstats *src, struct pstats *dst);
Index: kern/kern_exit.c
===
--- kern/kern_exit.c	(revision 231328)
+++ kern/kern_exit.c	(working copy)
@@ -680,7 +680,7 @@ sys_wait4(struct thread *td, struct wait_args *uap
  */
 void
 proc_reap(struct thread *td, struct proc *p, int *status, int options,
-struct rusage *rusage)
+struct rusage *rusage, int child)
 {
 	struct proc *q, *t;
 
@@ -720,7 +720,6 @@ proc_reap(struct thread *td, struct proc *p, int *
 	if (p-p_oppid  (t = pfind(p-p_oppid)) != NULL) {
 		PROC_LOCK(p);
 		proc_reparent(p, t);
-		p-p_pptr-p_dbg_child--;
 		p-p_oppid = 0;
 		PROC_UNLOCK(p);
 		pksignal(t, SIGCHLD, p-p_ksi);
@@ -738,7 +737,10 @@ proc_reap(struct thread *td, struct proc *p, int *
 	sx_xlock(allproc_lock);
 	LIST_REMOVE(p, p_list);	/* off zombproc */
 	sx_xunlock(allproc_lock);
-	LIST_REMOVE(p, p_sibling);
+	if (child)
+		LIST_REMOVE(p, p_sibling);
+	else
+		LIST_REMOVE(p, p_orphan);
 	leavepgrp(p);
 #ifdef PROCDESC
 	if (p-p_procdesc != NULL)
@@ -803,12 +805,54 @@ 

Re: [ptrace] please review follow fork/exec changes

2012-02-13 Thread Konstantin Belousov
On Mon, Feb 13, 2012 at 02:04:24PM -0800, Dmitry Mikulin wrote:
 
 
 On 02/13/2012 07:28 AM, Konstantin Belousov wrote:
 I looked at the orphan.patch.
 
 Am I right that the orphans are the real childs of the process which
 are temporarily reparented to the debugger ? Whatever they are, a comment
 should be added to proc.h describing what does it mean.
 
 Done.
 
 
 
 Please provide me with a test case that demonstrates the issue
 solved by the change.
 
 ftp://ftp.springdaemons.com/soft/I attached 2 source files that compile 
 into separate binaries. scescx should be able
 The problem I'm trying to solve is to allow a parent to collect it's child 
 exit status while we're following its child. Gdb detaches from the parent 
 upon successful switch-over from parent to child. At this point due to 
 re-parenting the parent loses the child to gdb and if it's in a wait() 
 it'll get a return status that it has no children to wait for.
This text should be put somewhere in the comment. It took me some time
to re-create the reason for the patch during the read.

I will take a look at the example tomorrow, thanks.
 
 
 The new LIST_FOREACH(q-p_orphans) body is copy/pasted, together
 with the comments, from the LIST_FOREACH(q-p_children). Can the
 common code be moved into some function ?
 
 Moved the common code into a function. Didn't have time to test though.
Ok. Do not put the space between function name and '('.
Both calls to proc_to_reap() has the space.

 
 
 Shouldn't there be some assertion in proc_reparent() for the case when
 we remove child from the orphans list, that the child is no longer
 debugged ?
 
 Hmm... Not sure I understand...
proc_reparent() can move the child both to and from the orphan list.
If child is traced, you instert it into the orhpan list.
When removing the child from the orphan list, it means that
debugger finished with the process. My suggestion is to assert this
in proc_reparent (but I am not completely sure that this can be done
easily).

 
 
 Why in proc_reparent(), in the case of P_TRACED child, you do
 PROC_UNLOC/PROC_LOCK ?
 
 No idea how it ended up like that... I'll clean it up.
 
 
 It seems that now wait4(2) can be called from the real (non-debugger)
 parent first and result in the call to proc_reap(), isn't it ? We would
 then just reparent the child back to the caller, still leaving the
 zombie and confusing debugger.
 When either gdb or the real parent gets to proc_reap() the process wouldn't 
 get destroyed, it'll get caught by the following clause:
 if (p-p_oppid  (t = pfind(p-p_oppid)) != NULL) {
 
 and the real parent with get the child back into the children's list while 
 gdb will get it into the orphan list. The second time around when 
 proc_reap() is entered, p-p_oppid will be 0 and the process will get 
 really reaped. Does it make sense? And proc_reparent() attempts to keep the 
 orphan list clean and not have the same entries and the list of siblings.
Right, this is what I figured. But I asked about some further implication
of this change:

if real parent spuriosly calls wait4(2) on the child pid after the child
exited, but before the debugger called the wait4(), then exactly the
code you noted above will be run. This results in the child being fully
returned to the original parent.

Next, the wait4() call from debugger gets an error, and zombie will be
kept around until parent calls wait4() for this pid once more.

Am I missed something ?
 
 The idea is to keep the real parent alive ling enough  to collect the 
 statuc of the child running under gdb.
 






pgpimDQrx4uk7.pgp
Description: PGP signature


Re: [ptrace] please review follow fork/exec changes

2012-02-13 Thread Dmitry Mikulin



The problem I'm trying to solve is to allow a parent to collect it's child
exit status while we're following its child. Gdb detaches from the parent
upon successful switch-over from parent to child. At this point due to
re-parenting the parent loses the child to gdb and if it's in a wait()
it'll get a return status that it has no children to wait for.

This text should be put somewhere in the comment. It took me some time
to re-create the reason for the patch during the read.


I'll find a place in the code to add this comment.



I will take a look at the example tomorrow, thanks.

The new LIST_FOREACH(q-p_orphans) body is copy/pasted, together
with the comments, from the LIST_FOREACH(q-p_children). Can the
common code be moved into some function ?

Moved the common code into a function. Didn't have time to test though.

Ok. Do not put the space between function name and '('.
Both calls to proc_to_reap() has the space.


Habit of a different coding convention... fixed




Shouldn't there be some assertion in proc_reparent() for the case when
we remove child from the orphans list, that the child is no longer
debugged ?

Hmm... Not sure I understand...

proc_reparent() can move the child both to and from the orphan list.
If child is traced, you instert it into the orhpan list.
When removing the child from the orphan list, it means that
debugger finished with the process. My suggestion is to assert this
in proc_reparent (but I am not completely sure that this can be done
easily).


Need to think about this one.




Why in proc_reparent(), in the case of P_TRACED child, you do
PROC_UNLOC/PROC_LOCK ?

No idea how it ended up like that... I'll clean it up.


It seems that now wait4(2) can be called from the real (non-debugger)
parent first and result in the call to proc_reap(), isn't it ? We would
then just reparent the child back to the caller, still leaving the
zombie and confusing debugger.

When either gdb or the real parent gets to proc_reap() the process wouldn't
get destroyed, it'll get caught by the following clause:
 if (p-p_oppid  (t = pfind(p-p_oppid)) != NULL) {

and the real parent with get the child back into the children's list while
gdb will get it into the orphan list. The second time around when
proc_reap() is entered, p-p_oppid will be 0 and the process will get
really reaped. Does it make sense? And proc_reparent() attempts to keep the
orphan list clean and not have the same entries and the list of siblings.

Right, this is what I figured. But I asked about some further implication
of this change:

if real parent spuriosly calls wait4(2) on the child pid after the child
exited, but before the debugger called the wait4(), then exactly the
code you noted above will be run. This results in the child being fully
returned to the original parent.

Next, the wait4() call from debugger gets an error, and zombie will be
kept around until parent calls wait4() for this pid once more.

Am I missed something ?


In this case the process will move from gdb's child list to gdb's orphan list 
when the real parent does a wait4(). Next time around the wait loop in gdb 
it'll be caught by the orphan's proc_reap().

___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-02-09 Thread Konstantin Belousov
On Wed, Feb 08, 2012 at 04:51:57PM -0800, Dmitry Mikulin wrote:
 The patch I sent earlier works for me. Just wanted to let you know to 
 illustrate what I would like to see from the kernel.
 
 I'm trying to see if there's way not to add flags with semantics similar to 
 TDB_EXEC. I think the problem with TDB_EXEC is that is serves a trigger for 
 a stop as well as an indicator to return PL_FLAG_EXEC. And in my case I 
 still want to see all the stops but I only want to see the PL_FLAG_EXEC 
 when PT_FOLLOW_EXEC is specified.
 
 Do you think the attached patch will do what I'd like without compromising 
 existing functionality?
 
The semantic of PL_FLAG_EXEC up until now is very simple: it indicates
that current stop occured during the first return to usermode after
successful exec. The proposed patch breaks the semantic, because now
some stops which satisfy the stated condition are no longer marked with
the flag.

That said, I am lost. You stated that you still need some stops at
exec even when not PT_FOLLOW_EXEC is requested. Why usermode cannot
remember whether the PT_FOLLOW_EXEC was set for the process, and ignore
PL_FLAG_EXEC if not requested ?

I just gave up and added PL_FLAG_EXECF, which is set when PT_FOLLOW_EXEC
was set and exec is active. Would this work for your purposes ?
PL_FLAG_EXECF has the same semantic as PL_FLAG_EXEC had in your
follow-exec.patch. But the stop set is not changed comparing with the
stock src.

Are you fine with PL_FLAG_CHILD part of the changes ? If yes, I will
commit it to make some progress.

diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 60639c9..e447c93 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1035,7 +1035,9 @@ fork_return(struct thread *td, struct trapframe *frame)
p-p_oppid = p-p_pptr-p_pid;
proc_reparent(p, dbg);
sx_xunlock(proctree_lock);
+   td-td_dbgflags |= TDB_CHILD;
ptracestop(td, SIGSTOP);
+   td-td_dbgflags = ~TDB_CHILD;
} else {
/*
 * ... otherwise clear the request.
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 4510380..4f93a79 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -660,6 +660,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
case PT_TO_SCX:
case PT_SYSCALL:
case PT_FOLLOW_FORK:
+   case PT_FOLLOW_EXEC:
case PT_DETACH:
sx_xlock(proctree_lock);
proctree_locked = 1;
@@ -873,6 +874,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
else
p-p_flag = ~P_FOLLOWFORK;
break;
+   case PT_FOLLOW_EXEC:
+   if (data)
+   p-p_flag |= P_FOLLOWEXEC;
+   else
+   p-p_flag = ~P_FOLLOWEXEC;
+   break;
 
case PT_STEP:
case PT_CONTINUE:
@@ -936,7 +943,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
p-p_sigparent = SIGCHLD;
}
p-p_oppid = 0;
-   p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK);
+   p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK |
+   P_FOLLOWEXEC);
 
/* should we send SIGCHLD? */
/* childproc_continued(p); */
@@ -1139,12 +1147,17 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
pl-pl_flags |= PL_FLAG_SCE;
else if (td2-td_dbgflags  TDB_SCX)
pl-pl_flags |= PL_FLAG_SCX;
-   if (td2-td_dbgflags  TDB_EXEC)
+   if (td2-td_dbgflags  TDB_EXEC) {
pl-pl_flags |= PL_FLAG_EXEC;
+   if (p-p_flag  P_FOLLOWEXEC)
+   pl-pl_flags |= PL_FLAG_EXECF;
+   }
if (td2-td_dbgflags  TDB_FORK) {
pl-pl_flags |= PL_FLAG_FORKED;
pl-pl_child_pid = td2-td_dbg_forked;
}
+   if (td2-td_dbgflags  TDB_CHILD)
+   pl-pl_flags |= PL_FLAG_CHILD;
pl-pl_sigmask = td2-td_sigmask;
pl-pl_siglist = td2-td_siglist;
strcpy(pl-pl_tdname, td2-td_name);
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 9ebfe83..bec7223 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -384,6 +384,7 @@ do {
\
  process */
 #defineTDB_STOPATFORK  0x0080 /* Stop at the return from fork 
(child
  only) */
+#defineTDB_CHILD   

Re: [ptrace] please review follow fork/exec changes

2012-02-09 Thread Dmitry Mikulin



The semantic of PL_FLAG_EXEC up until now is very simple: it indicates
that current stop occured during the first return to usermode after
successful exec. The proposed patch breaks the semantic, because now
some stops which satisfy the stated condition are no longer marked with
the flag.

That said, I am lost. You stated that you still need some stops at
exec even when not PT_FOLLOW_EXEC is requested. Why usermode cannot
remember whether the PT_FOLLOW_EXEC was set for the process, and ignore
PL_FLAG_EXEC if not requested ?


I was trying to avoid making ugly changes in gdb if it was possible not to make 
ugly changes in the kernel. I changed gdb to work without PT_FOLLOW_EXEC.


I just gave up and added PL_FLAG_EXECF, which is set when PT_FOLLOW_EXEC
was set and exec is active. Would this work for your purposes ?
PL_FLAG_EXECF has the same semantic as PL_FLAG_EXEC had in your
follow-exec.patch. But the stop set is not changed comparing with the
stock src.

Are you fine with PL_FLAG_CHILD part of the changes ? If yes, I will
commit it to make some progress.


yes, the PL_FLAG_CHILD part works for me.
Please commit it and we can move on to the next part of the review.



___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-02-09 Thread Konstantin Belousov
On Thu, Feb 09, 2012 at 12:48:26PM -0800, Dmitry Mikulin wrote:
 
 The semantic of PL_FLAG_EXEC up until now is very simple: it indicates
 that current stop occured during the first return to usermode after
 successful exec. The proposed patch breaks the semantic, because now
 some stops which satisfy the stated condition are no longer marked with
 the flag.
 
 That said, I am lost. You stated that you still need some stops at
 exec even when not PT_FOLLOW_EXEC is requested. Why usermode cannot
 remember whether the PT_FOLLOW_EXEC was set for the process, and ignore
 PL_FLAG_EXEC if not requested ?
 
 I was trying to avoid making ugly changes in gdb if it was possible not to 
 make ugly changes in the kernel. I changed gdb to work without 
 PT_FOLLOW_EXEC.
So, does the patch below helps you, or did I missed something again ?

 
 I just gave up and added PL_FLAG_EXECF, which is set when PT_FOLLOW_EXEC
 was set and exec is active. Would this work for your purposes ?
 PL_FLAG_EXECF has the same semantic as PL_FLAG_EXEC had in your
 follow-exec.patch. But the stop set is not changed comparing with the
 stock src.
 
 Are you fine with PL_FLAG_CHILD part of the changes ? If yes, I will
 commit it to make some progress.
 
 yes, the PL_FLAG_CHILD part works for me.
 Please commit it and we can move on to the next part of the review.

Committed as r231320. Below is what left for PT_FOLLOWEXEC.

diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 2060efe..4f93a79 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -660,6 +660,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
case PT_TO_SCX:
case PT_SYSCALL:
case PT_FOLLOW_FORK:
+   case PT_FOLLOW_EXEC:
case PT_DETACH:
sx_xlock(proctree_lock);
proctree_locked = 1;
@@ -873,6 +874,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
else
p-p_flag = ~P_FOLLOWFORK;
break;
+   case PT_FOLLOW_EXEC:
+   if (data)
+   p-p_flag |= P_FOLLOWEXEC;
+   else
+   p-p_flag = ~P_FOLLOWEXEC;
+   break;
 
case PT_STEP:
case PT_CONTINUE:
@@ -936,7 +943,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
p-p_sigparent = SIGCHLD;
}
p-p_oppid = 0;
-   p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK);
+   p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK |
+   P_FOLLOWEXEC);
 
/* should we send SIGCHLD? */
/* childproc_continued(p); */
@@ -1139,8 +1147,11 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
pl-pl_flags |= PL_FLAG_SCE;
else if (td2-td_dbgflags  TDB_SCX)
pl-pl_flags |= PL_FLAG_SCX;
-   if (td2-td_dbgflags  TDB_EXEC)
+   if (td2-td_dbgflags  TDB_EXEC) {
pl-pl_flags |= PL_FLAG_EXEC;
+   if (p-p_flag  P_FOLLOWEXEC)
+   pl-pl_flags |= PL_FLAG_EXECF;
+   }
if (td2-td_dbgflags  TDB_FORK) {
pl-pl_flags |= PL_FLAG_FORKED;
pl-pl_child_pid = td2-td_dbg_forked;
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 0245e88..bec7223 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -614,6 +614,7 @@ struct proc {
 #defineP_HWPMC 0x80 /* Process is using HWPMCs */
 
 #defineP_JAILED0x100 /* Process is in jail. */
+#defineP_FOLLOWEXEC0x200 /* Report execs with ptrace. */
 #defineP_INEXEC0x400 /* Process is in execve(). */
 #defineP_STATCHILD 0x800 /* Child process stopped or exited. */
 #defineP_INMEM 0x1000 /* Loaded into memory. */
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index 8a02495..81cebfc 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -64,6 +64,7 @@
 #definePT_SYSCALL  22
 
 #definePT_FOLLOW_FORK  23
+#definePT_FOLLOW_EXEC  24
 
 #define PT_GETREGS  33 /* get general-purpose registers */
 #define PT_SETREGS  34 /* set general-purpose registers */
@@ -100,14 +101,15 @@ struct ptrace_lwpinfo {
 #definePL_EVENT_NONE   0
 #definePL_EVENT_SIGNAL 1
int pl_flags;   /* LWP flags. */
-#definePL_FLAG_SA  0x01/* M:N thread */
-#definePL_FLAG_BOUND   0x02/* M:N bound thread */
-#definePL_FLAG_SCE 0x04/* syscall enter point */
-#definePL_FLAG_SCX 0x08/* syscall leave point */
-#definePL_FLAG_EXEC0x10/* exec(2) succeeded */
-#define

Re: [ptrace] please review follow fork/exec changes

2012-02-09 Thread Dmitry Mikulin



On 02/09/2012 04:17 PM, Konstantin Belousov wrote:

On Thu, Feb 09, 2012 at 12:48:26PM -0800, Dmitry Mikulin wrote:

The semantic of PL_FLAG_EXEC up until now is very simple: it indicates
that current stop occured during the first return to usermode after
successful exec. The proposed patch breaks the semantic, because now
some stops which satisfy the stated condition are no longer marked with
the flag.

That said, I am lost. You stated that you still need some stops at
exec even when not PT_FOLLOW_EXEC is requested. Why usermode cannot
remember whether the PT_FOLLOW_EXEC was set for the process, and ignore
PL_FLAG_EXEC if not requested ?

I was trying to avoid making ugly changes in gdb if it was possible not to
make ugly changes in the kernel. I changed gdb to work without
PT_FOLLOW_EXEC.

So, does the patch below helps you, or did I missed something again ?


It works, but I managed to make gdb work without it. So, PT_FOLLOW_EXEC is not 
needed now.
Sorry for the confusion.


___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-02-08 Thread Dmitry Mikulin

The patch I sent earlier works for me. Just wanted to let you know to 
illustrate what I would like to see from the kernel.

I'm trying to see if there's way not to add flags with semantics similar to 
TDB_EXEC. I think the problem with TDB_EXEC is that is serves a trigger for a 
stop as well as an indicator to return PL_FLAG_EXEC. And in my case I still 
want to see all the stops but I only want to see the PL_FLAG_EXEC when 
PT_FOLLOW_EXEC is specified.

Do you think the attached patch will do what I'd like without compromising 
existing functionality?

Index: sys/proc.h
===
--- sys/proc.h	(revision 231228)
+++ sys/proc.h	(working copy)
@@ -384,6 +384,7 @@ do {	\
   process */
 #define	TDB_STOPATFORK	0x0080 /* Stop at the return from fork (child
   only) */
+#define	TDB_CHILD	0x0100 /* New child indicator for ptrace() */
 
 /*
  * Private flags kept in td_pflags:
@@ -613,6 +614,7 @@ struct proc {
 #define	P_HWPMC		0x80 /* Process is using HWPMCs */
 
 #define	P_JAILED	0x100 /* Process is in jail. */
+#define	P_FOLLOWEXEC	0x200 /* Report execs with ptrace. */
 #define	P_INEXEC	0x400 /* Process is in execve(). */
 #define	P_STATCHILD	0x800 /* Child process stopped or exited. */
 #define	P_INMEM		0x1000 /* Loaded into memory. */
Index: sys/ptrace.h
===
--- sys/ptrace.h	(revision 231228)
+++ sys/ptrace.h	(working copy)
@@ -64,6 +64,7 @@
 #define	PT_SYSCALL	22
 
 #define	PT_FOLLOW_FORK	23
+#define	PT_FOLLOW_EXEC	24
 
 #define PT_GETREGS  33	/* get general-purpose registers */
 #define PT_SETREGS  34	/* set general-purpose registers */
@@ -106,7 +107,8 @@ struct ptrace_lwpinfo {
 #define	PL_FLAG_SCX	0x08	/* syscall leave point */
 #define	PL_FLAG_EXEC	0x10	/* exec(2) succeeded */
 #define	PL_FLAG_SI	0x20	/* siginfo is valid */
-#define	PL_FLAG_FORKED	0x40	/* new child */
+#define	PL_FLAG_FORKED	0x40	/* child born */
+#define	PL_FLAG_CHILD	0x80	/* I am from child */
 	sigset_t	pl_sigmask;	/* LWP signal mask */
 	sigset_t	pl_siglist;	/* LWP pending signal */
 	struct __siginfo pl_siginfo;	/* siginfo for signal */
Index: kern/kern_exec.c
===
--- kern/kern_exec.c	(revision 231228)
+++ kern/kern_exec.c	(working copy)
@@ -56,6 +56,7 @@ __FBSDID($FreeBSD$);
 #include sys/proc.h
 #include sys/pioctl.h
 #include sys/namei.h
+#include sys/ptrace.h
 #include sys/resourcevar.h
 #include sys/sdt.h
 #include sys/sf_buf.h
Index: kern/kern_fork.c
===
--- kern/kern_fork.c	(revision 231228)
+++ kern/kern_fork.c	(working copy)
@@ -1035,7 +1035,9 @@ fork_return(struct thread *td, struct trapframe *f
 			p-p_oppid = p-p_pptr-p_pid;
 			proc_reparent(p, dbg);
 			sx_xunlock(proctree_lock);
+			td-td_dbgflags |= TDB_CHILD;
 			ptracestop(td, SIGSTOP);
+			td-td_dbgflags = ~TDB_CHILD;
 		} else {
 			/*
 			 * ... otherwise clear the request.
Index: kern/sys_process.c
===
--- kern/sys_process.c	(revision 231228)
+++ kern/sys_process.c	(working copy)
@@ -660,6 +660,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 	case PT_TO_SCX:
 	case PT_SYSCALL:
 	case PT_FOLLOW_FORK:
+	case PT_FOLLOW_EXEC:
 	case PT_DETACH:
 		sx_xlock(proctree_lock);
 		proctree_locked = 1;
@@ -873,6 +874,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 		else
 			p-p_flag = ~P_FOLLOWFORK;
 		break;
+	case PT_FOLLOW_EXEC:
+		if (data)
+			p-p_flag |= P_FOLLOWEXEC;
+		else
+			p-p_flag = ~P_FOLLOWEXEC;
+		break;
 
 	case PT_STEP:
 	case PT_CONTINUE:
@@ -936,7 +943,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 	p-p_sigparent = SIGCHLD;
 			}
 			p-p_oppid = 0;
-			p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK);
+			p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK |
+			P_FOLLOWEXEC);
 
 			/* should we send SIGCHLD? */
 			/* childproc_continued(p); */
@@ -1139,12 +1147,15 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 			pl-pl_flags |= PL_FLAG_SCE;
 		else if (td2-td_dbgflags  TDB_SCX)
 			pl-pl_flags |= PL_FLAG_SCX;
-		if (td2-td_dbgflags  TDB_EXEC)
+		if (td2-td_dbgflags  TDB_EXEC 
+		(p-p_stops  S_PT_SCX || p-p_flag  P_FOLLOWEXEC))
 			pl-pl_flags |= PL_FLAG_EXEC;
 		if (td2-td_dbgflags  TDB_FORK) {
 			pl-pl_flags |= PL_FLAG_FORKED;
 			pl-pl_child_pid = td2-td_dbg_forked;
 		}
+		if (td2-td_dbgflags  TDB_CHILD)
+			pl-pl_flags |= PL_FLAG_CHILD;
 		pl-pl_sigmask = td2-td_sigmask;
 		pl-pl_siglist = td2-td_siglist;
 		strcpy(pl-pl_tdname, td2-td_name);
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org

Re: [ptrace] please review follow fork/exec changes

2012-02-07 Thread Konstantin Belousov
On Mon, Feb 06, 2012 at 01:19:30PM -0800, Dmitry Mikulin wrote:
 
 I see what is going on. The wait loop for P_PPWAIT in do_fork() simply
 do not allow the ptracestop() in the syscall return path to be reached.
 There seems to be more problems. In particular, I do not see anything
 which would prevent the child from being reapped while the loop is
 executing (assume that the parent is multithreaded and other thread
 processed SIGCHLD and called wait).
 
 Lets deal with these bugs after your proposal for interface changes is
 dealt with.
 
 OK.
 
 
 Yes, I agree with the proposal to add flag to the child lwp info.
 I think it will be easier if the flag is different from PL_FLAG_FORKED.
 I named it PL_FLAG_CHILD.
 
 PT_FOLLOW_EXEC is easy to implement, but my question is, how can debugger
 operate (correctly) if it ignores exec events ? After exec, the whole
 cached state of the debuggee must be invalidated, and since debugger
 ignores the notification when the invalidation shall be done, it probably
 gets very confused.
 
 You're right, the debugger needs to handle exec() events implicitly when it 
 starts up executables. The problem is that there is OS-independent 
 machinery in gdb which handles statup fork-exec sequence differently from 
 when the debuggee itself does an exec(). Basically in the event handling 
 code I need to be able to distinguish app startup by gdb from an exec done 
 by the app. Other OS-es have flags like PL_FLAG_EXEC set on demand: they 
 have an equivalent of PT_FOLLOW_EXEC. I attached a modified patch that 
 solves the problem. It tries to separate the always-on TDB_EXEC from the 
 on-demand TDB_FOLLOWEXEC without changing existing functionality. Let me 
 know if it's acceptable.

So, do you in fact need to distinguish exec stops from syscall exit
against exec stops from PT_FOLLOW_EXEC, or do you need to only get stops
at exec returns from PT_CONTINUE when explicitely requested them ?

I would prefer to not introduce another PL_FLAG_somethingEXEC with the
same semantic as PL_FLAG_EXEC. Instead, would the following patch be fine
for your purposes ? With it, stop on exec should only occur if PT_SCX
is requested, or PT_CONTINUE and PT_FOLLOW_EXEC.

[I am unable to fully test this until tomorrow].

diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 135f798..67cb1b2 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -56,6 +56,7 @@ __FBSDID($FreeBSD$);
 #include sys/proc.h
 #include sys/pioctl.h
 #include sys/namei.h
+#include sys/ptrace.h
 #include sys/resourcevar.h
 #include sys/sdt.h
 #include sys/sf_buf.h
@@ -889,7 +890,9 @@ exec_fail_dealloc:
 
if (error == 0) {
PROC_LOCK(p);
-   td-td_dbgflags |= TDB_EXEC;
+   if ((p-p_flag  P_TRACED) != 0 
+   ((P_FOLLOWEXEC) != 0 || (p-p_stops  S_PT_SCX) != 0))
+   td-td_dbgflags |= TDB_EXEC;
PROC_UNLOCK(p);
 
/*
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 60639c9..e447c93 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1035,7 +1035,9 @@ fork_return(struct thread *td, struct trapframe *frame)
p-p_oppid = p-p_pptr-p_pid;
proc_reparent(p, dbg);
sx_xunlock(proctree_lock);
+   td-td_dbgflags |= TDB_CHILD;
ptracestop(td, SIGSTOP);
+   td-td_dbgflags = ~TDB_CHILD;
} else {
/*
 * ... otherwise clear the request.
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 4510380..79bbaed 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -660,6 +660,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
case PT_TO_SCX:
case PT_SYSCALL:
case PT_FOLLOW_FORK:
+   case PT_FOLLOW_EXEC:
case PT_DETACH:
sx_xlock(proctree_lock);
proctree_locked = 1;
@@ -873,6 +874,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
else
p-p_flag = ~P_FOLLOWFORK;
break;
+   case PT_FOLLOW_EXEC:
+   if (data)
+   p-p_flag |= P_FOLLOWEXEC;
+   else
+   p-p_flag = ~P_FOLLOWEXEC;
+   break;
 
case PT_STEP:
case PT_CONTINUE:
@@ -936,7 +943,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
p-p_sigparent = SIGCHLD;
}
p-p_oppid = 0;
-   p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK);
+   p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK |
+   P_FOLLOWEXEC);
 
/* should we send SIGCHLD? */
/* 

Re: [ptrace] please review follow fork/exec changes

2012-02-07 Thread John Baldwin
On Monday, February 06, 2012 10:12:11 pm David Xu wrote:
 On 2012/1/26 7:48, Dmitry Mikulin wrote:
  snip
 
  The debugger needs to intercept fork() in both parent and child so it 
  can detach from the old process and attach to the new one. Maybe it'll 
  make more sense in the context of gdb changes. Should I send them too? 
  Don't think Marcel included that patch...
 
 
  Does the orphan list change intended to not lost the child after fork ?
  But the child shall be traced, so debugger would get the SIGTRAP on
  the attach on fork returning to usermode. I remember that I explicitely
  tested this when adding followfork changes.
 
  Yes, the debugger gets SIGTRAPs. The problem arises when the real 
  parent of the forked process has the code to collect termination 
  status. Since attaching to a process changes the parent/child 
  relationships, we need to keep track of the children lost due to 
  re-parenting so we can properly attribute their exit status to the 
  real parent.
 
 I recall that someone brought a topic in the list said that this should 
 be fixed, debugging a process should not change
 parent-child relation, instead a new link list data structure should be 
 added to struct proc  to trace debugged process,
 this will make code clean with a small memory overhead.

Yes, I have some old patches to start on this, but I hadn't really finished
them, and it makes wait() a bit more complicated.  It would be nice if
ptrace() had its own pwait() or some such instead of overloading wait().

-- 
John Baldwin
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-02-07 Thread Dmitry Mikulin




So, do you in fact need to distinguish exec stops from syscall exit
against exec stops from PT_FOLLOW_EXEC,


This is pretty much what I need. It's the same stop in syscall return right? I 
don't want to change when the stop happens, I want to have an lwpinfo flag that 
tells me when a stop occurred in a process under PT_FOLLOW_EXEC.


@@ -889,7 +890,9 @@ exec_fail_dealloc:

if (error == 0) {
PROC_LOCK(p);
-   td-td_dbgflags |= TDB_EXEC;
+   if ((p-p_flag  P_TRACED) != 0
+   ((P_FOLLOWEXEC) != 0 || (p-p_stops  S_PT_SCX) != 0))
+   td-td_dbgflags |= TDB_EXEC;
PROC_UNLOCK(p);
  


There's a small bug in the patch that makes it not work. The check for 
P_FOLLOWEXEC should be:

+   ((p-p_flag  P_FOLLOWEXEC) != 0 || (p-p_stops  S_PT_SCX) != 
0))


Looks like the patch should work for me but I need to verify.
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-02-07 Thread Dmitry Mikulin

Well, that didn't work... Not sure why since it broke existing gdb. My guess is 
we're not getting the exec stops we used to get. Might have to wait till 
tomorrow to get more details.


On 02/07/2012 12:45 PM, Dmitry Mikulin wrote:




So, do you in fact need to distinguish exec stops from syscall exit
against exec stops from PT_FOLLOW_EXEC,


This is pretty much what I need. It's the same stop in syscall return right? I 
don't want to change when the stop happens, I want to have an lwpinfo flag that 
tells me when a stop occurred in a process under PT_FOLLOW_EXEC.


@@ -889,7 +890,9 @@ exec_fail_dealloc:

  if (error == 0) {
  PROC_LOCK(p);
-td-td_dbgflags |= TDB_EXEC;
+if ((p-p_flag  P_TRACED) != 0
+((P_FOLLOWEXEC) != 0 || (p-p_stops  S_PT_SCX) != 0))
+td-td_dbgflags |= TDB_EXEC;
  PROC_UNLOCK(p);


There's a small bug in the patch that makes it not work. The check for 
P_FOLLOWEXEC should be:

+((p-p_flag  P_FOLLOWEXEC) != 0 || (p-p_stops  S_PT_SCX) != 0))


Looks like the patch should work for me but I need to verify.

___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-02-06 Thread Dmitry Mikulin



I see what is going on. The wait loop for P_PPWAIT in do_fork() simply
do not allow the ptracestop() in the syscall return path to be reached.
There seems to be more problems. In particular, I do not see anything
which would prevent the child from being reapped while the loop is
executing (assume that the parent is multithreaded and other thread
processed SIGCHLD and called wait).

Lets deal with these bugs after your proposal for interface changes is
dealt with.


OK.



Yes, I agree with the proposal to add flag to the child lwp info.
I think it will be easier if the flag is different from PL_FLAG_FORKED.
I named it PL_FLAG_CHILD.

PT_FOLLOW_EXEC is easy to implement, but my question is, how can debugger
operate (correctly) if it ignores exec events ? After exec, the whole
cached state of the debuggee must be invalidated, and since debugger
ignores the notification when the invalidation shall be done, it probably
gets very confused.


You're right, the debugger needs to handle exec() events implicitly when it 
starts up executables. The problem is that there is OS-independent machinery in 
gdb which handles statup fork-exec sequence differently from when the debuggee 
itself does an exec(). Basically in the event handling code I need to be able 
to distinguish app startup by gdb from an exec done by the app. Other OS-es 
have flags like PL_FLAG_EXEC set on demand: they have an equivalent of 
PT_FOLLOW_EXEC. I attached a modified patch that solves the problem. It tries 
to separate the always-on TDB_EXEC from the on-demand TDB_FOLLOWEXEC without 
changing existing functionality. Let me know if it's acceptable.

Another issue I'm investigating is that after the switch-over to the child gdb 
gets a SIGHUP when it continues the child. I think it has to do with the 
re-parenting/orphan business. I'll let you know what I find, but if you have an 
idea what might be causing it, please let me know.

Thanks.
Dmitry.



Index: kern/kern_exec.c
===
--- kern/kern_exec.c	(revision 231088)
+++ kern/kern_exec.c	(working copy)
@@ -890,6 +890,8 @@ exec_fail_dealloc:
 	if (error == 0) {
 		PROC_LOCK(p);
 		td-td_dbgflags |= TDB_EXEC;
+		if (p-p_flag  P_FOLLOWEXEC)
+			td-td_dbgflags |= TDB_FOLLOWEXEC;
 		PROC_UNLOCK(p);
 
 		/*
Index: kern/kern_fork.c
===
--- kern/kern_fork.c	(revision 231088)
+++ kern/kern_fork.c	(working copy)
@@ -1035,7 +1035,9 @@ fork_return(struct thread *td, struct trapframe *f
 			p-p_oppid = p-p_pptr-p_pid;
 			proc_reparent(p, dbg);
 			sx_xunlock(proctree_lock);
+			td-td_dbgflags |= TDB_CHILD;
 			ptracestop(td, SIGSTOP);
+			td-td_dbgflags = ~TDB_CHILD;
 		} else {
 			/*
 			 * ... otherwise clear the request.
Index: kern/sys_process.c
===
--- kern/sys_process.c	(revision 231088)
+++ kern/sys_process.c	(working copy)
@@ -660,6 +660,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 	case PT_TO_SCX:
 	case PT_SYSCALL:
 	case PT_FOLLOW_FORK:
+	case PT_FOLLOW_EXEC:
 	case PT_DETACH:
 		sx_xlock(proctree_lock);
 		proctree_locked = 1;
@@ -873,6 +874,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 		else
 			p-p_flag = ~P_FOLLOWFORK;
 		break;
+	case PT_FOLLOW_EXEC:
+		if (data)
+			p-p_flag = ~P_FOLLOWEXEC;
+		else
+			p-p_flag |= P_FOLLOWEXEC;
+		break;
 
 	case PT_STEP:
 	case PT_CONTINUE:
@@ -936,7 +943,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 	p-p_sigparent = SIGCHLD;
 			}
 			p-p_oppid = 0;
-			p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK);
+			p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK |
+			P_FOLLOWEXEC);
 
 			/* should we send SIGCHLD? */
 			/* childproc_continued(p); */
@@ -1141,10 +1149,14 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 			pl-pl_flags |= PL_FLAG_SCX;
 		if (td2-td_dbgflags  TDB_EXEC)
 			pl-pl_flags |= PL_FLAG_EXEC;
+		if (td2-td_dbgflags  TDB_FOLLOWEXEC)
+			pl-pl_flags |= PL_FLAG_FOLLOWEXEC;
 		if (td2-td_dbgflags  TDB_FORK) {
 			pl-pl_flags |= PL_FLAG_FORKED;
 			pl-pl_child_pid = td2-td_dbg_forked;
 		}
+		if (td2-td_dbgflags  TDB_CHILD)
+			pl-pl_flags |= PL_FLAG_CHILD;
 		pl-pl_sigmask = td2-td_sigmask;
 		pl-pl_siglist = td2-td_siglist;
 		strcpy(pl-pl_tdname, td2-td_name);
Index: kern/subr_syscall.c
===
--- kern/subr_syscall.c	(revision 230847)
+++ kern/subr_syscall.c	(working copy)
@@ -216,7 +216,8 @@ syscallret(struct thread *td, int error, struct sy
 		((td-td_dbgflags  (TDB_FORK | TDB_EXEC)) != 0 ||
 		(p-p_stops  S_PT_SCX) != 0))
 			ptracestop(td, SIGTRAP);
-		td-td_dbgflags = ~(TDB_SCX | TDB_EXEC | TDB_FORK);
+		td-td_dbgflags = 
+			~(TDB_SCX | TDB_EXEC | TDB_FOLLOWEXEC | TDB_FORK);
 		PROC_UNLOCK(p);
 	}
 }
Index: sys/proc.h
===
--- sys/proc.h	(revision 231088)
+++ 

Re: [ptrace] please review follow fork/exec changes

2012-02-06 Thread Dmitry Mikulin

Oops, this should be the part of the patch that sets the flag:

@@ -873,6 +872,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid,
 else
 p-p_flag = ~P_FOLLOWFORK;
 break;
+case PT_FOLLOW_EXEC:
+if (data)
+p-p_flag |= P_FOLLOWEXEC;
+else
+p-p_flag = ~P_FOLLOWEXEC;
+break;

The SIGHUP I mentioned is due to the fact that the parent exits immediately. I 
guess that's not a particularly well written program.


On 02/06/2012 01:19 PM, Dmitry Mikulin wrote:



I see what is going on. The wait loop for P_PPWAIT in do_fork() simply
do not allow the ptracestop() in the syscall return path to be reached.
There seems to be more problems. In particular, I do not see anything
which would prevent the child from being reapped while the loop is
executing (assume that the parent is multithreaded and other thread
processed SIGCHLD and called wait).

Lets deal with these bugs after your proposal for interface changes is
dealt with.


OK.



Yes, I agree with the proposal to add flag to the child lwp info.
I think it will be easier if the flag is different from PL_FLAG_FORKED.
I named it PL_FLAG_CHILD.

PT_FOLLOW_EXEC is easy to implement, but my question is, how can debugger
operate (correctly) if it ignores exec events ? After exec, the whole
cached state of the debuggee must be invalidated, and since debugger
ignores the notification when the invalidation shall be done, it probably
gets very confused.


You're right, the debugger needs to handle exec() events implicitly when it 
starts up executables. The problem is that there is OS-independent machinery in 
gdb which handles statup fork-exec sequence differently from when the debuggee 
itself does an exec(). Basically in the event handling code I need to be able 
to distinguish app startup by gdb from an exec done by the app. Other OS-es 
have flags like PL_FLAG_EXEC set on demand: they have an equivalent of 
PT_FOLLOW_EXEC. I attached a modified patch that solves the problem. It tries 
to separate the always-on TDB_EXEC from the on-demand TDB_FOLLOWEXEC without 
changing existing functionality. Let me know if it's acceptable.

Another issue I'm investigating is that after the switch-over to the child gdb 
gets a SIGHUP when it continues the child. I think it has to do with the 
re-parenting/orphan business. I'll let you know what I find, but if you have an 
idea what might be causing it, please let me know.

Thanks.
Dmitry.




___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-02-06 Thread David Xu

On 2012/1/26 7:48, Dmitry Mikulin wrote:

snip


The debugger needs to intercept fork() in both parent and child so it 
can detach from the old process and attach to the new one. Maybe it'll 
make more sense in the context of gdb changes. Should I send them too? 
Don't think Marcel included that patch...




Does the orphan list change intended to not lost the child after fork ?
But the child shall be traced, so debugger would get the SIGTRAP on
the attach on fork returning to usermode. I remember that I explicitely
tested this when adding followfork changes.


Yes, the debugger gets SIGTRAPs. The problem arises when the real 
parent of the forked process has the code to collect termination 
status. Since attaching to a process changes the parent/child 
relationships, we need to keep track of the children lost due to 
re-parenting so we can properly attribute their exit status to the 
real parent.


I recall that someone brought a topic in the list said that this should 
be fixed, debugging a process should not change
parent-child relation, instead a new link list data structure should be 
added to struct proc  to trace debugged process,

this will make code clean with a small memory overhead.

Regards,
David Xu





___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-02-04 Thread Konstantin Belousov
On Fri, Feb 03, 2012 at 04:01:46PM -0800, Dmitry Mikulin wrote:
 
 Please provide more details, I am looking forward for the panic
 message and backtrace.
 
 I can't seem to get the panic with the latest source base, but tracing 
 doesn't appear to work with vfork(). I attached a modified test case to 
 closer model what gdb is doing. If you change fork() to vfork() in simple.c 
 the parent doesn't get the events the same way it does under fork().
I see what is going on. The wait loop for P_PPWAIT in do_fork() simply
do not allow the ptracestop() in the syscall return path to be reached.
There seems to be more problems. In particular, I do not see anything
which would prevent the child from being reapped while the loop is
executing (assume that the parent is multithreaded and other thread
processed SIGCHLD and called wait).

Lets deal with these bugs after your proposal for interface changes is
dealt with.

 
 The lack of the notification for parent is exactly what the patch I
 posted fixes. More exactly, it is the lack of notification for parent
 with PT_CONTINUE loop. I will commit this today.
 
 Regarding a single notification. Currently, parent arrives at the
 syscall return code only after the child is attached to the debugger.
 See the cv_wait() in kern_fork.c:739. In other words, if you get the
 PL_FLAG_FORK, the child is already attached (at last it shall be). My
 scescx.c code illustrates this well, IMO.
 
 You still get a separate stop from the child, but I do not see how is it
 harmful.
 
 There a couple of tweaks to the interface that I'd like to have:
 - set PL_FLAG_FORKED in the child so gdb can identify the stop as a fork() 
 event.
 - add a switch similar to PT_FOLLOW_FORK to enable/disable exec() 
 notifications. Gdb gets confused by the events it hasn't explicitly asked 
 for and having a switch makes it easier to filter out unwanted stops.
 
 Do you think it's possible/makes sense?

Yes, I agree with the proposal to add flag to the child lwp info.
I think it will be easier if the flag is different from PL_FLAG_FORKED.
I named it PL_FLAG_CHILD.

PT_FOLLOW_EXEC is easy to implement, but my question is, how can debugger
operate (correctly) if it ignores exec events ? After exec, the whole
cached state of the debuggee must be invalidated, and since debugger
ignores the notification when the invalidation shall be done, it probably
gets very confused.

Anyway, below is the combined patch that adds PL_FLAG_CHILD and
PT_FOLLOW_EXEC. If you agree with this, I will commit them (separately).

diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 135f798..c756777 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -889,7 +889,8 @@ exec_fail_dealloc:
 
if (error == 0) {
PROC_LOCK(p);
-   td-td_dbgflags |= TDB_EXEC;
+   if ((p-p_flag  P_NOFOLLOWEXEC) == 0)
+   td-td_dbgflags |= TDB_EXEC;
PROC_UNLOCK(p);
 
/*
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 60639c9..e447c93 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1035,7 +1035,9 @@ fork_return(struct thread *td, struct trapframe *frame)
p-p_oppid = p-p_pptr-p_pid;
proc_reparent(p, dbg);
sx_xunlock(proctree_lock);
+   td-td_dbgflags |= TDB_CHILD;
ptracestop(td, SIGSTOP);
+   td-td_dbgflags = ~TDB_CHILD;
} else {
/*
 * ... otherwise clear the request.
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 4510380..f58039a 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -660,6 +660,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
case PT_TO_SCX:
case PT_SYSCALL:
case PT_FOLLOW_FORK:
+   case PT_FOLLOW_EXEC:
case PT_DETACH:
sx_xlock(proctree_lock);
proctree_locked = 1;
@@ -873,6 +874,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
else
p-p_flag = ~P_FOLLOWFORK;
break;
+   case PT_FOLLOW_EXEC:
+   if (data)
+   p-p_flag = ~P_NOFOLLOWEXEC;
+   else
+   p-p_flag |= P_NOFOLLOWEXEC;
+   break;
 
case PT_STEP:
case PT_CONTINUE:
@@ -936,7 +943,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void 
*addr, int data)
p-p_sigparent = SIGCHLD;
}
p-p_oppid = 0;
-   p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK);
+   p-p_flag = ~(P_TRACED | P_WAITED | P_FOLLOWFORK |
+   P_NOFOLLOWEXEC);
 
/* should we send SIGCHLD? */
  

Re: [ptrace] please review follow fork/exec changes

2012-02-03 Thread Dmitry Mikulin



Please provide more details, I am looking forward for the panic
message and backtrace.


I can't seem to get the panic with the latest source base, but tracing doesn't 
appear to work with vfork(). I attached a modified test case to closer model 
what gdb is doing. If you change fork() to vfork() in simple.c the parent 
doesn't get the events the same way it does under fork().


The lack of the notification for parent is exactly what the patch I
posted fixes. More exactly, it is the lack of notification for parent
with PT_CONTINUE loop. I will commit this today.

Regarding a single notification. Currently, parent arrives at the
syscall return code only after the child is attached to the debugger.
See the cv_wait() in kern_fork.c:739. In other words, if you get the
PL_FLAG_FORK, the child is already attached (at last it shall be). My
scescx.c code illustrates this well, IMO.

You still get a separate stop from the child, but I do not see how is it
harmful.


There a couple of tweaks to the interface that I'd like to have:
- set PL_FLAG_FORKED in the child so gdb can identify the stop as a fork() 
event.
- add a switch similar to PT_FOLLOW_FORK to enable/disable exec() 
notifications. Gdb gets confused by the events it hasn't explicitly asked for 
and having a switch makes it easier to filter out unwanted stops.

Do you think it's possible/makes sense?

Thanks.
Dmitry.
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org

Re: [ptrace] please review follow fork/exec changes

2012-01-30 Thread Kostik Belousov
On Mon, Jan 30, 2012 at 10:26:25AM -0800, Dmitry Mikulin wrote:
 
 
 On 01/28/2012 11:48 PM, Kostik Belousov wrote:
 On Fri, Jan 27, 2012 at 10:12:13AM -0800, Dmitry Mikulin wrote:
 Attached are 4 separate patches for each somewhat independent  portion of
 the kernel work related to the follow-fork implementation.
 Ok, as I said, I think that vfork-fork.patch is just wrong.
 
 Gdb needs to be able to read/write process memory between the time the 
 child is forked and exec is called (in the vfork case). Without the change 
 it causes a kernel panic when gdb tries to read/write process memory. Since 
 my understanding of the kernel is a bit limited, it was the best I could do 
 at the time. I will send more details about the panic once I get a working 
 fbsd system again. Maybe there's a better way to deal with the panic.
Please provide more details, I am looking forward for the panic
message and backtrace.

 
 Lets postpone discussion of the orphan.patch for later.
 
 OK.
 
 
 The follow-fork.patch and follow-exec.patch make me wonder, and I
 already expressed my doubts. IMO, all features, except one bug, are
 already presented in the stock src.
 
 More, suggested follow-{fork,exec} patches break the SCE/SCX tracers
 notification of fork and exec events, since TDB_FORK and TBD_EXEC flags
 are consumed before syscall returns (I also said this previously).
 
 
 
 
 
 Namely, if the process is being debugged, the successfull [f]execve()
 causes unconditional stop even. This makes PT_FOLLOW_EXEC unneccessary.
 
 Existing PT_FOLLOW_FORK implementation indeed has a bug, which was not
 revealed by my testing during the development, because I only tested
 SCE/SCX scenario. Namely, if PT_FOLLOW_FORK is requested, but the next
 stop is not SCX, then follow-fork notification is not sent. After this
 nit is fixed, PT_FOLLOW_FORK caller gets stops for the child creation.
 Child is put into stop state as needed to not loose it.
 
 I think this will fix only a part of the problem, the one that relates to 
 PT_CONTINUE.
 
 I still need the change that forces a stop in both child and parent on 
 fork(). Without my changes the notification is generated in the child but 
 not in the parent. I need to be able to have both processes stopped in gdb 
 in order to clean up and detach from the parent, and initialize and attach 
 to the child. The main reason I need both processes stopped is that gdb has 
 to be able to read/write into both processes address space and registers.  
 Ideally I would like to have a single event generated for fork() at a point 
 where both child and parent are stopped and available for ptrace read/write 
 requests.  Do you think it's possible?
The lack of the notification for parent is exactly what the patch I
posted fixes. More exactly, it is the lack of notification for parent
with PT_CONTINUE loop. I will commit this today.

Regarding a single notification. Currently, parent arrives at the
syscall return code only after the child is attached to the debugger.
See the cv_wait() in kern_fork.c:739. In other words, if you get the
PL_FLAG_FORK, the child is already attached (at last it shall be). My
scescx.c code illustrates this well, IMO.

You still get a separate stop from the child, but I do not see how is it
harmful.


pgpDwYkpcgypf.pgp
Description: PGP signature


Re: [ptrace] please review follow fork/exec changes

2012-01-30 Thread Dmitry Mikulin



On 01/28/2012 11:48 PM, Kostik Belousov wrote:

On Fri, Jan 27, 2012 at 10:12:13AM -0800, Dmitry Mikulin wrote:

Attached are 4 separate patches for each somewhat independent  portion of
the kernel work related to the follow-fork implementation.

Ok, as I said, I think that vfork-fork.patch is just wrong.


Gdb needs to be able to read/write process memory between the time the child is 
forked and exec is called (in the vfork case). Without the change it causes a 
kernel panic when gdb tries to read/write process memory. Since my 
understanding of the kernel is a bit limited, it was the best I could do at the 
time. I will send more details about the panic once I get a working fbsd system 
again. Maybe there's a better way to deal with the panic.


Lets postpone discussion of the orphan.patch for later.


OK.



The follow-fork.patch and follow-exec.patch make me wonder, and I
already expressed my doubts. IMO, all features, except one bug, are
already presented in the stock src.

More, suggested follow-{fork,exec} patches break the SCE/SCX tracers
notification of fork and exec events, since TDB_FORK and TBD_EXEC flags
are consumed before syscall returns (I also said this previously).







Namely, if the process is being debugged, the successfull [f]execve()
causes unconditional stop even. This makes PT_FOLLOW_EXEC unneccessary.

Existing PT_FOLLOW_FORK implementation indeed has a bug, which was not
revealed by my testing during the development, because I only tested
SCE/SCX scenario. Namely, if PT_FOLLOW_FORK is requested, but the next
stop is not SCX, then follow-fork notification is not sent. After this
nit is fixed, PT_FOLLOW_FORK caller gets stops for the child creation.
Child is put into stop state as needed to not loose it.


I think this will fix only a part of the problem, the one that relates to 
PT_CONTINUE.

I still need the change that forces a stop in both child and parent on fork(). 
Without my changes the notification is generated in the child but not in the 
parent. I need to be able to have both processes stopped in gdb in order to 
clean up and detach from the parent, and initialize and attach to the child. 
The main reason I need both processes stopped is that gdb has to be able to 
read/write into both processes address space and registers.  Ideally I would 
like to have a single event generated for fork() at a point where both child 
and parent are stopped and available for ptrace read/write requests.  Do you 
think it's possible?



I updated the test program I use to test this functionality, see
http://people.freebsd.org/~kib/misc/scescx.c
The default or -s flag causes it to use SCE/SCX tracing, while -c flag
switches it to use PT_CONTINUE tracing, which should be the kind of loop
performed by normal debuggers. You can see the exec/fork events and
child auto-attach illustrated with this test.

Can you, please, provide the test-case which illustrates the omissions
in the existing API (with the patch below applied), if any ?

diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c
index bba4479..75328f6 100644
--- a/sys/kern/subr_syscall.c
+++ b/sys/kern/subr_syscall.c
@@ -212,7 +212,8 @@ syscallret(struct thread *td, int error, struct 
syscall_args *sa __unused)
 * executes.  If debugger requested tracing of syscall
 * returns, do it now too.
 */
-   if (traced  ((td-td_dbgflags  TDB_EXEC) != 0 ||
+   if (traced
+   ((td-td_dbgflags  (TDB_FORK | TDB_EXEC)) != 0 ||
(p-p_stops  S_PT_SCX) != 0))
ptracestop(td, SIGTRAP);
td-td_dbgflags= ~(TDB_SCX | TDB_EXEC | TDB_FORK);

___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-01-30 Thread Dmitry Mikulin




Gdb needs to be able to read/write process memory between the time the
child is forked and exec is called (in the vfork case). Without the change
it causes a kernel panic when gdb tries to read/write process memory. Since
my understanding of the kernel is a bit limited, it was the best I could do
at the time. I will send more details about the panic once I get a working
fbsd system again. Maybe there's a better way to deal with the panic.

Please provide more details, I am looking forward for the panic
message and backtrace.


As soon as I get my FreeBSD box fixed, hopefully tomorrow.





Lets postpone discussion of the orphan.patch for later.

OK.


The follow-fork.patch and follow-exec.patch make me wonder, and I
already expressed my doubts. IMO, all features, except one bug, are
already presented in the stock src.

More, suggested follow-{fork,exec} patches break the SCE/SCX tracers
notification of fork and exec events, since TDB_FORK and TBD_EXEC flags
are consumed before syscall returns (I also said this previously).





Namely, if the process is being debugged, the successfull [f]execve()
causes unconditional stop even. This makes PT_FOLLOW_EXEC unneccessary.

Existing PT_FOLLOW_FORK implementation indeed has a bug, which was not
revealed by my testing during the development, because I only tested
SCE/SCX scenario. Namely, if PT_FOLLOW_FORK is requested, but the next
stop is not SCX, then follow-fork notification is not sent. After this
nit is fixed, PT_FOLLOW_FORK caller gets stops for the child creation.
Child is put into stop state as needed to not loose it.

I think this will fix only a part of the problem, the one that relates to
PT_CONTINUE.

I still need the change that forces a stop in both child and parent on
fork(). Without my changes the notification is generated in the child but
not in the parent. I need to be able to have both processes stopped in gdb
in order to clean up and detach from the parent, and initialize and attach
to the child. The main reason I need both processes stopped is that gdb has
to be able to read/write into both processes address space and registers.
Ideally I would like to have a single event generated for fork() at a point
where both child and parent are stopped and available for ptrace read/write
requests.  Do you think it's possible?

The lack of the notification for parent is exactly what the patch I
posted fixes. More exactly, it is the lack of notification for parent
with PT_CONTINUE loop. I will commit this today.

Regarding a single notification. Currently, parent arrives at the
syscall return code only after the child is attached to the debugger.
See the cv_wait() in kern_fork.c:739. In other words, if you get the
PL_FLAG_FORK, the child is already attached (at last it shall be). My
scescx.c code illustrates this well, IMO.


OK, I see. I need to verify that it works with gdb and possibly tweak it to 
match the kernel.



You still get a separate stop from the child, but I do not see how is it
harmful.


It's not harmful as long as gdb can tell that those stops are generated by the 
fork().

___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: [ptrace] please review follow fork/exec changes

2012-01-28 Thread Kostik Belousov
On Fri, Jan 27, 2012 at 10:12:13AM -0800, Dmitry Mikulin wrote:
 Attached are 4 separate patches for each somewhat independent  portion of 
 the kernel work related to the follow-fork implementation.
Ok, as I said, I think that vfork-fork.patch is just wrong.
Lets postpone discussion of the orphan.patch for later.

The follow-fork.patch and follow-exec.patch make me wonder, and I
already expressed my doubts. IMO, all features, except one bug, are
already presented in the stock src.

More, suggested follow-{fork,exec} patches break the SCE/SCX tracers
notification of fork and exec events, since TDB_FORK and TBD_EXEC flags
are consumed before syscall returns (I also said this previously).

Namely, if the process is being debugged, the successfull [f]execve()
causes unconditional stop even. This makes PT_FOLLOW_EXEC unneccessary.

Existing PT_FOLLOW_FORK implementation indeed has a bug, which was not
revealed by my testing during the development, because I only tested
SCE/SCX scenario. Namely, if PT_FOLLOW_FORK is requested, but the next
stop is not SCX, then follow-fork notification is not sent. After this
nit is fixed, PT_FOLLOW_FORK caller gets stops for the child creation.
Child is put into stop state as needed to not loose it.

I updated the test program I use to test this functionality, see
http://people.freebsd.org/~kib/misc/scescx.c
The default or -s flag causes it to use SCE/SCX tracing, while -c flag
switches it to use PT_CONTINUE tracing, which should be the kind of loop
performed by normal debuggers. You can see the exec/fork events and
child auto-attach illustrated with this test.

Can you, please, provide the test-case which illustrates the omissions
in the existing API (with the patch below applied), if any ?

diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c
index bba4479..75328f6 100644
--- a/sys/kern/subr_syscall.c
+++ b/sys/kern/subr_syscall.c
@@ -212,7 +212,8 @@ syscallret(struct thread *td, int error, struct 
syscall_args *sa __unused)
 * executes.  If debugger requested tracing of syscall
 * returns, do it now too.
 */
-   if (traced  ((td-td_dbgflags  TDB_EXEC) != 0 ||
+   if (traced 
+   ((td-td_dbgflags  (TDB_FORK | TDB_EXEC)) != 0 ||
(p-p_stops  S_PT_SCX) != 0))
ptracestop(td, SIGTRAP);
td-td_dbgflags = ~(TDB_SCX | TDB_EXEC | TDB_FORK);


pgp116s22XAVu.pgp
Description: PGP signature


Re: [ptrace] please review follow fork/exec changes

2012-01-27 Thread Dmitry Mikulin

Attached are 4 separate patches for each somewhat independent  portion of the 
kernel work related to the follow-fork implementation.


On 01/26/2012 04:23 AM, Kostik Belousov wrote:

On Wed, Jan 25, 2012 at 03:48:04PM -0800, Dmitry Mikulin wrote:

Thanks for taking a look at it. I'll try to explain the changes the best I
can: the work was done nearly 6 months ago...


I would certainly appreciate some more words describing the changes.

What is the goal of introducing the PT_FOLLOW_EXEC ? To not force
the debugger to filter all syscall exits to see exec events ?

PT_FOLLOW_EXEC was added to trace the exec() family of calls. When it's
enabled, the kernel will generate a trap to give debugger a chance to clean
up old process info and initialize its state with the new binary.


It was more a question, why PT_FLAG_EXEC is not enough.




Why did you moved the stopevent/ptracestop for exec events from
syscallret() to kern_execve() ? If moving, why the handling of TDB_EXEC
is not removed from syscallret() ? I do not think that TDB_EXEC can be
seen there after the patch. The same question about TDB_FORK.

The reason I moved the event notifications from syscallret() is because the
debugger is interested successful completion of either fork or exec, not
just the fact that they have been called. If, say, a call to fork() failed,
as far as debugger is concerned, fork() might as well had never been
called. Having a ptracestop in syscallret triggered a trap on every return
from fork without telling the debugger whether a new process had been
created or not. Same goes for exec().

PT_FLAG_EXEC is only set if an exec-kind of syscall succeeded. The same
is true for PT_FLAG_FORKED, the flag is set only if a new child was
successfully created.


Looking at the code now I think I should have removed TDB_EXEC/TDB_FORK
processing from syscallret(). I'll do that and verify that it works as
expected.


If possible, I would greatly prefer to have fork changes separated.

You mean separate fork changes into a separate patch from exec changes?

Yes. Even more, it seems that fork changes should be separated into
bug fixes and new functionality.


I doubt that disallowing RFMEM while tracing is the right change. It may
be to fix some (undescribed) bug, but RFMEM is documented behaviour used
not only for vfork(2), and the change just breaks rfork(2) for debugged
processes.

Even vfork() should not be broken, since I believe there are programs
that rely on the vfork() model, in particular, C shell. It will be
broken if vfork() is substituted by fork(). The fact that it breaks only
under debugger will make it esp. confusing.

I need to dig up the details since I can't recall the exact reason for
forcing fork() in cases of user calls to vfork() under gdb. I believe it
had to do with when child process memory was available for writing in case
of vfork() and it wasn't early enough to complete the switch over from
parent to child in gdb. After consulting with our internal kernel experts
we decided that doing fork() instead of vfork() under gdb is a low impact
change.


Why do we need to have TDB_FORK set for td2 ?

The debugger needs to intercept fork() in both parent and child so it can
detach from the old process and attach to the new one. Maybe it'll make
more sense in the context of gdb changes. Should I send them too? Don't
think Marcel included that patch...

No, I think the kernel changes are enough for now.


Does the orphan list change intended to not lost the child after fork ?
But the child shall be traced, so debugger would get the SIGTRAP on
the attach on fork returning to usermode. I remember that I explicitely
tested this when adding followfork changes.

Yes, the debugger gets SIGTRAPs. The problem arises when the real parent of
the forked process has the code to collect termination status. Since
attaching to a process changes the parent/child relationships, we need to
keep track of the children lost due to re-parenting so we can properly
attribute their exit status to the real parent.


I do not quite understand it. From the description it sounds as the problem
that is not related to follow fork changes at all, and shall be presented
regardless of the follow fork. If yes, I think this shall be separated
into a standalone patch.



Index: sys/kern/kern_exec.c
===
--- sys/kern/kern_exec.c	(revision 230617)
+++ sys/kern/kern_exec.c	(working copy)
@@ -55,6 +55,7 @@
 #include sys/priv.h
 #include sys/proc.h
 #include sys/pioctl.h
+#include sys/ptrace.h
 #include sys/namei.h
 #include sys/resourcevar.h
 #include sys/sdt.h
@@ -888,16 +889,22 @@
 	free(imgp-freepath, M_TEMP);
 
 	if (error == 0) {
+		if ((p-p_flag  (P_TRACED | P_FOLLOWEXEC)) == 
+		(P_TRACED |	P_FOLLOWEXEC)) {
+			PROC_LOCK(p);
+			td-td_dbgflags |= TDB_EXEC;
+			PROC_UNLOCK(p);
+		}
+ 		/*
+ 		 * Stop the process here if its stop event mask has
+ 		 * the S_EXEC bit set.
+ 		 */
+ 		STOPEVENT(p, 

Re: [ptrace] please review follow fork/exec changes

2012-01-26 Thread Kostik Belousov
On Wed, Jan 25, 2012 at 03:48:04PM -0800, Dmitry Mikulin wrote:
 Thanks for taking a look at it. I'll try to explain the changes the best I 
 can: the work was done nearly 6 months ago...
 
 I would certainly appreciate some more words describing the changes.
 
 What is the goal of introducing the PT_FOLLOW_EXEC ? To not force
 the debugger to filter all syscall exits to see exec events ?
 
 PT_FOLLOW_EXEC was added to trace the exec() family of calls. When it's 
 enabled, the kernel will generate a trap to give debugger a chance to clean 
 up old process info and initialize its state with the new binary.
 
It was more a question, why PT_FLAG_EXEC is not enough.

 
 
 
 Why did you moved the stopevent/ptracestop for exec events from
 syscallret() to kern_execve() ? If moving, why the handling of TDB_EXEC
 is not removed from syscallret() ? I do not think that TDB_EXEC can be
 seen there after the patch. The same question about TDB_FORK.
 
 The reason I moved the event notifications from syscallret() is because the 
 debugger is interested successful completion of either fork or exec, not 
 just the fact that they have been called. If, say, a call to fork() failed, 
 as far as debugger is concerned, fork() might as well had never been 
 called. Having a ptracestop in syscallret triggered a trap on every return 
 from fork without telling the debugger whether a new process had been 
 created or not. Same goes for exec().
PT_FLAG_EXEC is only set if an exec-kind of syscall succeeded. The same
is true for PT_FLAG_FORKED, the flag is set only if a new child was
successfully created.

 
 Looking at the code now I think I should have removed TDB_EXEC/TDB_FORK 
 processing from syscallret(). I'll do that and verify that it works as 
 expected.
 
 
 If possible, I would greatly prefer to have fork changes separated.
 
 You mean separate fork changes into a separate patch from exec changes?
Yes. Even more, it seems that fork changes should be separated into
bug fixes and new functionality.

 
 
 I doubt that disallowing RFMEM while tracing is the right change. It may
 be to fix some (undescribed) bug, but RFMEM is documented behaviour used
 not only for vfork(2), and the change just breaks rfork(2) for debugged
 processes.
 
 Even vfork() should not be broken, since I believe there are programs
 that rely on the vfork() model, in particular, C shell. It will be
 broken if vfork() is substituted by fork(). The fact that it breaks only
 under debugger will make it esp. confusing.
 
 I need to dig up the details since I can't recall the exact reason for 
 forcing fork() in cases of user calls to vfork() under gdb. I believe it 
 had to do with when child process memory was available for writing in case 
 of vfork() and it wasn't early enough to complete the switch over from 
 parent to child in gdb. After consulting with our internal kernel experts 
 we decided that doing fork() instead of vfork() under gdb is a low impact 
 change.
 
 
 Why do we need to have TDB_FORK set for td2 ?
 
 The debugger needs to intercept fork() in both parent and child so it can 
 detach from the old process and attach to the new one. Maybe it'll make 
 more sense in the context of gdb changes. Should I send them too? Don't 
 think Marcel included that patch...
No, I think the kernel changes are enough for now.

 
 
 Does the orphan list change intended to not lost the child after fork ?
 But the child shall be traced, so debugger would get the SIGTRAP on
 the attach on fork returning to usermode. I remember that I explicitely
 tested this when adding followfork changes.
 
 Yes, the debugger gets SIGTRAPs. The problem arises when the real parent of 
 the forked process has the code to collect termination status. Since 
 attaching to a process changes the parent/child relationships, we need to 
 keep track of the children lost due to re-parenting so we can properly 
 attribute their exit status to the real parent.
 
I do not quite understand it. From the description it sounds as the problem
that is not related to follow fork changes at all, and shall be presented
regardless of the follow fork. If yes, I think this shall be separated
into a standalone patch.


pgphUacrPo7lj.pgp
Description: PGP signature


Re: [ptrace] please review follow fork/exec changes

2012-01-26 Thread Dmitry Mikulin



On 01/26/2012 04:23 AM, Kostik Belousov wrote:

On Wed, Jan 25, 2012 at 03:48:04PM -0800, Dmitry Mikulin wrote:

Thanks for taking a look at it. I'll try to explain the changes the best I
can: the work was done nearly 6 months ago...


I would certainly appreciate some more words describing the changes.

What is the goal of introducing the PT_FOLLOW_EXEC ? To not force
the debugger to filter all syscall exits to see exec events ?

PT_FOLLOW_EXEC was added to trace the exec() family of calls. When it's
enabled, the kernel will generate a trap to give debugger a chance to clean
up old process info and initialize its state with the new binary.


It was more a question, why PT_FLAG_EXEC is not enough.


I don't see it in the code (sp?)  If you mean PL_FLAG_FORKED, than it's used to 
return lwpinfo, and PT_FOLLOW_EXEC is a ptrace request.






Why did you moved the stopevent/ptracestop for exec events from
syscallret() to kern_execve() ? If moving, why the handling of TDB_EXEC
is not removed from syscallret() ? I do not think that TDB_EXEC can be
seen there after the patch. The same question about TDB_FORK.

The reason I moved the event notifications from syscallret() is because the
debugger is interested successful completion of either fork or exec, not
just the fact that they have been called. If, say, a call to fork() failed,
as far as debugger is concerned, fork() might as well had never been
called. Having a ptracestop in syscallret triggered a trap on every return
from fork without telling the debugger whether a new process had been
created or not. Same goes for exec().

PT_FLAG_EXEC is only set if an exec-kind of syscall succeeded. The same
is true for PT_FLAG_FORKED, the flag is set only if a new child was
successfully created.


I found the test cases you sent me for your fork/exec tracing changes and now I 
see why I needed to make some of the changes. Before my patches tracing of 
fork/exec is done via PT_TO_SCE/PT_TO_SCX ptrace calls. Their semantics did not 
fit well into what gdb needs to do. They operate as a variant of PT_CONTINUE. 
What gdb needs is a process-wide setting that instructs the kernel to generate 
SIGTRAPs in fork/exec when the process is being controlled via the regular 
ptrace(PT_CONTINUE)/wait() sequence.




Looking at the code now I think I should have removed TDB_EXEC/TDB_FORK
processing from syscallret(). I'll do that and verify that it works as
expected.


If possible, I would greatly prefer to have fork changes separated.

You mean separate fork changes into a separate patch from exec changes?

Yes. Even more, it seems that fork changes should be separated into
bug fixes and new functionality.


OK, that's doable.




I doubt that disallowing RFMEM while tracing is the right change. It may
be to fix some (undescribed) bug, but RFMEM is documented behaviour used
not only for vfork(2), and the change just breaks rfork(2) for debugged
processes.

Even vfork() should not be broken, since I believe there are programs
that rely on the vfork() model, in particular, C shell. It will be
broken if vfork() is substituted by fork(). The fact that it breaks only
under debugger will make it esp. confusing.

I need to dig up the details since I can't recall the exact reason for
forcing fork() in cases of user calls to vfork() under gdb. I believe it
had to do with when child process memory was available for writing in case
of vfork() and it wasn't early enough to complete the switch over from
parent to child in gdb. After consulting with our internal kernel experts
we decided that doing fork() instead of vfork() under gdb is a low impact
change.


Why do we need to have TDB_FORK set for td2 ?

The debugger needs to intercept fork() in both parent and child so it can
detach from the old process and attach to the new one. Maybe it'll make
more sense in the context of gdb changes. Should I send them too? Don't
think Marcel included that patch...

No, I think the kernel changes are enough for now.


Does the orphan list change intended to not lost the child after fork ?
But the child shall be traced, so debugger would get the SIGTRAP on
the attach on fork returning to usermode. I remember that I explicitely
tested this when adding followfork changes.

Yes, the debugger gets SIGTRAPs. The problem arises when the real parent of
the forked process has the code to collect termination status. Since
attaching to a process changes the parent/child relationships, we need to
keep track of the children lost due to re-parenting so we can properly
attribute their exit status to the real parent.


I do not quite understand it. From the description it sounds as the problem
that is not related to follow fork changes at all, and shall be presented
regardless of the follow fork. If yes, I think this shall be separated
into a standalone patch.


You're right, it's not related. It just happened to prevent me from finishing 
the work.
I'll break up the changes into multiple patches and re-send.



Re: [ptrace] please review follow fork/exec changes

2012-01-25 Thread Dmitry Mikulin

Thanks for taking a look at it. I'll try to explain the changes the best I can: 
the work was done nearly 6 months ago...


I would certainly appreciate some more words describing the changes.

What is the goal of introducing the PT_FOLLOW_EXEC ? To not force
the debugger to filter all syscall exits to see exec events ?


PT_FOLLOW_EXEC was added to trace the exec() family of calls. When it's 
enabled, the kernel will generate a trap to give debugger a chance to clean up 
old process info and initialize its state with the new binary.





Why did you moved the stopevent/ptracestop for exec events from
syscallret() to kern_execve() ? If moving, why the handling of TDB_EXEC
is not removed from syscallret() ? I do not think that TDB_EXEC can be
seen there after the patch. The same question about TDB_FORK.


The reason I moved the event notifications from syscallret() is because the 
debugger is interested successful completion of either fork or exec, not just 
the fact that they have been called. If, say, a call to fork() failed, as far 
as debugger is concerned, fork() might as well had never been called. Having a 
ptracestop in syscallret triggered a trap on every return from fork without 
telling the debugger whether a new process had been created or not. Same goes 
for exec().

Looking at the code now I think I should have removed TDB_EXEC/TDB_FORK 
processing from syscallret(). I'll do that and verify that it works as expected.



If possible, I would greatly prefer to have fork changes separated.


You mean separate fork changes into a separate patch from exec changes?



I doubt that disallowing RFMEM while tracing is the right change. It may
be to fix some (undescribed) bug, but RFMEM is documented behaviour used
not only for vfork(2), and the change just breaks rfork(2) for debugged
processes.

Even vfork() should not be broken, since I believe there are programs
that rely on the vfork() model, in particular, C shell. It will be
broken if vfork() is substituted by fork(). The fact that it breaks only
under debugger will make it esp. confusing.


I need to dig up the details since I can't recall the exact reason for forcing 
fork() in cases of user calls to vfork() under gdb. I believe it had to do with 
when child process memory was available for writing in case of vfork() and it 
wasn't early enough to complete the switch over from parent to child in gdb. 
After consulting with our internal kernel experts we decided that doing fork() 
instead of vfork() under gdb is a low impact change.



Why do we need to have TDB_FORK set for td2 ?


The debugger needs to intercept fork() in both parent and child so it can 
detach from the old process and attach to the new one. Maybe it'll make more 
sense in the context of gdb changes. Should I send them too? Don't think Marcel 
included that patch...



Does the orphan list change intended to not lost the child after fork ?
But the child shall be traced, so debugger would get the SIGTRAP on
the attach on fork returning to usermode. I remember that I explicitely
tested this when adding followfork changes.


Yes, the debugger gets SIGTRAPs. The problem arises when the real parent of the forked 
process has the code to collect termination status. Since attaching to a process changes 
the parent/child relationships, we need to keep track of the children lost due to 
re-parenting so we can properly attribute their exit status to the real 
parent.


___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


[ptrace] please review follow fork/exec changes

2012-01-24 Thread Marcel Moolenaar
All,

Please review the attached changes (done by Dmitry -- CC'd) to add support for
PT_FOLLOW_EXEC and cleanup PT_FOLLOW_FORK.

I'll commit this when there are no comments/objections.
Thanks,

-- 
Marcel Moolenaar
marc...@juniper.net

Index: sys/kern/kern_exit.c

===

--- sys/kern/kern_exit.c	(revision 225189)

+++ sys/kern/kern_exit.c	(working copy)

@@ -680,7 +680,7 @@ wait4(struct thread *td, struct wait_args *uap)

  */

 void

 proc_reap(struct thread *td, struct proc *p, int *status, int options,

-struct rusage *rusage)

+struct rusage *rusage, int child)

 {

 	struct proc *q, *t;

 

@@ -720,7 +720,6 @@ proc_reap(struct thread *td, struct proc *p, int *

 	if (p-p_oppid  (t = pfind(p-p_oppid)) != NULL) {

 		PROC_LOCK(p);

 		proc_reparent(p, t);

-		p-p_pptr-p_dbg_child--;

 		p-p_oppid = 0;

 		PROC_UNLOCK(p);

 		pksignal(t, SIGCHLD, p-p_ksi);

@@ -738,7 +737,10 @@ proc_reap(struct thread *td, struct proc *p, int *

 	sx_xlock(allproc_lock);

 	LIST_REMOVE(p, p_list);	/* off zombproc */

 	sx_xunlock(allproc_lock);

-	LIST_REMOVE(p, p_sibling);

+	if (child)

+		LIST_REMOVE(p, p_sibling);

+	else

+		LIST_REMOVE(p, p_orphan);

 	leavepgrp(p);

 #ifdef PROCDESC

 	if (p-p_procdesc != NULL)

@@ -859,7 +861,7 @@ loop:

 		nfound++;

 		PROC_SLOCK(p);

 		if (p-p_state == PRS_ZOMBIE) {

-			proc_reap(td, p, status, options, rusage);

+			proc_reap(td, p, status, options, rusage, 1);

 			return (0);

 		}

 		if ((p-p_flag  P_STOPPED_SIG) 

@@ -893,16 +895,47 @@ loop:

 

 			if (status)

 *status = SIGCONT;

+		}

+		PROC_UNLOCK(p);

+	}

+	LIST_FOREACH(p, q-p_orphans, p_orphan) {

+		PROC_LOCK(p);

+		if (pid != WAIT_ANY 

+		p-p_pid != pid  p-p_pgid != -pid) {

+			PROC_UNLOCK(p);

+			continue;

+		}

+		if (p_canwait(td, p)) {

+			PROC_UNLOCK(p);

+			continue;

+		}

+

+		/*

+		 * This special case handles a kthread spawned by linux_clone

+		 * (see linux_misc.c).  The linux_wait4 and linux_waitpid

+		 * functions need to be able to distinguish between waiting

+		 * on a process and waiting on a thread.  It is a thread if

+		 * p_sigparent is not SIGCHLD, and the WLINUXCLONE option

+		 * signifies we want to wait for threads and not processes.

+		 */

+		if ((p-p_sigparent != SIGCHLD) ^

+		((options  WLINUXCLONE) != 0)) {

+			PROC_UNLOCK(p);

+			continue;

+		}

+

+		nfound++;

+		PROC_SLOCK(p);

+		if (p-p_state == PRS_ZOMBIE) {

+		  proc_reap(td, p, status, options, rusage, 0);

 			return (0);

 		}

+		PROC_SUNLOCK(p);

 		PROC_UNLOCK(p);

 	}

 	if (nfound == 0) {

 		sx_xunlock(proctree_lock);

-		if (td-td_proc-p_dbg_child)

-			return (0);

-		else

-			return (ECHILD);

+		return (ECHILD);

 	}

 	if (options  WNOHANG) {

 		sx_xunlock(proctree_lock);

@@ -932,6 +965,7 @@ proc_reparent(struct proc *child, struct proc *par

 #ifdef RACCT

 	int locked;

 #endif

+	struct proc *p;

 

 	sx_assert(proctree_lock, SX_XLOCKED);

 	PROC_LOCK_ASSERT(child, MA_OWNED);

@@ -952,5 +986,17 @@ proc_reparent(struct proc *child, struct proc *par

 	PROC_UNLOCK(child-p_pptr);

 	LIST_REMOVE(child, p_sibling);

 	LIST_INSERT_HEAD(parent-p_children, child, p_sibling);

+

+	LIST_FOREACH(p, parent-p_orphans, p_orphan) {

+		if (p == child) {

+			LIST_REMOVE(child, p_orphan);

+			break;

+		}

+	}

+	if (child-p_flag  P_TRACED) {

+		LIST_INSERT_HEAD(child-p_pptr-p_orphans, child, p_orphan);

+		PROC_UNLOCK(child);

+		PROC_LOCK(child);

+	}

 	child-p_pptr = parent;

 }

Index: sys/kern/kern_exec.c

===

--- sys/kern/kern_exec.c	(revision 225189)

+++ sys/kern/kern_exec.c	(working copy)

@@ -55,6 +55,7 @@ __FBSDID($FreeBSD$);

 #include sys/priv.h

 #include sys/proc.h

 #include sys/pioctl.h

+#include sys/ptrace.h

 #include sys/namei.h

 #include sys/resourcevar.h

 #include sys/sdt.h

@@ -895,16 +896,22 @@ exec_fail_dealloc:

 	free(imgp-freepath, M_TEMP);

 

 	if (error == 0) {

+		if ((p-p_flag  (P_TRACED | P_FOLLOWEXEC)) == 

+		(P_TRACED |	P_FOLLOWEXEC)) {

+			PROC_LOCK(p);

+			td-td_dbgflags |= TDB_EXEC;

+			PROC_UNLOCK(p);

+		}

+ 		/*

+ 		 * Stop the process here if its stop event mask has

+ 		 * the S_EXEC bit set.

+ 		 */

+ 		STOPEVENT(p, S_EXEC, 0);

+		PTRACESTOP_SC(p, td, S_PT_EXEC);

 		PROC_LOCK(p);

-		td-td_dbgflags |= TDB_EXEC;

+		td-td_dbgflags = ~TDB_EXEC;

 		PROC_UNLOCK(p);

-

-		/*

-		 * Stop the process here if its stop event mask has

-		 * the S_EXEC bit set.

-		 */

-		STOPEVENT(p, S_EXEC, 0);

-		goto done2;

+ 		goto done2;

 	}

 

 exec_fail:

Index: sys/kern/kern_fork.c

===

--- sys/kern/kern_fork.c	(revision 225189)

+++ sys/kern/kern_fork.c	(working copy)

@@ -59,6 +59,7 @@ __FBSDID($FreeBSD$);

 #include sys/proc.h

 #include sys/procdesc.h

 #include sys/pioctl.h

+#include sys/ptrace.h

 #include sys/racct.h

 #include 

Re: [ptrace] please review follow fork/exec changes

2012-01-24 Thread Kostik Belousov
On Tue, Jan 24, 2012 at 01:36:55PM -0800, Marcel Moolenaar wrote:
 All,
 
 Please review the attached changes (done by Dmitry -- CC'd) to add support for
 PT_FOLLOW_EXEC and cleanup PT_FOLLOW_FORK.
 
 I'll commit this when there are no comments/objections.
 Thanks,

I would certainly appreciate some more words describing the changes.

What is the goal of introducing the PT_FOLLOW_EXEC ? To not force
the debugger to filter all syscall exits to see exec events ?

Why did you moved the stopevent/ptracestop for exec events from
syscallret() to kern_execve() ? If moving, why the handling of TDB_EXEC
is not removed from syscallret() ? I do not think that TDB_EXEC can be
seen there after the patch. The same question about TDB_FORK.

If possible, I would greatly prefer to have fork changes separated.

I doubt that disallowing RFMEM while tracing is the right change. It may
be to fix some (undescribed) bug, but RFMEM is documented behaviour used
not only for vfork(2), and the change just breaks rfork(2) for debugged
processes.

Even vfork() should not be broken, since I believe there are programs
that rely on the vfork() model, in particular, C shell. It will be
broken if vfork() is substituted by fork(). The fact that it breaks only
under debugger will make it esp. confusing.

Why do we need to have TDB_FORK set for td2 ?

Does the orphan list change intended to not lost the child after fork ?
But the child shall be traced, so debugger would get the SIGTRAP on
the attach on fork returning to usermode. I remember that I explicitely
tested this when adding followfork changes.


pgp3FXLhsTAQ8.pgp
Description: PGP signature