The following example shows a set of three snippets of code that can be inserted into an application program to record the byte count of messages sent by the foo function (or any function called by the foo function).
The figure above shows an instrumented application. The boxes on the left represent pieces of code inserted by Dyninst, which are referred to as snippets. The text on the right is the original application code. The first snippet increments a counter when we enter the function foo, and the second decrements it when we exit foo. The bottom snippet uses this counter to determine whether or not a call to SengMsg came from inside an invocation of foo, and if so, it adds the number of bytes being sent to another counter.
Code snippets in Dyninst are defined by creating objects of various child classes of the class BPatch_snippet. Each object represents a piece of data or an operation to perform. The constructors for many snippet types take other snippets as arguments, which are used as the operands for the operation that the snippet represents.
BPatch_variableExpr *fooCnt = appThread->malloc(appImage->findType("int"));
BPatch_variableExpr *bytes = appThread->malloc(appImage->findType("int"));
int zero = 0;
To create the snippets shown in the diagram, the first thing we need to do is to allocate memory for the two counters. We do this as shown in the code above, by calling the malloc method of the BPatch_thread object representing the application to be instrumented (in this case, appThread). We pass malloc the type of variable we want to allocate. We get the object that we need to identify the type by calling findType. After allocating the counters, we then initialize them to zero using the method "writeValue."
BPatch_arithExpr fooCntPlusOne(BPatch_plus, *fooCnt, BPatch_constExpr(1))
BPatch_arithExpr addCounter(BPatch_assign, *fooCnt, fooCntPlusOne)
Next we need to create a snippet that will increment fooCnt. First, we perform the addition, using a BPatch_arithExpr object with a parameter indicating addition, and the value of fooCnt and the constant one as the quantities to be added. We then assign the result back to fooCnt, again using a BPatch_arithExpr, this time with a parameter indicating assignment.
BPatch_arithExpr fooCntMinusOne(BPatch_minus, *fooCnt, BPatch_constExpr(1))
BPatch_assign subCounter(BPatch_assign, *fooCnt, fooCntMinusOne)
The subCounter snippet is almost exactly the same as addCounter, with BPatch_minus substituted for BPatch_plus.
BPatch_paramExpr cntParam(2), sizeParam(3);
BPatch_arithExpr calcBytes(BPatch_times, cntParam, sizeParam);
BPatch_arithExpr addBytes(BPatch_plus, *bytes, calcBytes);
BPatch_arithExpr addCounter(BPatch_assign, *bytes, addBytes);
We next need to build the snippet that will be inserted into sengMsg. The first line above declares objects that represent the third and fourth parameters of a procedure (the index begins at zero). For the sendMsg procedure, these are the cnt and sz parameters. In the second line, we multiply these together to get the number of bytes being written. The third and fourth lines add the calculated value to the bytes counter, and assign the new value to it.
BPatch_boolExpr fooCntCheck(BPatch_gt, *fooCnt, BPatch_constExpr(0));
BPatch_ifExpr addCounterIfInFoo(fooCntCheck, addCounter);
Finally we will create the conditional statement. We only want to execute the addCounter snippet if the value of fooCnt is greater than zero. We test this using a BPatch_boolExpr. As shown in the first line above, we pass the constructor for this class an argument that specifies the comparison we want to make, BPatch_gt for "greater than." We also pass the two expressions we want to compare, our counter fooCnt and the constant zero. In the second line, we create the conditional statement by declaring a BPatch_ifExpr object, passing it our boolean expression as the condition, and the addCounter snippet as the code to execute if the boolean evaluates to true.