This chapter describes how to examine and modify the program state by
using the following windows:
Windows that display variables come in several different varieties:
- Locals
- File Variables
- Watches
- Variable
They're collectively called variable windows. You use the same
interactions in all variable windows to
display, modify, and browse your variables and data structures.
The only difference between these windows is the variables
they display. The values in each window
are updated as you trace through your program. The windows
display the following information:
- Locals
- Contains the list of variables local to the current
routine. Choose Locals from the Data menu
to open this window.
- File Variables
- Contains a list of all variables defined at file scope in the
current module. This includes external and static symbols. Choose
File Variables from the Data menu
to open this window.
- Watches
- The Watches window allows you to add and delete variables and
expressions. In other windows you can choose Watch.
This opens the Watches window, and adds to it the
text that's selected in another window.
Use the New item in the context-sensitive or Action menu
to add any expression to the Watches window. Once entered, you can
choose Edit to edit the expressions or typecast the variables.
- Variable
- This is another instance of a Watches window. A variable window is
created when you select a variable or expression in a window and use the
Inspect command.
Each line of a variable window has three elements. On the left is
a button.
The button changes, depending on the type of the variable or expression:
- structs (classes) (unions)
- Structures may be opened and closed by clicking on the button at the
left. When you open a structure or class, one line is added to the
window for each field of the structure. These new lines are indented.
If you click on the button again, the structure is closed, and the
window is returned to its original state.
- arrays
- Like structures, arrays may be opened and closed. When you
open an array, one line is added to the window for each element of the
array. The debugger displays at most 1000 elements of an array. If
it contains more, you can use the Type/Array...
to open different ranges. Multi-dimensional arrays are treated like an
array of arrays. When you open the first dimension, the lines that are
added are also arrays that you can open.
- pointers
-
When the variable is a pointer, you can click on the button. The
debugger follows the pointer and changes the line to represent the
item that's the result of the pointer reference. For example, if you
have a pointer to an integer, and you click on the button, the integer
value
is displayed. The button then changes to indicate that you can undo
the operation by clicking on it again.
In the case of pointers to pointers, clicking on the button
follows the pointers one level each time you click, until
a non-pointer value is reached. Clicking on the button at this point
takes you back to the original state. When the pointer points
to a structure, it's automatically opened when you click on the button.
If a pointer is really an array, you can use Type/Array...
to open it as an array.
Next comes the name of the variable, field, or array element being
displayed. Finally, the value is displayed. If the item being
displayed isn't a scalar item, the value displayed is an indication
that it's a complex data type. If the value changes when you run your
program, it's highlighted. If a variable goes out of scope, or a
pointer value becomes invalid, the value appears as question marks.
To modify a variable's value, double-click on the value
field, or cursor to it and press Enter. Double-clicking or
pressing Enter on the name field is equivalent to clicking on the
button. Press the right mouse button to access the following popup menu items:
- Modify...
- Modify the value of the selected item.
- Inspect
- Open a new Variable window containing the selected item.
If the item is a compound object (array, class, or structure), it's
opened automatically.
- Break
-
Set a breakpoint so that execution stops when the selected item's
value changes. This is the same as setting a breakpoint on the
object.
See the Breakpoints chapter.
- Edit
-
Open a dialog box in which you can edit an expression in the Watch
window. This is useful for typecasting variables or evaluating
expressions.
See the Expression Handling chapter.
- New
- Add a new variable or expression to the window. You're prompted
for the expression to add.
- Delete
- Delete the selected item from the window.
- Root
-
When the selected item is a field of a structure or an element of an
array, this menu item moves the currently selected item to the
parent of that item. For example, if you are examining
sym->field1->field2, Root
changes the current selection to sym->field1.
If you're examining a deeply nested field, use Root
repeatedly to find the originating expression.
- Type/Hex
- Change the value to be displayed in hexadecimal.
- Type/Decimal
- Change the value to be displayed in decimal.
- Type/Character
- Change the value to be displayed as a single character constant. This
is useful when you have a one-byte variable that really contains a
character.
The debugger often displays it as an integer by default.
- Type/String
-
The debugger automatically detects pointers to strings in the variable
windows and displays the string rather than the raw pointer value.
If the string isn't null-terminated, contains non-printable
characters, or isn't typed as a pointer to char, this
mechanism doesn't work. Type/String overrides the automatic string
detection and displays the pointer as a string regardless of its type.
- Type/Pointer
-
This undoes the effects of Type/String or Type/Array. It also
lets you see the raw pointer value when the debugger has automatically
displayed a pointer to char as a string.
- Type/Array...
-
Use this menu item to display a pointer as if it were an array, or to
display ranges of an array's elements. You're prompted for the
first and last element to display.
- Show/Raw Memory
-
Display raw memory at the address of this variable. This lets you
examine the actual binary representation of a variable.
- Show/Pointer Memory
-
Display the memory that the item points to. This is useful when you
have a pointer to a block of memory that doesn't have a type associated
with it.
- Show/Pointer Code
-
Display the code that the variable points to. If the item being
displayed is a pointer to function, you can use this menu item to
see the definition of that function.
- Options
- This menu contains the same options found in the section
``Variables
Options'' in the Debugger Environment chapter.
This menu item sets options on a per-window basis, overriding the
global settings. When you use the menu item to change these
settings, they aren't saved between debugging sessions. To
change an option permanently, see the
``Window
Options Dialog'' in the Debugger Environment chapter.
Use the Memory window or the Stack window to examine memory in raw form.
To open a Memory window, choose Memory At from the Data
menu. The Enter Memory Address dialog appears. Enter the memory address
and press Return to see the Memory window.
You can also use one of the Show/Pointer Memory or Show/Raw Memory
items in a variable window to display the memory associated with a
variable.
The Stack Window always shows the memory at the stack pointer. It moves
to track the top of the stack as your program executes. The stack
pointer location is at the top of the window. The location
of the BP or EBP register is also indicated.
Choose Stack from the Data menu
to open the Stack window.
To modify memory, double-click on a value in the Memory or
Stack window, or cursor to it and press Enter.
You're prompted for a new value.
Memory windows allow you to follow data structures in the absence of
debugging information. The Follow
menu items reposition the memory window to the address that's
found under the cursor. The Repeat and Previous
items let you repeat a follow action. This makes it simple
to follow linked lists.
Press the right mouse button to access these popup menu items:
- Modify
-
Modify the value at the selected address. You're prompted for
a new value. You should enter the value in the radix that the
window's currently displaying. You aren't limited to typing
constant values - you can enter an arbitrary expression to be used
for the new value.
- Break on Write
-
Set a breakpoint to stop execution when the selected value changes.
See the chapter Breakpoints.
- Near Follow
-
Display the memory that the selected memory points to,
treating it as a near pointer. The new offset to be displayed is
xxxx, where xxxx is the word under the cursor.
DGROUP is used as the segment if it can be located.
The program's initial stack segment is used otherwise.
When you're debugging a 16-bit or 32-bit application, the
appropriate word size is used.
- Far Follow
- Displays the memory that the selected memory points to,
treating it as a far pointer. The new address to be displayed is
the the segment and offset found at the cursor location. Note
that pointers are stored in memory with the offset value first and the
segment value second.
- Segment Follow
- Display the segment that the selected memory points to,
treating it as a segment selector. The new address to be displayed
is xxxx:0, where xxxx is the two-byte word
under the cursor.
- Cursor Follow
-
Make the selected position the new starting address in
the window. This means that the first byte in the memory
window becomes the byte that the cursor was pointing
to. This is useful for navigating through an array when no debugging
information is available.
- Repeat
- Repeat the previous Follow operation. The new address that's
used is at the same offset relative to the beginning of the window
as it was in the original Follow operation. Repeating a pointer or
segment follow is a linked list traversal. Repeating a Cursor Follow
operation advances to the next element in an array.
- Previous
- Back out of a Follow or Repeat operation. This
displays the memory window you were previously viewing.
Essentially, this undoes a Follow operation. You can back
all the way out to the first memory location you were examining.
- Home
- Undo all Follow and Repeat operations. This takes you back
to the very first location window you were examining. It's equivalent
to using Previous repeatedly.
- Left
- Scroll the window backward through memory by the size of
the displayed memory items.
- Right
- Scroll the window forward through memory by the size of
the displayed memory items.
- Address
-
Position the window at a new address. You're prompted to type in
a new address. You can type an arbitrary expression.
Expressions are discussed in the chapter
Expression Handling.
If you type the name of a variable, the address
of that variable is used. If the expression you type doesn't contain
a segment value, DGROUP is used as the segment if it can
be located.
The program's initial stack segment is used otherwise.
- Assembly
- Position the assembly window to the address of the memory under
the cursor. This is useful if you have incorrectly displayed a
pointer as data and wish to look at the code instead.
- Type/Byte
-
Display as hexadecimal bytes.
- Type/Word
- Display as hexadecimal 16-bit words.
- Type/Dword
- Display as hexadecimal 32-bit words.
- Type/Char
- Display as signed 8-bit integers.
- Type/Short
- Display as signed 16-bit integers.
- Type/Long
- Display as signed 32-bit integers.
- Type/Unsigned Char
- Display as unsigned 8-bit integers.
- Type/Unsigned Short
- Display as unsigned 16-bit integers.
- Type/Unsigned Long
- Display as unsigned 32-bit integers.
- Type/16:16 Pointer
- Display as 32-bit far pointers (16-bit segment, 16-bit offset).
- Type/16:32 Pointer
- Display as 48-bit far pointers (16-bit segment, 32-bit offset).
- Type/Binary
- Display as binary 8-bit words
- Type/Float
- Display as 32-bit floating-point values.
- Type/Double
- Display as 64-bit floating-point values.
Use the memory window to display the memory address of the
first node of your linked list. Move to the ``next'' field of your
structure and use the Near (or Far) Follow command. The next node of your
linked list is displayed. Now by using the Repeat
command you can traverse the linked list.
Display the memory address of
your array. Select the first byte of the second element
of your array, then use the Cursor Follow command to move
the second element of your array to the beginning of
the memory window. By using the Repeat
command you can traverse your array.