Museum

Home

Lab Overview

Retrotechnology Articles

⇒ Online Manual

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

open(2)

ptrace(2)

sigaction(2)

signal(2)

proc(4)  —  File Formats

NAME

proc − Process file system

SYNOPSIS

/proc

DESCRIPTION

The /proc file system enables running processes to be accessed and manipulated as files by the system calls open, close, read, write, lseek, and ioctl.  While the /proc file system is most useful for debuggers, the /proc file system enables any process with the correct permissions to control another running process.  Thus, a parent/child relationship does not have to exist between a debugger and the process that is being debugged. 

For each running and zombie process, there is an entry in the system process table, which appears as a file name in the /proc directory.  The file name is the decimal representation of the process id.  File names are padded with leading zeros (0) so that each file name is a minimum of 5 decimal digits.  For example, if a process has a process id of 123, its file name would be specified as 00123.  You do not have to specify the leading zeros when specifying the file name.  For example, specifying ls -l /proc/123 is acceptable. 

The only files that appear to exist in the /proc directory correspond to valid (active or zombie) processes in the system proc table.  Other than creating or terminating a process, you cannot create or remove files in the /proc directory.  The permissions for a file in the /proc directory are 0600, which indicates read and write permissions for the owner only.  The uid and gid for a file in the /proc directory are the uid and gid of the user who is running the process.  Attempts to manipulate the characteristics of a file in this directory through administrator commands return an error. 

Setting Up the /proc Filesystem

The /proc file system is layered beneath the Virtual File System (VFS).  It is a pseudo-file system that occupies no actual disk space.  The /proc pseudo-file system appears to contain files (which are actually running processes), and it is mounted by default at startup to make it visible to the operating system.  You can use the mount and umount commands to manually mount and dismount the file system, or you can define an entry for the /proc file system in your /etc/fstab file. 

To mount the /proc file system using the mount command, enter the following:

mount -t procfs /proc /proc

To dismount the file system, use the umount command as follows:

umount /proc

Because /proc is a pseudo-file system, it cannot be backed up, nor can you use the fsck command to perform file system checks.  Remove the following entry from your /etc/fstab file if you do not want the /proc file system mounted automatically:

/proc /proc procfs rw 0 0

This mounts the pseudodevice /proc on the /proc directory as read/write.  (There is no actual device entry for /proc.)  The file system type is procfs and the zeros (0) specify that the file system is not to be dumped or checked by the fsck command. 

The /proc file system should be unmounted if an entire system is to be backed up, starting from its root directory. 

Security Considerations

All auditing requirements for the /proc file system are handled at the Virtual File System (VFS).  The /proc file system is read only.  Only root or the superuser can open all processes using the /proc file system.  If you are a nonprivileged user, a debugging process can open an active process only if the following conditions are met:

       •Both the uid and the gid of the debugging (opening) process matches those of the running process. 

       •The debugging (opening) process has read permission for the executable file from which the active process was created. 

       •The executable file from which the active process was created must not have setuid or setgid permission unless the opening process has root or SEC_DEBUG privilege established or is the owner (for setuid) or a group member (for setgid). 

If a debugging process opens an active process and the active process calls exec(2) to start another image that has suid or sgid permissions, or if the debugging process does not have read permission for the image that the active process invokes, the debugging process is denied access to the process information for the new image with the exception of a close operation.  Hence, a file descriptor is not always valid after the active process executes another image.  This is also true when you have root or superuser privileges. 

Manipulating Processes: System Calls and ioctls

Files are manipulated using the open, close, read write, and ioctl system calls.  Once a process has been opened, its user virtual address space can be examined or written using the lseek system call followed by the read or write system calls.  Likewise, as long as a process is opened for both read and write, the ioctl system calls can be used to control, trace, or get status for a process that has been opened.  The close system call should be used when interaction with a process is complete.  Any number of number of opens for read and write are allowed; however, to prevent confusion, if several processes are trying to control another process, an exclusive open for write can be requested.  An open for write that includes the O_EXCL specifier only succeeds if the process is not already open for a write, even if you are root or an otherwise privileged user.  However, an open for write that does not specify O_EXCL always succeeds for root or an otherwise privileged user. 

When a file is closed, any tracing flags that were set are left on, unless the Run on Last Close (RLC) flag was set by an ioctl call.  If RLC is set, and the last file descriptor pertaining to the process is closed, all tracing flags are cleared and the process is set to run (if it was stopped).  Breakpoints are not affected by RLC because breakpoints are written into the text area of a running process by a debugger; the debugger is therefore always responsible for replacing the original instructions. 

Information and control operations are provided through ioctl.  The operations have the form:

#include <sys/types.h>
#include <sys/signal.h>
#include <sys/fault.h>
#include <sys/syscall.h>
#include <sys/procfs.h>
ioctl(fd, COMMAND, p);

The p argument is a generic pointer whose use depends on a specific ioctl code.  Where not mentioned in the description of the ioctl calls, the value should be zero.  <sys/procfs.h> contains definitions of ioctl codes and data structures used by the operations.  Certain operations can be performed only if the process file is open for writing; these include all operations that affect process control. 

Process and control operations involve the use of a set of flags.  The set types sigset_t, fltset_t, and sysset_t are masks.  The values used to set these masks correspond respectively to the signal, fault, and system call numbers defined in <sys/signal.h>, <sys/fault.h>, and <sys/syscall.h>.  Each set type is large enough to hold the masks bits for all legal values of the related action.  Although they are of different sizes, they have a common structure and can be manipulated by the following macros:

prfillset(&set);                /∗  turns on all flags
                                 ∗ in set ∗/
premptyset(&set);               /∗ turns off all flags
                                 ∗ in set ∗/
praddset(&set,flag);            /∗ turns on a specified
                                 ∗ flag ∗/
prdelset(&set,flag);            /∗ turns off a specified
                                 ∗ flag ∗/
r = prismember(&set,flag);      /∗ returns true if flag
                                 ∗ is on ∗/

Either prfilset or premptset must be used to initialize set before it is used in any operation.  The argument flag must be a member of the enumeration corresponding to the set.  The above macros must be used for manipulating the signal tracing mask; the macros in sys/signal.h must not be used. 

Ioctl Codes

The ioctl codes are divided into eight groups: process requests, signal interaction, fault trap interaction, system call interaction, traced process control, general registers, miscellaneous mapping control, and Digital UNIX specific requests.  The following subsections describe these ioctl codes. 

Process Requests

The following ioctls specify process requests:

PIOCSTATUS
Returns status information for the process.  The argument p points to the prstatus structure as follows:

typedef struct prstatus {
    long pr_flags;      /∗ specifies process flags ∗/
    short pr_why;       /∗ reason process is stopped ∗/
    long pr_what;       /∗ specifies detailed reasons ∗/
    struct siginfo pr_info;     /∗ data related to signal
                                 ∗ or fault ∗/
    short pr_cursig;            /∗ specifies current
                                 ∗ signal ∗/
    sigset_t pr_sigpend;        /∗ set of other pending
                                 ∗ signals ∗/
    sigset_t pr_sighold;        /∗ set of held signals ∗/
    struct sigaltstack pr_altstack;     /∗ alternate
                                         ∗ signal stack
                                         ∗ data ∗/
    struct sigaction pr_action; /∗ signal action of
                                 ∗ current signal ∗/
    pid_t pr_pid;       /∗ specifies process id ∗/
    pid_t pr_ppid;      /∗ specifies parent process id ∗/
    pid_t pr_pgrp;      /∗ specifies group process id ∗/
    pid_t pr_sid        /∗ specifies session id ∗/
    timestruc_t pr_utime;       /∗ specifies process
                                 ∗ user cpu time ∗/
    timestruc_t pr_stime;       /∗ specifies process
                                 ∗ system cpu time ∗/
    timestruc_t pr_cutime;      /∗ sum child processes
                                 ∗ user time ∗/
    timestruc_t pr_cstime;      /∗ sum child processes
                                 ∗ system time ∗/
    char pr_clname[8];  /∗ scheduling class name ∗/
    long pr_filler[20]  /∗ filler area for future
                         ∗ expansion ∗/
    long pr_instr;      /∗ specifies current
                         ∗ instruction ∗/
    gregset_t pr_reg;   /∗ specifies general registers ∗/
    u_long pr_subcode;  /∗ trap subcode instructions ∗/
    long pr_nthreads;   /∗ number of threads ∗/
    struct vnode ∗pr_exvp;      /∗ kernel address of
                                 ∗ vnode for executable
                                 ∗ file ∗/
    tid_t pr_tid;      /∗ thread id output by
                        ∗ PIOCSTATUS ∗/
} prstatus_t;

The following list describes each member of the structure pr_flags. 

The pr_flags bit-mask has the following flags:

       •PR_STOPPED specifies that the process is stopped. 

       •PR_ISTOP specifies that the process stopped on an event of interest (see PIOCSTOP)

       •PR_DSTOP specifies that the process will stop before entering user code (see PIOCSTOP). 

       •PR_ASLEEP specifies that a process is in an interruptible sleep within a system call. 

       •PR_RLC specifies that  a process has its run-on-last-close flag set. 

       •PR_TRACE specifies that a process is being traced using ptrace. 

       •PR_PCINVAL specifies that a process program counter refers to an invalid address. 

       •PR_ISSYS specifies that a process is a system process (see the PIOCSTOP ioctl). 

pr_why and pr_what

The pr_why and pr_what fields describe why a process is stopped and what stopped it.  The possible values for pr_why follow.  Included in the description of the pr_why values is an explanation of what pr_what holds.  The pr_why values are:

       •PR_REQUESTED indicates that PIOCSTOP was specified, hence the process was stopped.  In this instance, the pr_what field is not used. 

       •PR_SIGNALLED indicates that a process stopped upon receiving a signal (see PIOCSTRACE).  The pr_what field holds the signal number that caused the stop.  If this is a newly stopped process, the signal number is placed in pr_cursig. 

       •PR_FAULTED specifies that a process stopped upon encountering a fault (see PIOCSFAULT).  The pr_what field holds the number of the fault that stopped the process. 

       •PR_SYSENTRY and PR_SYSEXIT specify that a stop is to occur on an entry to or an exit from a system call (see PIOCSENTRY and PIOCSEXIT).  The pr_what field holds the number of the system call, including the habitat number, if any. 

       •PR_JOBCONTROL specifies that a process stopped because of the default action specified by a job control stop signal (see sigaction).  The pr_what field holds the stopping signal number.  The job control signal, SIGCONT, is traced only if the process is stopped because of a job control stop signal or if SIGCONT is being caught by a user signal handler. 

       •PR_DEAD specifies that a process has terminated.  At this point, the process and memory context are considered invalid.  The pr_what field holds the exist status of the process.  This function provides the debugger with the ability to determine that the process being debugged has terminated, and to see its exit status.  To trace this condition, use PRFS_STOPTERM in the PIOCSSPCACT ioctl. 

       •PR_FORKSTOP specifies that the process has stopped on exit from the fork system call that created it.  The PIOCRUN ioctl (with no parameters) must be used to restart the process. 

pr_info

Contains additional information specific to a signal or fault when a process has been stopped by either PR_SIGNALLED or PR_FAULTED (see <sys/siginfo.h>). 

pr_cursig

Identifies the number of the next signal to be delivered to a process. 

pr_sigpend

Is a mask of pending signals that are to be sent to a process. 

pr_sighold

Is a mask of those signals whose delivery will be delayed if sent to a process.  Note that this mask is 0 to (N-1), as opposed to pr_sigpend, which is 1 to N, where N is the max signal number.  The following macros: PRFILLSRT, PREMPTYSET, PRADDSET, PRDELSET, and PRISMEMBER must be used in conjunction with this field. 

pr_alstack

Provides alternate signal stack information for a process (see sigaltstack). 

pr_action

Contains any signal action related to the current signal (see sigaction).  The signal action is not defined if pr_cursig is zero. 

pr_pid

Contains the process identification number. 

pr_ppid

Contains the process identification number of the parent process. 

pr_pgrp

Contains the group identification number of the process. 

pr_sid

Contains the session identification number of the process. 

pr_utime and pr_stmine

Contain the user and system time (in seconds and nanoseconds) used by the process. 

pr_cutime and pr_cstime

Contain the total user and system time (in seconds and nanoseconds) used by all child processes (and their descendants) of the indicated parent process. 

pr_clname

Contains the name of the scheduling class that a process is using. 

pr_filler

Not currently used.  It is reserved for future use. 

pr_instr

Holds the machine instruction that is used by the program counter.  The amount of information retrieved from the process is typically the size of a machine’s smallest instruction; it is machine dependent.  If the machine instruction is an invalid address, pr_instr is not defined, and the PR_PCINVAL flag is set. 

pr_reg

An array that contains the contents of the general registers for the thread specified by pr_tid.  For a single-threaded process, this is the first thread. 

pr_subcode

Contains the trap subcode for the breakpoint instruction. 

pr_nthreads

Contains the number of threads currently in the process (task). 

pr_exvp

Contains the kernel address of the vnode structure that identifies the on-disk executable file from which the process was created. 

pr_tid

If the process is stopped on an event of interest, pr_tid contains the thread ID of the thread that hit the process (task) trace event.  NOTE:  In a multithreaded task, the PIOCSTOP ioctl sets pr_tid to the thread ID of the first thread and sets the registers in pr_reg accordingly. 

PIOCSTOP and PIOCWSTOP

Both of these ioctls specify that process is to stop on an event of interest.  For both ioctls, if the p argument is of a nonzero value, it points to prstatus_t structure that holds status information on a stopped process. 

The PIOCSTOP ioctl requires write access.  This ioctl code requests that a process stop on an event of interest and remains in effect until the process does stop.  The PIOCWSTOP ioctl waits for a process to stop on an event of interest. 

If PIOCSTOP is specified with a process that is stopped, but not stopped on an event of interest, the stop directive only takes affect when the process is restarted by the competing mechanism; the process will enter a PR_REQUESTED stop before executing any user level code.  If an attempt is ever made to interrupt a PIOCSTOP using a signal such as an alarm, the stop directive remains in effect even though it returns an error.  A signal or alarm is typically issued to avoid waiting forever for process to stop on event of interest that never occurs. 

An event of interest occurs when either a PR_REQUESTED stop has been specified or when a stop has been specified in tracing flag of a process that can be set by PIOCSTRACE, PIOCSFAULT, PIOCSENTRY, or PIOCSEXIT.  Of these tracing flags, PR_SIGNALLED is only considered to stop on an event of interest when it is controlled by ptrace and only if the signal is set in the traced signal set.  A PR_JOBCONTROL flag is not considered an event of interest.  A process can halt twice because of a stop signal.  If the signal is traced, it displays PR_SIGNALLED on the first stop.  If the process runs without clearing the signal, it shows PR_JOBCONTROL. 

A system process (indicated by the PR_ISSYS flag) never executes at user level, does not have a user level address space visible through /proc, and cannot be stopped.  Applying PIOCSTOP or PIOCWSTOP to a system process returns the error EBUSY. 

PIOCRUN

Starts a traced process again after it has been stopped.  This ioctl requires write access.  PIOCRUN fails with an EBUSY error if it is applied to a process that is not stopped on an event of interest--even if stopped due to a competing mechanism, it remains stopped.  The p argument points to a prrun structure that provides additional directives or actions that can be performed:

typedef struct prrun {
    long pr_flags;      /∗ specifies process flags ∗/
    sigset_t pr_trace;  /∗ specifies set of signals to
                         ∗ trace ∗/
    sigset_t pr_sighold;        /∗ specifies set of
                                 ∗ signals to hold ∗/
    fltset_t pr_fault;  /∗ specifies set of faults to
                         ∗ trace ∗/
    caddr_t pr_vaddr;   /∗ specifies virtual address
                         ∗ at which to resume ∗/
    long pr_filler[8];  /∗ filler area for future
                         ∗ expansion ∗/
    tid_t pr_tid;       /∗ Thread to resume for PIOCTRUN,
                         ∗ ignored by PIOCRUN  ∗/
}  prrun_t;

The fields in the prrun structure are only meaningful if the appropriate flags are set in pr_flags bit-mask.  The pr_flags bit-mask has the following flags:

       •PRCSIG specifies that the current signal, if any, be cleared (see the PIOCSSIG ioctl). 

       •PRCFAULT specifies that the current fault, if any, be cleared (see the PIOCCFAULT ioctl). 

       •PRSTRACE specifies that the traced signal set is set to pr_trace (see the PIOCSTRACE ioctl). 

       •PRSHOLD specifies that the held signal set is set to pr_sighold (see the PIOCSHOLD ioctl). 

       •PRSFAULT specifies that the traced fault set is set to pr_fault (see the PIOCSFAULT ioctl). 

       •PRSVADDR specifies the address at which execution resumes to pr_vaddr. 

       •PRSTEP tells the process to run and execute a single machine instruction.  When execution has completed, a hardware trace trap occurs.  If FLTTRACE is being traced, the process stops, otherwise it is sent SIGTRAP.  If SIGTRAP is being traced and not held, the process stops.  If If SIGTRAP is not being traced, the SIGTRAP signal kills the traced process and creates a core file.  This operation requires hardware support and might not be implemented on all processors. 

       •PRSABORT specifies that the process is to abort execution of a system call if the process is in a PR_SYSENTRY stop or it is marked PR_ASLEEP (see PIOCSENTRY and PIOCEXIT). 

       •PRSTOP specifies that a process stop again soon after it has resumed execution (see PIOCSTOP).  Specifically, when a process is stopped on PR_SIGNALLED or PR_FAULTED, the next stop displays PR_REQUESTED, no other stop has intervened, and the process will not have executed any user-level code. 

PIOCSRLC

This ioctl sets the run-on-last-close flag in the traced process.  When the last /proc file descriptor referring to the traced process is closed, all of the process’s tracing flags are cleared, any outstanding stop directive is canceled, and if the process is stopped, it is set running as though PIOCRUN had been applied to it.  This ioctl requires write access.  The flag run-on-last-close is off by default. 

PIOCRRLC

This ioctl turns the run-on-last-close flag off.  The tracing flags of a process are retained and the process is not restarted when the process file is closed.  This ioctl requires write access. 

PIOCNICE

The traced process’s nice priority is incremented by the amount contained in the int addressed by the p argument.  Only the superuser can increase the priority of a process in this manner, but any user can decrease the priority.  This ioctl requires write access. 

Signal Interaction

The following ioctls specify signal interaction. 

PIOCSTRACE

This defines a set of signals to be traced and the receipt of one of these signals causes the traced process to stop.  The set of signals is defined through the sigset_t structure that is pointed to by the argument p.  Receipt of SIGKILL cannot be traced.  This ioctl requires write access.  The sigset_t structure must be manipulated via the prfillset and related macros, which are defined in /usr/include/sys/procfs.h. 

If a signal that is included in the held signal set is sent to the traced process, the signal is not received and does not cause a process stop until it is removed from the held signal set, either by the process itself or by setting the held signal set with the PIOCSHOLD ioctl or using the PRSHOLD option defined by the PIOCRUN ioctl. 

PIOCGTRACE

The current traced signal set is returned in an instance of sigset_t structure pointed to by the p argument. 

PIOCSSIG

The current signal and its associated signal information are set according to the contents of the siginfo structure addressed by p (see <sys/siginfo.h>).  If the specified signal number is zero or if p is zero, the current signal is cleared.  This ioctl requires write access. 

The semantics of this ioctl are different from those of kill or PIOCKILL in that the signal is delivered to the process immediately after execution is resumed (even if it is being held) and an additional PR_SIGNALLED stop does not intervene even if the signal is traced.  Setting the current signal to SIGKILL terminates the process immediately, even if it is stopped. 

PIOCKILL

A signal is sent to the process with semantics identical to those of kill; p points to an int naming the signal.  Sending SIGKILL terminates the process immediately.  This ioctl requires write access. 

PIOCUNKILL

A signal is deleted (removed from the set of pending signals); the current signal, if any, is unaffected.  The p argument points to an int naming the signal.  It is an error to attempt to delete SIGKILL.  This ioctl requires write access. 

PIOCGHOLD

This ioctl returns the set of held signals (signals whose delivery is delayed if sent to the process) in an instance of sigset_t addressed by the p argument.  Signal number 0 is always returned if not held. 

PIOCSHOLD

This ioctl sets the held signal set but does not allow SIGKILL or SIGSTOP to be held.  It requires write access.  See PIOCGHOLD.  Signal number 0 cannot be held; it is ignored if specified. 

PIOCMAXSIG

This ioctl, with the PIOCACTION ioctl, provides information about the signal actions associated with the traced process (see sigaction).  In the int returned by the p argument, this ioctl returns the  maximum signal number understood by the system. This must be used to allocate storage for use with the PIOCACTION ioctl. 

PIOCACTION

This ioctl, with the PIOMAXSIG ioctl, provides information about the signal actions associated with the traced process.  This ioctl returns the traced process’s signal actions in an array of sigaction structures addressed by the p argument.  Signal numbers are displaced by 1 from array indices, so that the action for signal number n appears in position n-1 of the array.  Note that PIOCMAXSIG should be called before invoking the PIOCACTION or PIOCTACTION ioctls. 

See sigaction(2) for the definition of the sigaction structure. 

Fault Trap Interaction

The following ioctls specify fault trap interaction. 

PIOCSFAULT

This defines a set of hardware faults to be traced.  When incurring one of these faults the traced process stops.  This ioctl requires write access.  The set is defined via an instance of fltset_t addressed by p.  This structure must be manipulated by the prfillset and related macros, defined in /usr/include/sys/procfs.h. Fault names are defined in <sys/fault.h> and include the following.  Some of these may not occur on all processors; there may be processor-specific faults in addition to the following:

       •FTTILL specifies an illegal instruction

       •FLTPRIV specifies a privileged instruction

       •FLTBPT specifies a breakpoint trap

       •FLTTRACE specifies a trace trap

       •FLTACCESS specifies a memory access fault

       •FLTBOUNDS specifies a memory bounds violation

       •FLTIOVF specifies an integer overflow

       •FLTIZDIV specifies  an integer zero divide

       •FLTFPE specifies a floating-point exception

       •FLTSTACK specifies an unrecoverable stack fault

       •FLTPAGE specifies a recoverable page fault

When not traced, a fault normally results in the posting of a signal to the process that incurred the fault.  If the process stops on a fault, the signal is posted to the process when execution is resumed unless the fault is cleared by PIOCCFAULT or by the PRCFAULT option of PIOCRUN.  FLTPAGE is an exception (no pun intended); no signal is posted.  There may be additional processor-specific faults like this.  The pr_info structure member in the prstatus structure identifies the signal to be sent and contains machine-specific information about the fault. 

typedef struct {
       unsigned long word[FLTSET_SZ];
} fltset_t; Out of the above set of hardware faults, the Alpha AXP architecture supports only FLTILL, FLTBPT, FLTIOVF, FLTIZDIV, and FLTPAGE.  The complete list of faults supported by the Alpha architecture is in /usr/include/machine/trap.h.  In the Alpha AXP architecture, the trap subcode must also be examined.  This subcode is available in the pr_subcode field of the PRSTATUS structure.  The Alpha AXP architecture does not allow the AST fault, _AST, to be traced. 

PIOCGFAULT

The current traced fault set is returned in the fltset_t structure that is pointed to by the p argument.  This structure must be manipulated by the prfillset and related macros defined in /usr/include/sys/procfs.h. 

PIOCCFAULT

The current fault (if any) is cleared; the associated signal is not sent to the process.  This ioctl requires write access. 

System Call Interaction

The following ioctls specify system call interaction. 

PIOCSENTRY

This ioctl instructs the process to stop on entry to the specified system calls.  The set of syscalls to be traced is defined in the sysset_t structure addressed by the p argument.  See the PIOCEXIT ioctl for a description of the sysset_t structure.  This ioctl requires write access. This structure must be manipulated using the prfillset and related macros defined in /usr/include/sys/procfs.h. 

When an entry to a system call is being traced, the traced process stops after beginning the call to the system.  The system call arguments have been fetched from the process but are still in the user saved registers and/or the user stack space.  Their location is architecture dependent. 

PIOCSEXIT

This ioctl instructs the process to stop on exit from the specified system calls.  The set of syscalls to be traced is defined in the sysset_t structure addressed by the p argument.  This ioctl requires write access.  This structure must be manipulated using the PRFILLSET and related macros defined in /usr/include/sys/procfs.h. 

When exit from a system call is being traced, the traced process stops on completion of the system call prior to checking for signals and returning to user level.  All return values are stored into the traced process’s saved registers. 

If the traced process is stopped on an entry to a system call by PR_SYSENTRY, or if it is in an interruptible system call with PR_ASLEEP set, it may be instructed to go directly to system call exit by specifying the PRSABORT flag in a PIOCRUN request.  Unless exit from the system call is being traced, the process returns to the user level with the EINTR error. 

typedef struct {
        unsigned long    word[SYSSET_SZ];
} sysset_t; Because of the user level loader, it is not always possible to trace on exit from the exec system call.  The PIOCSSPCACT ioctl must be used to trace on exit from the exec system call. 

PIOCGENTRY

This ioctl returns the entry of the currently traced system call in the sysset_t structure pointed to by the p argument.  This structure must be interrogated using the prismember and related macros defined in /usr/include/sys/procfs.h. 

PIOCEXIT

This ioctl returns the exit set of the currently traced system call in the sysset_t structure pointed to by the p argument. This structure must be interrogated using the prismember and related macros defined in /usr/include/sys/procfs.h. 

Traced Process Control

The following ioctls specify traced process control. 

PIOCSFORK

This ioctl sets the inherit-on-fork-flag in the traced process.  The tracing flag of a process are inherited by the child of a fork.  This ioctl requires write access. 

PIOCRFORK

This ioctl turns the inherit-on-fork flag off.  Each child process starts with all tracing flags cleared.  This ioctl requires write access. 

General Registers

The following ioctls are the general registers. 

PIOCGREG

This ioctl retrieves the registers of the saved process from the gregset_t structure that is pointed by the p argument.  The register contents are accessible using a set of predefined indices as described under the PIOCSTATUS ioctl. 

In a multithreaded process, if the task is not stopped on an event of interest (a trace event), the registers are returned for the first thread.  If the task is stopped on an event of interest, the registers for the thread that hit the event are returned.  (See the pr_tid field as returned by PIOCSTATUS.) 

The gregset_t structure is described under the PIOCSREG ioctl. 

PIOCSREG

This ioctl sets the registers of the saved process in the gregset_t structure pointed to by the argument.  It requires write access.  The register contents are accessible using a set of predefined indices as described under the PIOCSTATUS ioctl.  Only the condition-code and trace-enable bits of the processor-status word (PSW) can be modified by this ioctl.  Other privileged registers cannot be modified at all.  This ioctl fails with an EBUSY error if applied to a process that is not stopped on an event of interest. 

struct gregset {
        long regs[PRC_NREGS];
}; typedef struct gregset gregset_t; On some architectures, the processor status word (PSW) does not exist. To use this ioctl, do the following: ensure that the traced process is stopped on a trace point, apply the PIOCGREG ioctl, modify the needed registers in the copy returned by the PIOCGREG ioctl, and then apply this ioctl. 

PIOCGFPREG

This ioctl retrieves the floating-point registers of a saved process from the fpregset_t structure pointed to by the p argument.  The EINVAL error is returned if floating-point hardware is not present on the machine. 

The fpregset_t structure is displayed under the PIOCSFPREG ioctl.  Note that this ioctl is architecture dependent. 

PIOCSFPREG

This ioctl sets the floating-point registers of a saved process in a fpregset_t structure pointed to by the p argument. It requires write access.  The EINVAL error is returned if floating-point hardware is not present on the machine.  This ioctl fails with an EBUSY error if it is applied to a process that is not stopped on an event of interest. 

struct fpregset {
        long regs[PRC_NREGS];
};
typedef struct fpregset fpregset_t;

Note that this ioctl is architecture dependent.  The PIOCSREG, PIOCGFPREG, and PIOCSFPREG ioctls can be used only if the task is stopped on an event of interest.  In a multithreaded task, the register set that is imanipulated is the set associated with the task that hit the trace event.  (See the pr_tid field as returned by PIOCSTATUS.)  If the task stopped because of a PIOCSTOP ioctl, the registers are those of the first thread. 

Miscellaneous Requests

The following ioctls perform a variety of requests. 

PIOCPSINFO

This ioctl returns miscellaneous information about a process similar to the information returned by the ps command.  The p argument is a pointer to a prpsinfo structure containing at least the following fields:

typedef struct prpsinfo  {
    char pr_state:      /∗ numeric process state
                         ∗ (see pr_sname) ∗/
    char pr_sname;      /∗ printable char representing
                         ∗ pr_state ∗/
    char pr_zomb;       /∗ !=0: process terminated
                         ∗ but not waited for ∗/
    char pr_nice;       /∗ nice for cpu usage ∗/
    u_long pr_flag;     /∗ process flags ∗/
    uid_t pr_uid;       /∗ real user id ∗/
    gid_t pr_gid;       /∗ real group id ∗/
    pid_t pr_pid;       /∗ unique process id ∗/
    pid_t pr_ppid;      /∗ process id of parent∗/
    pid_t pr_pgrp:      /∗ process id of process group
                         ∗ leader ∗/
    pid_t pr_sid;       /∗ session id ∗/
    caddr_t pr_addr;    /∗ process physical address ∗/
    long pr_size;       /∗ size of process image in
                         ∗ pages ∗/
    long pr_rssize;     /∗ resident set size in pages ∗/
    caddr_t pr_wchan;   /∗ wait addr for sleeping
                         ∗ process ∗/
    timestruc_t pr_start;       /∗ process start time,
                                 ∗ sec+nsec since the
                                 ∗ epoch ∗/
    timestruc_t pr_time;        /∗ usr+sys time for
                                 ∗ this process ∗/
    long pr_pri;        /∗ priority, high value =
                         ∗ high priority ∗/
    char pr_oldpri;     /∗ old style priority,
                         ∗ low value is high
                         ∗ priority ∗/
    char pr_cpu;         ∗ cpu usage for scheduling ∗/
    dev_t pr_ttydev;    /∗ controlling tty device
                         ∗ (PRNODEV if none) ∗/
    char pr_clname[8];  / ∗Scheduling class name ∗/
    char pr_fname[16];  /∗ last component of exec’d
                         ∗ pathname ∗/
    char pr_psargs[PRARGSIZ];   /∗ initial characters
                                 ∗ of arg list ∗/
    long pr_filler[20]; /∗ filler for future expansion ∗/
} prpsinfo_t;

Some fields in the prpsinfo structure, such as the pr_state and the pr_flag fields, are system-specific and may not have the same meaning on each version of the operating system.  The pr_addr field is not used. 

PIOCPSINFO can be applied to a process that has become a zombie, but not all fields are filled in. 

PIOCNMAP

This operation, like the PIOCMAP ioctl, provides information about the memory mappings (virtual address ranges) associated with the traced process.  In the int returned by the p argument, this ioctl returns the number of mappings that are currently active.  This information can be used to allocate storage that can be used with the PIOCMAP ioctl.  You must allocate space for p+1 mappings; see PIOCMAP. 

PIOCMAP

This memory mapping operation returns the list of currently active mappings.  For PIOCMAP, the p argument addresses an array of elements of type prmap_t; one array element (structure) is returned for each mapping with an additional all-zeroes element to mark the end of the list.  (See PIOCNMAP.) 

typedef_t struct prmap  {
    caddr_t pr_vaddr;   /∗ Virtual address base ∗/
    u_long pr_size;     /∗ Size of mapping in bytes ∗/
    off_t pr_off;       /∗ Offset into mapped object,
                         ∗ if any ∗/
    long pr_mflags;     /∗ Protection and attribute
                         ∗ flags ∗/
    long pr_filler[4];  /∗ Filler for future expansion ∗/
}  prmap_t;

The following list describes structure members:

       •The pr_vaddr contains the virtual address base (the lower limit) of the mapping within the traced process and the pr_size field contains its size in bytes.  The pr_off field specifies the offset within the mapped object (if any) to which the address base is mapped. 

       •The pr_mflags field is a bit-mask of protection and attribute flags as follows:

MA_READ specifies that mapping is readable by traced process

MA_WRITE specifies that mapping is writable by the traced process

MA_EXEC specifies that mapping is executable by the traced process The PIOCNMAP ioctl must be called immediately before the PIOCMAP ioctl. 

PIOCOPENM

If this ioctl is called with a NULL value for p, it returns a read-only file descriptor to the disk file from which the process was created. 

new_fd = ioctl(fd, PIOCOPENM, NULL)

PIOCCRED

This operation obtains the set of credentials associated with the process.  The p argument points to the prcred_t structure where the information from this operation is placed.  The pr_ngroups value determines the size of the field that the user must allocate and pass to the PIOCGROUPS ioctl. 

typedef struct prcred {
    uid_t  pr_euid;     /∗ contains effective user id ∗/
    uid_t  pr_ruid;     /∗ contains real user id ∗/
    uid_t  pr_suid;     /∗ contains saved user id
                         ∗ (from exec) ∗/
    uid_t  pr_egid;     /∗ contains effective group id ∗/
    uid_t  pr_rgid;     /∗ contains real group id ∗/
    uid_t  pr_sgid;     /∗ contains saved group id
                         ∗ (from exec) ∗/
    u_int  pr_ngroups;  /∗ number of supplementary groups ∗/
}  prcred_t;

PIOCGROUPS

Fetch the set of supplementary group IDs that are associated with the process.  The p argument points to an array of elements of type uid_t that are to be filled by the operation.  Note that the PIOCCRED ioctl must be applied beforehand to determine the number of groups (pr_ngroups) that are returned and the amount of storage that should be allocated to hold them. 

PIOCGETPR

This operation copies the proc structure of the traced process into the buffer addressed by the p argument.  It can be applied to a zombie process (see the PIOCPSINFO ioctl). 

PIOCGETU

This operation copies the user are of the traced process into the buffer addressed by the p argument.  Note that this ioctl returns EINVAL.  In Digital UNIX the u area does not physically exist; it is dispersed throughout several other structures. 

Operating System Specific Ioctls

The following ioctls have been created for use on Digital UNIX systems. 

PIOCSSPCACT

This ioctl is referred to as “"set special action” and requires write access.  It is used to enable or disable tracing of certain process control functions.  The p argument contains a mask that consists of the following values (note that a zero value disables all tracing).  The pr_why and pr_what values are the same as those described under the PIOCSTATUS ioctl. 

PRFS_STOPEXEC enables a trace on any exec call.  This causes a trace (or stop on event of interest) after the kernel exec routine regardless of which actual system call (from any habitat) was invoked by the user code. 

When the process stops, if a PIOCSTATUS ioctl is applied, pr_flags is set to PR_STOPPED and PR_ISTOP (if it is stopped on an event of interest).  The pr_why field is set to PR_SIGNALLED and both pr_what and pr_cursig are set to SIGTRAP. 

If a trace on signal SIGTRAP is not set, PRFS_STOPEXEC sets it and leaves it set.  PRFS_STOPEXEC causes the process to stop in user context.  To continue, issue a PIOCRUN ioctl with PRCSIG set in the pr_flags field of prrun structure. 

The stop on exec function is intended to be used by a parent that needs to get control of a child process before the child has begun to execute any user code.  This function is usually used as follows:

     1.The parent opens itself with /proc, sets PRFS_STOPEXEC and also sets inherit-on-fork using the PIOCSFORK ioctl, then forks a child that in turn calls exec(). 

     2.The parent waits for the child to stop on signal SIGTRAP.  The parent must then clear its signal trace map, and PRFS_STOPEXEC, and close itself. 

     3.The child can then be handled as explained above depending on whether or not it is being loaded with the user level loader. 

If the user level loader is invoked by exec(), a stop will occur in the context of the loader.  None of the expected user program text addresses will be valid.  Issuing a PIOCRUN ioctl with prrun.pr_flags set to PRCSIG will allow the user level loader to run the completion.  A second stop will now occur in the context of the actual user program.  At this time, any additional tracing flags or breakpoints may be set.  A PIOCRUN ioctl with prrun.pr_flags set to PRCSIG should be issued when the user program is started. 

PRFS_STOPTERM enables a trace on a task terminate.  This causes a trace (stop on event of interest) to occur when the task, or process, is in the process of terminating.  pr_why is set to PR_DEAD, and pr_what has the process’s exit or return value.  A PIOCRUN ioctl must be used to restart the task so it can finish exiting.  (If run-on-last-close is set (via PIOCSRLC), and the last file descriptor to the stopped process is closed, the process will be restarted as if a PIOCRUN had been issued.) 

PRFS_STOPFORK causes a child process to stop on a trace event in the fork code.  In the DEC OSF/1 kernel, the child of a fork() call never executes any code in the fork() system call that created it.  To stop the child on fork(), the parent process must be open via /proc and must have inherit-on-fork set (done via PIOCSFORK).  The parent must then invoke PIOCSSPCACT with the PRFS_STOPFORK flag set.  With both inherit-on-fork and child-stop-on-fork set, when the parent calls fork() the child will remain stopped before it has executed any user code.  The child can then be opened via /proc.  A PIOCSTATUS ioctl will show the child stopped on an event of interest (pr_flags will have PR_STOPPED and PR_ISTOP set) with pr_why set to PR_FORKSTOP and pr_what set to NULL.  At this point, breakpoints or other trace events can be set in the child.  To start the child running, PIOCRUN (with no parameters) should be invoked. (Specifically, PRSVADDR, in the prrun structure, should not be set.)  child-stop-on-fork is simpler to use than stop-on-exec and provides another way to gain control of a child process for debugging purposes.  Note that this same behavior will occur if the fork system call is being traced on exit and inherit-on-fork is set.  Note also that if the parent is a utility process (not a “victim” process), great care must be taken with the trace settings so that the utility itself does not stop on a trace event. 

PRFS_STOPTCR sets a condition called stop-on-thread-create.  This will cause the task in which a new thread is created by a user level call to thread_create() to stop on an event of interest before the new thread has executed any user level code.  Setting this flag will not cause a task stop when a fork() system call creates a new thread.  pr_why is set to PR_TCRSTOP, and pr_what is set to the thread ID of the newly created thread.  The PIOCRUN ioctl should be used to restart the task. 

PRFS_STOPTTERM sets a condition called stop-on-thread-terminate.  This will cause a task stop whenever any of its threads enters the kernel thread_terminate() routine because of a user level call to task_terminate().  pr_why is set to PR_TTSTOP, and pr_what is set to the thread ID of the terminating thread.  The PIOCRUN ioctl should be used to restart the task.  (The last thread of an exiting process does not cause a task stop if stop-on-thread-terminate is set.  Additionally, a thread killed by the PIOCTTERM ioctl will not cause a task trace stop even if stop-on-thread-terminate is set.) 

PRFS_KOLC sets the kill-on-last-close flag in the traced process.  This flag is off by default.  If the flag is set, the traced process is terminated by a SIGKILL signal when the last /proc file descriptor referring to the traced process is closed.  This action occurs even if the traced process is stopped on a trace event.  All further tracing is disabled.  If set, PRFS_KOLC overrides the run-on-last-close flag; see the description of the PIOCSRLC ioctl. 

PIOCGSPCACT

This ioctl is referred to as "get special actions".  It is used to return, in the address pointed to by the p argument, the latest mask value that was set by the PIOCSSPCACT ioctl.  User code can invoke this ioctl to get the current mask setting.  It can then OR in bits to be set, and/or AND out bits to be cleared; the PIOCSSPCACT can then be called with the modified mask to affect the desired change in tracing. 

The select(2) system call can be used with files that have been opened using /proc with some restrictions.  The select parameters are as follows:

select(fd_set ∗readfds, fd_set
    ∗writefds, fd_set ∗exceptfds,
    struct  timeval  ∗timeout)

As restrictions, readfds and writefds must be NULL, exceptfds must be a valid pointer, and timeout must be a valid pointer. 

The exceptfds parameter is used to specify which file descriptors are to be checked.  A positive indication is returned if the process, corresponding to the open file descriptor, has stopped on an event of interest.  (That is, a PIOCSTATUS ioctl would return prstatus.pr_flags with PR_ISTOP set. 

The timeout structure pointed to by timeout can contain either a NULL value (which causes the select to behave in a “polling” mode) or timeout value.  Any timeout value should be kept very small.  The logical behavior of select(2) with a timeout value is: if the first specified process is not stopped on an event of interest, delay for the timeout value, and then check the next process.  When all specified processes have been checked, return the modified exceptfds to the user. 

PIOCNTHR, PIOCTLIST

These ioctls are used to list the thread IDs of all the threads in a task.  PIOCNTHR must be called first; it lets the user know how large a buffer it must pass to the PIOCTLIST ioctl, and tells the kernel code the max number of thread IDs to return via the PIOCTLIST ioctl.  If PIOCNTHR is not invoked first, PIOCTLIST returns error EINVAL.  PIOCNTHR takes a pointer to an int, and PIOCTLIST expects a pointer to an array of tid_t (pointers to struct thread).  Note that if the task is not stopped, the actual number of threads in the task may change in the time between the invocation of PIOCNTHR and PIOCTLIST.  The actual list of threads returned by PIOCTLIST will be less than or equal to the value returned by PIOCNTHR.  To get around this, the task could be stopped (by PIOCSTOP for example) before PIOCNTHR is invoked, and restarted by PIOCRUN after PIOCTLIS has completed. 

Usage:

ioctl(fd, PIOCNTHR, p) where p is (int ∗p)
ioctl(fd, PIOCTLIST, p) where p is (tid_t p)

PIOCRTINH, PIOCSTINH

Inherit-on-thread-create is a status condition similar to inherit-on-fork.  It is off by default; it is set via PIOCSTINH, and cleared by the PIOCRTINH ioctl.  This condition is set and cleared at the task level.  When set, the tracing conditions of the first thread in a task are copied to the new thread created by a user invocation of thread_create().  (No action is taken by the kernel code when thread_create() is called by the kernel fork() code.) 

Usage:

ioctl(fd, PIOCSTINH, NULL)
ioctl(fd, PIOCRTINH, NULL)

For both PIOCRTINH and PIOCSTINH, the process must have been opened for write in order for the ioctl to be used.  Otherwise, error EBADF is returned. 

PIOCGFPCR, PIOCSFPCR

PIOCGFPCR returns the contents of the FP Control Register; PIOCSFPCR writes the specified value into the FP Control Register.  If the task is not stopped on an event of interest (prstatus pr_flags PR_ISTOP must be set), error EBUSY is returned.  If the task had not been using the FP hardware (the pcb pcb_ownedfp flag is not NULL) error EINVAL is returned.  For a multithreaded process, the FPCONTROL register is manipulated in the context of the thread that stopped the task. 

Usage:

ioctl(fd, PIOCGFPCR, p)  where p is (u_long ∗p)
ioctl(fd, PIOCSFPCR, p)  where p is (u_long ∗p)

For PIOCSFPCR, the process must have been opened for write in order for the ioctl to be used.  Otherwise, error EBADF is returned. 

PIOCXPTH

This ioctl accepts a libmach port name as an input parameter and returns the corresponding kernel thread ID in its place.  This thread ID is suitable for use by the thread specific ioctls (PIOCTxxx).  (The libmach port name is the value filled in by the user level call to thread_create().) 

Usage:

ioctl(fd, PIOCXPTH, p)    where p is (u_long ∗p)

The argument p contains the libmach port name as input, and it is overwritten with the thread ID on return from the ioctl. 

THREAD-SPECIFIC IOCTLS

In a multithreaded program, user code must be able to identify which thread or threads to examine or manipulate.  Each user process is composed of a task, which contains one or more threads; these are in a linked list in task->thread_list.  This list contains the address of the thread structure that identifies the thread to the kernel.  This kernel address is returned to the user via /proc ioctls as the ID of a thread.  This ID is also passed to the kernel by user ioctls to identify which thread in a task to manipulate.  The PIOCXPTH ioctl can be used to translate a libmach thread port name to a kernel thread ID. 

With the exception of PIOCTLIST, the thread specific ioctls (PIOCTxxx) can operate on one or more threads.  These ioctls are invoked in the context of a process, just like the “base” ioctls.  For example, if process 123 is opened via /proc — fd=open("/proc/123", O_RDWR), then ioctl(fd, PIOCTSTATUS, p) could be used to return status for 1 or more of its threads. 

However, unlike the “base” ioctls, which take the address of a fixed length entity for parameter p, the PIOCTxxx ioctls use p to specify the address of a buffer that varies in length, depending on the number of threads that are to be operated on.  Also, the PIOCTxxx ioctls always require a valid p parameter — because, the p parameter contains the number of threads to operate on, and their IDs (even if the number is 1). 

The structure, struct prthreads, which is defined in <sys/procfs.h>, is used as a common “header” for each of the PIOCTxxx ioctls except PIOCTABRUN. 

struct prthreads {
    long  pr_count;         /∗ number of threads to operate on
                             ∗ written by user, read by kernel
                             ∗/
    tid_t pr_error_thread;  /∗ if error, the ID of the thread
                             ∗ causing the error is written here
                             ∗ by the kernel
                             ∗/
    char  pr_data[1];       /∗ this is a place holder, its
                             ∗ address is used as the start of
                             ∗ the list of ioctl specific data
                             ∗ structures
                             ∗/
};

The structure, struct prabrun, which is also defined in <sys/procfs.h>, is used as a common “header” only for the PIOCTABRUN ioctl. 

struct prabrun {
    long  pr_count;         /∗ number of threads to operate on
                             ∗ written by user, read by kernel
                             ∗/
    tid_t pr_error_thread;  /∗ if error, the ID of the thread
                             ∗ causing the error is written here
                             ∗ by the kernel
                             ∗/
    prrun_t pr_run;         /∗ common run struct NOTE,
                             ∗ pr_tid unused
                             ∗/
    char  pr_data[1];       /∗ this is a place holder, its address
                             ∗ is used as the start of the list of
                             ∗ thread IDs to not run
                             ∗/
};

The PIOCTCFAULT ioctl is used below to show how these structure definitions are to be used. 

The “base” ioctl PIOCCFAULT is used to clear the current fault and prevent a signal from being generated.  This ioctl does not take a p parameter.  The PIOCTCFAULT ioctl provides the same functionality, but for a specific thread (or threads).  It will be used to illustrate how the p buffer is built and used.  The scenario is as follows:  Two threads, IDs 0xffffffff800c0a00 and 0xffffffff800c0b00, are stopped tracing on a fault.  PIOCTCFAULT is to be used to clear the current fault in each thread. 

char tmp[132];
struct prthreads ∗p;
tid_t th;
int count = 2;
        /∗ First, allocate a "p" buffer that is the right size
         ∗/
p = (struct prthreads ∗)malloc(sizeof(struct prthreads)
    - sizeof(char)
    + (count ∗ sizeof(tid_t));
        /∗ Second, fill in the header - set pr_error_thread to 0
         ∗ merely as a convenience, if there is an error the
         ∗ kernel will set it to the thread ID that caused the
         ∗ error
         ∗/
p->pr_count = count;
p->pr_error_thread = (tid_t)0;
        /∗ Third, fill in the list of thread IDs
         ∗/
th = (tid_t)p->pr_data;
∗th = 0xffffffff800c0a00;
th++;
∗th = 0xffffffff800c0b00;
        /∗ Last, make the ioctl call
         ∗/
if(ioctl(fd, PIOCTCFAULT, p) == -1) {
    sprintf(tmp, "PIOCTCFAULT error, thread %lx", \
           p->pr_error_thread);
    perror(tmp);
    free(p);
    return(-1);
}

In this example, the buffer in memory that is pointed to by p will contain the following 4 longwords. 

     2
     0
ffffffff800c0a00
ffffffff800c0b00

As the above example shows, if the ioctl() call returns error status, the ID of the thread on which the error was detected is returned in pr_error_thread.  When the kernel code detects an error, ioctl processing stops.  This means that the ioctl actions succeeded for each thread in the specified list that proceeded the thread for which the error was reported.  No ioctl action is attempted for any remaining threads in the list after an error is detected.  If a failure is encountered that is not related to a specific thread (more threads are specified to PIOCTABRUN than exist) the pr_error_thread value will be returned as 0. 

If a specified thread is not found in the task->thread_list, error EBADF is returned.  This is common to all of the PIOCTxxx ioctls. 

PIOCTRUN

This ioctl is used to run one or more threads that are stopped on an event of interest.  This ioctl provides the same functionality for the specified thread(s) as the “base” PIOCRUN ioctl provides for the process/task, with one exception.  The PRSHOLD flag of prrun.pr_flags is not recognized because signals can only be held on a task wide basis.  The corresponding prrun.pr_sighold entry is present but unused.  This ioctl requires write access. 

Unlike PIOCRUN, a prrun structure must always be specified for PIOCTRUN.  A thread is selected by filling in the pr_tid field of the prrun structure.  The PIOCTRUN ioctl does provide the same functionality as the PIOCRUN ioctl with a NULL p pointer if the prrun.pr_flags field is set to 0. 

If a specified thread is not stopped on an event of interest, error EBUSY  is returned.  If any error is detected while attempting to run a thread, the ioctl code returns; any threads in the list before the error will have been started, any threads in the list after the thread in error will not have been started. 

Usage:

ioctl(fd, PIOCTRUN, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads to run
                         ∗/
tid_t pr_error_thread;  /∗ set by kernel if error is detected
                         ∗/
struct prrun thread_1;  /∗ prrun struct, containing thread ID of
                         ∗ 1st thread to run in thread_1.pr_tid
                         ∗/
.
.
.
struct prrun thread_N;  /∗ prrun.pr_tid contains ID of last
                         ∗ thread to run in thread_N.pr_tid
                         ∗/

PIOCTABRUN

This ioctl provides the ability to run all the threads in the task that are stopped on an event of interest, except those that are specified in the thread list.  Any threads that are not stopped on an event of interest will cause an error to be generated.  This ioctl differs somewhat from the other PIOCTxxx ioctls in that the threads specified in the list are checked before any action is taken.  If any of the threads specified do not exit in the task->thread_list, error EBADF is returned, with the non-existent thread ID being placed in pr_error_thread.  The input buffer for this ioctl contains a single prrun structure, whose contents are applied to each thread that is to be run.  The pr_tid field of this prrun structure is not used; all threads must be specified in the list that follows the prrun structure.  With the exception of ignoring the pr_tid field, the prrun structure is treated the same as in the PIOCTRUN ioctl. This ioctl requires write access. 

Usage:

ioctl(fd, PIOCTABRUN, p)

The format of the buffer pointed to by p follows:

long count;             /∗ # of threads not to run in the list
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
struct prrun modifier;  /∗ NOTE, pr_tid is unused
                         ∗/
tid_t thread_1;         /∗ ID of first thread to not run
                         ∗/
.
.
.
tid_t thread_N;         /∗ ID of last thread to not run
                         ∗/

PIOCTSTOP, PIOCTSTATUS

PIOCTSTOP stops the specified thread(s) and returns status in the specified prstatus structure(s); PIOCTSTATUS just returns status.  The PIOCTSTOP ioctl requires write access.  If PIOCTSTOP is invoked for a thread, the thread must be restarted via PIOCTRUN or PIOCTABRUN; PIOCRUN will have no affect on it. 

These ioctls use the same status structure, prstatus, that is used by the “base” PIOCSTOP and PIOCSTATUS ioctls. 

Unlike PIOCSTOP, a prstatus structure must always be specified for PIOCTSTOP.  A thread is selected by filling in the pr_tid field of the prstatus structure.  (See the comment for the thread_1 entry below.) 

Usage:

ioctl(fd, PIOCTSTOP, p)
ioctl(fd, PIOCTSTATUS, p)

The buffer pointed to by p for both these ioctls is as follows:

long pr_count;          /∗ number of threads in list
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
struct prstatus thread_1; /∗ "selected" thread is in
                           ∗ thread_1.pr_tid
                           ∗/
.
.
.
struct prstatus thread_N; /∗ thread_N.pr_tid contains ID of last
                           ∗  thread to stop (PIOCTSTOP) or return
                           ∗  status for (PIOCTSTATUS)
                           ∗/

PIOCTGTRACE, PIOCTSTRACE

These ioctls get and set the set of signals that are being traced by the specified thread(s).  These parallel the “base” ioctls PIOCGTRACE and PIOCSTRACE.  The PIOCTSTRACE ioctl requires write access. 

Usage:

ioctl(fd, PIOCTGTRACE, p)
ioctl(fd, PIOCTSTRACE, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads specified
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
tsigset_t thread_1;     /∗ first thread to act on
∗/
.
.
.
tsigset_t thread_N;     /∗ last thread to act on
∗/

tsigset_t is defined in <sys/procfs.h> and has the following definition:

typedef struct tsigset {
        sigset_t pr_sigtrace;   /∗ set of signals to trace
                                 ∗/
        tid_t    pr_tid;        /∗ the thread ID to act upon
                                 ∗/
} tsigset_t;                    /∗ note, this is not a pointer
 ∗/

PIOCTGFAULT, PIOCTSFAULT

These ioctls get and set the set of faults that are being traced by the specified thread(s).  These parallel the “base” ioctls PIOCGFAULT and PIOCSFAULT.  The PIOCTSFAULT ioctl requires write access. 

Usage:

ioctl(fd, PIOCTGFAULT, p)
ioctl(fd, PIOCTSFAULT, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads specified
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
tfltset_t thread_1;     /∗ first thread to act on
                         ∗/
.
.
.
tfltset_t thread_N;     /∗ last thread to act on
                         ∗/

tfltset_t is defined in <sys/procfs.h> and has the following format:

typedef struct tfltset {
        fltset_t pr_flttrace;   /∗ fault trace mask - same as
                                 ∗ "base"
                                 ∗/
        tid_t   pr_tid;         /∗ the thread ID to act upon
                                 ∗/
} tfltset_t;                    /∗ note, this is not a pointer
                                 ∗/

PIOCTSENTRY, PIOCTGENTRY, PIOCTSEXIT, PIOCTGEXIT

PIOCTGENTRY and PIOCTSENTRY get and set the system calls that are traced on syscall() entry, for the specified thread(s).  These perform the same type of function as the “base” ioctls PIOCGENTRY and PIOCSENTRY.  The PIOCTSENTRY and PIOCTSEXIT ioctls require write access. 

PIOCTGEXIT and PIOCTSEXIT get and set the system calls that are traced on syscall() exit, for the specified thread(s).  These perform the same type of function as the “base” ioctls PIOCGEXIT and PIOCSEXIT. 

Usage:

ioctl(fd, PIOCTGENTRY, p)
ioctl(fd, PIOCTSENTRY, p)
ioctl(fd, PIOCTGEXIT, p)
ioctl(fd, PIOCTSEXIT, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads specified
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
tsysset_t thread_1;     /∗ first thread to act on
                         ∗/



tsysset_t thread_N;     /∗ last thread to act on
 ∗/

tsysset_t is defined in <sys/procfs.h> and has the following format:

typedef struct tsysset {
        t_sysset_t pr_systrace; /∗ set of system calls to trace
                                 ∗/
        tid_t pr_tid;           /∗ the thread ID to act upon
                                 ∗/
} tsysset_t;                    /∗ note, this is not a pointer
                                 ∗/

PIOCTSSIG

This ioctl allows the “current signal” to be cleared or changed to some other signa, only if the specified thread(s) is stopped on a signal trace event.  This functionality is different than the “base” PIOCSSIG ioctl.  This ioctl requires write access. 

Usage:

ioctl(fd, PIOCTSSIG, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads specified
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
tsiginfo_t thread_1;    /∗ first thread to act on
                         ∗/



tsiginfo_t thread_N;    /∗ last thread to act on
                         ∗/

tsiginfo_t is defined in <sys/procfs.h> and has the following format:

typedef struct tsiginfo {
        siginto_t pr_siginfo;   /∗ the actual siginfo structure
                                 ∗/
        tid_t pr_tid;           /∗ the thread ID to act upon
                                 ∗/
} tsiginfo_t;                   /∗ note, this is not a pointer
                                 ∗/

PIOCTKILL

This ioctl allows a thread-specific signal to be sent to a specified thread.  Multiple threads can be specified, and a different signal can be sent to each specified thread.  This ioctl requires write access. 

NOTE:  The PIOCTKILL ioctl cannot be used to send an asynchronous signal. 

Usage:

ioctl(fd, PIOCTKILL, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads specified
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
tsignal_t thread_1;     /∗ first thread to act on
                         ∗/



tsignal_t thread_N;     /∗ last thread to act on
 ∗/

tsignal_t is defined in <sys/procfs.h> and has the following format:

typedef struct tsignal {
        int pr_signal;          /∗ the signal to send
                                 ∗/
        tid_t pr_tid;           /∗ the thread ID to act upon
                                 ∗/
} tsignal_t;                    /∗ note, this is not a pointer
                                 ∗/

PIOCTUNKILL

This ioctl allows a thread-specific signal that is pending for a specified thread to be deleted from the list of pending signals.  Multiple threads can be specified, and a different signal can be removed from each specified thread.  This ioctl requires write access. 

Usage:

ioctl(fd, PIOCTUNKILL, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads specified
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
tsignal_t thread_1;     /∗ first thread to act on
                         ∗/



tsignal_t thread_N;     /∗ last thread to act on
                         ∗/

tsignal_t is defined in <sys/procfs.h> and has the following format:

typedef struct tsignal {
        int pr_signal;          /∗ the signal to remove
                                 ∗/
        tid_t pr_tid;           /∗ the thread ID to act upon
                                 ∗/
} tsignal_t;                    /∗ note, this is not a pointer
                                 ∗/

PIOCTCFAULT

This ioctl clears the current fault (if any) for the specified thread or threads, and prevents a signal from being generated.  This ioctl requires write access. 

Usage:

ioctl(fd, PIOCTCFAULT, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads in list
                         ∗/
tid_t pr_error_thread ; /∗ thread ID if error
                         ∗/
tid_t thread_1;         /∗ ID of first thread in list
                         ∗/
.
.
.
tid_t thread_N;         /∗ ID of last thread in list
                         ∗/

PIOCTGFPREG, PIOCTSFPREG∗

These ioctls are used to get and set the Floating Point registers for the specified thread(s); they perform the same type of functions as the “base” ioctls PIOCGFPREG and PIOCSFPREG.  The PIOCTSFPREG∗ ioctl requires write access. 

For PIOCTGFPREG, if the FP hardware had not been in use (pcb_ownedfp is NULL) all NULLs are returned.  If a specified thread is not stopped on an event of interest, error EBUSY is returned. 

For PIOCTSFPREG, if a specified thread is not stopped on an event of interest, error EBUSY is returned.  No check is made to see if the FP hardware had been in use. 

Usage:

ioctl(fd, PIOCTGFPREG, p)
ioctl(fd, PIOCTSFPREG, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads specified
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
tfpregset_t thread_1;   /∗ first thread to act on
                         ∗/



tfpregset_t thread_N;   /∗ last thread to act on
                         ∗/

tfpregset_t is defined in <sys/procfs.h> and has the following format:

struct tfpregset {
        fpregset_t pr_fpregs;   /∗ floating point registers
                                 ∗/
        tid_t pr_tid;           /∗ the thread ID to act upon
                                 ∗/
};
typedef struct tfpregset tfpregset_t;

PIOCTGREG, PIOCTSREG

These ioctls are used to get and set the general registers for the specified thread(s); they perform the same type of functions as the “base” ioctls PIOCGREG and PIOCSREG.  The PIOCTSREG ioctl requires write access. 

For PIOCTSREG, if a specified thread is not stopped on an event of interest, error EBUSY is returned. 

Usage:

ioctl(fd, PIOCTGREG, p)
ioctl(fd, PIOCTSREG, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads specified
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
tgregset_t thread_1;    /∗ first thread to act on
                         ∗/



tgregset_t thread_N;    /∗ last thread to act on
                         ∗/

tgregset_t is defined in <sys/procfs.h> and has the following format:

struct tgregset {
        gregset_t pr_regs;      /∗ general registers
                                 ∗/
        tid_t pr_tid;           /∗ the thread ID to act upon
                                 ∗/
};
typedef struct tgregset tgregset_t;

PIOCACTION

This returns the signal handler routines for all signals, for each specified thread. 

Usage:

ioctl(fd, PIOCTACTION, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads in list
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
tsigaction_t thread_1;  /∗ first thread to get action routines for
                         ∗/



tsigaction_t thread_N;  /∗ last thread to get action routines for
                         ∗/

tsigaction_t is defined in <sys/procfs.h> and has the following format:

typedef struct tsigaction {
    struct sigaction pr_sigaction[NSIG];/∗ array of sigaction
                                         ∗ structs
                                         ∗/
    tid_t pr_tid;                       /∗ thread ID
                                         ∗/
} tsigaction_t;

PIOCTTERM

Terminate each thread specified in the list contained in the buffer pointed to by p.  The affected thread(s) will not stop on an event of interest even if stop-on-thread-terminate had been set via PIOCSSPCACT with PRFS_STOPTTERM set.  This ioctl requires write access. 

Usage:

ioctl(fd, PIOCTTERM, p)

The buffer pointed to by p has the following format:

long pr_count;          /∗ number of threads in list
                         ∗/
tid_t pr_error_thread;  /∗ thread ID if error
                         ∗/
tid_t thread_1;         /∗ ID of first thread in list
                         ∗/



tid_t thread_N;         /∗ ID of last thread in list
                         ∗/

Task vs Thread Tracing and Control

Tracing and process control can be done at the task and/or thread level.  Care should be used if task and thread tracing or control ioctls are mixed.  Because only threads can execute, a task trace really occurs when some thread in a task recognizes a task trace event. 

If a thread is stopped at an event of interest, either because of a thread trace or by the PIOCTSTOP)O ioctl, the PIOCTRUN (or PIOCTABRUN) ioctl must be used to restart it.  The PIOCRUN ioctl has no effect on any thread that is stopped on a thread specific event. 

Only one trace event, per process, can occur at a time.  If one thread is stopped on a trace event, no other thread or task trace event can occur until the first thread is restarted. 

The number of threads that can be specified is limited by the maximum size of the buffer that the base ioctl code can handle.  This is an architecture-specific limit. 

The basic trace events are stop on fault, or signal, or system call entry or exit.  The Digital UNIX implementation of /proc adds the distinction of a task (effectively a process) trace event, and a thread trace event.  Using signals as an example, when a signal is about to be delivered, a check is made to see if the signal is to be traced.  This check is done for the task first, then if a match is not found the check is repeated at the thread level.  For signals, there is one trace bitmap associated with the task, and one trace bitmap for each thread in the process.  Any thread executing the signal delivery code first checks the task trace bitmap for a trace event, and then (if there was no match at the task level) checks its particular thread trace bitmap for a match.  The task level trace, therefore, takes precedence over the thread level trace.  In the Alpha AXP architecture, a breakpoint instruction causes a SIGTRAP signal to be delivered to the process.  Because all threads share the same virtual memory, any thread can execute the breakpoint instruction and take a SIGTRAP signal.  If SIGTRAP is being traced at the task level, this is not a problem, because every thread first checks the task trace bitmap. 

But consider the following scenario:  SIGTRAP is not being traced at the task level.  The task has three threads, but only one thread has trace on signal SIGTRAP selected.  If either of the two remaining threads execute the breakpoint instruction, the signal trace event will not occur, and the “victim” process will dump core. 

FILES

/procContains the directory listing of active processes

/proc/nnnnnContains the process image

RELATED INFORMATION

Functions: open(2), ptrace(2), sigaction(2), signal(2). 

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026