United States |
Previous | Contents | Index |
A debugger helps you find run-time errors by letting you observe and interactively manipulate program execution step by step, until you discover where the program functions incorrectly. The OpenVMS Debugger is symbolic, meaning that you can refer to symbolic names for the memory addresses allocated to variables, routines, labels, and so on. You need not use virtual addresses.
The language of the source program you are currently debugging
determines the format you use to enter and display data. The current
language also determines the format used for features, such as comment
characters, operators, and operator precedence, which have
language-specific settings. However, if you have modules written in
another language, you can switch from one language to another during
your debugging session.
8.1 Debugging Compaq C++ Programs
The OpenVMS Debugger supports the language constructs of Compaq C++
and other debugger-supported programming languages. This section
describes features specific to debugging C++ programs. For more
information on the OpenVMS Debugger, see the OpenVMS Debugger Manual.
8.1.1 Compiling and Linking in Preparation for Debugging
To use the debugger, compile and link your program with the /debug qualifier on both commands. On the compiler command, the /debug qualifier writes into the object module the debug symbol records declared in the program source file. These records make the names of variables and other declared symbols accessible to debugger commands. If your program has several compilation units, make sure you use the /debug qualifier to compile each unit you want to debug.
Additionally, use the
/nooptimize
qualifier with the compiler command. Optimized code can
reduce program size and increase execution speed, but can also create
inconsistencies in memory content that adversely affects debugging. Use
the default
/optimize
qualifier only with programs that have been completely debugged.
8.1.2 Debugger Support
Additionally, compilation with normal (full) optimization will have the following noticeable effects OpenVMS Alpha systems:
On the linker command, the /debug qualifier incorporates into the executable image all the symbol information contained in the object modules. Using the /debug qualifier on the linker command also starts the debugger at run time.
Compaq C++ provides a set of debugger options that you can specify
to the
/debug
qualifier on the compiler command line. These options determine the
kind of information that the Compaq C++ compiler places in the
object module for use by the OpenVMS Debugger. These debugger options
include using traceback records and using the debugger symbol table.
For more information, see Section 1.2.
8.1.3 Starting and Ending a Debugging Session
When you enter the DCL run command and specify your executable image file, the OpenVMS Debugger takes control. The debugger displays a message indicating its version, the programming language the source code is written in, and the name of the image file. When the DBG> prompt appears, you can enter debugger commands.
To execute the program, enter the debugger go command. Execution proceeds until the debugger pauses or stops the program (for example, to prompt you for user input, to signal an error, or to inform you that your program completed successfully).
To interrupt the debugging session in progress, press Ctrl/C. The DBG> prompt displays and you can again enter debugger commands.
To end a debugging session, enter the debugger
exit
command or press Ctrl/Z.
8.1.4 Features Basic to Debugging Compaq C++ Programs
This section describes features essential for debugging Compaq C++
programs.
8.1.4.1 Determining Language Mode
The OpenVMS Debugger is in C++ language mode when invoked against a main program or routine written in C++. If you are debugging an application with modules written in some language other than C++, you may switch back to C++ language mode by using the command set language c_plus_plus .
You can use the show language command to determine the language mode set. For example:
DBG> show language language: C_PLUS_PLUS DBG> |
Use of the %name lexical function is required with debugger commands to reference certain entities in Compaq C++, such as functions and data members. When used, this function is always placed between the command and the reference. Examples of correct usage are shown in the following sections for cases where its use is required.
Starting with OpenVMS Version 6.1, the OpenVMS Debugger no longer requires the use of the %name lexical to reference entities in Compaq C++. |
This section describes the built-in operators that you can use in debugger commands. The operators in C++ language expressions are as follows:
Symbol | Function | Kind |
---|---|---|
* | Indirection | Prefix |
& | Address of | Prefix |
sizeof | size of | Prefix |
-- | Unary minus (negation) | Prefix |
+ | Addition | Infix |
-- | Subtraction | Infix |
* | Multiplication | Infix |
/ | Division | Infix |
% | Remainder | Infix |
<< | Left shift | Infix |
>> | Right shift | Infix |
== | Equal to | Infix |
!= | Not equal to | Infix |
> | Greater than | Infix |
>= | Greater than or equal to | Infix |
< | Less than | Infix |
<= | Less than or equal to | Infix |
~ (tilde) | Bit-wise NOT | Prefix |
& | Bit-wise AND | Infix |
| | Bit-wise OR | Infix |
^ | Bit-wise exclusive OR | Infix |
! | Logical NOT | Prefix |
&& | Logical AND | Infix |
|| | Logical OR | Infix |
Because the exclamation point (!) is an operator, it cannot be used in C++ programs as a comment delimiter. However, to permit debugger log files to be used as debugger input, the debugger still recognizes the exclamation point as a comment delimiter if it is the first nonspace character on a line. In C++ language mode, the debugger accepts a forward slash immediately followed by an asterisk (/*) as the comment delimiter. The comment continues to the end of the current line. A matching asterisk immediately followed by a slash (*/) is neither needed nor recognized.
The debugger accepts the asterisk (*) prefix as an indirection operator in both C++ language expressions and debugger address expressions. In address expressions, the asterisk prefix is synonymous to the period (.) prefix or the at sign (@) prefix when the language is set to C++.
To prevent unintended modifications to the program being debugged, the
debugger does not support any of the assignment operators in C++ (or
any other language). Thus, such operators as =, +=, --=, ++, and -- are
not recognized. To alter the contents of a memory location, you must do
so with an explicit
deposit
command.
8.1.4.4 Constructs in Language and Address Expressions
The supported constructs in language and address expressions for C++ are as follows:
Symbol | Construct |
---|---|
[ ] | Subscripting |
. (period) | Structure component selection |
-> | Pointer dereferencing |
Predefined data types supported in the debugger are as follows:
C++ Data Type | OpenVMS Data Type Name |
---|---|
int | Longword Integer (L) |
unsigned int | Longword Unsigned (LU) |
short int | Word Integer (W) |
unsigned short int | Word Unsigned (WU) |
char | Byte Integer (B) |
unsigned char | Byte Unsigned (BU) |
float | F_Floating (F) |
double | D_Floating (D) |
enum | None |
struct | None |
union | None |
class | None |
Pointer type | None |
Array type | None |
Uppercase letters in parentheses represent standard data type mnemonics in the OpenVMS common language environment. For more information, see OpenVMS Programming Interfaces: Calling a System Routine.
Supported data types specific to OpenVMS Alpha systems are as follows:
C++ Data Type | OpenVMS Alpha Data Type Name |
---|---|
__int16 | Word Integer (W) |
unsigned __int16 | Word Unsigned (WU) |
__int32 | Longword Integer (L) |
unsigned __int32 | Longword Unsigned (LU) |
__int64 | Quadword Integer (Q) |
unsigned __int64 | Quadword Unsigned (QU) |
__g_float | G_Floating (G) |
__f_float | F_Floating (F) |
__s_float | IEEE S_Floating (FS) |
__t_float | IEEE T_Floating (FT) |
Discussions in Section 8.2 use the term qualified class names to describe how to compose the names of class members when using the debugger. If a class is not defined within another class, the qualified class name is merely the name of the class itself. However, if a class is nested within another class, the name of the immediately containing class must precede it separated with a pair of colons (::). If the containing class is itself nested, its name must be prefixed, and so on.
The following are examples of properly qualified class names:
DBG> set break %name 'C::f' ! f is a member of class C DBG> set break %name 'FOO::BAR::BAZ::g' ! g is a member of BAZ, ! which is nested in BAR, ! which is nested in FOO |
This section describes how to use the OpenVMS Debugger with C++ data.
8.2.1 Nonstatic Data Members
This section describes how to refer to data members that are not
declared static.
8.2.1.1 Noninherited Data Members
To refer to a nonstatic data member that is defined directly in a C++ class (or a struct or union ), use its name just as with a C language struct or union member. The following example shows the correct use of a nonstatic data member reference:
DBG> examine x.m, p->m |
Currently, debugger support distinguishes nonstatic data members inherited from various base classes by prefixing their names with a sequence of significant base class names on the inheritance path to the member, and then the class that the member is declared in. A base class on a path from an object to a member is significant if the base class in question is derived from using multiple inheritance. Thus, a base class is significant if it is mentioned in a base list containing more than one base specifier.
This notation generates the minimum number of base class prefixes necessary to describe the inheritance path to a base class, because it involves naming only those base classes where one must choose where to proceed next when traversing the path. When no multiple inheritance is involved, the reference has the following syntax:
%name'CLASS::member' |
To refer to nonstatic data members inherited from base classes of an object, place single quotes around the sequence of significant qualified base class names and the member name (separated by double colons) with %name . Specify the sequence of significant base classes in the order from the object's most derived significant class, to the significant base class closest to the object.
For example, consider the inheritance graph for the following declarations:
struct A { int a_member; }; struct B : A { int b_member; }; struct C { int c_member; }; struct D : B, C { int d_member; }; struct E : D { int e_member; }; struct F { int f_member; }; struct G : F { int g_member; }; struct H : E, G { int h_member; }; struct I : H { int i_member; }; struct J : I { int j_member; }; static J j_object; |
Because classes B, C, E, and G are mentioned in base lists, which involve multiple inheritance, they are the significant classes that appear as prefixes. The following examples are references to all the members through debugger deposit commands. Note that the class of the inherited member itself appears before the member name, regardless of whether or not the member belongs to a significant class.
DBG> deposit j_object.%name'E::B::A::a_member' = 1 DBG> deposit j_object.%name'E::B::b_member' = 2 DBG> deposit j_object.%name'E::C::c_member' = 3 DBG> deposit j_object.%name'E::D::d_member' = 4 DBG> deposit j_object.%name'E::e_member' = 5 DBG> deposit j_object.%name'G::F::f_member' = 6 DBG> deposit j_object.%name'G::g_member' = 7 DBG> deposit j_object.%name'H::h_member' = 8 DBG> deposit j_object.%name'I::i_member' = 9 DBG> deposit j_object.%name'j_member' = 10 DBG> examine j_object 6212\j_object E::B::A::a_member: 1 E::B::b_member: 2 E::C::c_member: 3 E::D::d_member: 4 E::e_member: 5 G::F::f_member: 6 G::g_member: 7 H::h_member: 8 I::i_member: 9 j_member: 10 DBG> |
In the OpenVMS Debugger, symbolic access to data members of virtual
base classes is currently not supported. Objects of classes with
virtual base classes have a pointer member named
__bptr
.
8.2.2 Static Data Members
To refer to a static data member, place single quotes around its qualified class name, two colons (::), and then the member name, with %name .
The following examples show the correct use of static data member references:
DBG> examine %name 'C::s' DBG> examine %name 'FOO::BAR::BAZ::sdm' |
To access the values of objects declared with a reference, use the name of the object.
The OpenVMS Debugger treats data members declared with a reference type as though they were pointer variables; thus, you must use the * or -> dereference operators on their names.
For example, consider the following code:
class C { public: int &ref_mem; C(int &arg) : ref_mem(arg) {} }; main() { auto int obj = 5; auto int &ref_obj = obj; auto C c(obj); obj = 23; } ... |
The following sequence shows the correct way to use the debugger to examine the members:
stepped on return from routine REF\main to REF\main\%LINE 13+16 13: } DBG> examine obj, ref_obj REF\main\obj: 23 REF\main\ref_obj: 23 DBG> examine c REF\main\c ref_mem: 2144211292 DBG> symbolize c.ref_mem address 7FCE1154: REF\main\c DBG> examine *c.ref_mem *REF\main\c.ref_mem: 23 |
Values that are pointers to members are represented as a struct with the members __thunk and __offset . The __thunk member contains the address of the member pointed to. The __offset member contains an offset adjustment when the pointer to member refers to a multiply inherited base class. For example:
struct A { int mem0; }; struct B { int mem1; int mem2; }; struct C : public A, public B { int mem3; int mem4; }; /* pointer to member initalized with pointer to member address of * the same class. */ int C::*pmc = &C::mem2; /* pointer to member initialized with pointer to member address of one of the * base classses. An implicit conversion occurs. */ int C::*pmbc = &B::mem2; extern "C" printf (const char *,...); main() { C *cinst = new C; cinst->*pmc = 7; printf("cinst pointer to member value is %d\n",cinst->mem2); } |
If you compile this program with the /nooptimize/debug qualifiers, from the last line in the program, you can use the pointer to member to display the following information:
DBG>set break %line 31 DBG>go DBG>go cinst pointer to member value is 7 DBG> Set Mode Noscreen; Set Step Source DBG> ex cinst PTRMEMBER\main\cinst: 004136F8 DBG> ex *cinst *PTRMEMBER\main\cinst A::mem0: 00000000 B::mem1: 00000000 B::mem2: 00000007 mem3: 00000000 mem4: 00000000 DBG> ex pmc PTRMEMBER\pmc __thunk: 00010060 __offset: 00000000 DBG> call 00010060(004136F8) value returned is 00413700 DBG> ex 00413700 00413700: 00000007 DBG> ex pmbc PTRMEMBER\pmbc __thunk: 00010098 __offset: 00000004 DBG> call 00010098(004136F8+4) value returned is 00413700 DBG> ex 00413700 00413700: 00000007 DBG> exit |
To examine and display the value of an object or member by type, use the command examine/type . Similarly, you can modify the value of an expression to be deposited to a type you specify by using the command deposit/type . With the /type qualifier, the syntax for these commands is as follows:
deposit/type=(name) examine/type=(name) |
The type denoted by name must be the name of a variable or
data type declared in the program. The
/type
qualifier is particularly useful for referencing C++ objects that have
been declared with more than one type.
8.3 Using the OpenVMS Debugger with C++ Functions
This section describes how to reference the various kinds of functions
and function arguments.
8.3.1 Referring to Overloaded Functions
To find the symbolic names of functions in your code, use the show symbol command. If the function is overloaded, use the wildcard character (*) in the name specification to display the overloaded symbol names.
For example, consider the following code:
class base { public: base(); base( int ); ~base(); int base_f1(); void base_f2(); void base_f2( int ); void base_f2( char ); }; |
The following sequence shows how to display overloaded symbols and determine the appropriate function reference:
DBG> set break %name 'base::base_f2' %DEBUG-E-NOTUNQOVR, symbol 'base::base_f2' is overloaded use SHOW SYMBOL to find the unique symbol names DBG> show symbol *base_f2 overloaded symbol CXX_T10_179\base::base_f2 overloaded instance CXX_T10_179\base::base_f2__1 overloaded instance CXX_T10_179\base::base_f2__2 overloaded instance CXX_T10_179\base::base_f2__3 DBG> set break %name 'base::base_f2__2' DBG> step stepped to CXX_T10_179\main\%LINE 20 20: x.base_f2(); DBG> step stepped to CXX_T10_179\main\%LINE 21 21: x.base_f2(5); DBG> step break at routine CXX_T10_179\base::base_f2__2 12: void base_f2( int ) {} DBG> step stepped to CXX_T10_179\main\%LINE 22 22: x.base_f2('W'); stepped to CXX_T10_179\main\%LINE 22 DBG> go %DEBUG-I-EXITSTATUS, is '%SYSTEM-S-NORMAL, normal successful completion' DBG> ^Z |
To refer to a member function, place single quotes around it, and include %name , its qualified class name, two colons (::), and the name of the member function. If the member function is overloaded, append the suffix __ integer-number.
The following examples show the correct use of member function references:
DBG> set break %name 'MYSTRING::length' DBG> set break %name 'MYCOMPLEX::format__1', %name 'MYCOMPLEX::format__2' |
To refer to a constructor, state the name. If a constructor is overloaded, append the suffix __ integer-number.
The following examples show the correct use of constructor references:
DBG> set break FOO DBG> set break MYSTRING__1 |
To refer to a destructor, place single quotes around its name, and include the tilde ( ~ ), with %name .
The following example shows the correct use of a destructor reference:
DBG> set break %name '~FOO' |
To refer to conversion operators from a class SRC to a type dest , quote SRC , two colons (::), and then dest with %name .
The set of atomic types are drawn from the following set of names:
void char signed_char unsigned_char signed_short unsigned_short int signed_int unsigned_int signed_long unsigned_long float double long_double |
Pointer types are named (type)* . Reference types are named (type)& . The types struct , union , class , and enum are named by their tags, and the qualifiers const and volatile precede their types with a space in between. For example:
DBG> set break %name 'C::int', %name 'C::(const S)&' |
The following operators may be overloaded by user-defined functions:
+ - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && | ++ -- ->* , -> [] () delete new |
To refer to such user-defined functions, place single quotes around the operator characters and include %name . As with regular functions, prefix the string quoted by %name with a qualified class name and two colons (::) if the user-defined operator is a member function. Similarly, if the function is overloaded, append the suffix __ integer_number to the operator characters. In particular, this suffix is necessary if both unary and binary instances of an operator such as + are defined, or if prefix instances of ++ or -- are defined.
The following examples show the correct use of user-defined function references:
DBG> set break %name 'MYSTRING::+' DBG> set break %name 'COUNTER::++__1', %name 'COUNTER::++__2' |
See §7.2 of The C++ Programming Language, 2nd Edition for details.
8.3.7 Referring to Function Arguments
In OpenVMS Debugger referencing, you use this , *this , and this->m as follows:
DBG> examine this |
DBG> examine *this |
DBG> examine this->m |
When calling C++ member functions from the debugger, you cannot make the call using the same syntax that you would use in a C++ source file. You must call the class qualified member function name with the object as the first argument. For example:
extern "C" void printf(const char *,...); class C12 { int i; int j; public: C12() : i(1), j(2) {} method(); }; C12::method() { i = i + j; printf("C12::method called: i=%d, j=%d\n",i,j); } main() { C12 cinst; cinst.method(); printf("End of example.\n"); } |
When you compile this example with /debug/noopt , you can call the member function with the following command:
DBG> call %name"C12::method"(cinst) |
When using the %name lexical function for the qualified member function name, do not leave any space between %name and the method name. For example:
DBG> go break at routine METHOD\main 19: C12 cinst; DBG> Step stepped to METHOD\main\%LINE 20 20: cinst.method(); DBG> Step C12::method called: i=3, j=2 stepped to METHOD\main\%LINE 21 21: printf("End of example.\n"); DBG> show sym *method* routine METHOD\C12::method DBG> call %name"C12::method"(cinst) C12::method called: i=5, j=2 value returned is 0000001D DBG> call %name"C12::method"(cinst) C12::method called: i=7, j=2 value returned is 0000001D DBG> go End of example. %DEBUG-I-EXITSTATUS, is '%SYSTEM-S-NORMAL, normal successful completion' DBG> exit $ log |
Previous | Next | Contents | Index |
|