DTrace's interaction with processes is slightly different than
most traditional debuggers and observability tools. Many such
tools appear to execute within the scope of the process, allowing
users dereference pointers to program variables directly. Rather
than appearing to execute within or as part of the process itself,
DTrace probes execute in the Oracle Linux kernel. To access process data,
a probe uses the copyin
or
copyinstr
subroutines to copy user process data
into the address space of the kernel.
For example, consider the following write()
system call:
ssize_t write(intfd
, const void *buf
, size_tnbytes
);
The following D program illustrates an incorrect attempt to print
the contents of a string that is passed to the
write()
system call:
syscall::write:entry { printf("%s", stringof(arg1)); /* incorrect use of arg1 */ }
If you attempt to run this script, DTrace produces error messages similar to the following:
dtrace: error on enabled probe ID 1 (ID 37: syscall::write:entry): \ invalid address (0x10038a000) in action #1
The arg1
variable, which contains the value of
the buf
parameter, is an address that
refers to memory in the process executing the system call. To read
the string at that address, use the copyinstr
subroutine and record its result with the
printf
action, for example:
syscall::write:entry { printf("%s", copyinstr(arg1)); /* correct use of arg1 */ }
In the previous script, the output shows all of the strings that
are being passed to the write()
system call.
Occasionally, however, you might see irregular output similar to
the following:
0 37 write:entry mada&^%**&
The copyinstr
subroutine acts on an input
argument, which is the user address of a null-terminated ASCII
string, but buffers that are passed to the
write()
system call might refer to binary data
rather than ASCII strings or to ASCII strings that do not include
a terminating null byte. To print only as much of the string as
the caller intended, use the two parameter version of the
copyinstr
subroutine, which includes the size
of the targeted string buffer:
syscall::write:entry { printf("%s", copyinstr(arg1, arg2)); }
Alternatively, you can use the copyin
subroutine, which takes an address and size, for example:
syscall::write:entry { printf("%s", stringof(copyin(arg1, arg2))); }
Note that the stringof
operator is necessary so
that DTrace properly converts the user data that is retrieved by
copyin
to a string. The use of
stringof
is not necessary with the
copyinstr
subroutine because it always returns
the type string
.