12.1 copyin and copyinstr Subroutines

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(int fd, const void *buf, size_t nbytes);

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.