|
» |
|
|
|
NAMEttrace() — tracing facility for multithreaded processes SYNOPSIS#include <sys/ttrace.h>
int ttrace (ttreq_t request, pid_t pid, lwpid_t lwpid,
uint64_t addr, uint64_t data, uint64_t addr2); RemarksWhile the POSIX API is defined and will not change, the present
underlying system calls are not guaranteed to be compatible with
future versions. Much of the functionality of this capability 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. DESCRIPTIONThe
ttrace()
system call provides a means by which a process can control
the execution of another process.
Its primary use is for the implementation of breakpoint and event driven
debugging; see
adb(1)
and
dde(1).
ttrace()
is designed to function for both single and multithreaded
traced processes.
The traced process
behaves normally until one of its threads encounters a signal (see
signal(2)
for the list), or an
event
(these are discussed in detail in the
EVENTS
section below)
at which time the thread enters a stopped state
and the tracing process is notified via
ttrace_wait(). RequestsMost of the
ttrace()
requests are to be used only by the tracing process.
However, some requests (those suffixed by
_NOATTACH)
can be used by any process provided that the effective user
ID of the calling process matches the real and saved uid of
the target process.
This is true unless the calling process has the
OWNER
privilege. ttrace()
requests are divided in four groups: requests that target a process,
requests that target a specific thread within the process,
requests that perform a series of requests on a process or thread, and
non-debug-related requests that target neither a process or a thread. The
request
argument determines the action to be taken by
ttrace()
and is one of the following: Process-Wide RequestsFor all process-wide requests (those prefixed by
TT_PROC_),
pid
is the process ID of the target process and
lwpid
must be set to zero.
- TT_PROC_SETTRC
This request must be issued by a child process
if it is to be traced by its parent. The
addr2
argument specifies the action to be taken by the loader
when the child process does an
exec().
If the value is
TT_GEN_SHLIB_BPT,
the loader will communicate certain events to the debugger
through an architected break instruction.
The information obtained through these events can be used by
the debugger to identify all the load modules in the program
and their unwind information.
If the debugger is not interested in these events
the value must be set to 0 (zero). The
pid,
lwpid,
and
addr
arguments must be set to 0 (zero) and
data
must be set to
TT_VERSION.
Peculiar results occur if the parent does not expect to trace the child. Note:
It is critical for future backward compatibility that the
TT_VERSION
macro itself be used and not its value.
- TT_PROC_ATTACH
This request allows the calling process to trace the process identified by
pid.
The process
pid
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 uid of the process
pid
unless the tracing process has the
OWNER
privilege. When this call returns, the target process (all its threads) is stopped. The
addr
argument specifies the action to be taken if the debugger exits without
having detached the target process. If the value is
TT_KILL_ON_EXIT,
the attached process(es) will be killed. If the value is
TT_DETACH_ON_EXIT,
the attached process(es) will be resumed and detached as if the debugger
had performed a
TT_PROC_DETACH
request. The
addr2
argument specifies the action to be taken by the loader
when the target process does an
exec().
If the value is
TT_GEN_SHLIB_BPT,
the loader will communicate certain events to the debugger
through an architected break instruction.
The information obtained through these events can be used
by the debugger to identify all the load modules in the program
and their unwind information.
If the debugger is not interested in these events
the value must be set to 0 (zero). The
lwpid
argument must be set to zero and
data
must be
TT_VERSION
(see
TT_PROC_SETTRC
above). - TT_PROC_DETACH
This request detaches the traced process and allows it to continue
executing. It behaves identically to
TT_PROC_CONTINUE
except that the process is no longer being traced after the call
returns. For this request, the
lwpid,
addr,
data,
and
addr2
arguments must be set to zero. - TT_PROC_RDTEXT, TT_PROC_RDTEXT_NOATTACH
These requests allow reading from the target process
text. The
addr
argument specifies the offset to be read from.
The
data
argument specifies the number of bytes to read and the
addr2
argument specifies where to store that data in the tracing process. The
lwpid
argument must be set to zero. - TT_PROC_RDDATA, TT_PROC_RDDATA_NOATTACH
These requests allow reading from the data space. The
addr
argument specifies the offset to be read from.
The
data
argument specifies the number of bytes to read and the
addr2
argument specifies where to store that data in the tracing process. The
lwpid
argument must be set to zero. - TT_PROC_WRTEXT, TT_PROC_WRDATA
These requests allow writing into the target process text
(TT_PROC_WRTEXT)
and data spaces
(TT_PROC_WRDATA). The
addr
argument specifies the offset to be written to.
The
data
argument specifies the number of bytes to write.a
The
addr2
argument specifies where to get the data in the tracing process. The
lwpid
argument must be set to zero. - TT_PROC_STOP
This request causes the traced process (all its threads) to stop.
If a thread was already stopped by the debugger prior to this
call, its state is not modified. The
lwpid,
addr,
data,
and
addr2
arguments must be set to zero. - TT_PROC_CONTINUE
This request causes the entire traced process to resume execution.
All threads that had been stopped directly (request) or indirectly (event)
by the debugger are resumed with all their pending signals intact. The
data,
addr,
and
addr2
arguments must be set to zero. - TT_PROC_GET_PATHNAME
This request is used by the calling process to access the path name of
the executable file provided as a
path
or
file
argument to
exec().
The request reads
data
bytes of data of the pathname string from the traced process' context into
the data buffer in user space pointed to by
addr. In the typical case,
data
is equal to the value of the
ttexec_data_t.tts_len
member of the
ttstate_t
structure returned via the
TT_LWP_GET_STATE
or other
ttrace
requests returning a Lightweight Process (LWP or lwp) state.
The length of the path does not include
a terminating null character. The data is available during the entire
life of the process. The
lwpid
and
addr2
arguments must be set to zero. - TT_PROC_GET_EVENT_MASK
This request returns the process-wide event flags
and signal mask values. The
data
argument specifies the number of bytes to be read from the context of the
traced process into the
ttevent_t
data structure in user space pointed to by
addr. The
lwpid
and
addr2
arguments must be set to zero. The
ttevent_t
data structure is as follows:
typedef struct {
sigset_t tte_signals;
ttevents_t tte_events;
tteopt_t tte_opts;
The options provided in
tte_opts
control the behavior of child processes produced by
fork()
and are as follows:
TTEO_NONE = 0x0000
TTEO_NOSTRCCHLD = 0x0001
TTEO_PROC_INHERIT = 0x0002
TTEO_LWP_INHERIT = 0x0004
TTEO_NORM_SIGTRAP = 0x0008 If
TTEO_NOSTRCCHLD
is set, the child process resulting
from a
fork()
will not be traced.
This makes it possible for a debugger to debug another debugger.
The
TTEO_PROC_INHERIT
and
TTEO_LWP_INHERIT
options allow
events to be inherited by child processes and threads respectively.
Refer to the
EVENTS
section below. If
TTEO_NORM_SIGTRAP
is set, the SIGTRAP signal behaves normally. That is, it is getting
delivered (the default behavior is to drop these signals). - TT_PROC_SET_EVENT_MASK
This request allows the tracing process to establish
events and signals the traced process will respond to.
Refer to the
EVENTS
section for a description of these events. The
addr
argument is a pointer to a
ttevent_t
structure to be copied into the target process.
The
data
argument specifies the number of bytes to be transferred. The
lwpid
and
addr2
arguments must be set to zero. - TT_PROC_GET_SIGMASK
This request returns the process-wide signal mask value for
the target process that was set using
TT_PROC_SET_SIGMASK. The
data
argument specifies the number of bytes to be read from the
context of the traced process into the
ttmask_t
data structure in user space pointed by
addr. The
lwpid
and
addr2
arguments must be set to zero. The
ttmask_t
data structure is as follows:
typedef struct {
sigset_t ttm_signals;
ttmopt_t ttm_opts;
The options provided in
ttm_opts
control the behavior of signal masks on child processes
produced by
fork()
and are as follows:
TTMO_NONE = 0x0000
TTMO_PROC_INHERIT = 0x0001
TTMO_LWP_INHERIT = 0x0002 The
TTMO_PROC_INHERIT
and
TT_LWP_INHERIT
option allow signal masks to be inherited by child processes
and threads respectively. - TT_PROC_SET_SIGMASK
This request allows the tracing process to change the signal
mask on the target process. The
addr
argument is a pointer to a
ttmask_t
structure to be copied into the target process.
The
data
argument specifies the number of bytes to be transferred. The
lwpid
and
addr2
arguments must be set to zero. The resulting signal mask on the traced process will be a union
of the current signal mask on the target process and the set pointed by the
ttm_signals
field in the
ttmask_t
structure.
Setting the
ttm_signals
to an empty set results in clearing the signal mask that was
previously set using this request. - TT_PROC_GET_FIRST_LWP_STATE
This request returns the
ttstate_t
structure associated with the first thread on the stopped list.
It resets the list pointer to the first entry in the list.
The
TT_PROC_GET_NEXT_LWP_STATE
request (see below) provides the means to
examine the state of other stopped threads. The
data
argument specifies the number bytes to be read from the context of the
traced process into the
ttstate_t
data structure in the user space pointed to by
addr.
The
lwpid
and
addr2
arguments must be zero. The
ttstate_t
structure provides the debugger with the means to query the system
for the state of a thread. It is established when a thread enters
the debugger stopped state and, except for the
TTS_WAITEDFOR
bit, is invariant until the thread is resumed. Its layout is as follows:
typedef struct {
pid_t tts_pid;
lwpid_t tts_lwpid;
uint64_t tts_user_tid;
ttevents_t tts_event;
ttsf_t tts_flags;
int tts_scno;
int tts_scnargs;
uint64_t tts_scarg[SCALL_MAXARGS];
union {
ttexec_data_t tts_exec;
ttfork_data_t tts_fork;
ttprefork_data_t tts_prefork;
ttsignal_data_t tts_signal;
ttthread_data_t tts_thread;
ttsyscall_data_t tts_syscall;
ttexit_data_t tts_exit;
ttbpt_data_t tts_bpt_sstep;
char tts_fill[128];
tts_pid
is the process ID. tts_lwpid
is the
lwpid
of the stopped thread. tts_user_tid
is the thread's user ID. tts_event
is the event that caused the stop
(TTEVT_NONE
if the thread stopped because of a
ttrace
command). The
tts_flags
provide information about the state of the thread before
it was stopped.
The information specifies whether or not the thread has been waited for by
ttrace_wait(),
whether or not it is processing a system call, whether it is a 32-bit
or a 64-bit process and whether the thread is in the
exit()
system call.
The values are as follows:
TTS_WASSUSPENDED = 0x0001
TTS_WASSLEEPING = 0x0002
TTS_WASRUNNING = 0x0004
TTS_WAITEDFOR = 0x0008
TTS_INSYSCALL = 0x0010
TTS_IS32BIT = 0x0020
TTS_ATEXIT = 0x0040 The following three arguments provide information
regarding the system call being executed when the thread was stopped.
This information is valid only if the
TTS_INSYSCALL
bit is set in
tts_flags. tts_scno
is the system call number. tts_scnargs
is the number of arguments of the system call. tts_scarg
is the argument list of the system call. The data associated with a
TTEVT_EXEC
event is as follows:
typedef struct {
int tts_pathlen;
tts_pathlen
is the length of the pathname of the
exec()
system call. The data associated with a
TTEVT_FORK,
TTEVT_VFORK
or
TTEVT_FORK_FAIL
event is as follows:
typedef struct {
pid_t tts_fpid;
lwpid_t tts_flwpid;
int tts_isparent;
int tts_errno;
tts_fpid
is the process ID of the other side of the fork.
This field is set to zero for the
TTEVT_FORK_FAIL
event. tts_flwpid
is the thread ID of the other side of the fork.
This field is set to zero for the
TTEVT_FORK_FAIL
event. tts_isparent
is zero for the child event and one for the parent. tts_errno
is set to error code indicating the reason for error in
TTEVT_FORK_FAIL
event.
This field is set to zero for the
TTEVT_FORK
and
TTEVT_VFORK
events. The data associated with a
TTEVT_PREFORK
event is as follows:
typedef enum {
TTS_FORK,
TTS_VFORK
typedef struct {
pid_t tts_fpid;
lwpid_t tts_flwpid;
ttpf_t tts_type;
tts_fpid
is the process ID of the other side of the fork. tts_flwpid
is the thread ID of the other side of the fork. tts_type
is the type of fork. The data associated with a
TTEVT_SIGNAL
event is as follows:
typedef struct {
int tts_signo;
ttsigf_t tts_sigflags;
uint64_t tts_sigaction;
siginfo_t tts_siginfo;
tts_signal
is the signal number. tts_sigflags
is
TTSF_USERSIGINFO
if a
siginfo
was delivered with the signal, 0 otherwise. tts_sigaction
is the disposition of the signal. tts_siginfo
is the
siginfo,
if applicable. The data associated with a
TTEVT_LWP_CREATE,
TTEVT_LWP_TERMINATE
or
TTEVT_LWP_ABORT_SYSCALL
event is as follows:
typedef struct {
lwpid_t tts_target_lwpid;
tts_target_lwpid
is the
lwpid
of the targeted lwp. The data associated with a
TTEVT_SYSCALL
event is as follows:
typedef struct {
int64_t tts_rval[2];
int tts_errno;
The
tts_rval
fields are the return value(s) of the system call. tts_errno
is the error status if the system call failed. The data associated with a
TTEVT_LWP_EXIT
event is as follows:
typedef struct {
int tts_exitcode;
tts_exitcode
is the exit code of the process. The data associated with a
TTEVT_BPT_SSTEP
event is as follows: On PA-RISC systems:
typedef struct {
int tts_isbpt;
tts_isbpt
is set to zero if it is a single-step
and to one if the event is a breakpoint (including single-stepping
into a breakpoint). On
Itanium(\rg-based
systems:
typedef enum {
TTBPT_SSTEP = 0, /* Single stepping */
TTBPT_BPT, /* Breakpoint */
TTBPT_TBRANCH /* Taken Branch */
typedef struct {
ttbpt_type_t tts_isbpt;
- TT_PROC_GET_NEXT_LWP_STATE
This request is identical to
TT_PROC_GET_FIRST_LWP_STATE
except that it returns the state for the next thread on the stopped list.
As events cause threads to stop, they are added to this list. This provides
a way for the tracing process to examine the state of all the stopped threads
in the target process. Both these requests return either a 1 (one)
if valid data is returned or 0 (zero) otherwise.
Valid data is returned if the status is that
there was a stopped thread for which to return. - TT_PROC_GET_MPROTECT
This request allows the debugger to obtain protection information for
a page in the address space of the code being debugged.
The
addr
argument specifies the address for which the protection is to be obtained.
The
addr2
argument specifies the address of an integer in which the protection data
will be copied. For this request, the
lwpid
and
data
arguments must be set to zero. - TT_PROC_SET_MPROTECT
This requests allows the debugger to modify the protection of
the address space of the code being debugged.
The
addr
argument specifies the start address.
The
data
argument specifies the extent (in bytes) of the space to be modified.
The
addr2
argument contains the new protection. Note that protection changes affect
whole pages (see
mprotect(2)
for more information). For this request, the
lwpid
argument must be set to zero. - TT_PROC_SET_SCBM
This request allows the debugger to pass a bitmap to the kernel
indicating which system calls should cause a debugger stop. The
addr
argument must be set to
TTSCBM_SELECT
or
TTSCBM_UNSELECT
to indicate whether the bitmap represents a positive (meaning that
the calls in the bitmap will result in a stop) or a negative (meaning
that all calls except those in the bit map will result in a stop) list. The
data
argument is the size of the bitmap, in bytes. A size of zero indicates
that the current bitmap, if any, should be cleared. The
addr2
argument is the user address where the bitmap is located. If
data
is zero, this value must be zero too. The
lwpid
argument must be zero. - TT_PROC_EXIT
This request causes the traced process to terminate.
It has the same consequence as
exit()
being invoked by one of the process threads.
The
lwpid,
addr,
data,
and
addr2
arguments must be zero. - TT_PROC_CORE
This request causes the traced process to generate a core file
without modifying the process's state.
If
addr
is zero, the core file is created in the target process's current
working directory and is named
core.pid;
where,
pid
is the process ID of the target process.
If
addr
is non-zero, it is the address of a buffer containing
the path of the core file to be created.
Up to
MAXPATHLEN
bytes will be read from the buffer.
If the path is not absolute (not starting with a slash), it is
relative to the target process's current working directory.
In both cases, the directory must exist and, if present, the
file must be a regular file.
In all cases, the debugger's credentials are used and standard
permission checking applies.
The
lwpid,
data,
and
addr2
arguments must be zero. Interaction with
coreadm()
and
coreadm:
If a process has a non-default core file setting and
addr
is zero, then the core file will be will be generated with the
core file setting in effect.
If
addr
is a non-NULL value, then the core file will be generated
in the target path, as specified by
addr,
and will be created as
core.pid. - TT_PROC_GET_NUM_IBPT_REGS, TT_PROC_GET_NUM_DBPT_REGS
These requests return the number of physical hardware instruction
or data breakpoint registers that are available for use. - TT_PROC_SET_IBPT_REGS, TT_PROC_SET_DBPT_REGS
These requests write process-wide breakpoint values into breakpoint registers.
data
bytes from
addr2
will be written to the instruction or data breakpoint register(s) named by
addr.
For Itanium-based systems,
addr
must be an even number less than the value returned by
TT_PROC_GET_NUM_IBPT_REGS
or
TT_PROC_GET_NUM_DBPT_REGS
respectively.
data
must be 16 bytes. The request will set a value into the pair
of instruction or data breakpoint registers
addr
and
addr+1. Note:
The available breakpoint registers must be shared between process-wide
breakpoints and per-thread breakpoints. If a breakpoint register is
currently being used as a per-thread breakpoint in any thread
within the target process, it may not be used for a process-wide
breakpoint. Note:
This does not limit the number of
break
instructions that may be present in the program text. Note:
These requests are not supported on PA-RISC versions of HP-UX. - TT_PROC_GET_IBPT_REGS, TT_PROC_GET_DBPT_REGS
These requests read process-wide breakpoint values from breakpoint registers.
data
bytes are copied from the instruction or data breakpoint register(s) specified by
addr
to
addr2
in debugger memory.
data
must be 16 bytes. The request will get the value of the
pair of instruction or data breakpoint registers
addr
and
addr+1. Note:
These requests are not supported on PA-RISC versions of HP-UX. - TT_PROC_GET_ARGS, TT_PROC_GET_ARGS_NOATTACH
These requests return a pointer to the argument list passed to the
initial thread of the process at
execve()
time (that is,
argc,
argv,
envp).
If the target
process has not overwritten these arguments, this address can be
used to retrieve the full argument and environment list. Note:
These requests are not supported on PA-RISC versions of HP-UX.
Thread RequestsFor all thread requests (those prefixed by
TT_LWP_),
pid
is the process id of the target process and
lwpid
is the target thread within the target process.
- TT_LWP_STOP
This request causes the thread identified by
lwpid
to stop executing.
If the thread is already stopped
by the debugger,
or
by an event,
an error is returned. The
addr,
data,
and
addr2
arguments must be zero. - TT_LWP_CONTINUE
This request causes the thread identified by
lwpid
to resume execution or, rather, to return to the state it was in prior
to being stopped
by the debugger.
If the thread had not previously been
stopped by the debugger, an error is returned. If
addr
is not
TT_NOPC,
that value is loaded in the program counter before
execution is resumed. Unexpected behavior will result if this value
is not within the same function since only the PC, not the context,
is being modified. If
data
is non-zero, it is expected to be a valid signal number and the thread
will continue as if it had received this signal. The
addr2
argument must be zero. - TT_LWP_SINGLE
This request causes the stopped thread identified by
lwpid
to resume execution for one machine instruction.
It causes a flag to be set so that an interrupt occurs
upon the completion of one machine instruction,
and then executes the same steps as listed above for the
TT_LWP_CONTINUE
request. - TT_LWP_TBRANCH
This request causes the stopped thread identified by
lwpid
to
resume execution until a taken branch instruction is executed.
It causes a flag to be set so that an interrupt occurs upon
completion of the next taken branch instruction, and then
executes the same steps as listed above for the
TT_LWP_CONTINUE
request. Note:
This request is not supported on PA-RISC versions of HP-UX. - TT_LWP_GET_EVENT_MASK
This request is the same as
TT_PROC_GET_EVENT_MASK
except for the thread identified by
lwpid. - TT_LWP_SET_EVENT_MASK
This request is the same as
TT_PROC_SET_EVENT_MASK
except for the thread identified by
lwpid. - TT_LWP_GET_SIGMASK
This request is the same as
TT_PROC_GET_SIGMASK
except for the thread identified by
lwpid. - TT_LWP_SET_SIGMASK
This request is the same as
TT_PROC_SET_SIGMASK
except for the thread identified by
lwpid. - TT_LWP_GET_STATE
This calls returns the state of the thread identified by
lwpid.
If the thread was not previously stopped by the debugger or waiting
to be continued after an event, an error is returned. - TT_LWP_SET_IBPT_REGS, TT_LWP_SET_DBPT_REGS
These requests write per-thread breakpoint values into breakpoint registers.
data
bytes from
addr2
will be written to the instruction or data breakpoint register(s) named by
addr.
For Itanium-based systems,
addr
must be an even number less than the value returned by
TT_PROC_GET_NUM_IBPT_REGS
or
TT_PROC_GET_NUM_DBPT_REGS
respectively.
data
must be 16 bytes. The request will set a value into the pair
of instruction or data breakpoint registers
addr
and
addr+1.
These values will be enabled only when the specified thread is running.
They are identical to
TT_PROC_SET_IBPT_REGS
and
TT_PROC_SET_DBPT_REGS
respectively in other respects. Note:
The available breakpoint registers must be shared between process-wide
breakpoints and per-thread breakpoints. If a breakpoint register is
currently being used as a process-wide breakpoint within the target process,
it may not be used for a per-thread breakpoint in any thread of the target process. Note:
These requests are not supported on PA-RISC versions of HP-UX. - TT_LWP_GET_IBPT_REGS, TT_LWP_GET_DBPT_REGS
These requests read per-thread breakpoint values from breakpoint registers.
They are identical to
TT_PROC_GET_IBPT_REGS
and
TT_PROC_GET_DBPT_REGS
respectively in other respects. Note:
These requests are not supported on PA-RISC versions of HP-UX. - TT_LWP_RDRSEBS, TT_LWP_WRRSEBS, TT_LWP_RDRSEBS_NOATTACH
These requests allow the calling process to access stacked general register
values that have not yet been written to the RSE backing store.
data
bytes that would have been spilled at
addr
on the user's RSE backing store, had the RSE been flushed, are
copied to or from
addr2
in the calling process.
The
addr
argument must be 8-byte-aligned and conform to
ar.bspstore
≤
addr
<
ar.bsp.
data
must be a multiple of 8 bytes, and
addr+data
must also conform to
ar.bspstore
≤
addr+data
<
ar.bsp.
As a special case, to retrieve the final NaT collection,
addr
==
ar.bsp | 0x1f8
and
data
==
8
is also accepted. Note:
This facility should be used only to modify values of registers that
were dirty when the thread was stopped. Do not use this facility
if the values of ar.bsp or ar.bspstore have been modified. Note:
These requests are not supported on PA-RISC versions of HP-UX. - TT_LWP_RUREGS, TT_LWP_RUREGS_NOATTACH
With these requests, on Itanium-based systems the register specified by
addr
is returned to the calling process making the request.
The
data
argument is the size of the read.
The
addr2
argument points to the location in the calling process's address space
where the data will be written.
The
addr
argument must be a value defined by
__uregs_t
in
<machine/sys/uregs.h>. The registers that may be read or written vary depending on whether the target
thread is stopped in a syscall or interruption context.
Retrieve the
__reason
value first to determine which applies.
The following registers may be read or written in each context:
-
On PA-RISC systems, the words at offset
addr
in the
save_state
structure are returned to the calling process.
The
data
argument is the size of the read.
The
addr2
argument points to the location in the calling process's address space
where the data will be written.
The
addr
argument must be word-aligned and
addr+data
must be less than or equal to
sizeof (save_state_t)
(see the file
<machine/save_state.h>). Note:
On Itanium-based systems, 8, 9 and 16 byte reads are supported.
Static general registers may be read with 8 or 9 byte requests.
The NaT bit corresponding to the general register is returned
in bit 0 of the 9th byte if requested. Floating point register
reads must be 16 byte requests. All other register reads must
be 8 byte requests. Individual bits, such as __p1...__p63, will
be returned in bit 0 of an 8 byte word. On PA-RISC systems, only 4 and 8 byte reads and writes are currently supported. - TT_LWP_WUREGS
With this request, on Itanium-based systems:
data
bytes of data pointed to by
addr2
are written to the register specified by
addr
which must be a
__uregs_t
value as noted above.
On PA-RISC systems:
data
bytes of data pointed to by
addr2
are written at offset
addr
in the
save_state
structure.
Only these 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. Note:
On Itanium-based systems, 8, 9 and 16 byte writes are supported.
Static general registers may be written as 8 or 9 byte requests.
Bit 0 of the 9th byte is written to the NaT bit corresponding to
the general register if requested. An 8 byte write to a static
general register will clear the corresponding NaT bit. Floating
point register writes must be 16 byte requests. All other register
writes must be 8 byte requests. On PA-RISC systems,
only 4 and 8 bytes reads and writes are currently supported.
Vectored RequestsFor all vectored requests (those prefixed by
TT_VEC_),
pid
is the process ID of the target process.
- TT_VEC_GENERIC
This request performs a series of requests on arbitrary threads within
a single target process specified by
pid.
The
lwpid
argument must be 0 (zero). The
addr
argument points to an array of up to
TT_VEC_MAX
tt_vec_ts,
in the calling process's address space.
Each contains a request to be performed and the corresponding arguments.
The
tt_vec_t
contains at least the following fields:
-
The array of
tt_vec_ts
must be cleared (for example, with
bzero())
prior to filling in the fields listed above.
(The names of fields in this structure, other than those listed above,
(if any) are subject to change without notice.) See the descriptions of the individual requests for details of the
addr,
data
and
addr2
arguments required for each. The
data
argument specifies the number of request elements in the array pointed to by
addr. The
addr2
argument points to a location in the calling process's address space
containing a single
tt_vec_res_t.
The
tt_vec_res_t
contains at least the following fields:
-
The
tt_vec_res_t
must be cleared (for example, with
bzero())
prior to filling in the fields listed above. On return,
ttvr_count
will contain the number of requests from the array pointed to by
addr
which succeeded.
TT_VEC_GENERIC
stops processing requests from the array upon encountering an error. The first
ttvr_count
elements of the array pointed to by
ttvr_ret1
will be filled in with the return values of the corresponding requests.
Although none of the requests supported by
TT_VEC_GENERIC
at this time produce return values, additional requests which
produce return values may be supported in the future. - TT_VEC_LWP_RUREGS
This request performs a series of
TT_LWP_RUREGS
requests on a single thread within the target process in a single call.
The
lwpid
argument must specify a valid thread within the target process. The
addr
argument points to a location in the calling process's address space
containing an array of up to
TT_VEC_MAX
tt_reg_vecs,
each containing the arguments for the request(s) to be performed.
The
tt_reg_vec_t
structure contains the following fields:
-
The
ttrv_reg,
ttrv_size,
and
ttrv_addr
arguments correspond to the
addr,
data,
and
addr2
arguments (respectively) of the
TT_LWP_RUREGS
request.
See the description of the
TT_LWP_RUREGS
request for details. The
data
argument specifies the number of request elements in the array pointed to by
addr. The
addr2
argument points to an 8-byte location in the calling process's
address space into which the number of successful requests
will be written.
The
TT_VEC_LWP_RUREGS
request stops processing requests upon encountering an error.
Non-debug-related RequestThere is currently only one non debug-related request:
- TT_NDR_GET_FLEV
This call returns the
feature level
of the operating system and has been introduced to help debugger developers
make their tools more portable from one version to another.
The
pid,
lwpid,
addr,
data,
and
addr2
arguments must be 0 (zero). 11.0
systems can be identified by the fact that this call will return an error.
Later releases will return the
TT_FEATURE_LEVEL
value the operating system was compiled with (see
ttrace.h).
The release
levels for systems newer than
11.0
are:
- Level 5:
internal change. - Level 6:
add
DETACH_ON_EXIT
attach option. - Level 7:
add
TTEVT_BPT_SSTEP
event. - Level 8:
add
TT_PROC_SET_IBPT,
TT_PROC_SET_DBPT,
TT_PROC_GET_IBPT,
TT_PROC_GET_DBPT,
TT_PROC_GET_NUM_IBPT_REGS,
TT_PROC_GET_NUM_DBPT_REGS,
TT_PROC_GET_ARGS,
TT_LWP_SET_IBPT,
TT_LWP_SET_DBPT,
TT_LWP_GET_IBPT,
TT_LWP_GET_DBPT,
TT_LWP_RDRSEBS,
TT_LWP_WRRSEBS,
TT_LWP_TBRANCH
requests. - Level 9:
add
TT_PROC_GET_SIGMASK,
TT_PROC_SET_SIGMASK,
TT_LWP_GET_SIGMASK,
TT_LWP_SET_SIGMASK
requests. - Level 10:
add
TTEVT_PREFORK,
TTEVT_FORK_FAIL
events. - Level 11:
allow the
TT_PROC_CORE
request to generate user specified core file names. - Level 12:
add
_NOATTACH
requests. - Level 13:
add
TTEVT_UT_CREATE,
TTEVT_UT_EXIT
events. - Level 14:
add
TT_PROC_GET_ARGS_NOATTACH,
TT_VEC_GENERIC,
TT_VEC_LWP_RUREGS
requests; add syscall timestamps; and add
TT_GEN_SHLIB_BPT
settrc/attach option.
EventsAs noted earlier, a tracing process can set event flags in the
context of a traced process, or its individual threads, to cause the threads
to respond to specific events during their execution.
When an event flag is set in the context of the process, all threads in
the process respond to the event.
When set in the context of a thread, only the specific thread will respond
to the event. ImportantIf an event is requested by the process, the event mask of
the thread is not examined. For the event mask of the thread to be
significant, the process event must be be unset.
Similarly, if an event option is enabled in the process, the option for
the thread is not considered.
Event masks may be inherited across
fork()
using the
tte_opts
options in the
ttevent_t
structure.
If
TTEO_PROC_INHERIT
is set, the child process inherits the event mask of its parent.
If
TTEO_LWP_INHERIT
is set, the lwp inherits the event mask
of the lwp that invoked
fork().
If the latter is set, the lwp created by
lwp_create()
also inherits the event mask of the creating thread. These events are:
- TTEVT_SIGNAL
This event flag indicates that the traced thread needs to examine
signal mask bits when processing signals. This means that, by default,
threads stop when receiving a signal.
If the signal being processed has its mask bit set,
signal processing continues as though the process were not traced:
the traced thread is not stopped, and
the tracing process is not notified of the signal.
On the other hand, if the signal mask bit is not set for the signal being
processed,
the traced thread is stopped and the tracing process is notified via
ttrace_wait(). Note that the SIGKILL signal can never be unmasked.
It behaves as though its mask bit were always set.
This means that a SIGKILL signal cannot be used to stop a traced thread.
The SIGTRAP signal is also special in that it is
used to stop traced threads when they respond to a trap, such as a breakpoint
or a single step.
Consequently, masking SIGTRAP, even though allowed,
will result in unexpected behavior in these conditions. - TTEVT_FORK
This event flag indicates that the traced thread needs to take special
action when it invokes
fork().
When set, both the parent thread and the initial thread in the
child process stop (after the child process is marked as a traced
process and adopts its parent's debugger). Both threads log the fact
that they stopped in response to a
TTEVT_FORK
event.
The parent thread provides the
pid
of the child process in the appropriate portion of the
ttstate_t
structure.
The initial thread of the child
process provides the pid of the parent in the same location.
See the
ttstate_t
structure description for further details. - TTEVT_VFORK
This event flag indicates that the traced thread needs to take special
action when it invokes
vfork().
The behavior is identical to that of
TTEVT_FORK
but
it is important to note that the caveats with
respect to
vfork(),
continue to apply here.
In particular, it needs to be remembered that when the
child process stops, its parent is asleep, and that
the child borrows the parent's address space
until a call to
exec()
or an exit (either by a call to
exit()
or abnormally) takes place. Continuing the parent process before the
above steps take place results in an error. - TTEVT_PREFORK
This event flag indicates that the traced thread needs to notify
the debugger, during a
fork()
or
vfork()
operation, just after the child process ID and thread ID is known
and before the child process is created and set to run.
The parent thread is stopped and it provides the
pid
of the child process and
lwpid
of the child's initial thread. Note:
Upon continuation from this event, the traced thread does
not guarantee that the child process with an earlier returned
pid
and
lwpid
can be created since the
fork()
or
vfork()
operation might fail. - TTEVT_FORK_FAIL
This event flag indicates that the traced thread needs to notify
the debugger upon the failure of a
fork()
or
vfork()
operation.
The traced parent thread is stopped and returns the error
code for fork failure. - TTEVT_EXEC
This event flag indicates that a traced thread needs to notify the debugger
upon completion of loading the new executable file, in the
exec()
system call.
The length of the pathname string (not including a null terminating
character) is returned in the
ttstate_t
structure.
The path may subsequently be obtained using the
TT_PROC_GET_PATHNAME
request. - TTEVT_SYSCALL_RETURN
This event flag indicates that the traced process will notify the
debugger upon return of all system calls.
The traced process will also provide the following information:
the system call number, its number of arguments and all its arguments,
its return value and its error return in the
ttstate_t
structure.
If the system call is a
fork(),
vfork()
or
exec()
and if, respectively, the
TTEVT_FORK,
TTEVT_VFORK
or
TTEVT_EXEC
event is set, only the notification associated with
these events is performed.
See the
TT_PROC_SET_SCBM
request. - TTEVT_SYSCALL_ENTRY
This event flag requests notification of system call entry points. By
default, all system calls stop at this event if it is selected. The
information provided is the same as for
TTEVT_SYSCALL_RETURN
events but the return value and error are always zero. - TTEVT_SYSCALL_RESTART
Identical to
TTEVT_SYSCALL_ENTRY
but for system call restarts. - TTEVT_EXIT
This event flag indicates that the traced process needs to notify the
debugger action when it invokes
exit().
When set, the traced thread stops while still potentially multithreaded. - TTEVT_LWP_CREATE
This event flag indicates that the debugger wants to be notified when the
lwp_create()
system call is invoked to create a thread.
When set, the calling thread stops and provides the debugger with the
lwpid
of the newly created thread. - TTEVT_LWP_EXIT
This event flag indicates that the debugger wants to be notified
when a thread is exiting via the
lwp_exit()
system call. The thread stops upon entry to the system call. - TTEVT_LWP_TERMINATE
This event flag indicates that the debugger wants to be notified
when a caller thread invokes the
lwp_terminate()
call on a target thread.
When set, the calling thread stops upon entering the system call
and provides the
lwpid
of the thread to be terminated in the
ttstate_t
structure. - TTEVT_LWP_ABORT_SYSCALL
This event flag indicates that the debugger is to be notified when the
lwp_abort_syscall()
system call is invoked. The
lwpid
of the target thread is provided in the
ttstate_t
structure. - TTEVT_BPT_SSTEP
This event flag tells the kernel to perform event-based single-stepping
and breakpoint notification. If this event is requested, SIGTRAP loses
all special meaning. It is highly recommended that debuggers use this
event instead of the old signal-based method as it will allow breakpoints
and single-steps to take place regardless of the signals the thread is blocking.
Unlike the signal-based method, it also guarantees that single-steps and
breakpoint events are generated in the context of the thread even if
other threads are active in the process. Note that mixing signal-based
and event-based breakpoint/single-stepping may result in unexpected SIGTRAPs
being posted to the process being debugged.
Security RestrictionsFor security reasons,
ttrace()
inhibits the set-user-ID facility on subsequent
exec()
calls. Some or all of the actions associated with this system call require 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. ERRORSIf a request fails,
ttrace
returns
-1
and
errno
is set to one of the following:
- EACCES
The
pid
argument to the
TT_PROC_ATTACH
is the
pid
of the invoker. - EACCES
The process identified by the
pid
argument to
TT_PROC_ATTACH
is exiting. - EACCES
The process is already being traced. - EAGAIN
Unable to attach to a process. This error can only be encountered when
attaching to a process in the middle of an
exec()
syscall. - EDEADLK
One thread of a multithreaded process (p1) has performed a
vfork(),
the child (p2) is stopped at the vfork event and the debugger is attempting
to stop or resume a thread in the parent process (p1). - EFAULT
Invalid user address. - EINTR
Cannot suspend process or attach is interrupted
(TT_PROC_ATTACH). - EINVAL
request
is an illegal number. - EINVAL
A non-zero value has been passed in a parameter expecting a zero value or
vice-versa. - EINVAL
The
data
argument of
TT_PROC_SETTRC
or
TT_PROC_ATTACH
is not
TT_VERSION. - EINVAL
Size too large for data transfer. - EINVAL
Invalid signal number. - EINVAL
Misaligned request or not a word multiple
(TT_PROC_RDTEXT,
TT_PROC_RDTEXT_NOATTACH,
TT_PROC_WRTEXT). - EINVAL
Invalid signal
(TT_LWP_CONTINUE,
TT_LWP_SINGLE). - EINVAL
Invalid offset
(TT_LWP_RUREGS,
TT_LWP_RUREGS_NOATTACH,
TT_LWP_WUREGS). - EINVAL
An offset in the
save_state
structure is not word-aligned. - EINVAL
An invalid register is targeted by
TT_LWP_WUREGS. - EINVAL
The core file argument to a
TT_PROC_CORE
request exists and is not a regular file. - EINVAL
The
data
argument to
TT_VEC_GENERIC
is greater than
TT_VEC_MAX. - EINVAL
An invalid request is specified in the
ttv_req
field of a
tt_vec_t
passed to
TT_VEC_GENERIC. - EINVAL
Undocumented fields in a
tt_vec_t
passed to
TT_VEC_GENERIC
are not 0 (zero). - EINVAL
The
ttvr_count
or
ttvr_ret1
field of a
tt_vec_res_t
passed to
TT_VEC_GENERIC
is NULL. - EINVAL
The size argument to a
TT_PROC_GET_PATHNAME
is larger than
MAXPATHLEN. - ENODATA
Data in this register is not readable or not writable at this time. - ENOENT
The directory portion of the core file argument to a
TT_PROC_CORE
request does not exist. - ENOMEM
System is out of memory. - EPROTO
Attempting to stop a thread already stopped by the debugger. - EPROTO
Attempting to resume a thread not stopped by the debugger. - EPROTO
Attempting to read or write registers while the thread is not stopped. - EPROTO
Attempting to obtain the state of a thread which was not stopped
by the debugger. - EPROTO
Invoked before an exec event took place
(TT_PROC_GET_PATHNAME). - EPROTO
The process is exiting and the request is not allowed in this condition. - EPROTO
The debugger is attempting to modify wide registers after having
modified narrow registers. - EPROTO
The debugger is attempting to first modify the text of a process in
the middle of a vfork. Text modification is allowed during vfork as long
as it was first modified before the vfork. - ESRCH
pid
and/or
lwpid
identify a process or a thread to be traced that does not exist
or has not executed a
ttrace()
with the
TT_PROC_SETTRC
request.
EXAMPLESA simple no-frills system call tracer:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ttrace.h>
#include <sys/scall_define.h>
pid_t ppid;
typedef struct {
int val;
char *name;
} _exp_t;
static char *
gen_name(_exp_t *base, int val)
{
_exp_t *rp;
for (rp = base; rp->name; rp++) {
if (val == rp->val) {
return rp->name;
}
}
return NULL;
}
static char *
ev_name(ttevents_t ev)
{
static char buf[32];
char *p;
static _exp_t tab[] = {
TTEVT_SIGNAL, "SIGNAL",
TTEVT_FORK, "FORK",
TTEVT_EXEC, "EXEC",
TTEVT_EXIT, "EXIT",
TTEVT_VFORK, "VFORK",
TTEVT_SYSCALL, "SYSCALL",
TTEVT_SYSCALL_ENTRY, "SYSCALL_ENTRY",
TTEVT_LWP_CREATE, "LWP_CREATE",
TTEVT_LWP_TERMINATE, "LWP_TERMINATE",
TTEVT_LWP_EXIT, "LWP_EXIT",
TTEVT_LWP_ABORT_SYSCALL,"LWP_ABORT_SYSCALL",
#if TT_FEATURE_LEVEL >= 7
TTEVT_BPT_SSTEP, "LWP_BPT_SSTEP",
#endif
-1, NULL
};
p = gen_name(tab, (int) ev);
if (p) {
return p;
}
(void) sprintf(buf, "EVENT_%#x", ev);
return buf;
}
static void
errexit(const char *p)
{
(void) fprintf(stderr, "%s: %s\n", p, strerror(errno));
if (ppid) {
(void) kill(ppid, SIGINT);
}
exit (1);
}
static void
dottrace(ttreq_t req, pid_t pid, lwpid_t lwpid, uint64_t addr, uint64_t data,
uint64_t addr2)
{
int rval;
char *p;
static _exp_t tab[] = {
TT_PROC_SETTRC, "PROC_SETTRC",
TT_PROC_ATTACH, "PROC_ATTACH",
TT_PROC_DETACH, "PROC_DETACH",
TT_PROC_CONTINUE, "PROC_CONTINUE",
TT_PROC_SET_EVENT_MASK, "PROC_SET_EVENT_MASK",
TT_PROC_GET_FIRST_LWP_STATE, "PROC_GET_FIRST_LWP_STATE",
TT_PROC_GET_NEXT_LWP_STATE, "PROC_GET_NEXT_LWP_STATE",
TT_LWP_CONTINUE, "LWP_CONTINUE",
-1, NULL
};
rval = ttrace(req, pid, lwpid, addr, data, addr2);
if (rval == -1) {
p = gen_name(tab, req);
errexit(p ? p : "ttrace");
}
}
static void
show_syscall(const ttstate_t *stp)
{
int nargs = stp->tts_scnargs;
ttevents_t evt = stp->tts_event;
int i;
char *p;
const uint64_t *argp;
static _exp_t tab[] = {
SYS_open, "open",
SYS_close, "close",
SYS_read, "read",
SYS_write, "write",
SYS_ioctl, "ioctl",
SYS_lseek, "lseek",
SYS_fstat, "fstat",
SYS_stat, "stat",
SYS_poll, "poll",
SYS_select, "select",
SYS_mmap, "mmap",
SYS_wait, "wait",
SYS_waitpid, "waitpid",
SYS_waitid, "waitid",
SYS_time, "time",
SYS_brk, "brk",
SYS_sigsuspend, "sigsuspend",
SYS_sigprocmask, "sigprocmask",
SYS_sigtimedwait, "sigtimedwait",
-1, NULL,
};
if (stp->tts_scno == SYS_siginhibit || stp->tts_scno == SYS_sigenable) {
return;
}
if (evt == TTEVT_NONE) {
evt = TTEVT_SYSCALL;
}
p = gen_name(tab, stp->tts_scno);
if (p == NULL) {
char buf[32];
(void) sprintf(buf, "syscall_%#x", stp->tts_scno);
p = buf;
}
(void) printf("%s", p);
for (i = 0; i < nargs; i++) {
(void) printf("(");
for (i = 0, argp = stp->tts_scarg; i < nargs; i++, argp++) {
(void) printf("%#llx", *argp);
(void) printf("%s",
(i == nargs - 1) ? "" : ", ");
}
(void) printf(")");
}
if (stp->tts_event == TTEVT_SYSCALL_RETURN) {
if (stp->tts_u.tts_syscall.tts_errno) {
(void) printf(" ERR%d",
stp->tts_u.tts_syscall.tts_errno);
}
else {
(void) printf(" = %lld",
stp->tts_u.tts_syscall.tts_rval[0]);
}
}
else {
(void) printf(" ...");
}
(void) printf("\n");
}
static void
show_event(const ttstate_t *stp)
{
switch(stp->tts_event) {
case TTEVT_NONE:
case TTEVT_SYSCALL:
case TTEVT_SYSCALL_ENTRY:
case TTEVT_SYSCALL_RESTART:
show_syscall(stp);
break;
case TTEVT_EXIT:
(void) printf("%s %d\n", ev_name(stp->tts_event),
stp->tts_u.tts_exit.tts_exitcode);
break;
case TTEVT_SIGNAL:
(void) printf("%s %d\n", ev_name(stp->tts_event),
stp->tts_u.tts_signal.tts_signo);
break;
default:
(void) printf("%s\n", ev_name(stp->tts_event));
}
}
main(int argc, char **argv)
{
ttevent_t ev;
ttstate_t st;
pid_t pid;
int pfd1[2];
int pfd2[2];
char c;
--argc, ++argv;
pid = atoi(*argv);
ev.tte_events = TTEVT_SYSCALL|TTEVT_EXEC|TTEVT_EXIT;
ev.tte_opts = TTEO_NONE;
if (pid) {
siginfo_t si;
dottrace(TT_PROC_ATTACH, pid, 0, TT_DETACH_ON_EXIT,
TT_VERSION, 0);
if (waitid(P_PID, pid, &si, WEXITED|WSTOPPED) < 0 ||
si.si_pid != pid || si.si_code != CLD_STOPPED) {
errexit("waitid");
}
dottrace(TT_PROC_GET_FIRST_LWP_STATE, pid, 0, (uint64_t) &st,
(uint64_t) sizeof st, 0);
show_event(&st);
dottrace(TT_PROC_SET_EVENT_MASK, pid, 0,
(uint64_t) &ev, sizeof ev, 0);
}
else {
if (pipe(pfd1) < 0 || pipe(pfd2) < 0) {
errexit("pipe");
}
switch(pid = fork()) {
case -1:
errexit("fork");
case 0:
ppid = getppid();
dottrace(TT_PROC_SETTRC, 0, 0, 0, TT_VERSION, 0);
/* tell parent we are SETTRC'ed */
if (write(pfd2[1], (void *) &c, sizeof c) != sizeof c) {
errexit("write");
}
/* wait for exec event to be set*/
if (read(pfd1[0], (void *) &c, sizeof c) != sizeof c) {
errexit("read");
}
(void) close(pfd1[0]);
(void) close(pfd1[1]);
(void) close(pfd2[0]);
(void) close(pfd2[1]);
(void) execvp(*argv, argv);
ppid = 0;
errexit("exec");
}
if (read(pfd2[0], (void *) &c, sizeof c) != sizeof c) {
errexit("read");
}
dottrace(TT_PROC_SET_EVENT_MASK, pid, 0,
(uint64_t) &ev, sizeof ev, 0);
/* tell the child to exec */
if (write(pfd1[1], (void *) &c, sizeof c) != sizeof c) {
errexit("write");
}
(void) close(pfd1[0]);
(void) close(pfd1[1]);
(void) close(pfd2[0]);
(void) close(pfd2[1]);
}
dottrace(TT_PROC_CONTINUE, pid, 0, 0, 0, 0);
for (;;) {
int rval = ttrace_wait(pid, 0, TTRACE_WAITOK, &st, sizeof st);
if (rval < 0) {
errexit("ttrace_wait");
}
show_event(&st);
if (st.tts_event == TTEVT_EXIT) {
break;
}
dottrace(TT_LWP_CONTINUE, pid, st.tts_lwpid, TT_NOPC,
st.tts_event == TTEVT_SIGNAL ?
(uint64_t) st.tts_u.tts_signal.tts_signo : 0L, 0L);
}
return 0;
} WARNINGSIf the
addr
argument to a
TT_LWP_CONTINUE
or
TT_LWP_SINGLE
request is not
TT_NOPC,
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. AUTHORttrace
was developed by HP. STANDARDS CONFORMANCEttrace(): LOCAL
|