Speculation Example

One potential use for speculations is to highlight a particular code path. The
following example shows the entire code path under the open(2) system call
only when the open fails:

Example 7-1 specopen.d: Code Flow for Failed open(2)

#!/usr/sbin/dtrace -Fs
syscall::openat:entry,
syscall::openat64:entry
{
/*
* The call to speculation() creates a new speculation. If this fails,
* dtrace(1M) will generate an error message indicating the reason for
* the failed speculation(), but subsequent speculative tracing will be
* silently discarded.
*/
self->spec = speculation();
speculate(self->spec);
/*
* Because this printf() follows the speculate(), it is being
* speculatively traced; it will only appear in the data buffer if the
* speculation is subsequently commited.
*/
printf("%s", stringof(copyinstr(arg1)));
}
fbt:::
/self->spec/
{
/*
* A speculate() with no other actions speculates the default action:
* tracing the EPID.
*/
speculate(self->spec);
}
syscall::openat:return,
syscall::openat64:return
/self->spec/
{
/*
* To balance the output with the -F option, we want to be sure that
* every entry has a matching return. Because we speculated the
* open entry above, we want to also speculate the open return.
* This is also a convenient time to trace the errno value.
*/
speculate(self->spec);
trace(errno);
}
syscall::openat:return,
syscall::openat64:return
/self->spec && errno != 0/
{
/*
* If errno is non-zero, we want to commit the speculation.
*/
commit(self->spec);
self->spec = 0;
}
syscall::openat:return,
syscall::openat64:return
/self->spec && errno == 0/
{
/*
* If errno is not set, we discard the speculation.
*/
discard(self->spec);
self->spec = 0;
}

Running the above script produces output similar to the following example: