![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Debugger Issues The following section documents debugger features specific to debugging Apex C or C++ programs with the Apex debugger. For documentation on the Apex debugger commands and expressions, see Using the Apex Debugger.
The following topics are covered in this chapter:
Debugging Information
The compiler generates debugging information by default. To have the compiler not generate debugging information, which will speed up the compilation and use less disk space, compile with the option -nosienna. With this option, the debugger will still be able to step through the code, but will not have any symbolic information (so, for example, it will be unable to print the values of any variables).
The debugging information is placed in two subdirectories. Unless -nosienna is used, the symbolic information will be put in .Rational/Compilation/cna, which is located at the base of the view in which the source code is compiled. The mapping between the machine instruction addresses and the source code is put in .Rational/Compilation/lin. (This information is always written, even if -nosienna is used.)
Locating Source Files
The debugger will be able to locate all source files that were compiled under Apex. When debugging programs that contain code that was not compiled with Apex, it may be necessary to tell the debugger where to find the source code. This should be done with
set source $source directories
where directories is the list of directories containing the non-Apex source code.
Reading Debugging Files
The debugging information for each object file is not read in by the debugger until it is actually needed. This reduces the startup time and memory usage of the debugger when debugging large programs. But some debugger commands may pause momentarily as a lot of this information is read in from disk,
Syntax and Lexical ConventionsThe debugger supports debugging C and C++. The set language command is provided to allow the user to specify a language preference.
set language [ C | C++ ]
By default the debugger will set the language to match the language of the main program source file. The use of a set language command will override this default behavior. The chosen language conventions will be assumed in all further debugger expressions given via the command line interface; expressions selected directly from a source file from one of the visual interfaces will use the language conventions appropriate to the source file.
Scope and Name LookupWhenever a symbol name is used in a debugger command, it is looked up in the current debugger context using the normal C/C++ name lookup rules. For example, the name of a variable that is local to a function can only be used if the current debugger context is within that function.
In addition to the normal lookup rules, the debugger can also look up the names of non-inline functions (including class member functions) and classes that have a non-inline constructor, even if the names are not visible from the current context. The debugger will be able to find such symbols given only the simple name, even if they are defined within a namespace or class.
ExpressionsScope resolution operator
The debugger supports the C++ scope resolution operator, ::. For example, it understands all of the following
class_name::member namespace_name::member ::global_name
Qualified names
Multiple inheritance makes it is possible to inherit members from different base classes that have the same name. In this situation:
class_instance.member or class_pointer->member
is ambiguous because member may refer to either of the base classes members.
A qualified name may be used to help resolve this ambiguity.
class_instance.base_class::member
The debugger can resolve all legal C++ qualified names and will emit an error message when the class qualification still results in an ambiguity.
Names
The debugger does not understand and cannot look up the names of macros. But it should be able to understand all other C++ names.
Unsupported C++ expression forms
Operators
The following operators are not supported in C/C++ expressions:
++, --, (comma), new, delete, .*, ->*, sizeof
All other operators are allowed in debugger expressions.
However, the debugger will not find user-defined versions of operators unless the explicit function call notation is used. For example, if aa and bb are variables of type foo, and a user defined
operator + (const foo &, const foo &)
exists, then the debugger command
p aa + bb
will result in the debugger error message
=> aa does not have an integer or a floating point type
p operator+(aa, bb)
will correctly call the user-defined operator+.
ClassesBreakpoints
A breakpoint on a member function can be set in a couple of ways. If the member function is indicated by:
- 1 . an instance of a class:
b class_instance.member_function
b class_pointer->member_function
then a conditional breakpoint will be set that will stop the program only on calls made via the given class instance. In the case of
b class_pointer->member_function
the conditional breakpoint will be set for the object to which the variable class_pointer currently points. The debugger will not break every time member_function is called through the variable class_pointer.
- 2 . a qualified or unqualified member function name:
Constructors
Class constructors have the same name as their defining class. This creates an ambiguity when using the class name in debugger expressions. The resolution of the ambiguity by the debugger will depend on the context. When the class identifier is used in a navigation command or in a context where a class name is required the debugger will assume the class definition is desired. All other references to the class identifier will refer to the class constructor(s).
v class_identifier // navigate to the class definition b class_identifier // set breakpoint at constructor b class_identifier::member // class_identifier refers to class name p class_identifier // print addresses of constructor overloadingsNavigation to a constructor can be done by giving a qualified name of the constructor.
v class_identifier::class_identifier
Member Functions
this
When the current debugger context is within a non-static member function, the debugger understands the keyword this, which points to the class object for which the member function was called. It can be used to access members of the class, for example
this->member
Visibility from within member functions
Inside the body of a non static member function the class members are directly visible without explicit class instance qualification. The this parameter is implicitly used to qualify all such references. Calls to unqualified member functions from the debugger may be made in this situation.
Calling member functions
The implicit this parameter identifying the class instance must be passed in to all non-static member functions. Static member functions may be called from the debugger without a qualifying class instance just like any normal function.
p static_member_function()
But all non-static member function calls must specify a class instance.
p class_instance.member_function()
p class_pointer->member_function()
Virtual functions
When a virtual member function is referenced via an object (for example, object.func as opposed to class_name::func), the debugger uses the virtual call mechanism to resolve the name, so the function being referred to depends on the dynamic type of the object, not its static type. This virtual resolution is used in all contexts, including navigation, setting breakpoints, and evaluating expressions.
Exception HandlingThe debugger supports two commands, catch and propagate, for dealing with C++ exceptions:
catch [ type_spec ] [ within function_or_line_number ] propagate [ type_spec ] [ within function_or_line_number ]
Where type_spec :== type_name | type_name * and function_or_line_number :== function_name | line_number. type_name must be visible from the current source file. The propagate command used in conjunction with other catch commands identifies scenarios where the user does not want the debugger to stop the program in response to an exception being thrown. A typical usage of these commands might be to catch all exceptions but propagate exceptions thrown in certain functions or propagate all exceptions that match a particular type profile.
Examples
catch
The debugger will stop the program when any exception is thrown.
catchouter_class::inner_class
The debugger will stop the program when any expression is thrown that matches outer_class::inner_class.
catch withinclass_name::func
The debugger will stop the program when any exception is thrown from within class_name::func.
catch within 125
The debugger will stop the program when any exception is thrown from line number 125 of the current source file.
catch short * withinclass_name::func
The debugger will stop the program when a short * object is thrown from within class_name::func.
propagate
The debugger will not stop the program when any exception is thrown.
propagateouter_class::inner_class
The debugger will not stop the program when any expression is thrown that matches outer_class::inner_class.
propagate withinclass_name::func
The debugger will not stop the program when any exception is thrown from within class_name::func.
propagate within 125
The debugger will not stop the program when any exception is thrown from line number 125 of the current source file.
propagate short * withinclass_name::func
The debugger will not stop the program when a short * object is thrown from within class_name::func.
Rational Software Corporation http://www.rational.com support@rational.com techpubs@rational.com Copyright © 1993-2002, Rational Software Corporation. All rights reserved. |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |