13.2.5 Using Statically Defined Probes

The DTrace helper device (/dev/dtrace/helper) enables a user-space application that contains USDT probes to send probe provider information to DTrace.

If the program that is to be traced is run by a user other than root, change the mode of the DTrace helper device to allow the user to record tracing information:

# chmod 666 /dev/dtrace/helper

Alternatively, if the acl package is installed on your system, you can use an ACL rule to limit access to a specific user, as shown in the following example:

# setfacl -m u:guest:rw /dev/dtrace/helper
# ls -l /dev/dtrace
total 0
crw-rw----  1 root root 10, 16 Sep 26 10:38 dtrace
crw-rw----+ 1 root root 10, 17 Sep 26 10:38 helper
drwxr-xr-x  2 root root     80 Sep 26 10:38 provider
# getfacl /dev/dtrace/helper
getfacl: Removing leading '/' from absolute path names
# file: dev/dtrace/helper
# owner: root
# group: root
user::rw-
user:guest:rw-
group::rw-
mask::rw-
other::---
Note

You must change the mode on the device before the user runs the program.

The full name of a probe in a user application takes the usual providerPID:module:function:name form, where:

provider

Is the name of the provider, as defined in the provider definition file.

PID

Is the process ID of the running executable.

module

Is the name of the executable.

function

Is the name of the function where the probe is located.

name

Is the name of the probe, as defined in the provider definition file with any two consecutive underscores (__) replaced by a dash (-).

For example, for a myserv process with a PID of 1173, the full name of the query-receive probe would be myserv1173:myserv:main_look:query-receive.

The following simple example shows how to invoke a traced process from dtrace:

# dtrace -c ./myserv -qs /dev/stdin <<EOF
  $target:::query-receive
    {
      printf("%s:%s:%s:%s %s %s\n", probeprov, probemod, probefunc, probename,
                                    stringof(args[0]), stringof(args[1]));
    }
  $target:::query-respond
    {
      printf("%s:%s:%s:%s\n", probeprov, probemod, probefunc, probename);
    }
EOF

myserv1173:myserv:main_look:query-receive foo1 msg1
myserv1173:myserv:process_query:query-respond
myserv1173:myserv:main_look:query-receive bar2 msg1
myserv1173:myserv:process_query:query-respond
...
Note

For the query-receive probe, stringof() is used to cast args[0] and args[1] to type string. Otherwise, a DTrace compilation error similar to the following is displayed:

dtrace: failed to compile script /dev/stdin: line 7:
printf( ) argument #5 is incompatible with conversion #4 prototype:
	conversion: %s
	 prototype: char [] or string (or use stringof)
	  argument: char *

If the probe arguments were defined as type string instead of char * in the probe definition file, a compilation warning similar to the following would be displayed:

In file included from src1.c:5:
myserv.h:39: warning: parameter names (without types) in function declaration

In this case, casting the probe arguments to the type string would no longer be required.

The following script illustrates the complete process of instrumenting, compiling and tracing a simple user-space program. Save it in a file named testscript:

#!/bin/bash

# Define the probes
cat > prov.d <<EOF
provider myprog
{
  probe dbquery__entry(char *);
  probe dbquery__result(int);
};
EOF

# Create the C program
cat > test.c <<EOF
#include <stdio.h>
#include "prov.h"

int
main(void)
{
        char *query = "select value from table where name = 'foo'";
        /* If the dbquery-entry probe is enabled, trigger it */
        if (MYPROG_DBQUERY_ENTRY_ENABLED())
                MYPROG_DBQUERY_ENTRY(query);
        /* Pretend to run query and obtain result */
        sleep(1);
        int result = 42;
        /* If the dbquery-result probe is enabled, trigger it */
        if (MYPROG_DBQUERY_RESULT_ENABLED())
                MYPROG_DBQUERY_RESULT(result);
        return (0);
}
EOF



test.o: test.c prov.h
  gcc -c test.c

prov.o: prov.d test.o
  dtrace -G -s prov.d test.o

test: prov.o
  gcc -o test prov.o test.o
EOF

# Make the executable
make test

# Trace the program
dtrace -c ./test -qs /dev/stdin <<EOF
myprog\$target:::dbquery-entry
{
        self->ts = timestamp;
        printf("Query = %s\n", stringof(args[0]));
}

myprog\$target:::dbquery-result
{
        printf("Query time = %d microseconds; Result = %d\n",
            (timestamp - self->ts) / 1000, args[0]);
}
EOF

The output from running this script shows the compilation steps, as well as the results of tracing the program:

# chmod +x testscript
# ./testscript
dtrace -h -s prov.d
gcc -c test.c
dtrace -G -s prov.d test.o
gcc -o test prov.o test.o
Query = select value from table where name = 'foo'
Query time = 1000481 microseconds; Result = 42