tracing system calls (long)

Roger A. Faulkner raf at andante.UUCP
Sun Sep 4 17:55:41 AEST 1988


In article <66624 at sun.uucp> brent%terra at Sun.COM (Brent Callaghan) writes:
>In article <2040 at cuuxb.ATT.COM>, dlm at cuuxb.ATT.COM (Dennis L. Mumaugh) writes:
>> 1).  We have a system call trace program that reports on each and
>> every system call a process makes -- useful for support to figure
>> out what a program  REALLY  is  doing.

[ Dennis was referring to AT&T's as yet unreleased truss(1) command. ]

>And how!  Actually any SunOs 4.0 user can do that now with
>the trace(1) command.

[ output of 'trace date' omitted ]

Great minds run in the same paths, with some variations.
AT&T's truss(1) command was developed without any knowledge of Sun's trace(1)
command's actual or planned existence.  I presume the reverse is also true.

I wish to point out some of the ways in which AT&T's truss(1) is superior to
Sun's trace(1).  I do not especially want to put Sun down (though some could
read it that way), only to indicate some shortcomings in what they have done
and to impress on your minds some of the delicacy of debugger interfaces.

Sun does get credit for being first; trace(1) is already available on SunOS
4.0 while truss(1) is planned for a future release of System V from AT&T.
And no, it is not available in SVR3.2 as of now; it does exist as an add-on
package for SVR3.1 and SVR3.2 on the 3B2, but not yet to the outside world.
Complain to AT&T, not to me.

First and foremost, it must be observed that trace(1) is based on Sun's
enhanced ptrace(2) system call while truss(1) is based on AT&T's proc(4)
process filesystem, invented by Tom Killian of Bell Labs research and
extended and implemented for System V by Ron Gomes, with significant
input from me.  The deficiencies in trace(1) are largely due to the
deficiencies in ptrace(2) as compared to proc(4).

Ron Gomes did proc(4), I did truss(1); the credit (or blame) goes to us.

1. truss(1) can follow children created by fork(2).  You can trace a shell
   script of arbitrary complexity.  My favorite is spell(1), which runs
   an 8-member pipeline.  trace(1) can't do this because the ptrace(2)ed
   condition is not inherited; proc(4) tracing flags can be inherited.

2. Both trace(1) and truss(1) can grab existing processes.  However,
   truss(1) will grab an arbitrary number while trace(1) will grab only
   one.  Also, there is a bug in ptrace(2):  If a process terminates
   while being traced, its termination status is delivered (via wait(2))
   to the controlling process, not to the process's parent.  If a process
   is grabbed by trace(1) and then dies on a signal, the process's parent
   is not informed of the termination; to it, the process just vanished.
   (Terminating via exit(2) works OK because trace(1) lets go in time.)

3. truss(1) allows you to specify which system calls you wish to trace
   or exclude.  trace(1) traces all syscalls regardless.  proc(4) accepts
   a bit-mask to specify which syscalls to stop on; ptrace(2) stops on
   all syscalls.  Untraced syscalls incur no overhead with proc(4).

4. truss(1) does symbolic interpretation of syscall arguments, using
   #define names from relevant system header files.  trace(1) shows
   arguments only in decimal, octal, or hexadecimal.  truss(1) has
   an option to turn off symbolic interpretation, for unredeemed
   hackers like me who must see the raw bits to be happy.

5. truss(1) (verbose option) shows the contents of structures passed by
   address to specified system calls.  The contents are shown on output;
   values passed back from the operating system (like the stat structure
   from stat(2)) are displayed properly.  trace(1) doesn't do this.

6. truss(1) shows all characters of any filename argument; trace(1)
   shows only the first 32.  This is related to the next item.

7. trace(1) uses a heuristic based on the number of printable characters
   in the first 32 bytes of the I/O buffer for a read(2) or write(2) to
   decide whether or not to print the first 32 bytes of the buffer as a
   string (ambiguously, since '\' may or may not be an actual character
   in the I/O buffer).  truss(1) always prints the first 16 bytes in an
   unambiguous format.  Also, truss(1) accepts an option to print the
   entire contents of the I/O buffer for read()s or write()s on specified
   file descriptors.  This feature came only after I had an opportunity
   to play directly with trace(1); kudos to Sun, this is very useful.

8. truss(1) optionally prints the argument and environment strings passed
   in each exec(2) system call.  trace(1) could do this too, but it is
   useful mostly when following children, which trace(1) can't do.

9. Both truss(1) and trace(1) accept an option to count system calls rather
   than showing them line-by-line.  truss(1) only counts those syscalls which
   are being traced; child process syscalls may be included in the counts.

10.truss(1) reports sleeping system calls as "sleeping ..." if they remain
   asleep for more than 2 seconds.  trace(1) can't do this because of the
   ptrace(2) interface.

11.Both truss(1) and trace(1) report the receipt of signals.  Neither
   reports a signal before it is received (sent but blocked).  truss(1),
   by virtue of the proc(4) interface, reports any machine fault which
   the process incurs when it is incurred, even if the associated signal
   is blocked; trace(1) cannot do this with ptrace(2).

12.truss(1) accepts options to trace or exclude specified signals or
   machine faults.  proc(4) accepts a bit-mask of signals or faults
   to stop upon; ptrace(2) stops on all signals but no faults.

13.When truss(1) encounters an exec(2) of a set-uid or set-gid object
   (a process tracing security violation), proc(4) forces it to give up
   and allow the process to continue unmolested.  When trace(1) encounters
   such an exec(2), ptrace(2) silently disables the setting of the set-uid
   or set-gid and trace(1) continues to trace the process.  The process
   will eventually fail because it doesn't have correct permissions.
   The proc(4) interface does a proper job of enforcing security without
   changing process behavior; ptrace(2) just botches it (and always has).
   If truss(1) is run as super-user, set-uid and set-gid processes can
   be traced with no problem.  Running trace(1) as super-user helps some
   but it still has the same problem for non-super-user grabbed processes.

14.The ptrace(2) mechanism is intimately intertwined with the signal
   mechanism.  In particular, stopping on syscalls involves sending
   SIGTRAP.  If a process uses SIGTRAP for interprocess communication
   (I would call such a process terminally brain-damaged, but nothing in
   the system prevents such things), it will fail when trace(1) is applied
   to it.  The proc(4) mechanism is independent of the signal mechanism and
   does not suffer from this sort of problem.  A program using proc(4) can
   choose to trace signals or not; a signal is just one of the events a
   process can stop on, others are machine faults and syscalls.  A process
   can be stopped without sending SIGSTOP.  Provisions exist for cooperating
   with job-control stop/start signals and ptrace(2) as well.

15.ptrace(2) causes a traced process to die when its controlling process
   dies.  If a process is grabbed by trace(1) and trace(1) is killed with
   'kill -9', then the traced process also dies.  trace(1) catches all
   other signals in order to let go of the traced process before exiting.
   truss(1) doesn't have this problem; when it is killed with 'kill -9',
   the traced process continues unmolested.

16.There is a serious bug in SunOS 4.0 involving the interaction of
   job-control stop signals (SIGSTOP and its relatives) and ptrace(2).
   If a process is stopped by sending it a job-control stop signal and
   trace(1) is applied to it while it is so stopped, then trace(1) hangs
   and becomes unkillable, even with 'kill -9'.  The whole ptrace(2)
   mechanism is then locked out and any instance of dbx also becomes
   hung and unkillable.  The only recourse is a reboot.

				Roger A. Faulkner
				allegra!raf



More information about the Comp.unix.wizards mailing list