Dynamic Probe Class Library Programming Guide

The term probe refers to a software instrumentation code patch
that your analysis tool can insert into one or more target application
processes. Probes are created by the analysis tool, and therefore are
custom designed to perform whatever work is required by the tool. For
example, depending on the needs of the analysis tool, probes could be inserted
into the target application to collect and report performance information
(such as execution time), keep track of pass counts for test coverage tools,
or report or modify the contents of variables for debuggers. For an
overview of probes, refer to What is a probe?.

For the purposes of this book, a probe is defined as "a probe expression
that may optionally call functions". A probe expression
(described in more detail in What is a probe expression?) is a simple instruction or sequence of instructions that
represents the executable code to be inserted into the target
application. An analysis tool can create probe expressions to perform
conditional control flow, integer arithmetic, and bitwise operations.
For instructions detailing how an analysis tool can create probe expressions,
refer to Creating probe expressions.

When more complicated logic is needed (such as iteration, recursion, and
complex data structure manipulation), a probe expression can call
functions. Specifically, a probe expression can call:

a DPCL system-defined function for sending collected data back to the
analysis tool.

UNIX functions (like getrusage, times, and
vtimes).

functions contained in the target application.

a C function compiled into an object file called a "probe
module". A probe module (described in more detail in What is a probe module?) is a compiled object file containing one or more
functions written in C. Once an analysis tool loads a particular probe
module into a target application, a probe expression is able to call any of
the functions contained in the module. For instructions detailing how
an analysis tool can do this, see Creating and calling probe module functions.

A probe expression (described in more detail in What is a probe expression?) is a simple instruction or sequence of instructions that
represent the executable code to be inserted into one or more target
application processes. A probe expression is a type of data structure
called an abstract syntax tree (a term we have borrowed from compiler
technology). These data structures are called "abstract syntax trees"
(as opposed to simply "syntax trees") because they are removed from the
syntactic representation of the code. Compilers need to create abstract
syntax trees from a program's source code as an intermediary stage before
manipulating and converting the data structure into executable
instructions. Since the DPCL system also needs to create executable
instructions (for insertion into one or more target application processes), it
also needs to create these abstract syntax trees. To create a probe
expression, you need to:

Determine the basic logic for the probe expression. This is not a
task that the analysis tool code preforms -- instead, it is a task that
you, the creator of the analysis tool code, should perform. Creating
the probe expression that will execute in one or more target application
processes can be a "building block" task that involves first creating simple
probe expressions and then combining and sequencing them into a single probe
expression that represents the complete code patch to be inserted into the
target application processes. To do this, it can sometimes be helpful
to have a C or pseudocode version of the basic logic you want to build into
the probe expression. This C or pseudocode version can then serve as a
map of the logic you need to create using probe expressions.

Use ProbeExp objects to represent the various parts of the
probe expression logic -- the individual "nodes" of the abstract syntax
tree -- and then combine and sequence these ProbeExp objects
into a final ProbeExp object that represents the complete code
patch to be inserted into the target application process.

The next step (Step 2: Build the probe expression) describes how an analysis tool can create a probe
expression that it can later execute within a target application
process. The procedure for creating a probe expression can be a
"building block" task in which smaller probe expressions are eventually
combined and sequenced into the full probe expression.

For example, the analysis tool can create probe expressions representing
constant or variable values, and then combine these into more complex probe
expressions representing simple operations on the values, or function calls
that pass the values as parameters to the function. The analysis tool
could then take two of these more complex probe expressions and combine them
into a single probe expression that represents a sequence of the two existing
expressions. Then the analysis tool could join two such sequences into
a longer sequence or combine them into a conditional statement. And so
on, depending on the complexity of the probe logic, until the analysis tool
has a single probe expression representing the full probe logic.

While the procedure for building a probe expression is the topic of the
next step (Step 2: Build the probe expression), you should at this point determine the basic logic that
the probe expression will perform. To adequately do this, you should
understand the programmatic capabilities of probe expressions. A probe
expression can represent:

The analysis tool can combine these probe expressions representing
operations into probe expressions representing more complex operations, a
sequence of instructions, or parts of a conditional statement.

a sequence of instructions. Probe expressions can
represent a sequence of two existing probe expressions.

The analysis tool can combine these probe expressions into longer sequences
or parts of a conditional statement.

a function call. Probe expressions can represent a call
to:

the DPCL system-defined function Ais_send (for sending data
back to the analysis tool).

a function contained in a probe module.

a function that is already present in the application.

a UNIX system call.

The analysis tool can combine these probe expressions into probe
expressions representing a sequence of instructions or a conditional
statement.

a conditional statement. Probe expressions can represent
a conditional statement. The test condition, the code to execute if the
condition tests true, and the code to execute if the condition tests false are
all existing probe expressions.

The analysis tool can combine these probe expressions representing
conditional statements into more complex conditional statements or a sequence
of instructions.

Since the procedure for creating a full probe expression can be a "building
block" task in which simple probe expressions are combined to form more
complex ones, you might want to sketch out the logic in C code or
pseudocode. This will give you a map for building the probe expression
(as described next in Step 2: Build the probe expression).

Once you have determined the basic logic you want to build into the probe
expression, you can create the analysis tool code that builds the probe
expression. The analysis tool must first create ProbeExp
objects to represent the various parts of the probe expression logic --
the individual "nodes" of the abstract syntax tree -- and combine and
sequence these ProbeExp objects into a final ProbeExp
object that represents the complete code patch to be inserted into the target
application process. To build a probe expression, the analysis tool
can:

create probe expressions to represent data values. These can
be:

constant values.

variable values (including a variable in the target application).

the actual value of a particular function parameter in the target
application.

create a probe expression to represent operations.

combine existing probe expressions into a new probe expression
representing a sequence of instructions.

Like most programming vehicles, probes require scratch space for both
temporary and persistent data. The DPCL system automatically allocates
probe temporary data each time a probe expression executes, and deallocates
the data when the probe expression completes. Probe persistent data, on
the other hand, must be explicitly allocated by the analysis tool code.
Creating probe expressions to represent probe temporary data describes how an analysis tool can use ProbeExp
class constructors to create probe expressions representing temporary
data. Creating probe expressions to represent persistent data describes how an analysis tool can explicitly allocate
probe persistent data.

The DPCL system automatically allocates probe temporary data each time the
probe expression is executed, and deallocates the data when the probe
expression completes. Unlike probe persistent data (described next in Creating probe expressions to represent persistent data), the analysis tool does not need to explicitly allocate
memory for the data. To create a probe expression to represent
temporary data, the analysis tool uses the ProbeExp class
constructor to specify the data type and initial value of the data.

Using the SourceObj::reference function, the
analysis tool is able to create a probe expression that references a global or
static data variable in the target application. To do this, the
analysis tool must navigate the target application's source code
structure to identify the variable of interest. (If you are unfamiliar
with SourceObj objects and the concept of source hierarchies, you
may want to refer to What is the SourceObj class? before reading the following example code.

The following example code:

Calls the Process::get_program_object function to
return the top-level source object (SourceObj object) associated
with a process.

Identifies the program module that contains the variable. To do
this, it uses the SourceObj::child_count function to
initialize a for loop and then, within the for loop,
uses the SourceObj::child and
SourceObj::module_name functions to identify the target
module.

Calls the SourceObj::bexpand function to expand the
module. This enables the analysis tool to navigate further down the
source hierarchy to examine additional program structure (including global
data variables). An analysis tool could also expand a module using the
asynchronous SourceObj::expand function.

Identifies the variable. To do this, the analysis tool code again
uses the SourceObj::child_count function to initialize
a for loop, and then, within the for loop, uses the
SourceObj::child and
SourceObj::get_variable_name functions to identify the
target variable.

Calls the SourceObj::reference function to create a
probe expression that represents the variable.

Unlike temporary data, probe persistent data must be explicitly allocated
and deallocated by the analysis tool code. If your analysis tool code
requires probe data to be persistent from one invocation of the probe to the
next, it must allocate memory within the target application
process(es). To create a probe expression to allocate persistent data
in a single process, the analysis tool can use the
Process::alloc_mem or its blocking equivalent
Process::balloc_mem. To create a probe
expression to allocate persistent data on an application-wide basis (for all
Process objects managed by the Application object), the
analysis tool can use the functions
Application::alloc_mem or
Application::balloc_mem.

Keep in mind that, as with traditional programming, if your code allocates
memory, it must later free that memory or it will create a memory leak.
To create a probe expression that frees memory in a single process, the
analysis tool can use the Process::free_mem function or
its blocking equivalent Process::bfree_mem. To
create a probe expression that frees memory on an application-wide basis (in
all Process objects managed by an Application object),
the analysis tool can use the functions
Application::free_mem and
Application::bfree_mem.

Using the ProbeType::get_actual function, the
analysis tool can create a probe expression that represents the actual value
of a particular function parameter in the target application. When
executed within the target application, the probe expression will determine
the actual value of the parameter at that point in time. If the
analysis tool were a debugger, for example, it might want to display this
information to the user. The probe expression representing the actual
parameter value can then be combined into a more complex probe expression that
determines the actual parameter value and sends that information back to the
analysis tool which displays it to the user.

In order to use the ProbeType::get_actual function,
the analysis tool must first create a ProbeType object (using the
ProbeType::function_type function) that represents the
prototype (or type signature) of the function. The DPCL system needs to
know this type information in order to correctly identify an actual parameter
value for the function; if the ProbeType object created using
the ProbeType::function_type function does not match
the function prototype in the target application, the
ProbeType::get_actual function will not return the
correct information.

The following example code calls the
ProbeType::function_type function to create a
ProbeType object that represents a function prototype. This
example then uses the ProbeType::get_actual function to
create a probe expression that represents the actual parameter value of one of
the function's parameters.

// create a prototype for a function that has an two arguments: and int
// and a pointer to int; and has no return value
ProbeType pr_args[2];
pr_args[0] = int32_type();
pr_args[1] = pointer_type(int32_type());
ProbeType proto = function_type(void_type(), 2, pr_args);
// create a probe expression representing the first parameter in a call
// to a function having this prototype
ProbeExp ap = proto.get_actual(0);

For more information on the ProbeType object, refer to What is the ProbeType class?. For more information on the
ProbeType::function_type or
ProbeType::get_actual function, refer to the
function's UNIX man page or the DPCL Class
Reference

Writing the analysis tool code that creates probe expressions representing
operations is a fairly straightforward task. This is because the
ProbeExp class has overloaded common operators so that expressions
written within the context of the class do not execute locally, but instead
call member functions that create the probe expression. For example,
the following line of code:

ProbeExp pe3 = pe1 + pe2;

creates the probe expression pe3 which represents the addition
of probe expressions pe1 and pe2. With the
exception of the simple assignment operator (=), and the unary
address operator (&), the ProbeExp class has
overloaded all of the C++ operators in this way. This includes
arithmetic operators (+, -, *, /,
%), bitwise operators (<<, >>,
~, ^, &, |), relational
operators (<, >, ==, !=,
<=, >=), logical operators (&&,
||, !), assignment operators (+=,
-=, *=, /=, %=,
<<=, >>=, ^=, &=,
|=), and dereference operators (*,
[]). Whenever any of these operators are used
within the context of a probe expression, they create a probe expression that
represents the operation. The operands can either be objects in memory,
or probe expressions that evaluate to values. This means that a probe
expression representing an operation could itself be used as an operand when
creating another probe expression.

As already mentioned, the two operators that are not overloaded by the
ProbeExp class are the simple assignment operator (=)
and the unary address operator (&). So these two
operators retain their original semantics -- "pe2 = pe1"
performs the assignment of probe expression pe1 into probe
expression pe2 within the analysis tool, and "&pe1"
takes the address of the probe expression pe1 within the analysis
tool. Instead of overloading the = and &
operators, the ProbeExp class instead provides the member functions
assign and address. For example, the following
line of code:

ProbeExp pea = pe1.assign(pe2);

creates a probe expression that assigns the value computed by the probe
expression pe2 into the storage location indicated by
pe1, and this next line of code:

ProbeExp peb = pe.address();

creates a probe expression peb that represents the address of
the probe expression pe.

The following tables outline the various operations that can be represented
in probe expressions. Be aware that not all of the operator functions
summarized in these tables are compatible with all operator types. For
more information on any of the functions listed in these tables (including
information on which types are valid for each overloaded operator function),
refer to theDPCL Class Reference.

Combine the probe expression into a probe expression representing a
conditional statement. The probe expression representing the operation
could, in the conditional statement, represent the test condition, the code
that executes if the condition tests true, or the code that executes if the
condition tests false. For more information, see Step 2d: Create probe expressions to represent conditional logic.

The preceding substep (Step 2b: Create probe expressions to represent operations) illustrates how an analysis tool can create probe
expressions that represent operations. This substep now shows how an
analysis tool can combine two probe expressions into a single probe expression
that represents a sequence of the two operations. Such sequence probe
expressions can then themselves be combined to form even longer sequences of
instructions. To combine two probe expressions into a sequence, the
analysis tool uses the ProbeExp::sequence
function. For example, say the logic that an analysis tool wants to
build into a probe expression can be represented in C code as:

pe1 = pe1 + 1;
fcn(pe1);
pe2 = pe1;
send(pe2);

To mimic this logic in a single probe expression, the analysis tool first
creates probe expressions that represent the four basic operations:

Finally, these two sequence probe expressions are combined into a longer
sequence representing the entire probe logic.

ProbeExp seqall = seq1.sequence(seq2);

Once the analysis tool has created a sequence probe expression, it
can:

Repeat this step to combine the sequence probe expression into a longer
sequence.

Combine the sequence probe expression into a probe expression representing
a conditional statement. The sequence probe expression could be the
test condition, the code that executes if the condition tests true, or the
code that executes if the condition tests false. For more information,
see Step 2d: Create probe expressions to represent conditional logic.

Next, the probe expression representing the test condition calls the
ifelse function. The probe expression to execute if the
condition tests true is supplied as a parameter to the function. The
ifelse function returns a single probe expression that represents
the entire conditional statement.

ProbeExp exp = ce.ifelse(te);

So in the above example, if the probe expression ce evaluates to
a non-zero value, the probe expression te executes. If the
probe expression ce evaluates to zero, however, te does
not execute. Instead, execution continues past the conditional
statement. In the above example, this entire conditional logic is
stored in the ProbeExp object exp.

The above example illustrates how a probe expression can mimic an
If statement. The analysis tool can also use the
ProbeExp::ifelse function to create a probe expression
that mimics an If/Else statement. All it needs to do is
supply an additional parameter to the ifelse function -- one
representing the code to execute if the test condition tests false. For
example, say the logic that an analysis tool wants to build into a probe
expression can be represented in C code as the If/Else
expression:

if (pe1 > 0)
send(pe1);
else
send(pe2);

To mimic this logic in a probe expression, the analysis tool first creates
probe expressions to represent the test condition, the code to execute if the
condition tests true, and the code to execute if the condition tests
false.

Next, the probe expression representing the test condition calls the
ifelse function. The probe expression to execute if the
condition tests true, and the probe expression to execute if the condition
tests false are both supplied as parameters to the function. The
ifelse function returns a single probe expression that represents
the entire conditional statement.

ProbeExp exp = ce.ifelse(te, ee);

So in the above example, if the probe expression ce evaluates to
a non-zero value, the probe expression te executes. If the
probe expression ce evaluates to zero, the probe expression
ee executes. In the above example, this entire conditional
logic is stored in the ProbeExp object exp.

Once the analysis tool has created a conditional probe expression, it
can:

Repeat this step to include the conditional probe expression as part of a
more complex conditional statement.

a UNIX function like getrusage, times, or
vtimes. The ability to call UNIX functions enables a probe
to get performance and system-resource information for a target application
process.

In all four of these situations, the analysis tool uses the
ProbeExp::call function to create a probe expression
that represents a function call. For more information on the
ProbeExp::call function, refer to its UNIX man page, or
its entry in the DPCL Class Reference.

Once the analysis tool has created a probe expression that represents a
function call, it can:

Combine the probe expression into a probe expression representing a
conditional statement. The probe expression representing the function
could be the code that executes if the condition tests true, or the code that
executes if the condition tests false. For more information, see Step 2d: Create probe expressions to represent conditional logic.

The Ais_send function enables a probe to send data back to the
analysis tool. The Ais_send function takes three parameters
-- a message handle for managing where the data is sent, the address of
the data to send, and the size of the data being sent. To send the data
located at the address &pcount back to the analysis tool, the
call to the Ais_send function, if written in C code, would
be:

Ais_send(handle, &pcount, 4);

To mimic this function call in a probe expression, the analysis tool first
creates an array of probe expressions, with each expression in the array
representing one of the parameters to the Ais_send function.
As described in Step 2b: Create probe expressions to represent operations, the ProbeExp class did not overload the unary
address operator (&). Note that the following code calls the
ProbeExp::address function to mimic the unary address
operator used in the preceding C code.

Next the analysis tool creates a probe expression that represents the call
to Ais_send. The parameter values intended for the
Ais_send function are passed as the probe expression array
parms to the ProbeExp::call function.
The first parameter to the ProbeExp::call function
indicates the number of probe expressions in the array. In this
example, there are three probe expressions in the array.

ProbeExp sendexp = Ais_send.call(3, parms);

Creating probe expressions to represent actual function parameter values in the target application contains example code that shows how the analysis tool can
create a probe expression that, when executed within a target application
process, will determine the actual value of a function parameter at that point
in time. The following example code expands on this earlier example to
show how the analysis tool can create a probe expression that, when executed
within a target application process, will call the Ais_send
function to send this actual parameter information back to the analysis
tool.

The analysis tool can also use the ProbeExp::call
function to create a probe expression that represents a call to a UNIX
function like getrusage, times, or
vtimes. The ability to call UNIX functions enables a probe
to get performance and system-resource information for a target application
process. For example, say that, in order to get system resource usage
for a target application process, the analysis tool needs to create a probe
expression that calls the UNIX function getrusage. In C
code, a call to this function would look like:

Next the analysis tool creates a probe expression that represents a call to
the getrusage function. In this example,
moduleobj is the module in the source tree that contains the
getrusage function, and i is the index of the
getrusage function in that module.

The analysis tool can also use the ProbeExp::call
function to create a probe expression that represents a call to a function
contained in a probe module (a compiled object file containing one or more
functions written in C) that has been loaded into a target application
process. Once an analysis tool loads a particular probe module into a
target application process, a probe expression is able to call any of the
functions contained in the module. See Creating and calling probe module functions for more information on creating probe modules.

Say that a probe module you have created contains a function
count that is designed to count the number of times the subroutine
is called. This probe module function takes one parameter -- the
predefined global variable Ais_msg_handle (which is used by the
DPCL system when the probe sends data back to the analysis tool). In C
code, a call to this function would look like:

count(handle);

To mimic this call in a probe expression, the analysis tool:

calls the ProbeModule::get_reference function to
create a probe expression that represents a reference to the count
function. The analysis tool supplies the
ProbeModule::get_reference function with the index of
the count function within the probe module; the
ProbeModule::get_reference function returns a probe
expression representing a reference to the count function.
To identify the count function within the probe module, the analysis tool can
use the ProbeModule::get_count and
ProbeModule::get_name functions.

For more information on the
ProbeModule::get_reference,
ProbeModule::get_count, and
ProbeModule::get_name function, refer to their UNIX man
pages, or their entries in the DPCL Class Reference.

creates an array of probe expressions, with each expression in the array
representing one of the parameters to the function. Since the
count function has only one input parameter, this array has only
one expression.

ProbeExp parms[1];
parms[0] = Ais_msg_handle;

combines these probe expressions (which represent a reference to the probe
module function count and the parameters to supply to that
function) into a single expression that represents the function call.
The parameter value intended for the count function is passed as
the probe expression array args to the
ProbeExp::call function. The first parameter to
the ProbeExp::call function indicates the number of
probe expressions in the array. In this example, there is only one
probe expression in the array.

Using the SourceObj::reference function, the
analysis tool is able to create a probe expression that represents a function
in the target application. This probe expression can then be combined
by the analysis tool into a probe expression representing a call to that
function. To create a probe expression that represents a target
application function, however, the analysis tool must first navigate the
target application's source code structure to identify the function of
interest. If you are unfamiliar with SourceObj objects and
the concept of source hierarchies, you may want to refer to What is the SourceObj class? before reading the following example code.

The following example code:

Calls the Process::get_program_object function to
return the top-level source object (SourceObj object) associated
with a process.

Identifies the program module that contains the function. To do
this, it uses the SourceObj::child_count function to
initialize a for loop and then, within the for loop, use
the SourceObj::child and
SourceObj::module_name functions to identify the target
module.

Calls the SourceObj::bexpand function to expand the
module. This enables the analysis tool to navigate further down the
source hierarchy to examine additional program structure (including
functions). The analysis tool code could also expand a module using the
asynchronous SourceObj::expand function.

Identifies the function. To do this, the analysis tool code again
uses the SourceObj::child_count function to initialize
a for loop, and then, within the for loop, uses the
SourceObj::child and
SourceObj::get_demangled_name functions to identify the
target function.

Calls the SourceObj::reference function to create a
probe expression that represents the function.

Uses the ProbeExp::call function to combine the
probe expression representing the function into a more complex probe
expression representing a function call.

Creates another probe expression that represents an Ais_send
function call that sends the value of pcount back to the analysis
tool.

Combines the two probe expressions into a single probe expression that
represents a sequence of the two expressions.

Since this example uses the Ais_send function, note that it also
provides a data callback routine for handling the data sent. Refer to Chapter 10, Creating data callback routines for more information on data callback routines.

A probe module is a compiled object file containing one or more functions
written in C. Once an analysis tool loads a particular probe module
into a target application, a probe expression is able to call any of the
functions contained in the module. It is often preferable for a probe
expression to call a probe module function rather than try to create the same
probe logic with probe expressions alone. This is because probe
modules:

can be reused by other analysis tools.

enable you to code the probe logic in a straightforward way using
C. For complicated probe logic this can be easier than the process of
building an abstract syntax tree of probe expressions (as described in Creating probe expressions).

can contain more complicated probe logic than is possible is a simple
probe expression.

In addition to these advantages, be aware that, if the probe is to be
executed as a phase probe, than its logic must be contained in a probe module
function. This is because phase probes, unlike point probes and
one-shot probes, cannot be a simple probe expression that does not call a
probe module function. To create a probe module and call one of its
functions, you must:

Create the probe module function.

Compile the probe module.

Instantiate a ProbeModule class object to represent the probe
module.

Load the probe module into one or more processes.

Create a probe expression to call the probe module function(s).

Create a data callback function to respond to any data message that can be
sent by the probe.

The first step in creating and calling a probe module function is to write the
actual function. To send data back to the analysis tool, the probe
module can call the built-in DPCL function Ais_send. The
Ais_send function takes three parameters -- a message handle
for managing where the data is sent, the address of the data to send, and the
size of the data being sent. In order to make the prototype of the
Ais_send function available to the compiler, your analysis tool
code should include the header file dpclExt.h.

For example, the following probe module function is a generic pass counter
that, when installed within a subroutine in a target application process, will
count the number of times the subroutine is called. Each time the
counter is incremented 10 times, the probe will call the Ais_send
function to send a message back to the analysis tool.

If your probe module function calls the Ais_send function as in
this example, your analysis tool code will need to include a data callback
routine to respond to data sent by the probe module. Refer to Chapter 10, Creating data callback routines for more information on data callback routines. For
more information on the Ais_send function, refer to its UNIX man
page, or its entry in the DPCL Class Reference.

Once you have written your probe module function, you'll need to
compile it into an object file. This object file is the probe
module. Before compiling the probe module, you'll need to create
an export file to export its functions. What's more, if the probe
module function calls any functions outside of the probe module, you'll
need to create an import file. For example, in the preceding step, we
encapsulated a simple pass counter into a function called
count. Here's our export file:

* Any line started with a '*' is a comment
* We have a single function to export
count

Also, since the count function calls the built-in DPCL function
Ais_send, we also create an import file:

#! .
Ais_send

Finally, we compile the file. Our export file is named
count.exp, and our import file is named
count.imp.

In order to load a probe module into one or more target application
processes, the analysis tool must create a ProbeModule class object
that represents the probe module. The probe module class is defined in
the header file ProbeModule.h. To assign a probe
module file name to a ProbeModule class object, you can use a
non-default constructor, a non-default constructor with a copy constructor, or
the default constructor with an assignment operator.

In order for a probe expression to call a probe module function, the probe
module function must be loaded into the same target application process(es)
within which the probe expression will execute. To load a probe module
on a single process basis, the analysis tool can use the asynchronous function
Process::load_module or its blocking equivalent
Process::bload_module. To load a probe module on
an application-wide basis (for all Process objects managed by an
Application object), the analysis tool can use the functions
Application::load_module or
Application::bload_module.

For more information on the Process::load_module,
Process::bload_module,
Application::load_module, and
Application::bload_module functions, refer to their
UNIX man pages, or their entries in the DPCL Class Reference.

If it is going to execute the probe module function as a phase probe, the
analysis tool uses the ProbeModule::get_reference
function to create a probe expression that represents a reference to the
function. See Executing phase probes for more information.

For additional information on the ProbeExp::call and
ProbeModule::get_reference functions, refer to their
UNIX man pages, or their entries in the DPCL Class Reference.

As described in Step 1: Create probe module function, a probe module function can send data back to the
analysis tool by calling the DPCL system-defined function
Ais_send. If your probe module function does call the
Ais_send function, then the analysis tool code must contain a data
callback function that will handle the data that the Ais_send
function will send. See Chapter 10, Creating data callback routines for more information on how to do this.

encapsulates a general-purpose pass counter into the function
count in the file count.c,.

compiles count.c into a probe module count
(using the count.exp and count.imp files
to export and import functions as needed,

creates a ProbeModule object to represent the probe module
count, and loads the module into process P,

gets a reference to, and creates a probe expression to call, the
count function, and

handles data sent by the Ais_send function using a data
callback routine. If your probe module uses the Ais_send
function to send data back to the analysis tool, then the analysis tool code
must contain a data callback routine. Refer to Chapter 10, Creating data callback routines for more information on data callback routines.