The Digital Ladebug debugger debugs programs compiled with the DEC C++ compiler on the Digital UNIX operating system. The following features are supported:
this
pointer to
refer to class members
Some of these features are discussed further in this chapter. This chapter also explains the limitations on Ladebug support for the C++ language.
To prepare to use the Ladebug debugger on a C++ program, invoke
the compiler with the appropriate debugging flag: -g,
-g2,
or -g3.
For example:
% cxx -g sample.cxx -o sample
The -g
flag on the compiler command instructs the
compiler to write the program's debugger symbol table into the
executable image. This flag also turns off the default optimization,
which could cause a confusing debugging session.
Refer to the cxx(1)
reference page or other compiler
documentation for information about the various -gn
flags and their relationship to optimization.
Traceback information and symbol table information are both necessary for debugging. They:
Traceback and symbol table information result in a larger object
file. When you have finished debugging your program, you can remove
traceback information with the the strip
command (see
strip(1)
). To remove symbol table information, you
can compile and link again with -g0
or -g1
to create a new executable program.
Typical uses of the debugging flags at the various stages of program development are as follows:
-g
(or -g2
) flag. You can specify
-O0
(which is the default with the -g
or -g2
flag) to enable debugging and to create
unoptimized code. This flag also might be chosen later to debug
reported problems from later stages.
-g0
or -g1
to reduce the size of the
object file+ (and therefore the memory needed for program
execution), usually with optimized code.
+ g1 results in a larger object file than -g0 but smaller than the other gn flags.
To call overloaded functions from the debugger, you must set
$overloadmenu
to 1 (the default), as follows:
(ladebug) set $overloadmenu = 1
Then, use the following call
command syntax:
call function ([parameter[, . . . ]])
For example:
(ladebug) call foo(15)
The debugger will call the function that you select from the menu of overloaded names.
The debugger maintains the concept of a current context in which to perform lookup of program variable names. The current context includes a file scope and either a function scope or a class scope. The debugger automatically updates the current context when program execution suspends.
The class
command lets you set the scope to a class
in the program you are debugging. The syntax for the class
command is as follows:
class class_name
Explicitly setting the debugger's current context to a class allows for visibility into a class to:
After the class scope is set, you can set breakpoints in the class's member functions and examine data without explicitly mentioning the class name. If you do not want to affect the current context, you can use the scope resolution operator (::) to access a class whose members are not currently visible.
To display the current class scope (if one exists), enter the
class
command with no argument.
Example 10-1 shows the use of the class
command to set the class scope to S
in order
to make member function foo
visible so a breakpoint
can be set in foo.
(ladebug) stop in main; run [#1: stop in main ] [1] stopped at [int main(void):26 0x120000744] 26 int result = s.bar(); (ladebug) stop in foo Symbol foo not visible in current scope. foo has no valid breakpoint address Warning: Breakpoint not set (ladebug) class S class S { int i; int j; S (void); ~S (void); int foo (void); virtual int bar (void); } (ladebug) stop in foo [#2: stop in foo (void) ] (ladebug)
The whatis
and print
commands display
information on a class. Use the whatis
command to
display static information about the classes. Use the print
command to view dynamic information about class objects.
The whatis
command displays the class type
declaration, including:
For classes that are derived from other classes, the data members and member functions inherited from the base class are not displayed. Any member functions that are redefined from the base class are displayed.
The whatis
command used on a class name displays all
class information, including constructors. To use this command on a
constructor only, use the following syntax:
whatis class_name::class_name
Constructors and destructors of nested classes must be accessed
with the class
command. The following syntax is for a
constructor:
class class_name::(type signature)
The following syntax is for a destructor:
class class_name~::(type signature)
The print
command lets you display the value of
data members and static members. Information regarding the public,
private, or protected status of class members is not provided, since
the debugger relaxes the related status rules to be more helpful to
users.
The type signatures of member functions, constructors, and destructors are displayed in a form that is appropriate for later use in resolving references to overloaded functions.
Example 10-2 shows the whatis
and print
commands in conjunction with a class.
(ladebug) list 1, 9 1 class S { 2 public: 3 int i; 4 int j; 5 S() { i = 1; j = 2; } 6 ~S() { } 7 int foo (); 8 virtual int bar(); 9 }; (ladebug) whatis S class S { int i; int j; S (void); ~S (void); int foo (void); virtual int bar (void); } S (ladebug) whatis S :: bar int bar (void) (ladebug) stop in S :: foo [#2: stop in S :: foo ] (ladebug) run [2] stopped at [int S::foo(void):13 0x120000648] 13 return i; (ladebug) print S :: i 1 (ladebug)
The print
and whatis
commands display
information on instances of classes (objects). Use the whatis
command to display the class type of an object. Use the
print
command to display the current value of an
object. You can print an object's contents all at one time by using
the following print
command syntax:
print object
You can also display individual object members using the member
access operators, period (.) and right arrow (->), in a print
command.
You can use the scope resolution operator (::) to reference global variables, to reference hidden members in base classes, to explicitly reference a member that is inherited, or otherwise to name a member hidden by the current context.
When you are in the context of a nested class, you must use the scope resolution operator to access members of the enclosing class.
Example 10-3 shows how to use the
print
and whatis
commands to display
object information.
(ladebug) whatis s class S { int i; int j; S (void); ~S (void); int foo (void); virtual int bar (void); } s (ladebug) stop in S::foo; run [#1: stop in s.foo ] [1] stopped at [int S::foo(void):13 0x120000638] 35 return i; (ladebug) print *this class { i = 1; j = 2; } (ladebug) print i, j 1 2 (ladebug) print this->i, this->j 1 2 (ladebug)
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.
Base class member information is nested within the inherited class
information. Ladebug displays members that are inherited from a base
class, using the following notation:
baseclass:{var1:value1,var2:value2, . . . varN:valueN}
Pointers to members of a class are not supported.
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 10-4 shows a case where the expanded syntax is necessary.
(ladebug) print dinst.ambig Ambiguous reference Selecting 'ambig' failed! Error: no value for dinst.ambig (ladebug) print dinst.B::ambig 2 (ladebug)
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 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.
The stack trace in Figure 10-1 displays a
member function foo
of an object declared with class
type S.
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):
If you had changed the default value for the $overloadmenu
variable, to enable menu selection of overloaded
names, set the $overloadmenu
to 1 as shown in
Example 10-5. Using this method,
whenever you specify a function name that is overloaded, a menu
will appear with all the possible functions; you must select
from this menu. In Example 10-5, a
breakpoint is set in foo,
which is overloaded.
(ladebug) set $overloadmenu = 1 (ladebug) stop in foo Enter the number of the overloaded function you want ---------------------------------------------------- 1 int foo (void) 2 void foo (const char *) 3 void foo (char *) 4 void foo (double) 5 int foo (const double *) 6 None of the above ---------------------------------------------------- 5 [#1: stop in int S::foo(const double*) ] (ladebug)
If you prefer this method, set the $overloadmenu
variable to 0. To see the possible type signatures for the
overloaded function, first display all the declarations of an
overloaded function by using one of the following whatis
commands:
whatis function whatis class_name::function
You cannot select a version of an overloaded function that has
a type signature containing ellipsis points (...). Pointers
to functions with type signatures that contain the list
parameter or ellipsis arguments are not supported.
Use one of the displayed function type signatures to
refer to the desired version of the overloaded function.
If a function has no parameter, include the void
parameter as the function's type signature. In Example 10-6, the function context is set
to foo()
, which is overloaded.
(ladebug) func foo Error: foo is overloaded (ladebug) func foo(double) S::foo(double) in c++over.C line No. 156: 156 printf ("void S::foo (double d = %f)\en", d); (ladebug)
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 10.12.1 for information on setting breakpoints in exception handlers.
To set a breakpoint that stops in a member function, use one of the
following stop in
commands:
stop in function stop in class_name::function
These 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 10-7, a breakpoint is set for the
bar
member function of class S.
(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 following stop
in
commands:
stop in object.function stop in objectpointer->function
These forms of setting the breakpoint cause the debugger to stop at
the member function in all objects declared with the same class type
as the specified object. In Example 10-8,
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.
(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. Use one of the following
stop in
commands:
stop in object.function if & object == this stop in objectpointer->function if & objectpointer == this
These forms of the stop in
command instruct the
debugger to stop in the function only for the object specified
by the this
pointer. In Example 10-9, which is running the same program as Example 10-8, 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.
(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)
To set a breakpoint in an overloaded function, you must provide
the full type signature of the function. Use one of the following
stop in
commands:
stop in function (type_signature) stop in class_name::function (type_signature)
If the desired version of the function has no parameters, you
must enter void
for the type signature. In Example 10-10, the breakpoint is set for
specific versions of the overloaded function foo.
(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 following stop in all
commands:
stop in all function stop in all class_name::function
In Example 10-11, the breakpoint is set
for all versions of the overloaded function foo.
(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 10-12, the breakpoint is set for the 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)
To set a breakpoint in a constructor, use one of the following
stop in
commands:
stop in class_name::class_name [(type_signature)] stop in class_name [(type_signature)]
The type signature is only necessary to resolve an ambiguous reference to a constructor that is overloaded. In Example 10-13, a breakpoint is set in a constructor.
(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::NS(void) ] (ladebug) status #1 PC==0x1200005b8 in S::S(void) "c++ex.C":5 { break } (ladebug)
You can similarly set a breakpoint in a destructor using the
following stop in
command syntax:
stop in ~class_name
In Example 10-14, the breakpoint is set for the destructor.
(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)
As with any function's type signature specification, constructors
and destructors that have no parameters must be referenced with a
type signature of void.
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 10.14.
You can use the whatis
command on an instantiation
of the function template as shown in Example 10-15.
(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 10-16.
(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 S.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 10-17 displays the class definition of a particular instantiation of a parameterized stack.
(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 10-18.
(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 S 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)
As an alternative, you can use the following syntax:
(ladebug) class stack<int,100>
You can debug C++ exception handlers in programs by setting breakpoints in the exception handler or in the predefined C++ functions that are used when exceptions occur. You can also examine and modify variables that are used in exception handlers.
As shown in Example 10-19, you can set a breakpoint for an exception handler at the line number where the code for the exception handler begins. You can then step through the exception handler, examine or modify variables, or continue executing the program. You can also set breakpoints in C++ functions used to handle exceptions as follows:
terminate | Gains control when any unhandled exception occurs and terminates the progrm |
unexpected | Gains control when a function containing an exception specification tries to throw an exception that is not in the exception specification |
(ladebug) list 24 24 try 25 { 26 foo(); 27 } 28 catch(char * str) { printf("Caught %s.\n",str); } 29 catch(...) { printf("Caught something.\n"); } 30 31 return 0; 32 } (ladebug) stop at 24 [#1: stop at "except.C":26 ] (ladebug) stop in unexpected [#2: stop in unexpected ] (ladebug) run [1] stopped at [int main(void):26 0x400370] 26 foo(); (ladebug) cont [2] stopped at [unexpected:631 0x4010a8] (Cannot find source file cxx_exc.c) (ladebug) cont In my_unexpected(). Caught HELP. Thread has finished executing (ladebug)
After you set a breakpoint to stop the execution in the exception handler, you can access the variables used in the exception handler the same way you would examine and modify other program variables. See Section 8.3.
By default, the debugger gives no information on virtual base class pointers for the following:
By setting the $verbose
debugger variable to 1, you
can request that this information be printed in subsequent debugger
responses.
When the $verbose
debugger variable is set to 1 and
you display the contents of a class using the whatis
command, several of the class members listed are not in the source
code of the original class definition. The following line shows
sample output from the whatis
command:
array [subrange 0 ... 0 of int] of vtable * _\|_vptr;
The vtable
variable contains the addresses of all
virtual functions associated with the class. Several other class
members are generated by the compiler for internal use.
The compiler generates additional parameters for nonstatic member
functions. When the $verbose
debugger variable is
set to 1, these extra parameters are displayed as part of each
member function's type signature. If you specify a version of an
overloaded function by entering its type signature and the variable
is set to 1, you must include these parameters. Do not include these
parameters if the variable is set to 0.
When the $verbose
variable is set to 1, the output of
the dump
command includes not only standard program
variables but also compiler-generated temporary variables.
Example 10-20 prints class information
using the whatis
command when the $verbose
variable is set to 1.
(ladebug) print $verbose 0 (ladebug) whatis S class S { int i; int j; S (void); ~S (void); int foo (void); virtual int bar (void); } S (ladebug) set $verbose = 1 (ladebug) print $verbose 1 (ladebug) whatis S class S { int i; int j; array [subrange 0 ... 0 of int] of vtbl * _\|_vptr; S (S* const); S (S* const, const S&); ~S (S* const, int); int foo (S* const); S& operator = (S* const, const S&); virtual int bar (S* const); } S (ladebug)
When displaying information on virtual base classes, the debugger
prints pointers to the table describing the base class for each
virtual base class object member. This pointer is known as the
bptr
base pointer. This pointer is printed after the
class member information.
Ladebug interprets C++ names and expressions using the language rules described in The Annotated C++ Reference Manual (Ellis and Stroustrup, 1990, Addison- Wesley). C++ is a distinct language, rather than a superset of C. Where the semantics of C and C++ differ, Ladebug provides the interpretation appropriate for the language of the program being debugged.
To make Ladebug more useful, it relaxes some standard C++ name visibility rules. For example, you can reference both public and private class members.
The following limitations apply when you debug a C++ program:
-g
flag, do not set a breakpoint on an inline member function; it
may confuse the debugger.
new
and delete.
As alternatives, use
the malloc()
and free()
routines
from C.
Limitations for debugging templates include:
stack<double,f*10>.
This form is not yet supported in the Digital Ladebug debugger; you
must enter the value of the expression (for example, if f
is 10 in the stack example, you must enter 100).