Chapter 6. Examining Debugger Data

After you have learned how to set traps in CASEVision, the next step is to look at the facilities for examining the data. This chapter covers:

The Debugger also lets you examine data at the machine level. The tools for viewing disassembled code, machine registers, and data by specific memory location are described in Appendix A, "Debugger Reference."

Tracing Through Call Stack View

The Call Stack View window displays the functions in the call stack (referred to as frames) when the process has stopped. The window is shown in Figure 6-1 with the major menus displayed.

Figure 6-1. Call Stack View Window With Config and Display Menus and Preferences Dialog Box

Figure 6-1 Call Stack View Window With Config and Display Menus and Preferences Dialog Box

In addition to the functions, the Call Stack View window lets you see the argument names, values, and types as well as the locations of the functions and the PC. If symbolic information for the arguments has been stripped from the executable, the label <stripped> will appear in place of the arguments, as in the function _start in the above example. You also have the option of setting the maximum depth of the Call Stack View by selecting "Preferences..." from the Config menu.

To move through the call stack, you simply double-click a frame in the stack. The frame becomes highlighted to indicate the current context. The source display in Main View (or Source View) scrolls automatically to the location where the function was called, and any other active views (such as the Variable Browser or Structure Browser) will update. The source display has two special annotations:

  • The location of the current program state is indicated by a large green (depending on color scheme) arrow representing the PC.

  • The location of the call to the function selected in the Call Stack View window is indicated by a smaller blue (depending on color scheme) arrow representing the current context, and the source line becomes highlighted.

Figure 6-2 illustrates the correspondence between a frame and the source code when a frame is clicked in the Call Stack View window. In this example, the stack frame spin has been selected; Main View scrolls to the place where the trap occurred. If the second stack (main) had been selected, then the window would have scrolled to the place where the function main calls spin.

Figure 6-2. Tracing Through Call Stack View

Figure 6-2 Tracing Through Call Stack View

Evaluating Expressions

You can evaluate any valid expression (in C, C++, or Fortran) at a stopping point in the process and trace it through the process. Expressions are evaluated by default in the frame and language of the current context. Expressions may contain data names or constants; however, they may not contain names known only to the C pre-processor, as in a #define directive or a macro.

To evaluate expressions, you can use the Expression View, which lets you evaluate multiple expressions simultaneously, updating their values each time the process stops.


Note: Expressions can also be evaluated from the command line.


Expression View

The Expression View window is shown in Figure 6-3 with its major menus displayed. Note that Expression View has two popup menus. The Language menu is invoked by holding down the right mouse button while the cursor is in the Expression column. The Format menu is displayed by holding down the right mouse button in the Result column.

To specify the expression to be evaluated, first click in the Expression column, on the left side of the window, then enter the expression in the selected field. This expression can be typed directly or pasted in from the source code display. It must be a valid expression in the current or selected language: C, C++, or Fortran. To change languages, display the Language menu and make your selection. When you press <Enter>, the result of the expression is displayed in the right column.

Figure 6-3. Expression View With Major Menus Displayed

Figure 6-3 Expression View With Major Menus Displayed

If you want to change the type of result information displayed in the right column, hold down the right mouse button over the right column. This displays the Format menu. You can see the value asa string, or as decimal, unsigned, octal, hexadecimal, float, or characters. You can also display the type, the address (in decimal, octal, or hex), or the size of the result in bits.


Caution: The CASEVision Debugger uses the target program's symbol table to determine the types of variables. Some variables in libraries, such as errno and _environ, are not fully described in the symbol table. As a result, the Debugger may not know their types. When the Debugger evaluates such a variable, it assumes that the variable is a full-word integer. This gives the correct value for full-word integers or pointers, but the wrong value for non-full-word integers and for floating-point values.

To see the value correctly of a variable of unknown type, you can cast the address of the variable to a pointer to the correct type, using C type-cast syntax. For example, the global variable _environ should be of type char**. You can see its value by evaluating *(char***)&_environ.

After you display the current value of the expression, you may find it useful to leave the window open so that you can trace the expression as it changes value from trap to trap (or when you change the current context by double-clicking in the callstack). Like the other views involved with variables, Expression View has variable change indicators for value fields that let you see previous values, as shown in Figure 6-4.

Figure 6-4. Change Indicators in Expression View

Figure 6-4 Change Indicators in Expression View

Another useful technique is to save your expressions to a file for later reuse. Expressions are saved by choosing "Save Expressions..." from the Config menu and retrieved by selecting "Load Expressions..."

Assigning Values to Variables

To assign a value to a variable, click the left column and enter the variable name. The current value appears in the right column. If this Result field is editable (highlighted), you can click it and enter a new value or legal expression. Pressing <Enter> performs the assignment. You can perform an assignment to any expression that evaluates to a legal lvalue (in C). The C operator = is not valid in Expression View. The valid expression operations are shown in the following paragraphs.

Evaluating Expressions in C

The valid C expressions are shown in Table 6-1.

Table 6-1. Valid C Operations

Operation

Symbol

Arithmetic (unary)

+ - ++ --

(increment and decrement do not have side effects)

Arithmetic (binary)

+ - * / %

Logical

&& || !

Relational

< > <= >= == !=

Bit

& | ^ << >> ~

Dereference

*

Address

&

Array indexing

[ ]

Conditional

? :

Member extraction

. -> (these operations are interchangeable)

Sizeof

 

Type-cast

 

Function call

 

Assignment

= += -= /= %= >>= <<= &= ^= |=
(Note that a new assignment is made at each stepping point. Use assignments with caution to avoid inadvertently modifying variables. )


C Function Calls

Function calls can be evaluated in expressions, as long as enough actual parameters are supplied. Arguments are passed by value. Following the rules of C, each actual parameter is converted to a value of the same type as the formal parameter, before the call. If the types of the formal parameters are unknown, integral arguments are widened to full words, and floating-point arguments are converted to doubles.

Functions may return pointers, scalar values, unions, or structs. Note that if the function returns a pointer into its stack frame (rarely a good programming practice), the value pointed to will be meaningless, since the temporary stack frame is destroyed immediately after the call is completed.

Function calls may be nested. For example, if the user's program contains a successor function succ, the Debugger will evaluate the expression succ(succ(succ(3))) to 6.

Evaluating Expressions in C++

C++ expressions may contain any of the C operations. You can use the word this to explicitly reference data members of an object in a member function. When stopped in a member function, the scope for this is searched automatically for data members. Names may be used in either mangled or demangled form. Names qualified by class name are supported (for example, Symbol::a).

If you wish to look at a static member variable for a c++ class, you need not specify the variable with the class qualifier if you are within the context of the class. For example, you would specify myclass::myvariable for the static variable myvariable outside of class myclass and myvariable inside myclass.

Limitations

Constructors may be called from Expression View, just like any other member function. To call a constructor, you must pass in a first argument that points to the object to be created. C++ function calls have the same possibility of side effects as C functions.

Evaluating Expressions in Fortran

Fortran expressions may contain any of the arithmetic, relational, or logical operators. Relational and logical operator keywords may be spelled in upper case, lower case, or mixed case.

The usual forms of Fortran constants, including complex constants, may be used in expressions. String constants and string operations, however, are not supported. The operators in Table 6-2 are supported on data of integral, real, and complex types.

Table 6-2. Valid Fortran Operations

Operation

Symbol

Arithmetic (unary)

- +

Arithmetic (binary)

- + * / **

Logical

.NOT. .AND. .OR. .XOR. .EQV .NEQV.

Relational

.GT. .GE. .LT. .LE. .EQ. .NE.

Array indexing

( )

Intrinsic function calls (except string intrinsics)

 

Function subroutine calls

 

Assignment

= (Note that a new assignment is made at each stepping point. Use assignments with caution to avoid inadvertently modifying variables. )


Fortran Variables

Names of Fortran variables, functions, parameters, arrays, pointers, and arguments are all supported in expressions, as are names in common blocks and equivalence statements. Names may be spelled in upper case, lower case, or mixed case.

Fortran Function Calls

The Debugger evaluates function calls the same way that compiled code does. If an argument can be passed by reference, it is; otherwise, a temporary expression is allocated and passed by reference. Following the rules of Fortran, actual arguments are not converted to match the types of formal arguments. Side effects can be caused by Fortran function calls. A useful technique to protect the value of a parameter from being modified by a function subroutine is to pass an expression such as (parameter + 0) instead of just the parameter name. This causes a reference to a temporary expression to be passed to the function rather than a reference to the parameter itself; the value is the same.