hp.com home products and services support and drivers solutions how to buy
cd-rom home
End of Jump to page title
HP OpenVMS systems
documentation

Jump to content


HP OpenVMS Debugger Manual

HP OpenVMS Debugger Manual


Previous Contents Index

3.4.1 Deactivating, Activating, and Canceling Watchpoints

After a watchpoint is set, you can deactivate it, activate it, or cancel it.

To deactivate a watchpoint, use the DEACTIVATE WATCH command. This causes the debugger to ignore the watchpoint during program execution. However, you can activate it at a later time, for example, when you rerun the program (see Section 1.3.3). A deactivated watchpoint is listed as such in a SHOW WATCH display.

To activate a watchpoint, use the ACTIVATE WATCH command. Activating a watchpoint causes it to take effect during program execution. You can always activate a static watchpoint, but the debugger cancels a nonstatic watchpoint if execution moves out of the scope in which the variable is defined (see Section 3.4.3).

The commands DEACTIVATE WATCH/ALL and ACTIVATE WATCH/ALL operate on all watchpoints and are particularly useful when rerunning a program with the RERUN command.

To cancel a watchpoint, use the CANCEL WATCH command. A canceled watchpoint is no longer listed in a SHOW WATCH display.

3.4.2 Watchpoint Options

The SET WATCH command provides the same options for controlling the behavior of the debugger at watchpoints that the SET BREAK and SET TRACE commands provide for breakpoints and tracepoints---namely the /AFTER, /[NO]SILENT, /[NO]SOURCE, and /TEMPORARY qualifiers, and the optional WHEN and DO clauses. See Section 3.3.4 for examples.

3.4.3 Watching Nonstatic Variables

Note

The generic term nonstatic variable is used here to denote what is called an automatic variable in some languages.

Storage for a variable in your program is allocated either statically or nonstatically. A static variable is associated with the same memory address throughout execution of the program. A nonstatic variable is allocated on the call stack or in a register and has a value only when its defining routine is active on the call stack. As explained in this section, the technique for setting a watchpoint, the watchpoint's behavior, and the speed of program execution are different for the two kinds of variables.

To determine how a variable is allocated, use the EVALUATE/ADDRESS command. A static variable generally has its address in P0 space (0 to 3FFFFFFF, hexadecimal). A nonstatic variable generally has its address in P1 space (40000000 to 7FFFFFFF, hexadecimal) or is in a register. In the following Pascal code example, X is declared as a static variable, but Y is a nonstatic variable (by default). The EVALUATE/ADDRESS command, entered while debugging, shows that X is allocated at memory location 512, but Y is allocated in register R0.


   .
   .
   .
VAR 
     X: [STATIC] INTEGER; 
     Y: INTEGER; 
   .
   .
   .


DBG> EVALUATE/ADDRESS X
512
DBG> EVALUATE/ADDRESS Y
%R0
DBG>

When using the SET WATCH command, note the following distinction. You can set a watchpoint on a static variable throughout execution of your program, but you can set a watchpoint on a nonstatic variable only when execution is paused within the scope of the variable's defining routine. Otherwise, the debugger issues a warning. For example:


DBG> SET WATCH Y
%DEBUG-W-SYMNOTACT, nonstatic variable 'MOD4\ROUT3\Y' 
    is not active
DBG>

Section 3.4.3.2 describes how to set a watchpoint on a nonstatic variable.

3.4.3.1 Execution Speed

When a watchpoint is set, the speed of program execution depends on whether the variable is static or nonstatic. To watch a static variable, the debugger write-protects the page containing the variable. If your program attempts to write to that page (modify the value of that variable), an access violation occurs and the debugger handles the exception. The debugger temporarily unprotects the page to allow the instruction to complete and then determines whether the watched variable was modified. Except when writing to that page, the program executes at full speed.

Because problems arise if the call stack or registers are write-protected, the debugger must use another technique to watch a nonstatic variable. It traces every instruction in the variable's defining routine and checks the value of the variable after each instruction has been executed. Because this significantly slows down the execution of the program, the debugger issues the following message when you set a nonstatic watchpoint:


DBG> SET WATCH Y
%DEBUG-I-WPTTRACE, nonstatic watchpoint, tracing every instruction
DBG>

3.4.3.2 Setting a Watchpoint on a Nonstatic Variable

To set a watchpoint on a nonstatic variable, make sure that execution is paused within the defining routine. A convenient technique is to set a tracepoint on the routine that includes a DO clause to set the watchpoint. Thus, whenever the routine is called, the tracepoint is triggered and the watchpoint is automatically set on the local variable. In the following example, the WPTTRACE message indicates that a watchpoint has been set on Y, a nonstatic variable that is local to routine ROUT3:


DBG> SET TRACE/NOSOURCE ROUT3 DO (SET WATCH Y)
DBG> GO
   .
   .
   .
trace at routine MOD4\ROUT3
%DEBUG-I-WPTTRACE, nonstatic watchpoint, tracing every instruction
   .
   .
   .
watch of MOD4\ROUT3\Y at MOD4\ROUT3\%LINE 16
   16:     Y := 4
   old value:    3
   new value:    4
break at MOD4\ROUT3\%LINE 17
   17:     SWAP(X,Y);
DBG>

When execution returns to the caller of routine ROUT3, variable Y is no longer active. Therefore, the debugger automatically cancels the watchpoint and issues the following messages:


%DEBUG-I-WATCHVAR, watched variable MOD4\ROUT3\Y has gone out of scope
%DEBUG-I-WATCHCAN, watchpoint now canceled

3.4.3.3 Options for Watching Nonstatic Variables

The SET WATCH command qualifiers /OVER, /INTO, and /[NO]STATIC provide options for watching nonstatic variables.

When you set a watchpoint on a nonstatic variable, you can direct the debugger to do one of two things at a routine call:

Using the SET WATCH/OVER command results in better performance. However, if the called routine modifies the watched variable, the watchpoint is triggered only after execution returns from that routine. The SET WATCH/INTO command slows down program execution but enables you to monitor watchpoints more precisely within called routines.

The debugger determines whether a variable is static or nonstatic by looking at its address (P0 space, P1 space, or register). When entering a SET WATCH command, you can override this decision with the /[NO]STATIC qualifier. For example, if you have allocated nonstack storage in P1 space, use the SET WATCH/STATIC command to specify that a particular variable is static even though it is in P1 space. Conversely, if you have allocated your own call stack in P0 space, use the SET WATCH/NOSTATIC command to specify that a particular variable is nonstatic even though it is in P0 space.

3.4.3.4 Setting Watchpoints in Installed Writable Shareable Images

When setting a watchpoint in an installed writable shareable image, use the SET WATCH/NOSTATIC command (see Section 3.4.3.3).

The reason you must set a nonstatic watchpoint is as follows. Variables declared in such shareable images are typically static variables. By default, the debugger watches a static variable by write-protecting the page containing that variable. However, the debugger cannot write-protect a page in an installed writable shareable image. Therefore, the debugger must use the slower method of detecting changes, as for nonstatic variables---that is, by checking the value at the watched location after each instruction has been executed (see Section 3.4.3.1).

If any other process modifies the watched location's value, the debugger may report that your program modified the watched location.


Chapter 4
Examining and Manipulating Program Data

This chapter explains how to use the EXAMINE and DEPOSIT commands to display and modify the values of symbols declared in your program as well as the contents of arbitrary program locations. The chapter also explains how to use the EVALUATE and other commands that evaluate language expressions.

The topics covered in this chapter are organized as follows:

The examples in this chapter do not cover all language-dependent behavior. When debugging in any language, be sure also to consult the following documentation:

4.1 General Concepts

This section introduces the EXAMINE, DEPOSIT, and EVALUATE commands and discusses concepts that are common to those commands.

4.1.1 Accessing Variables While Debugging

Note

The generic term nonstatic variable is used here to denote what is called an automatic variable in some languages.

Before you try to examine or deposit into a nonstatic (stack-local or register) variable, its defining routine must be active on the call stack. That is, program execution must be paused somewhere within the defining routine. See Section 3.4.3 for more information about nonstatic variables.

You can examine a static variable at any time during program execution, and you can examine a nonstatic variable as soon as execution reaches its defining routine. However, before you examine any variable, you should execute the program beyond the point where the variable is declared and initialized. The value contained in any uninitialized variable should be considered invalid.

Many compilers optimize code to make the program run faster. If the code that you are debugging has been optimized, some program locations might not match what you would expect from looking at the source code. In particular, some optimization techniques eliminate certain variables so that you no longer have access to them while debugging.

Section 14.1 explains the effect of several optimization techniques on the executable code. When first debugging a program, it is best to disable optimization, if possible, with the /NOOPTIMIZE (or equivalent) compiler command qualifier.

In some cases, when using the EXAMINE or DEPOSIT command with a variable name (or any other symbolic address expression) you might need to set a module or specify a scope or a path name. Those concepts are described in Chapter 5. The examples in this chapter assume that all modules are set and that all variable names are uniquely defined.

4.1.2 Using the EXAMINE Command

For high-level language programs, the EXAMINE command is used mostly to display the current value of variables, and it has the following syntax:


EXAMINE address-expression[,...] 

For example, the following command displays the current value of the integer variable X:


DBG> EXAMINE X
MOD3\X:   17
DBG>

When displaying the value, the debugger prefixes the variable name with its path name---in this case, the name of the module where variable X is declared (see Section 5.3.2).

The EXAMINE command usually displays the current value of the entity, denoted by an address expression, in the type associated with that location (for example, integer, real, array, record, and so on).

When you enter an EXAMINE command, the debugger evaluates the address expression to yield a program location (a memory address or a register). The debugger then displays the value stored at that location as follows:

See Section 4.1.5 for more information about the types associated with symbolic and nonsymbolic address expressions.

By default, when displaying the value, the debugger identifies the address expression and its path name symbolically if symbol information is available. See Section 4.1.11 for more information about symbolizing addresses.

4.1.3 Using the DUMP Command

Use the debugger command DUMP to display the contents of memory, in a manner similar to that of the DCL command DUMP, in one of the following formats:

Binary
Byte
Decimal
Hexadecimal
Longword (default)
Octal
Quadword
Word

The DUMP command has the following syntax:


DUMP address-expression1[:address-expression2] 

The default for address-expression2 is address-expression1. For example, the following command displays the current value of registers R16 through R25 in quadword format.


DBG> DUMP/QUADWORD R16:R25
 0000000000000078 0000000000030038 8.......x....... %R16 
 000000202020786B 0000000000030041 A.......kx   ... %R18 
 0000000000030140 0000000000007800 .x......@....... %R20 
 0000000000010038 0000000000000007 ........8....... %R22 
 0000000000000006 0000000000000000 ................ %R24 
 
DBG> 

You can use the command DUMP to display registers, variables, and arrays. The debugger makes no attempt to interpret the structure of arrays. The following qualifiers determine how the debugger displays output from the DUMP command:
Qualifier Formats Output As
/BINARY Binary integers
/BYTE One-byte integers
/DECIMAL Decimal integers
/HEXADECIMAL Hexadecimal integers
/LONGWORD Longword integers (length 4 bytes)
/OCTAL Octal integers
/QUADWORD Quadword integers (length 8 bytes)
/WORD Word integers (length 2 bytes)

By default, the debugger displays examined entities that do not have a compiler-generated type as longwords.

4.1.4 Using the DEPOSIT Command

For high-level languages, the DEPOSIT command is used mostly to assign a new value to a variable. The command is similar to an assignment statement in most programming languages, and has the following syntax:


DEPOSIT address-expression = language-expression

For example, the following DEPOSIT command assigns the value 23 to the integer variable X:


 
DBG> EXAMINE X
MOD3\X:   17
DBG> DEPOSIT X = 23
DBG> EXAMINE X
MOD3\X:   23
DBG>
 

The DEPOSIT command usually evaluates a language expression and deposits the resulting value into a program location denoted by an address expression.

When you enter a DEPOSIT command, the debugger does the following:

Note that the debugger might do type conversion during a deposit operation if the language rules allow it. For example, assume X is an integer variable. In the following example, the real value 2.0 is converted to the integer value 2, which is then assigned to X:


DBG> DEPOSIT X = 2.0
DBG> EXAMINE X
MOD3\X:   2
DBG>

In general, the debugger tries to follow the assignment rules for the current language.

4.1.5 Address Expressions and Their Associated Types

The symbols that are declared in your program (variable names, routine names, and so on) are symbolic address expressions. They denote memory addresses or registers. Symbolic address expressions (also called symbolic names in this chapter) have compiler-generated types, and the debugger knows the type and location that are associated with symbolic names. Section 4.1.11 explains how to obtain memory addresses and register names from symbolic names and how to symbolize program locations.

Symbolic names include the following categories:

Program locations that do not have a symbolic name are not associated with a compiler-generated type. To enable you to examine and deposit into such locations, the debugger associates them with the default type longword integer. If you specify a location that does not have a symbolic name, the EXAMINE command displays the contents of four bytes starting at the address specified and formats the displayed information as an integer value. In the following example, the memory address 926 is not associated with a symbolic name (note that the address is not symbolized when the EXAMINE command is executed). Therefore, the EXAMINE command displays the value at that address as a longword integer.


DBG> EXAMINE 926
926:  749404624
DBG>

By default you can deposit up to four bytes of integer data into a program location that does not have a symbolic name. This data is formatted as a longword integer. For example:


DBG> DEPOSIT 926 = 84
DBG> EXAMINE 926
926:  84
DBG>

Techniques for examining and depositing into locations that do not have a symbolic name are described in Section 4.5.

The EXAMINE and DEPOSIT commands accept type qualifiers (/ASCII:n, /BYTE, and so on) that enable you to override the type associated with a program location. This is useful either if you want the contents of the location to be interpreted and displayed in another type, or if you want to deposit some value of a particular type into a location that is associated with another type. Techniques for overriding a type are described in Section 4.5.

4.1.6 Evaluating Language Expressions

A language expression consists of any combination of one or more symbols, literals, and operators that is evaluated to a single value in the syntax of the current language and in the current radix. (The current language and current radix are defined in Section 4.1.9 and Section 4.1.10, respectively.) Several debugger commands and constructs evaluate language expressions:

This discussion applies to all commands and constructs that evaluate language expressions, but it focuses on using the EVALUATE command.

The EVALUATE command evaluates one or more language expressions in the syntax of the current language and in the current radix and displays the resulting values. The command has the following syntax:


EVALUATE language-expression[,...] 

One use of the EVALUATE command is to perform arithmetic calculations that might be unrelated to your program. For example:


 
DBG> EVALUATE (8+12)*6/4
30
DBG>
 

The debugger uses the rules of operator precedence of the current language when evaluating language expressions.

You can also evaluate language expressions that include variables and other constructs. For example, the following EVALUATE command subtracts 3 from the current value of the integer variable X, multiplies the result by 4, and displays the resulting value:


 
DBG> DEPOSIT X = 23
DBG> EVALUATE (X - 3) * 4
80
DBG>
 

However, you cannot evaluate a language expression that includes a function call. For example, if PRODUCT is a function that multiplies two integers, you cannot enter the EVALUATE PRODUCT(3,5) command. If your program assigns the returned value of a function to a variable, you can examine the resulting value of that variable.

If an expression contains symbols with different compiler generated types, the debugger uses the type-conversion rules of the current language to evaluate the expression. If the types are incompatible, a diagnostic message is issued. Debugger support for operators and other constructs in language expressions is listed in the debugger's online help for each language (type HELP Language).

The built-in symbol %CURVAL denotes the current value---the value last displayed by an EVALUATE or EXAMINE command or deposited by a DEPOSIT command. The backslash (\) also denotes the current value when used in that context. For example:


 
DBG> EXAMINE X
MOD3\X:  23
DBG> EVALUATE %CURVAL
23
DBG> DEPOSIT Y = 47
DBG> EVALUATE \
47
DBG>
 


Previous Next Contents Index