Debugging C++ applications using ProbeVue

Learn various ways you can debug C++ applications using ProbeVue. Get an explanation of Vue language syntaxes for probing several function types in C++, learn how to access their arguments, and explore the structure of header files. This article also explains several limitations, while providing key points for writing Vue script.

Prateek Goel (pragoel1@in.ibm.com), Systems Software Engineer, IBM

Photo of Prateel GoelPrateek Goel is a systems software engineer working with the UPT AIX Release team for past 2 years. During this time he has been involved with testing the data integrity of a file transfer over the network and currently is Subject Matter Expert (SME) for ProbeVue.



Srividhya Kalyanasundaram (srikalya@in.ibm.com), Staff Software Engineer, IBM

Photo of Srividhya KalyanasundaramSrividhya Kalyanasundaram is a staff software engineer working for the UPT AIX Release Team as a subject matter expert for Kerberos security. She has been working in IBM for the past three years focussing on testing Kerberos security, NFSv4, NDAF and Probevue components. Before joining IBM, she worked on HP-NSK platforms on development of POSIX threads library and Backup/Restore application using NDMP protocol. She holds a Bachelor of Engineering degree in Computer Science from Bharathidasan University, Trichy, India. You can contact her at srikalya@in.ibm.com.



02 March 2010

Also available in Chinese

Introduction

ProbeVue is a dynamic tracing facility that was introduced in AIX® 6.1. Initially, it was designed to dynamically trace C applications and system calls in the system. Over time, however, ProbeVue has extended its support to probing C++ applications and for taking live dump and base system calls. This article covers ProbeVue's support of C++ applications.

ProbeVue uses user-written Vue script (using the Vue language) to identify what probes(trace hooks) to put at the entry or exit of which function, and what action must be taken after that probe point(trace point) is hit.

It has the following features:

  • Trace hooks do not have to be precompiled as part of your source code.
  • ProbeVue works on 32- or 64-bit kernel or user applications without any modification.
  • Trace hooks do not exist until they are placed using ProbeVue.
  • Trace data captured as part of the tracing actions are available for viewing immediately and can be displayed as output to the terminal or saved to a file for later viewing.
  • Trace hooks can be applied at the entry or exit of any function. (Currently, the exit probe point is supported for system calls only.)
  • Tracing of arguments passed to the function is feasible when the probe type is entry and requires that the function prototype be defined at the beginning of the Vue script or through a header file.
  • Tracing of the exit/return value of a function is possible by applying a trace hook at an exit point and specifying the function prototype.
  • ProbeVue can be used for performance analysis as well as for debugging problems.

Prerequisites

There are several prerequisites that must be in place before using ProbeVue:

  • AIX 610 or later.
  • File sets: There are no specific filesets required; they are shipped with the base operating system.
  • The ProbeVue feature must be enabled before you can probe anything. You can enable this using smit probevue.
  • The IBM XLC++ compiler must be installed on your machine in the /usr/vacpp directory.

Vue script syntax

Probing C++ functions

To probe C++ functions, use the following commands:

Non-class function with arguments

  @@uftxlc++:PID:*:"Func(arg1_type, arg2_type,..,argN_type)":entry

Non-class function without arguments

@@uftxlc++:PID:*:"Func":entry

Class function with arguments

@@uftxlc++:PID:*:"Class::Func(arg1_type, arg2_type,..,argN_type)":entry

Class function without arguments

@@uftxlc++:PID:*:"Class::Func":entry

Function with template return or argument type

@@uftxlc++:PID:*:"Class::Func<type1,..,typeN>(arg1_type,..,argN_type)":entry

Template functions are always specified with fully parameterized types. The angle brackets assign a specific type (that is, the parameterized type) to the generic type represented by the "T" argument types.

Probing C++ library routines

C++ library routines can be probed using @@uft instead of @@uftxlc++. Following is the demonstration of the same.

Alternative to @@uftxlc++

An alternative to @@uftxlc++ is @@uft, and it can be used if your executable is not stripped. It works in the following way:

  1. Run dump -tv on a non-stripped executable to get functions of an executable, and dump -Tv to get library routines.
  2. Check it out for the CPP section, and pick up the function you are interested in. Listing 1 shows an example.
    Listing 1. Getting the function
    -----------------------------------------------------------------
                       Case 1 : C++ executable functions
    -----------------------------------------------------------------
    # dump -tv ./a.out 
    [Index] m        Value       Scn   Aux  Sclass           Type     Name
    [110]   m   0x0000008f     debug     3    FILE        C++:COM     .file
    [113]   a0                                    IBM XL C/C++ Enterprise Edition for AIX
    [149]   m   0x10000660     .text     1    weak                  .hello__1AFv
    
    Note : You can probe functions which have 
             4th field "Scn" = ".text"
                            and 
        6th field "Sclass"="extern" Or "unamex" Or "weak"
    -----------------------------------------------------------------
                      Case 2 : C++ library functions
    -----------------------------------------------------------------
    # dump -Tv ./a.out
    ./a.out:
                            ***Loader Section***
                            ***Loader Symbol Table Information***
    [Index]      Value      Scn     IMEX    Sclass   Type           IMPid Name
    [2]     0x00000000    undef      IMP     DS EXTref   libc.a(shr.o) atexit
    
    Note : You can probe functions which have 
              4th field "IMEX" = "IMP"
                        and 
              5th field "Sclass" = "DS"
  3. Use that function in the following format: @@uft:PID:*:picked_function:entry. For example:
    Case 1 : @@uft:PID:*:hello__1AFv:entry
    
    Case 2 : @@uft:PID:*:atexit:entry

Example for basic probing

The example in Listing 2 demonstrates debugging C++ source code to ensure that all of the required functions are being called and in what sequence. This example shows the C++ source code that contains a non-class function, a Private member function of a class, and a Public member function of a class.

Listing 2. C++ Source Code : class.C
#include<iostream>
using namespace std;

void func3()                    // A Non-Class function
{
        cout << "In func3" << endl;
}

class space
{
        private:
                int func2()      // Private member function of class space
                {
                        cout << "In space private func2" << endl;
                        return 1;
                }
        public:
                void func1()    //  Public member function of class space
                {
                        cout << "In space public func1" << endl;
                        int rv = func2();            // Calling Private function func2
                        cout << "Return value of space private func2: " << rv <<endl;
                }
};
int main()
{
        space s;
        s.func1();    // Calling Public function of class space 
        func3();      // Calling Non-class function func3 
}

The Vue script in Listing 3 performs the following functions:

  • Probe the function func1 of class space.
  • Probe the function func2 of class space.
  • Probe the function func3 - A non-class function.
  • Probe the function main.
Listing 3. Vue Script : class.e
# Asking ProbeVue to put probe at func1 of class space 
@@uftxlc++:$__CPID:*:"space::func1":entry
{
 # And take this action once the function func1 is called
        printf("Function : func1 called\n");
}

#Asking ProbeVue to put probe on func2 of class space
@@uftxlc++:$__CPID:*:"space::func2":entry
{
 # And take this action once the function func2 is called
        printf("Function : func2 called\n");
}

#Asking ProbeVue to put probe on func3
@@uftxlc++:$__CPID:*:"func3":entry
{
 # And take this action once the function func3 is called
        printf("Function : func3 called\n");
}

#Asking ProbeVue to put probe on main function as well
@@uft:$__CPID:*:main:entry
{
 # And take this action once the function main is called
        printf("Function : main called\n ");
}

#To terminate ProbeVue session once the executable exits we do the following
#Asking ProbeVue to put probe on exit system call of the process
@@syscall:$__CPID:exit:entry
{
  # And exit once the exit system call is called
        printf("Process called exit system call\n");
        printf("Process exiting hence, Probevue also exiting\n");
        exit();
}

Output:
# probevue -X ./class ./class.e
In space public func1  <-- Following this the output is from executable
In space private func2
Return value of space private func2: 1
In func3
Function : main called  <-- Following this the output is from Probevue
 Function : func1 called
Function : func2 called
Function : func3 called
Process called exit system call
Process exiting hence, Probevue also exiting

You can tune the example in Listing 3 further to find the number of times each function is called.

Accessing arguments

In addition to providing the facility to place probes and identifying which functions are called and in which sequence, ProbeVue also lets you collect the values of the parameters passed to a function. To access arguments you need to specify the prototype of the function for ProbeVue to recognize the data type of the argument to be fetched. This is done by writing the prototypes in a header file. This section explains how to access the arguments in Vue script; the header file is covered in the next section. Arguments are accessed by adding their position (1, 2, 3 and so on) after the __arg variable. Now, take a look at how to access basic and derived data types of arguments.

Accessing basic data types

Basic data types are fairly easy to access because they have a very simple syntax. You access them as you would any other Vue script variable, except for a small change. You can access other basic data types similarly.

C++ function definition

void func1(int a)  // A non-class member function
Listing 4. Vue script format to access the argument
##C++
#include "headerfile.h"
##Vue
@@uftxlc++:PID:*:"func1(int)":entry
{
        printf("Probing function func1\n");
        printf("Arguments=%d\n",__arg1);  # Accessing argument of function func1
}

If the previous function was a class member function, then you would have used an __arg2 variable.

Accessing derived data types

The previous example contains a class object and string. To access derived data types, you use the copy_userdata function, which copies the required data from a non-vue variable, that is, from memory pointed by an argument to a Vue script variable. You cannot use direct __arg2 or __arg3 variables.

C++ function definition

void spacefriend(space *s,char *)  // A class member function
Listing 5. Vue script format to access the argument
##C++
#include "headerfile.h"
##Vue
struct space s1; 
@@uftxlc++:PID:*:"space::spacefriend(space *, char *)":entry
{
        String st[100];
        printf("Probing spacefriend\n");
        copy_userdata(__arg2, s1);     # accessing argument space * here
        printf("Argument s1.x = %d\n",s1.x);
        copy_userdata(__arg3,st);  # accessing argument char * here
        printf(" Argument 2 of function spacefriend %s",st);
}

Note that when you try to access an argument of a class member function the actual argument count starts from 2 instead of 1. In Probevue, __arg1 refers to "this" pointer of C++ while accessing a class member function. Therefore, the argument space * is __arg2 and char * is __arg3 in Listing 5. A C++ class is treated as a C-like structure, so in the Vue script you access it like any other structure.

For a non-class function argument, numbering starts from __arg1. For a class member function, it starts from __arg2.

Header files

To access the arguments of any given function you need to provide the function prototype for ProbeVue so that it knows which argument is of which data type. The prototype of a function can be defined in header files. This section explains how to compose a header file and how to include it in Vue script.

Writing a header file

As mentioned, a header file is a collection of function prototypes that you want to probe and access arguments. This header file should ideally contain all the class definitions, member functions, and variables. Therefore, the header file should include the prototype of the function and also a dummy function definition. You also must replace the function main with some other unique function name. As shown in Listing 8, main has been replaced with the name dummy. All the other statements inside the main function should remain intact. A header file can be included using the following Vue script syntax:

##C++
#include "headerfile.h"  
##Vue

These 3 lines must be the first 3 lines in the Vue script if you are going to include the header file. Note that there must be space between include and the opening quote marks (").

Note: The header file should have #include<iostream.h> instead of #include<iostream>.

Example for accessing arguments

Listing 6 shows how to access the arguments of a class function as well as a non-class function. The C++ code contains:

  • A class named space.
  • A public function in the class space named func, which takes 2 arguments of type int and does not return anything.
  • Function func is overloaded with another func definition having 2 arguments of type char.
  • A friend function named spacefriend, which is a friend of class space, and which takes the class object as an argument and prints the value of its variable x.
  • A template function GetMul with template type arguments and a return type as well.
  • A main function calls the public function func with int arguments of class space. It then calls the friend function spacefriend and passes the class object address as its argument, and calls the template function, beginning with integer types and then floating data types. Finally, it calls the overloaded function func with char type arguments.
Listing 6. C++ Source Code: class.C
#include<iostream.h>
using namespace std;
class space
{
private :       int x;
        public:
                void func(int a, int b)  // Overloaded function with int type arguments
                {
                        cout << "In space private func2 - int instance" << endl;
                }
                void func(char a, char b) // Overloaded function with char type arguments
                {
                        cout << "In space private func2 - char instance" << endl;
                }
        space()  // Overloaded Constructor
        {
                x=22;
        }
        friend void spacefriend(space *);  // declaring spacefriend as friend function
        template < class T >
                T GetMul (T t2,T t3)  // Template function GetMul
                {
                        T result=0;
                        result=(T)t2*(T)t3;
                        return ((T)result);
                }

};
void spacefriend(space *s)  // Definition of friend of function
{
        cout << "I am space friend accessing x = " << s->x << endl;
}
int main()  // Main function starts
{
        space s;
        s.func(2,10);   // Calling int instance of overloaded function "func"
        spacefriend(&s);  // Calling friend function
        int x=3, rv;
        float y=2.1, rv1;
        rv=s.GetMul(x,x);    // Calling template function with integer arguments
        rv1=s.GetMul(y,y);   // Calling template function with floating type arguments
        cout << " (int) Template return value = " << rv << endl;
        cout << " (float) Template return value = " << rv1 << endl;
        s.func('a','b');    // Calling overloaded function "func" with char type arguments

}

The Vue script in Listing 7 does the following:

  • Puts a probe on the overloaded function func for both instances int and char, and fetches its arguments using __arg2 and __arg3 because it is a class member function.
  • Puts a probe on function spacefriend, and fetches its argument using __arg1 because it is a non-class function.
  • Puts a probe on the template function GetMul for both instances int and float, and fetches arguments using __arg2 and __arg3.
  • Puts a probe on the exit system call to exit when the process exits.
Listing 7. Vue Script: class.e
##C++
#include "class.h"
##Vue
struct space s1; //declaring structure corresponding to class space
#Probing int instance of overloaded function "func" 
@@uftxlc++:$__CPID:*:"space::func(int, int)":entry
{
        printf("Probing space func - int instance\n");
        printf("Argument1=%d\n",__arg2);
        printf("Argument2=%d\n",__arg3);
}
#Probing friend function "spacefriend"
@@uftxlc++:$__CPID:*:"spacefriend(space *)":entry
{
        printf("Probing spacefriend\n");
        copy_userdata(__arg1, s1);
        printf("Argument s1.x = %d\n",s1.x);
}
#Probing int instance of template function "GetMul" 
@@uftxlc++:$__CPID:*:"space::GetMul<int>(int,int)":entry
{
        printf("Probing template (int) GetMul\n");
        printf("Argument1=%d\n",__arg2);
        printf("Argument2=%d\n",__arg3);
}
#Probing float instance of template function "GetMul" 
@@uftxlc++:$__CPID:*:"space::GetMul<float>(float,float)":entry
{
        printf("Probing template (float) GetMul\n");
        printf("Argument1=%f\n",__arg2);
        printf("Argument2=%f\n",__arg3);
}
#Probing char instance of overloaded function "func" 
@@uftxlc++:$__CPID:*:"space::func(char, char)":entry
{
        printf("Probing space func - char instance\n");
        printf("Argument1=%c\n",__arg2);
        printf("Argument2=%c\n",__arg3);
}
@@syscall:$__CPID:exit:entry
{
        exit();
}


Output :
# probevue -X ./class ./class.e
In space private func2 - int instance  <-- Following this the output is from executable
I am space friend accessing x = 22
 (int) Template return value = 9
 (float) Template return value = 4.41
In space private func2 - char instance
Probing space func - int instance  <-- Following this the output is from Probevue
Argument1=2
Argument2=10
Probing spacefriend
Argument s1.x = 22
Probing template (int) GetMul
Argument1=3
Argument2=3
Probing template (float) GetMul
Argument1=2.100000
Argument2=2.100000
Probing space func - char instance
Argument1=a
Argument2=b

The header file in Listing 8 contains the prototype of the functions and classes you are probing. Note that the name of function main has been changed to dummy. Everything else remains the same.

Listing 8. Header File : class.h
#include<iostream.h>
using namespace std;
/* Declare function prototypes */
class space
{
        int x;
        public:
                void func(int a, int b)
                {
                        cout << "In space private func2 - int instance" << endl;
                }
                void func(char a, char b)
                {
                        cout << "In space private func2 - char instance" << endl;
                }
        space()
        {
                x=22;
        }
       friend void spacefriend(space *);
        template < class T >
                T GetMul (T t2,T t3)
                {
                        T result=0;
                        result=(T)t2*(T)t3;
                        return ((T)result);
                }

};
void spacefriend(space *s)
{
        cout << "I am space friend accessing x = " << s->x << endl;
}
void dummy()
{
        space s;
        s.func(2,10);
        spacefriend(&s);
        int x=3, rv;
        float y=2.1, rv1;
        rv=s.GetMul(x,x);
        rv1=s.GetMul(y,y);
        cout << " (int) Template return value = " << rv << endl;
        cout << " (float) Template return value = " << rv1 << endl;
        s.func('a','b');

}

Limitations

As with any code, there are several limitations in using ProbeVue. These include:

  • Access to data fields inherited from a virtual base class is not supported.
  • Template classes are not supported and should not be included in the C++ header. However, the template function is supported.
  • Pointers to members are not supported.
  • The exit point of C++ functions cannot be probed. Therefore, it cannot retrieve the return value of a function.

Conclusion

In this article, you learned how you can easily start debugging C++ applications using ProbeVue. You learned Vue language syntaxes for probing several function types in C++, how to access their arguments, and the structure of header files. You also discovered several limitations in writing Vue scripts.

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into AIX and Unix on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=AIX and UNIX
ArticleID=469266
ArticleTitle=Debugging C++ applications using ProbeVue
publish-date=03022010