Tru64 UNIX
Ladebug Debugger Manual


Previous Contents Index

5.6.1 Displaying Static and Dynamic Type Information

When displaying object information for C++ class pointers or references, the user has the option of viewing either the static type information or the dynamic type information.

The static type of a class pointer or reference is its type as defined in the source code (cannot change). The dynamic type is the type of the object being referenced, before any casts were made to that object (may change during program execution).

Ladebug provides a debugger variable, $usedynamictypes, which allows the user to control which form of the type information will be displayed. The default value for this variable is true (1), which indicates that the dynamic type information will be displayed. Setting this variable to false (0) instructs Ladebug to display static type information. The output of the following commands will be affected: print, trace, tracei, and whatis.

The display of dynamic type information is supported for C++ class pointers and references. All other types display their static type information. In addition, if the dynamic type of an object cannot be determined, Ladebug defaults to the use of the static type information.

This debugger functionality does not relax the C++ visibility rules regarding object member access through a pointer/reference (only members of the static type are accessible). For more information about the C++ visibility rules, see The Annotated C++ Reference Manual.

In order for the dynamic type information to be displayed, the object's static type must have at least one virtual function defined as part of its interface (either one it introduced or one it inherited from a base class). If no virtual functions are present for an object, only the static type information for that object will be available for display.

Example 5-4 shows the Ladebug output with $usedynamictypes set to 0 (false).

Example 5-4 Displaying Static Type Information

(ladebug) list 4, 13
      4 class Base { 
      5 
      6    protected: 
      7         int _number; 
      8 
      9    public: 
     10         Base(); 
     11         virtual ~Base(); 
     12         virtual void init(); 
     13 }; 
(ladebug) list 16, 25
     16 class Derived : public Base { 
     17 
     18    private: 
     19         int _size; 
     20 
     21    public: 
     22         Derived(); 
     23         virtual ~Derived(); 
     24         virtual void init(); 
     25 }; 
(ladebug) stop in main
[#1: stop in int main(void) ] 
(ladebug) run
[1] stopped at [int main(void):54 0x120001fe8] 
     54    Derived  d; 
(ladebug) next
stopped at [int main(void):55 0x120001ffc] 
     55    Base* bptr = &d; 
(ladebug) next
stopped at [int main(void):57 0x120002000] 
     57    initReference(d); 
(ladebug) whatis *bptr
class Base  { 
  int _number; 
  Base(void); 
  virtual ~Base(void); 
  virtual void init(void); 
} 
(ladebug) print *bptr
class Base { 
  _number = 0; 
} 
(ladebug) step
stopped at [void initReference(Base&):66 0x120002044] 
     66     b.init(); 
(ladebug) whatis b
Base& b 
(ladebug) print b
class Base { 
  _number = 0; 
} 

Example 5-5 displays Ladebug output with $usedynamictypes set to 1 (true).

Example 5-5 Displaying Dynamic Type Information

(ladebug) whatis *bptr
class Derived : Base { 
  int _size; 
  Derived(void); 
  virtual ~Derived(void); 
  virtual void init(void); 
} 
(ladebug) print *bptr
class Derived { 
  _size = 0; 
  _number = 0;                     // class Base 
} 
(ladebug) step
stopped at [void initReference(Base&):66 0x120002044] 
     66     b.init(); 
(ladebug) whatis b
Derived& b 
(ladebug) print b
class Derived { 
  _size = 0; 
  _number = 0;                     // class Base 
} 

5.7 Displaying Virtual and Inherited Class Information

When you use the print command to display information on an instance of a derived class, Ladebug displays both the new class members as well as the members inherited from a base class.

Pointers to members of a class are not supported.

When you use the print command to display the format of C++ classes, the class name (or structure/union name) is displayed at the top of the output. Data members of a class that are inherited from another class are commented using a double slash (//). Only those data members that are inherited within the current class being printed are commented.

Example 5-6 shows how Ladebug uses C++ style comments to identify inherited class members. In the example, class V inherits from class T, which inherits from class S. When printing a class V object, the data members x and y are commented with "// class T", signifying that they are inherited from class T. The members i and j are commented with "// class T::S" showing that they are inherited from class T which inherits them from class S. This commenting is also provided for C++ structs.

Example 5-6 Displaying Inherited Class Members

(ladebug) list 15, 25 
     15 class T : public S 
     16 { 
     17   protected: 
     18      long x; 
     19      short y; 
     20 
     21   public: 
     22      T(); 
     23      virtual ~T() {}; 
     24      virtual int bar(void); 
     25 }; 
(ladebug) list 28, 37 
     28 class V : public T 
     29 { 
     30   protected: 
     31      int z; 
     32 
     33   public: 
     34      V(); 
     35      virtual ~V() {}; 
     36      virtual int bar(void); 
     37 }; 
(ladebug) stop at "example.C":88
[#3: stop at "example.C":88 ] 
(ladebug) run
[3] stopped at [int main(void):88 0x120002284] 
     88    s.foo(); 
(ladebug) whatis T
class T : S { 
  long x; 
  short y; 
  T(void); 
  virtual ~T(void); 
  virtual int bar(void); 
} 
(ladebug) whatis V
class V : T { 
  int z; 
  V(void); 
  virtual ~V(void); 
  virtual int bar(void); 
} 
(ladebug) print t
class T { 
  x = 5; 
  y = 10; 
  i = 1;                           // class S 
  j = 2;                           // class S 
} 
(ladebug) print v
class V { 
  z = 25; 
  x = 5;                           // class T 
  y = 10;                          // class T 
  i = 1;                           // class T::S 
  j = 2;                           // class T::S 
} 
 

If you have two members in an object with the same name but different base class types (multiple inheritance), you can refer to the members using the following syntax:

object.class::member

This syntax is more effective than using the object.member and object->member syntaxes, which can be ambiguous. In all cases, the DIGITAL Ladebug debugger uses the C++ language rules as defined in The Annotated C++ Reference Manual to determine which member you are specifying.

Example 5-7 shows a case where the expanded syntax is necessary.

Example 5-7 Resolving References to Objects of Multiple Inherited Classes

(ladebug) print dinst.ambig
Ambiguous reference 
Selecting 'ambig' failed! 
Error: no value for dinst.ambig 
(ladebug) print dinst.B::ambig
2 
(ladebug) 

5.8 Member Functions on the Stack Trace

The implicit this pointer, which is a part of all nonstatic member functions, is displayed as the address on the stack trace. The class type of the object is also given.

Sometimes the debugger does not see class type names with internal linkage. When this happens, the debugger issues the following error message:


Name is overloaded. 

Trying to examine an inlined member function that is not called results in the following error:


Member function has been inlined. 

Ladebug will report this error regardless of the setting of the -noinline_auto compilation flag. As a workaround, include a call to the given member function somewhere in your program. (The call does not need to be executed.)

If a program is not compiled with the -g flag, a breakpoint set on an inline member function may confuse the debugger.

The stack trace in Figure 5-1 displays a member function foo of an object declared with class type S.

Figure 5-1 A Stack Trace Displaying a Member Function


5.9 Resolving Ambiguous References to Overloaded Functions

In most cases, the debugger works with one specific function at a time. In the case of overloaded function names, you must specify the desired overloaded function. There are two ways to resolve references to overloaded function names, both under the the control of the $overloadmenu debugger variable (the default setting of this debugger variable is 1):

5.10 Setting Breakpoints

When you set a breakpoint in a C function, the debugger confirms it by echoing the breakpoint command along with the status number for the breakpoint. When you set a breakpoint in a C++ function, the debugger also prints the type signature of the function in which the breakpoint was set.

The following sections describe setting breakpoints in member functions, in overloaded functions, and in constructors and destructors. See Section 5.12.1 for information on setting breakpoints in exception handlers.

5.10.1 Setting Breakpoints in Member Functions

To set a breakpoint that stops in a member function, use the stop in commands.

The stop in forms of specifying a breakpoint in a function use the static class type information to determine the address of the function at which to set the breakpoint, and presume that no run-time information from an object is needed.

In Example 5-10, a breakpoint is set for the bar member function of class S.

Example 5-10 Setting Breakpoints in Member Functions

(ladebug) stop in S::bar
[#1: stop in S::bar(void) ] 
(ladebug) status
#1 PC==0x120000658 in S::bar(void) "c++ex.C":18 { break } 
(ladebug) run
[1] stopped at [S::bar(void):18 0x120000658]       
     18      return j; 
(ladebug) where
>0  0x120000658 in ((S*)0x120000658)->bar() c++ex.C:18 
#1  0x120000750 in main() c++ex.C:26 
(ladebug) 

If you need run-time information from the object to determine the correct virtual function at which to set a breakpoint, qualify the function name with the object, using one of the stop in commands.

In Example 5-11, objects s and t are both declared to be of class type S. A breakpoint is set for the bar member function. The first time the debugger stops at bar() is for object s. The second time the debugger stops in bar() is for object t.

Example 5-11 Setting Breakpoints in Virtual Member Functions

(ladebug) stop in main
[#1: stop in main(void) ] 
(ladebug) run
[1] stopped at [main(void):26 0x120000744] 
     26      int result = s.bar(); 
(ladebug) stop in s.bar
[#2: stop in S::bar(void) ] 
(ladebug) status
#1 PC==0x120000744 in main(void) "c++ex.C":26 { break } 
#2 PC==0x120000658 in S::bar(void) "c++ex.C":18 { break } 
(ladebug) print &s
0x140000000 
(ladebug) print &t
0x140000008 
(ladebug) cont
[2] stopped at [S::bar(void):18 0x120000658]       
     18      return j; 
(ladebug) where
>0  0x120000658 in ((S*)0x140000000)->bar() c++ex.C:18 
#1  0x120000750 in main() c++ex.C:26 
(ladebug) cont
[2] stopped at [S::bar(void):18 0x120000658]       
     18      return j; 
(ladebug) where
>0  0x120000658 in ((S*)0x140000008)->bar() c++ex.C:18 
#1  0x12000076c in main() c++ex.C:27 
(ladebug) 

To set a breakpoint that stops only in the member function for this specific object and not all instances of the same class type, you must specify this as an additional conditional clause to the stop command.

In Example 5-12, which is running the same program as Example 5-11, the breakpoint is set for the member function for object s only. After stopping in bar() for object s, further execution of the program results in the program running to completion.

Example 5-12 Setting Breakpoints in Member Functions for a Specific Object

(ladebug) stop in s.bar if &s==this
[#2: stop in s.bar if &s==this ] 
(ladebug) status
#1 PC==0x120000744 in main(void) "c++ex.C":26 { break } 
#2 (PC==0x120000658 in S::bar(void) "c++ex.C":18 and if &s==this) {break} 
(ladebug) print &s
0x140000000 
(ladebug) cont
[2] stopped at [S::bar(void):18 0x120000658]       
     18      return j; 
(ladebug) where
>0  0x120000658 in ((S*)0x10000010)->bar() c++ex.C:18 
#1  0x120000750 in main() c++ex.C:26 
(ladebug) cont
Thread has finished executing 
(ladebug) 

5.10.2 Setting Breakpoints in Overloaded Functions

To set a breakpoint in an overloaded function, you must provide the full type signature of the function using one of the stop in commands.

In Example 5-13, the breakpoint is set for specific versions of the overloaded function foo.

Example 5-13 Setting Breakpoints in Specific Overloaded Functions

(ladebug) stop in foo(double)
[#1: stop in void S::foo(double) ] 
(ladebug) stop in foo(void)
[#2: stop in int S::foo(void) ] 
(ladebug) status
#1 PC==0x120001508 in void S::foo(double) "c++over.C":156 { break } 
#2 PC==0x120000ef4 in int S::foo(void) "c++over.C":59 { break } 
(ladebug) 

To set a breakpoint that stops in all versions of an overloaded function, use one of the stop in all commands.

In Example 5-14, the breakpoint is set for all versions of the overloaded function foo.

Example 5-14 Setting Breakpoints in All Versions of an Overloaded Function

(ladebug) stop in all foo
[#1: stop in all foo ] 
(ladebug) 

You can also set a breakpoint in an overloaded function by setting a breakpoint at the line number where the function begins. Be sure the current file context points to the file containing the function's source code before you set the breakpoint. In Example 5-15, the breakpoint is set for the overloaded functions by line number.

Example 5-15 Setting Breakpoints in Overloaded Functions by Line Number

(ladebug) stop at 59
[#1: stop at "c++over.C":59 ] 
(ladebug) stop at 156
[#2: stop at "c++over.C":156 ] 
(ladebug) status
#1 PC==0x120000ef4 in S::foo(void) "c++over.C":59 { break } 
#2 PC==0x120001508 in S::foo(double) "c++over.C":156 { break } 
(ladebug) 

5.10.3 Setting Breakpoints in Constructors and Destructors

To set a breakpoint in a constructor, use one of the stop in commands.

The type signature is only necessary to resolve an ambiguous reference to a constructor that is overloaded. In Example 5-16, a breakpoint is set in a constructor.

Example 5-16 Setting Breakpoints in Constructors

(ladebug) class S
class S  { 
  int i; 
  int j; 
  S (void); 
  ~S (void); 
  int foo (void); 
  virtual int bar (void); 
} 
(ladebug) stop in S
[#1: stop in S::S(void) ] 
(ladebug) status
#1 PC==0x1200005b8 in S::S(void) "c++ex.C":5 { break } 
(ladebug) 

In Example 5-17, the breakpoint is set for the destructor.

Example 5-17 Setting Breakpoints in Destructors

(ladebug) stop in  S
[#1: stop in ~S::S(void) ] 
(ladebug) status
#1 PC==0x1200005f8 in S::~S(void) "c++ex.C":6 { break } 
(ladebug) 

5.11 Class Templates and Function Templates

The debugger provides support for debugging class templates and function templates in much the same way as other classes and functions in C++, with the limitations described in Section 5.14.

You can use the whatis command on an instantiation of the function template as shown in Example 5-18.

Example 5-18 Example of a Function Template

(ladebug) list 1
      1 // remember to compile with -define_templates 
      2 template<class T> int compare(T t1, T t2) 
      3 { 
      4         if (t1 < t2) return 0; 
      5         else         return 1; 
      6 } 
      7 
      8 main() 
      9 { 
>    10         int i = compare(1,2); 
     11 } 
(ladebug) whatis compare
int compare (int, int) 
(ladebug) 

You can set a breakpoint in a template function as shown in Example 5-19.

Example 5-19 Setting a Breakpoint in the Template Function

(ladebug) stop in compare
[#2: stop in compare(int, int) ] 
(ladebug) run
[2] stopped at [compare(int, int):4 0x120000560]   
      4         if (t1 < t2) return 0; 
(ladebug) stop in stack<int,100>.pop
[#1: stop in stack<int,100>::pop(void) ] 
(ladebug) run
stopped at [stack<int,100>::pop(void):17 0x120001e0c]  
     17         return s[--top]; 
(ladebug) func
stack<int,100>::pop(void) in c++classtemp.C line No. 17: 
     17         return s[--top]; 
(ladebug) print top
2 
(ladebug) 

Example 5-20 displays the class definition of a particular instantiation of a parameterized stack.

Example 5-20 Displaying an Instantiated Class Template

(ladebug) whatis stack<int,100>
class stack<int,100>  { 
  array [subrange 0 ... 99 of int] of int s; 
  int top; 
  stack<int,100> (void); 
  void push (int); 
  int pop (void); 
} stack<int,100> 
(ladebug) 

You can explicitly set your current class scope to a particular instantiation of a class template if you are not in the proper class scope. See Example 5-21.

Example 5-21 Setting Current Class Scope to an Instantiated Class

(ladebug) stop in push
Symbol push not visible in current scope. 
push has no valid breakpoint address 
Warning: Breakpoint not set 
(ladebug) class
Current context is not a class 
(ladebug) class stack<int,100>
class stack<int,100>  { 
  array [subrange 0 ... 99 of int] of int s; 
  int top; 
  stack<int,100> (void); 
  ~stack<int,100> (void); 
  void push (int); 
  int pop (void); 
} 
(ladebug) stop in push
[#4: stop in stack<int,100>::push(int) ] 
(ladebug) run
[4] stopped at [stack<int,100>::push(int):10 0x120001cd0] 
     10               s[top++] = item; 
(ladebug) 


Previous Next Contents Index