Subroutine Examples
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 passed to the write
system call:
syscall::write:entry { printf("%s", stringof(arg1)); /* incorrect use of arg1 */ }
If you try to run this script, DTrace will produce error messages similar to the following example:
dtrace: error on enabled probe ID 1 (ID 37: syscall::write:entry): \ invalid address (0x10038a000) in action #1
The arg1
variable, containing 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:
syscall::write:entry { printf("%s", copyinstr(arg1)); /* correct use of arg1 */ }
The output of this script shows all of the strings being passed to the write
system call. Occasionally, however, you might see irregular output similar to the following example:
0 37 write:entry mada&^%**&
The copyinstr
subroutine acts on an input argument that is the user address of a null-terminated ASCII string. However, buffers passed to the write
system call might refer to binary data rather than ASCII strings or to ASCII strings which 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)); }
An alternate way to accomplish the same end would be to use the copyin
subroutine which takes an address and size:
syscall::write:entry { printf("%s", stringof(copyin(arg1, arg2))); }
Notice that the stringof
operator is necessary so that DTrace properly converts the user data retrieved using copyin
to a string. The use of stringof
is not necessary when using copyinstr
because this function always returns type string
.