9 Scripting
WARNING:
Oracle Linux 7 is now in Extended Support. See Oracle Linux Extended Support and Oracle Open Source Support Policies for more information.
Migrate applications and data to Oracle Linux 8 or Oracle Linux 9 as soon as possible.
For more information about DTrace, see Oracle Linux: DTrace Release Notes and Oracle Linux: Using DTrace for System Tracing.
You can use the dtrace command to create interpreter files from D programs, which are similar to shell scripts that can be installed as reusable interactive DTrace tools. The D compiler and the dtrace command provide a set of macro variables that are expanded by the D compiler to make it easy to create DTrace scripts. This chapter provides a reference for the macro variable facility and tips for creating persistent scripts.
Interpreter Files
Similar to your shell and utilities such as awk and perl, you can use the dtrace command to create executable interpreter files.
An interpreter file begins with a line of the following form:
#!pathname [arg]
where pathname is the path of the interpreter and arg is a single, optional argument. When an interpreter file is executed, the system invokes the specified interpreter. If arg was specified in the interpreter file, it is passed as an argument to the interpreter. The path to the interpreter file and any additional arguments that were specified when it was executed are then appended to the interpreter argument list. Therefore, you always need to create DTrace interpreter files with at least the following arguments:
#!/usr/sbin/dtrace -s
When your interpreter file is executed, the argument to the -s option is the pathname of the interpreter file. The dtrace command then reads, compiles, and executes this file as if you had typed the following command in your shell:
# dtrace -s interpreter-file
      The following example shows how you would create and execute a
      dtrace interpreter file. First, type the
      following D source code and save it in a file named
      interp.d:
    
                  
#!/usr/sbin/dtrace -s
BEGIN
{
  trace("hello");
  exit(0);
}
      Then, make the interp.d file executable and
      execute it as follows:
    
                  
# chmod a+rx interp.d # ./interp.d dtrace: script './interp.d' matched 1 probe CPU ID FUNCTION:NAME 0 1 :BEGIN hello #
      Remember that the #! directive must comprise
      the first two characters of your file with no intervening or
      preceding white space. The D compiler automatically ignores this
      line when it processes the interpreter file.
    
                  
      The dtrace command uses
      getopt() to process command-line options so
      that you can combine multiple options in your single interpreter
      argument. For example, to add the -q option to
      the previous example you could change the interpreter directive to
      the following:
    
                  
#!/usr/sbin/dtrace -qs
Note:
If you specify multiple options, the -s option must always end the list of options so that the next argument, the interpreter file name, is correctly processed as the argument to the -s option.
      If you need to specify more than one option that requires an
      argument in your interpreter file, use the #pragma D
      option directive to set your options. Several
      dtrace command-line options have
      #pragma equivalents that you can use. See
      Options and Tunables.
    
                  
Macro Variables
      The D compiler defines a set of built-in macro variables that you
      can use when writing D programs or interpreter files. Macro
      variables are identifiers that are prefixed with a dollar sign
      ($) and are expanded once by the D compiler
      when processing your input file. The following table describes the
      macro variables that the D compiler provides.
    
                  
Table 9-1 D Macro Variables
| Name | Description | Reference | 
|---|---|---|
| 
                                     | Macro arguments | |
| 
                                     | Effective group ID | 
                See the  | 
| 
                                     | Effective user ID | 
                See the  | 
| 
                                     | Real group ID | 
                See the  | 
| 
                                     | Process ID | 
                See the  | 
| 
                                     | Process group ID | 
                See the  | 
| 
                                     | Parent process ID | 
                See the  | 
| 
                                     | Session ID | 
                See the  | 
| 
                                     | Target process ID | Target Process ID | 
| 
                                     | Real user ID | 
                See the  | 
      With the exception of the $[0-9]+ macro
      arguments and the $target macro variable, all
      of the macro variables expand to integers that correspond to
      system attributes, such as the process ID and the user ID. The
      variables expand to the attribute value associated with the
      current dtrace process or whatever process is
      running the D compiler.
    
                  
      Using macro variables in interpreter files enables you to create
      persistent D programs that you do not need to edit every time you
      want to use them. For example, to count all system calls, except
      those that are executed by the dtrace command,
      you would use the following D program clause containing
      $pid:
    
                  
syscall:::entry
/pid != $pid/
{
  @calls = count();
}This clause always produces the desired result, even though each invocation of the dtrace command has a different process ID. Macro variables can be used in a D program anywhere that an integer, identifier, or string can be used.
Macro variables are expanded only one time when the input file is parsed, not recursively.
Except in probe descriptions, each macro variable is expanded to form a separate input token and cannot be concatenated with other text to yield a single token.
      For example, if $pid expands to the value
      456, the D code in the following example would
      expand to the two adjacent tokens 123 and
      456, resulting in a syntax error, rather than
      the single integer token 123456:
    
                  
123$pid
      However, in probe descriptions, macro variables are expanded and
      concatenated with adjacent text. For example, the following clause
      uses the DTrace pid provider to instrument the
      dtrace command:
    
                  
# dtrace -c ./a.out -n 'pid$target:libc.so::entry'
      Macro variables are only expanded one time within each probe
      description field and they may not contain probe description
      delimiters (:).
    
                  
Macro Arguments
      The D compiler also provides a set of macro variables
      corresponding to any additional argument operands that are
      specified as part of the dtrace command
      invocation. These macro arguments are
      accessed by using the built-in names $0, for
      the name of the D program file or dtrace
      command, $1, for the first additional operand,
      $2 for the second operand, and so on. If you
      use the -s option, $0
      expands to the value of the name of the input file that is used
      with this option. For D programs that are specified on the command
      line, $0 expands to the value of
      argv[0], which is used to execute the
      dtrace command itself.
    
                  
Macro arguments can expand to integers, identifiers, or strings, depending on the form of the corresponding text. As with all macro variables, macro arguments can be used anywhere integer, identifier, and string tokens can be used in a D program.
All of the following examples could form valid D expressions assuming appropriate macro argument values:
execname == $1 /* with a string macro argument */ x += $1 /* with an integer macro argument */ trace(x->$1) /* with an identifier macro argument */
Macro arguments can be used to create DTrace interpreter files that act like real Linux commands and use information that is specified by a user or by another tool to modify their behavior.
      For example, the following D interpreter file traces
      write() system calls that are executed by a
      particular process ID and saved in a file named
      tracewrite:
    
                  
#!/usr/sbin/dtrace -s 
syscall::write:entry
/pid == $1/
{
}
      If you make this interpreter file executable, you can specify the
      value of $1 by using an additional command-line
      argument to your interpreter file, for example:
    
                  
# chmod a+rx ./tracewrite # ./tracewrite 12345
      The resulting command invocation counts each
      write() system call that is executed by the
      process ID 12345.
    
                  
If your D program references a macro argument that is not provided on the command line, an appropriate error message is printed and your program fails to compile, as shown in the following example:
# ./tracewrite dtrace: failed to compile script ./tracewrite: line 4: macro argument $1 is not defined
      D programs can reference unspecified macro arguments if you set
      the defaultargs option. If
      defaultargs is set, unspecified arguments have
      the value 0. See Options and Tunables for
      more information about D compiler options. The D compiler also
      produces an error message if additional arguments that are not
      referenced by your D program are specified on the command line.
    
                  
The macro argument values must match the form of an integer, identifier, or string. If the argument does not match any of these forms, the D compiler reports an appropriate error message. When specifying string macro arguments to a DTrace interpreter file, you should surround the argument in an extra pair of single quotes to avoid interpretation of the double quotes and string contents by your shell:
# ./foo '"a string argument"'
      If you want your D macro arguments to be interpreted as string
      tokens, even if they match the form of an integer or identifier,
      prefix the macro variable or argument name with two leading dollar
      signs, for example, $$1, which forces the D
      compiler to interpret the argument value as if it were a string
      surrounded by double quotes. All of the usual D string escape
      sequences, per Table 2-6, are expanded inside
      of any string macro arguments, regardless of whether they are
      referenced by using the $arg or
      $$arg form of the macro. If the
      defaultargs option is set, unspecified
      arguments that are referenced with the $$arg
      form have the value of the empty string ("").
    
                  
Target Process ID
      Use the $target macro variable to create
      scripts to be applied to the user process of interest that you
      specify with the -p option or that you create
      by using the dtrace command with the
      -c option. The D programs that you specify on
      the command line or by using the -s option are
      compiled after processes are created or grabbed, and the
      $target variable expands to the integer process
      ID of the first such process.
    
                  
      For example, you could use the following D script to determine the
      distribution of system calls that are executed by a particular
      subject process. Save it in a file named
      syscall.d:
    
                  
syscall:::entry
/pid == $target/
{
  @[probefunc] = count();
}
      To determine the number of system calls executed by the
      date command, save the script in the file named
      syscall.d, then run the following command:
    
                  
# dtrace -s syscall.d -c date dtrace: script 'syscall.d' matched 296 probes Tue Oct 16 15:12:07 BST 2012 access 1 arch_prctl 1 clock_gettime 1 exit_group 1 getrlimit 1 lseek 1 rt_sigprocmask 1 set_robust_list 1 set_tid_address 1 write 1 futex 2 rt_sigaction 2 brk 3 munmap 3 read 5 open 6 mprotect 7 close 8 newfstat 8 mmap 16