Chapter 7. Viewing Program Data

After you set traps (breakpoints) in your program, use the Run button to execute your program. When a trap stops a process, you can view your program data using the tools described in this chapter. 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 the ProDev WorkShop: Debugger Reference Manual.

Traceback Through the Call Stack Window

The Views menu may be used to bring up the Call Stack window. This window displays the functions/subroutines (that is, the “frames”) in the call stack when the process associated with your program has stopped. This display provides a traceback of subprograms from the system routine which starts your executable, found at the bottom of the list, to the routine in which you are currently stopped, found at the top of the list.

If the trap/breakpoint at which you are currently stopped is located in your source code, that code is displayed in the source pane of the Main View window. If the trap/breakpoint is located in a system routine, the Call Stack allows you to double-click on another routine's name to bring up that routine's source and associated data.

The Call Stack window lets you see the argument names, values, types, and locations of functions, as well as the program counter (PC).

If symbolic information for the arguments has been stripped from the executable file, the label <stripped> appears in place of the arguments. By default call stack depth is set to 10, but you can reset the depth of the Call Stack by selecting Config -> Preferences from the Main View window.

To move through the call stack, double-click a frame in the stack. The frame becomes highlighted to indicate the current context. The source display in the Main View or Source View windows scrolls automatically to the location where the function was called and any other active views update.

The source display has two special annotations:

  • The location of the current program state is indicated by a large arrow. This represents the PC (program counter).

  • The location of the call to the function selected in the Call Stack window is indicated by a smaller arrow. This represents the current context, and the source line is highlighted.

Options for Viewing Variables

The WorkShop Debugger provides several options for viewing variables or expressions involving these variables. In this section only brief descriptions of these options are provided along with references where further information may be obtained elsewhere in this document.

Using the cvd Command Line

At the bottom of the Main View window is the cvd command/message pane. Here, you can enter print xxx commands to obtain the current value of variable xxx.

For examples of these commands, see “Viewing Variables Using the cvd Command Line” in Chapter 2.

For the syntax of these commands (such as assign, print, printd, printo, printx, and so on), see the ProDev WorkShop: Debugger Reference Manual.

Using Click to Evaluate

In the Main View window's source pane, a click of the right mouse button brings up a pop-up menu from which you can select Click to Evaluate . When this option is on, a click on a variable causes its value to appear. If you click on a subscript variable, its address appears. If you hold down the left mouse button and wipe across a variable and its subscripts to highlight them, the current value is displayed. The same is true if an expression in the source is highlighted.

Using the Array Browser

To view values of arrays, select Views -> Array Browser from the Main View menu bar.

This calls up the Array Browser window. When the name of an array is entered into the Array field, the values of 1-dimensional arrays or the values in a selected plane of a multi-dimensional array are displayed.

See “Viewing Variables Using the Array Browser” in Chapter 2 for short description of the Array Browser. The ProDev WorkShop: Debugger Reference Manual provides a more detailed description and graphic of the window and associated submenus.

Using the Data Explorer

To view C structures, select Views -> Data Explorer from the Main View menu bar.

This calls up the Data Explorer window. When the name of a structure is entered into the Expression field, the objects in the structure display in the lower portion of the window. The ProDev WorkShop: Debugger Reference Manual provides a more detailed description and graphic of the window and associated submenus.

Using the Variable Browser

To call up the Variable Browser window, select Views -> Variable Browser from the Main View menu bar.

This window lists the names and values of variables associated with the current routine in which the process has stopped.

See “Viewing Variables Using the Variable Browser” in Chapter 2 for a short description of the Variable Browser. The ProDev WorkShop: Debugger Reference Manual provides a more detailed description and graphic of the window and associated submenus.

Using the Expression View

Select the following from the Main View menu bar to bring up the Expression View window: Views -> Expression View.

Expressions may be entered into this window in the Expression column; and the corresponding Results entry displays the value of the evaluated expression using values of variables associated with the current routine in which the process has stopped.

See “Viewing Variables Using the Expression View Window” in Chapter 2 for a short description of the Expressions View window. The ProDev WorkShop: Debugger Reference Manual section on the Expression View Window provides a more detailed description and graphic of the window and associated submenus.

The next section of this chapter, “Evaluating Expressions”, gives further details on how to create acceptable expressions for the Expression View.

Using the Data View Window

When you “dive” on a variable in the Source View window (click the right mouse button over a variable), the Data View window appears, displaying that variable's information. Pointers and structures can be re-selected (re-dived) in the Data View window to expand portions of the object that is of interest.

Evaluating Expressions

You can evaluate any valid expression at a stopping point 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 preprocessor, such as in a #define directive or a macro.

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

You can also evaluate expressions from the command line. See the ProDev WorkShop: Debugger Reference Manual for more information.

Expression View Window

The Expression View window has two pop-up menus, the Language menu and the Format menu:

  • 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, click in the Expression column and then enter the expression in the selected field. It must be a valid expression in the current or selected language: Ada, 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 Result column.

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. From here you can select the following:

  • Select the Default Value menu to see the value as decimal, unsigned, octal, hex, float, char, or string characters.

  • Select the Type Address Of menu to display the address in decimal, octal, or hexadecimal.

  • Select Bit Size to specify the size of the result, in bits.


Caution: The Debugger uses the symbol table of the target program to determine variable type. 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 fullword integer. This gives the correct value for fullword integers or pointers, but the wrong value for non-fullword integers and for floating-point values.

To see the value of a variable of unknown type, use C type cast syntax to cast the address of the variable to a pointer that points to the correct type. 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 call stack). Like other views involved with variables, Expression View has variable change indicators for value fields that let you see previous values.

Another useful technique is to save your expressions to a file for later reuse. To save expressions, select Config ->  Save Expressions from the Main View menu bar.

To load expressions, select Config ->  Load Expressions from the Main View menu bar.

Assigning Values to Variables

To assign a value to a variable, click the left column of the Expression View window 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. Press Enter to assign the new value. 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. Valid expression operations are shown in the following paragraphs.

Evaluating Expressions in C

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

Table 7-1. Valid C Operations

Operation

Symbol

Arithmetic[a]

+ - ++ --

Arithmetic (binary)

+ - * / %

Logical

&& || !

Relational

< > <= >= == !=

Bit

& | ^ << >> ~

Dereference

*

Address

&

Array indexing

[ ]

Conditional

? :

Member extraction[b]

. ->

Assignment[c]

= += -= /= %= >>= <<= &= ^= |=

Sizeof

 

Type-cast

 

Function call

 

[a] Unary - increment and decrement do not have side-effects

[b] These operations are interchangeable.

[c] 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, because the temporary stack frame is destroyed immediately after the call is completed.

Function calls may be nested. For example, if your program contains a successor function succ, the Debugger evaluates 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 de-mangled 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 other member functions. 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

You can enter any Fortran expression under the Expression heading and its current value appears in the same row under the Results column. 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 7-2 are supported on data of integer, real, and complex types.

Table 7-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[a]

=

[a] 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 it can be, an argument is passed by reference; 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.