HPlogo HP-UX Reference > P

ptrace(2)

PA-RISC Only; TO BE OBSOLETED
HP-UX 11i Version 2: December 2007 Update
» 

Technical documentation

 » Table of Contents

 » Index

NAME

ptrace() — process trace

SYNOPSIS

#include <sys/ptrace.h> long ptrace( int request, pid_t pid, long addr, long data, long addr2 );

Remarks

ptrace() is not available on Itanium(R)-based systems. Its use is discouraged because it is targeted for removal from HP-UX. Please use ttrace(2) instead.

Much of the functionality of ptrace() is highly dependent on the underlying hardware. An application that uses this system call should not be expected to be portable across architectures or implementations.

DESCRIPTION

The ptrace() system call provides a means by which a process can control the execution of another process. Its primary use is for the implementation of a breakpoint debugging mechanism (see adb(1)) and involves a tracing and a traced process. The traced process behaves normally until it encounters a signal (see signal(2) for the list) at which time it enters a stopped state and the tracing process is notified via wait() (see wait(2)).

A traced process may also enter the stopped state without encountering a signal. This can happen if the traced process stops in response to specific events that it encounters during the course of its execution. To make this happen, the tracing process has to set specific event flags in the context of the traced process. This mechanism will be described later in greater detail.

When the traced process is in the stopped state, the tracing process can use ptrace() to examine and modify the "core image". Also, the tracing process can cause the traced process to either terminate or continue, with the possibility of ignoring the signal that caused it to stop.

To forestall possible fraud, ptrace() inhibits the set-user-ID facility on subsequent exec*() calls. If a traced process calls exec*() it stops before executing the first instruction of the new image, showing signal SIGTRAP.

The request argument determines the precise action to be taken by ptrace().

The following request argument is used by the child process that will be traced.

PT_SETTRC

This request must be issued by a child process if it is to be traced by its parent. It turns on the child's trace flag which stipulates that the child should be left in a stopped state upon receipt of a signal rather than the state specified by func (see signal(2)). The pid, addr, data, and addr2 arguments are ignored and a return value is not defined for this request. Peculiar results occur if the parent does not expect to trace the child.

The remainder of the request argument values can only be used by the tracing process. For each, pid is the process ID of the process being traced which must be in a stopped state before these requests are made. The responsibility of ensuring that the traced process is in a stopped state before a request is issued lies with the tracing process.

PT_RDUSER

PT_RIUSER

The word specified by the address in the addr argument in the address space of the traced process is returned to the tracing process. If the instruction (I) and data (D) space are separated, request PT_RIUSER returns a word from I space and request PT_RDUSER returns a word from D space. If I and D space are not separated, either request produces equivalent results. The data and addr2 arguments are ignored.

These two requests fail if addr is not the start address of a word, in which case a value of -1 is returned to the tracing process and errno is set to EIO.

PT_RUAREA

The word specified by the address in the addr argument in the user area of the traced process in the system's address space (see <sys/user.h>) is returned to the tracing process. The addresses in this area are system dependent but start at zero and the limit can be obtained from <sys/user.h>. The data and addr2 arguments are ignored.

This request fails if addr is not the starting address of a word or is outside the user area, in which case the value of -1 is returned to the tracing process and errno is set to EIO.

PT_WDUSER

PT_WIUSER

The value in the data argument is written into the address space of the traced process at the location specified in the addr argument. PT_WIUSER writes a word into I space and PT_WDUSER writes a word in D space. Upon successful completion, the value written into the address space of the traced process is returned to the tracing process. The addr2 argument is ignored.

These two requests fail if addr is not the starting address of a word. It will also fail if the addr argument is a location in a pure procedure space and either another process is executing in that space or the tracing process does not have write access to the executable file corresponding to that space. A value of -1 is returned to the tracing process if it fails and errno is set to EIO.

PT_WUAREA

This request is not supported and returns a -1, along with setting errno to EIO (no affect upon the user area of the traced process).

PT_RUREGS

The word at the location specified by the addr argument in the save_state structure at the base of the per-process kernel stack is returned to the tracing process. The addr argument must be word-aligned and less than STACKSIZE*NBPG (see <sys/param.h> and <machine/param.h>). The save_state structure contains the registers and other information about the process. The data and addr2 arguments are ignored.

PT_WUREGS

The word at the location specified by the addr argument in the save_state structure at the base of the per-process kernel stack is updated. Only a few locations can be written in this way: the general registers, most floating-point registers, a few control registers, and certain bits of the interruption processor status word. The addr2 argument is ignored.

PT_RDDATA

PT_RDTEXT

These requests are identical to PT_RDUSER and PT_RIUSER except that the data argument specifies the number of bytes to read and the addr2 argument specifies where to store that data in the tracing process.

PT_WRDATA

PT_WRTEXT

These requests are identical to PT_WDUSER and PT_WIUSER except that the data argument specifies the number of bytes to write and the addr2 argument specifies where to read that data in the tracing process.

PT_CONTIN

This request causes the traced process to resume execution. If the data argument is 0, all pending signals including the one that caused the traced process to stop, are canceled before it resumes execution. If the data argument is a valid signal number, the traced process resumes execution as if it had incurred that signal and any other pending signals are canceled. The addr2 argument is ignored.

If the addr argument is not 1, the Instruction Address Offset Queue (program counter) is loaded with the values addr and addr+4 before execution resumes. Otherwise, execution resumes from the point where it was interrupted.

Upon successful completion, the value of the data argument is returned to the tracing process.

This request fails if the data argument is not 0 or a valid signal number and a value of -1 is returned to the tracing process and errno is set to EIO.

PT_EXIT

This request causes the traced process to terminate in the same manner as doing an exit() call. The addr, data, and addr2 arguments are ignored.

PT_SINGLE

This request causes a flag to be set so that an interrupt occurs upon the completion of one machine instruction. It then executes the same way as listed for request PT_CONTIN, effectively allowing the single-stepping of the traced process. If the processor does not provide a trace bit, this request returns an error.

Whether or not the trace bit remains set after this interrupt is a function of the hardware.

PT_ATTACH

This request stops the process specified by the pid argument and allows the calling process to trace it. The process does not have to be a child of the calling process but the effective user ID of the calling process must match the real and saved user ID of process pid unless the tracing process has the OWNER privilege. The calling process can use the wait() system call to wait for process pid to stop. The addr, data, and addr2 arguments are ignored.

PT_DETACH

This request detaches the traced process specified by the pid argument and allows it to continue its execution in the manner of PT_CONTIN.

If the addr argument is not 1, the Instruction Address Offset Queue (program counter) is loaded with the values from the addr and addr2 arguments.

PT_CONTIN1

This request causes the traced process to resume execution with all its pending signals intact. If the data argument is 0, the signal that caused the traced process to stop is canceled before the traced process resumes execution. If the data argument is a valid signal number, the traced process resumes execution as if it had received that signal. The addr argument must be equal to 1 for this request and the addr2 argument is ignored. Upon successful completion, the value of data is returned to the tracing process.

This request fails if data is not 0 or a valid signal number and a value of -1 is returned to the tracing process and errno is set to EIO.

PT_SINGLE1

This request causes a flag to be set so that an interrupt occurs upon the completion of one machine instruction. It then executes the same steps as listed above for request PT_CONTIN1 and provides the single stepping of the traced process. If the processor does not provide a trace bit, this request returns an error.

Whether or not the trace bit remains set after this interrupt is a function of the hardware.

As noted earlier, a tracing process can set event flags in the context of the traced process to make it respond to specific events during its execution. These events are:

PTRACE_SIGNAL

This event flag indicates that when processing signals, the traced process needs to examine signal mask bits set in its context by the tracing process. See the ptrace_event structure description under PT_SET_EVENT_MASK for further details.

If the signal being processed has its signal mask bit set, signal processing continues as though the process was not traced. The traced process is not stopped and the tracing process is not notified of the signal. If the signal mask bit is not set for the signal being processed, the traced process is stopped and the tracing process is notified via a wait() call (see wait(2)).

Note that the SIGKILL signal is an exception to this rule in that it can never be unmasked; it behaves as though its mask bit were always set, whether or not it is actually set. Consequently, a SIGKILL signal cannot be used to stop a traced process.

In this respect, a SIGTRAP signal is also special in that it is specifically used to stop traced processes. A SIGTRAP signal should therefore never be masked. Setting a mask bit for SIGTRAP will result in unexpected system behavior.

PTRACE_FORK

This event flag indicates that the traced process needs to take special action when it invokes the fork() call. When set, both the parent and child processes stop (the child after marking itself as the traced process and adopting its parent's debugger). Both processes log the fact that they stopped in response to a PTRACE_FORK event. Further, the child's pid argument value is logged in the parent's context and the parent's pid argument value is logged in the child's context. The child does not inherit its parent's event flags. See the ptrace_state structure description under PT_GET_PROCESS_STATE for further details.

PTRACE_VFORK

This event flag indicates that the traced process needs to take special action when it invokes vfork(). When set, the child process stops after marking itself as a traced process and adopting its parent's debugger. The fact that a PTRACE_VFORK event was handled is logged in the context of both the parent and child processes. Further, the child's pid argument value is logged in the parent's context and the parent's pid argument value is logged in the child's context. The child does not inherit its parent's event flags. See the ptrace_state structure description under PT_GET_PROCESS_STATE for further details.

It is important to note that the warnings with respect to vfork() (see vfork(2)), continue to apply here. It needs to be remembered that when the child process stops, its parent process is suspended and that the child borrows the parent's memory and thread of control until a call is done to either exec*() or exit(), or it exits abnormally (see exec(2) and exit(2)).

PTRACE_EXEC

This event flag indicates that the traced process needs to take special action when it invokes exec*(). When set, the traced process stops after logging the fact that it stopped in response to a PTRACE_EXEC event. It also logs information pertaining to the path or file argument of exec*(). This includes a pointer to the path name string and the length of the path name string. See the ptrace_state structure description under PT_GET_PROCESS_STATE for further details.

PTRACE_EXIT

This event flag indicates that the traced process needs to take special action when it invokes exit(). When set, the traced process stops after logging the PTRACE_EXIT event.

PT_SET_EVENT_MASK

This request is used by the calling process to specify event flags and signal mask values that it wants the traced process to respond to. It does so by writing the contents of the ptrace_event data structure in the user space pointed to by the addr argument into the context of the traced process. The data argument specifies the number of bytes to be transferred. The addr2 argument is ignored.

The request fails if the number of bytes specified is less than zero or greater than the size of the ptrace_event structure and results in errno being set to EIO. The typedef for the ptrace_event data structure is shown below:

typedef struct ptrace_event{ sigset_t pe_signals; events_t pe_set_event; char pe_spare[28]; } ptrace_event_t;

Event flags are set in the pe_set_event member of the ptrace_event data structure. An event flag is set when the tracing process wants the traced process to respond to a particular event. As detailed earlier, the event flags defined are PTRACE_EXEC, PTRACE_EXIT, PTRACE_FORK, PTRACE_SIGNAL, and PTRACE_VFORK. See the definition of events_t in <sys/ptrace.h> for more details.

Signal mask values are set in the pe_signals member of the ptrace_event structure. This member is activated by a PTRACE_SIGNAL event flag being set in the pe_set_event member. Mask values set in the pe_signals member correspond to signals that need to be masked from the tracing process that the traced process received; that is, these are signals received by the traced process that the tracing process does not want to be informed about. The pe_signals member is described by the type definition sigset_t which is defined in <signal.h>.

PT_GET_EVENT_MASK

This request is used by the calling process to determine the event flags and signal mask values that have been set in the traced process's context by the last PT_SET_EVENT_MASK request. The data argument specifies the number of bytes to be read from the traced process' context into the ptrace_event data structure pointed to by addr argument. The addr2 argument is ignored.

The request fails if the number of bytes requested is less than zero or greater than the size of the ptrace_event structure which results in errno being set to EIO.

PT_GET_PROCESS_STATE

This request is used by the calling process to access state information logged by the traced process after it has responded to an event. The request reads data bytes of data from the traced process's context into the ptrace_state data structure pointed to by the addr argument. The addr2 argument is ignored.

The ptrace_state data structure is defined in <sys/ptrace.h> and has the structure:

typedef struct ptrace_state{ events_t pe_report_event; int pe_path_len; pid_t pe_other_pid; } ptrace_state_t;

The event that the traced process responded to and stopped for is logged in the pe_report_event member. One of the following structure members PTRACE_EXEC, PTRACE_EXIT, PTRACE_FORK, PTRACE_SIGNAL, or PTRACE_VFORK is logged here. See the definition of events_t in <sys/ptrace.h> for more details.

If the event that the traced process responded to was PTRACE_EXEC, then the pe_path_len member provides the length of the path name string (that is, the executable file path name) not including the null terminating character.

If the event that the traced process responded to was PTRACE_FORK or PTRACE_VFORK, then the pe_other_pid member provides the parent's pid when accessed from the child's context, and the child's pid when accessed from the parent's context.

The request fails if the number of bytes requested is less than zero or greater than the size of the ptrace_event structure and results in errno being set to EIO.

PT_GET_PROCESS_PATHNAME

If the traced process is responded to and stopped for a PTRACE_EXEC event, then the calling process uses this request to access the path name of the executable file that is provided as a path or file argument to exec*(). The request reads the number of bytes of the path name string specified by the data argument from the traced process's context into the data buffer in user space pointed to by the addr argument. The addr2 argument is ignored. In the typical case, the value in the data argument is equal to the value of the pe_path_len member of the ptrace_state structure returned via the PT_GET_PROCESS_STATE request.

If the number of bytes requested is greater than zero but less than the length of the path name string, then the number of bytes requested is returned. If the number of bytes requested is greater than the length of the path name string, then the full path name string (including the null terminating character) is returned.

The request fails if the number of bytes requested is less than zero and results in errno being set to EIO.

Security Restrictions

Some or all of the actions associated with this system call are subject to compartmental restrictions. See compartments(5) for more information about compartmentalization on systems that support that feature. Compartmental restrictions can be overridden if the process possesses the COMMALLOWED privilege (PRIV_COMMALLOWED). Processes owned by the superuser may not have this privilege. Processes owned by any user may have this privilege, depending on system configuration.

Some or all of the actions associated with this system call reqnire the OWNER privilege. Processes owned by the superuser have this privilege. Processes owned by other users may have this privilege, depending on system configuration. See privileges(5) for more information about privileged access on systems that support fine-grained privileges.

EXAMPLES

The following example illustrates the use of some of the ptrace() calls by a tracing process.

#include <stdio.h> #include <signal.h> #include <sys/wait.h> #include <sys/ptrace.h> #define BUFSIZ 1024 #define MAXPATH 1024 pid_t npid, cpid, pid; int status, errors=0, pathlength; ptrace_event_t *event_addr; ptrace_state_t *state_addr; char *buf_addr; size_t event_len, state_len; int filed[2]; child() { int n, bar; close(filed[1]); /* Wait for parent to write to pipe */ while ((n = read(filed[0], &bar, BUFSIZ)) == 0); /* Now the child can exec. */ if (execlp("ls", "ls", (char *)0) < 0) /* error during exec */ printf("Child: exec failed\n"); exit(0); } parent() { close(filed[0]); /* Before child does an exec, attach it and set its event flag. */ if (ptrace(PT_ATTACH,pid)) /* failed to attach process */ printf("Parent: Failed to attach child\n"); if (pid != wait(&status)) /* wait failed */ printf("Parent: attach failed with wrong wait status\n"); if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) printf("Parent: SIGTRAP didn't stop child\n"); /* * The child process has now stopped. Set its event flag indicating * that it needs to trigger on a PTRACE_EXEC event. */ event_addr->pe_set_event = PTRACE_EXEC; if (ptrace(PT_SET_EVENT_MASK, pid, event_addr, event_len)) printf("Parent: PT_SET_EVENT_MASK ptrace request failed\n"); if (pid != wait(&status)) /* wait failed */ printf("Parent: wait() failed with wrong wait status\n"); /* * Send the child a message so it can break out of the while loop. * Get it running so it can exec. */ write(filed[1], "now run", 7); if (ptrace(PT_CONTIN, pid, 1, 0) != 0) printf("Parent: failed to get child process running\n"); /* * Wait for the traced child to stop after the exec system call in * response to an exec event set in its ptrace_event structure. */ if (pid != (npid = wait(&status))) /* wait failed */ printf("Parent: wait() failed with wrong status\n"); if (!WIFSTOPPED(status)) printf("Parent: invalid wait() completion\n"); /* * Child has stopped; fetch its process state and examine state * information. */ if (ptrace(PT_GET_PROCESS_STATE, pid, state_addr, state_len) < 0) printf("Parent: PT_GET_PROCESS_STATE ptrace request failed\n"); if (pid != wait(&status)) /* wait failed */ printf("Parent: wait() failed with wrong wait status\n"); /* Check if the pathlength value returned is non-zero */ if ((pathlength = state_addr->pe_path_len) == 0) printf("Parent: zero length pathname returned\n"); /* Fetch exec'd file pathname and store it in the buffer. */ if (ptrace(PT_GET_PROCESS_PATHNAME, pid, buf_addr, (pathlength+1)) < 0){ printf("Parent: Failed to get exec pathname\n"); } else { printf("Parent: the exec pathname is %s\n", buf_addr); if (pid != wait(&status)) /* wait failed */ printf("Parent: wait() failed with wrong status\n"); } } main() { event_len = sizeof(ptrace_event_t); state_len = sizeof(ptrace_state_t); event_addr = calloc(event_len, 1); state_addr = calloc(state_len, 1); buf_addr = calloc(MAXPATH, 1); pipe(filed); switch (pid = fork()) { case -1: exit(1); case 0: child(); break; default: parent(); break; } }

ERRORS

If the ptrace() call fails, errno is set to one of the following values:

EACCES

The executable image of the process being attached resides across an interruptible NFS mount.

EIO

Argument request contains an illegal number.

EIO

The PT_SETTRC request is called with a data argument that is less than zero, not a multiple of four or contains an address that is not word-aligned.

EIO

Attempting to write to a memory segment of the traced process that is not writable, attempting to write to page 0 or the request argument is out of range.

EIO

The PT_CONTIN request is being used with an invalid data signal number argument.

EIO

Attempting to write to the user area via the PT_WUAREA request.

EPERM

The specified process cannot be attached for tracing.

EPERM

The process specified in the pid argument is already being traced or refers to the calling process itself.

ESRCH

pid specifies a process to be traced that does not exist or has not executed a ptrace() call that has done a PT_SETTRC request.

STANDARDS CONFORMANCE

ptrace(): SVID2, SVID3, XPG2