4.4 Destructive Actions

4.4.1 Process Destructive Actions
4.4.2 Kernel Destructive Actions

Some DTrace actions are destructive in that they change the state of the system in some well-defined way. Destructive actions may not be used unless they have been explicitly enabled. When using dtrace, you can enable destructive actions using the -w option. If you attempt to perform destructive actions without explicitly enabling them, dtrace fails with a message similar to the following example:

dtrace: failed to enable 'syscall': destructive actions not allowed

4.4.1 Process Destructive Actions

Some destructive actions are destructive only to a particular process.

4.4.1.1 copyout

void copyout(void *buf, uintptr_t addr, size_t nbytes)

The copyout action copies nbytes from the buffer specified by buf to the address specified by addr in the address space of the process associated with the current thread. If the user-space address does not correspond to a valid, faulted-in page in the current address space, an error is generated.

4.4.1.2 copyoutstr

void copyoutstr(string str, uintptr_t addr, size_t maxlen)

The copyoutstr action copies the string specified by str to the address specified by addr in the address space of the process associated with the current thread. If the user-space address does not correspond to a valid, faulted-in page in the current address space, an error will be generated. The string length is limited to the value set by the strsize option. See Chapter 10, Options and Tunables for details.

4.4.1.3 raise

void raise(int signal)

The raise action sends the specified signal to the currently running process. This action is similar to using the kill command to send a signal to a process. The raise action can be used to send a signal at a precise point in the execution of a process.

4.4.1.4 stop

void stop(void)

The stop action forces the process that fires the enabled probe to stop when it next leaves the kernel, as if stopped by a proc action. The stop action can be used to stop a process at any DTrace probe point. This action can be used to capture a program in a particular state that would be difficult to achieve with a simple breakpoint, and then attach a traditional debugger such as gdb to the process. You can also use the gcore utility to save the state of a stopped process in a core file for later analysis.

4.4.1.5 system

void system(string program, ...)

The system action causes the specified program to be executed as if it were given to the shell as input. The program string may contain any of the printf or printa format conversions. Arguments must be specified that match the format conversions. Refer to Chapter 6, Output Formatting for details on valid format conversions.

The following example runs the date command once per second:

# dtrace -wqn tick-1sec'{system("date")}'
Tue Oct 16 10:21:34 BST 2012
Tue Oct 16 10:21:35 BST 2012
Tue Oct 16 10:21:36 BST 2012
^C
#

The following example shows a more elaborate use of the action, using printf conversions in the program string along with traditional filtering tools such as pipes:

#pragma D option destructive
#pragma D option quiet

proc:::signal-send
/args[2] == SIGINT/
{
  printf("SIGINT sent to %s by ", args[1]->pr_fname);
  system("getent passwd %d | cut -d: -f5", uid);
}

Running the above script results in output similar to the following example:

# dtrace -s whosend.d
SIGINT sent to top by root
SIGINT sent to bash by root
SIGINT sent to bash by A Nother
^C
SIGINT sent to dtrace by root

The execution of the specified command does not occur in the context of the firing probe. It occurs when the buffer containing the details of the system action are processed at user-level. How and when this processing occurs depends on the buffering policy, as described in Chapter 5, Buffers and Buffering. With the default buffering policy, the buffer processing rate is specified by the switchrate option. You can see the delay inherent in system if you explicitly tune the switchrate higher than its one-second default, as shown in the following example:

#pragma D option quiet
#pragma D option destructive
#pragma D option switchrate=5sec

tick-1sec
/n++ < 5/
{
  printf("walltime : %Y\n", walltimestamp);
  printf("date : ");
  system("date");
  printf("\n");
}

tick-1sec
/n == 5/
{
  exit(0);
}

Running the above script results in output similar to the following example:

# dtrace -s time.d
walltime : 2012 Oct 16 10:26:07
date : Tue Oct 16 10:26:11 BST 2012

walltime : 2012 Oct 16 10:26:08
date : Tue Oct 16 10:26:11 BST 2012

walltime : 2012 Oct 16 10:26:09
date : Tue Oct 16 10:26:11 BST 2012

walltime : 2012 Oct 16 10:26:10
date : Tue Oct 16 10:26:11 BST 2012

walltime : 2012 Oct 16 10:26:11
date : Tue Oct 16 10:26:11 BST 2012

Notice that the walltime values differ, but the date values are identical. This result reflects the fact that the execution of the date command occurred when the buffer was processed, not when the system action was recorded.

4.4.2 Kernel Destructive Actions

Some destructive actions are destructive to the entire system. These actions must obviously be used extremely carefully, as they will affect every process on the system and any other system implicitly or explicitly depending upon the affected system's network services.

4.4.2.1 chill

void chill(int nanoseconds)

The chill action causes DTrace to spin for the specified number of nanoseconds. chill is primarily useful for exploring problems that might be timing related. For example, you can use this action to open race condition windows, or to bring periodic events into or out of phase with one another. Because interrupts are disabled while in DTrace probe context, any use of chill results in interrupt, scheduling, or dispatch latency. Therefore, chill can cause unexpected systemic effects and it should not used indiscriminately. Because system activity relies on periodic interrupt handling, DTrace refuses to execute the chill action for more than 500 milliseconds out of each one-second interval on any given CPU. If the maximum chill interval is exceeded, DTrace reports an illegal operation error, as shown in the following example:

# dtrace -w -n syscall::openat:entry'{chill(500000001)}'
dtrace: allowing destructive actions
dtrace: description 'syscall::openat:entry' matched 1 probe 
dtrace: 57 errors
CPU     ID                    FUNCTION:NAME 
dtrace: error on enabled probe ID 1 (ID 14: syscall::openat:entry): \
illegal operation in action #1

This limit is enforced even if the time is spread across multiple calls to chill, or multiple DTrace consumers of a single probe. For example, the same error would be generated by the following command:

# dtrace -w -n syscall::openat:entry'{chill(250000000); chill(250000001);}'

4.4.2.2 panic

void panic(void)

The panic action causes a kernel panic when triggered. This action should be used to force a system crash dump at a time of interest. You can use this action together with ring buffering to understand a problem. For more information, see Chapter 5, Buffers and Buffering. When the panic action is used, a panic message appears that denotes the probe causing the panic. rsyslogd also emits a message upon reboot. The message buffer of the crash dump contains the probe and event control block (ECB) responsible for the panic action.