truss -f "hangs" when traced process vfork()s

From: Sam Lawrance <boris_at_brooknet.com.au>
Date: Mon, 13 Sep 2004 21:51:36 +1000
Hello,

If I run "truss -f make clean" in a port directory, I wind up with a
situation like the following.

There are three processes concerned: truss, the initially traced
process, and the newly forked child:

root    77739  0.0  0.2  1304  764  v1  I+    7:50PM   0:00.02 truss -f
make clean
root    77740  0.0  0.1   540  376  v1  DL+   7:50PM   0:00.01 make
clean
root    77741  0.0  0.1   540  376  v1  DV+   7:50PM   0:00.00 make
clean

Backtrace of truss. Truss is waiting for an event to be reported from
procfs (everything past msleep omitted).

msleep(c1c07f28,c1c07e6c,15c,c08052e3,0) at msleep+0x312
procfs_ioctl(c16ee960,c1c07e00,c173d480,40147004,ce674c60) at
procfs_ioctl+0x139
pfs_ioctl(ce674b88) at pfs_ioctl+0xd9
vn_ioctl(c2f0ae14,40147004,ce674c60,c293bc00,c16ee960) at vn_ioctl+0x187
ioctl(c16ee960,ce674d14,3,1,292) at ioctl+0x551
syscall(2f,2f,2f,8057038,2) at syscall+0x283
Xint0x80_syscall() at Xint0x80_syscall+0x1f
--- syscall (54, FreeBSD ELF32, ioctl), eip = 0x280d8123, esp =
0xbfbfeccc, ebp = 0xbfbfed50 ---

Backtrace of the initially traced process. The process has vfork()ed and
is awaiting return from fork1(). vfork() calls fork1() with the RFPPWAIT
flag set, so the syscall won't return until the child process exits.

msleep(c1c07e00,c1c0706c,5c,c080749a,0) at msleep+0x322
fork1(c1908c80,80000034,0,d33b9ce4,c1908c80) at fork1+0x14f9
vfork(c1908c80,d33b9d14,0,1,213) at vfork+0x1b
syscall(2f,2f,2f,8080ba5,0) at syscall+0x283
Xint0x80_syscall() at Xint0x80_syscall+0x1f
--- syscall (66, FreeBSD ELF32, vfork), eip = 0x805c0a0, esp =
0xbfbfd780, ebp = 0xbfbfdbb8 ---

Backtrace of the child process. The process has been stopped because it
has generated an event and has tracing flags set (like its parent).

msleep(c1c0712c,c1c0706c,5c,c080b3bb,0,c1c07128) at msleep+0x322
stopevent(c1c07000,4,1) at stopevent+0x54
syscall(2f,2f,2f,0,0) at syscall+0x1f7
Xint0x80_syscall() at Xint0x80_syscall+0x1f
--- syscall (6, FreeBSD ELF32, close), eip = 0x8064d03, esp =
0xbfbfd76c, ebp = 0xbfbfdbb8 ---

Normally, truss will fork a copy of itself to trace the child process
once it gets the PID. However, the initially traced process is still in
vfork().

So:
- truss is waiting (PIOCFWAIT) for the initially traced process to stop
- the initially traced process is waiting for vfork() to return
- the child process created by the vfork() has been created, stopped at
the first event, and is waiting to be continued (PIOCCONT)
- but since truss is still waiting for for the initial process to stop
on return from vfork(), it doesn't have a PID for the child, and so has
not forked another truss to trace the child. The child is stranded and
won't return.

I haven't thought much about a solution, but perhaps truss needs to fork
at syscall entry rather than syscall exit, in cases where the traced
process has executed a fork that RFPPWAITs.

Is this right? Shall I file a PR?

--
FreeBSD dirk.no.domain 5.3-BETA4 FreeBSD 5.3-BETA4 #5: Mon Sep 13
11:20:19 EST 2004 sam_at_dirk.no.domain:/usr/obj/usr/src/sys/GENERIC i386
Received on Mon Sep 13 2004 - 09:50:26 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:11 UTC