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