TOC PREV NEXT INDEX DOC LIST MASTER INDEX



Machine Level Debugging

The Apex environment lets you to perform machine-level debugging by displaying assembly level code, and by displaying and modifying registers and memory locations.

The following topics are covered in this chapter:


Displaying Assembly Language

There are a number of ways to display the assembly language code of your program.

If Show Source mode is active and your code is being displayed in the Source pane of the Debugger window, it is possible to display disassembled machine instructions interspersed with source code, if available. Do this by either selecting the Disassembly hot button in the Toolbar, selecting the Debug > Visit Assembly in an editor window, or by positioning your cursor anywhere in the Source pane and entering I (capital I). To return to the source display, deselect the Disassembly button or enter I again in the Source pane. An example of a Source pane in disassembly mode is illustrated in Figure 5.

Figure 5 Disassembly Mode

Note that in Disassembly mode, all Source pane icons such as breakpoint stop signs are displayed. Breakpoint commands entered while this mode is active cause the breakpoints to be set at the highlighted instruction.

If you are using the non-GUI debugger, viewing of assembly code can be done in several ways. If you are using screen-mode, the debugger supports two sub-modes, instruction and source. The I (uppercase i) command toggles the sub-mode, switching from one to the other. In source mode, the source window displays program source code and the s, i, and o commands single-step at the source statement level.

Source mode is the default. In instruction mode, the source window contains disassembled machine instructions, interspersed with source code, if available. Although the source window contains machine instructions, control it with all regular debugger commands. In this mode, the s, i, and o debugger commands are interpreted as their machine instruction counterparts, the si, ii, and oi commands. The b command is interpreted as bi, setting a breakpoint at the machine instruction under the cursor. All searching and window control commands are available.

If screen mode is not being used, the li and wi commands display assembly code.

li

List disassembled instructions

Syntax
Arguments
Description

li lists the specified number of lines including disassembled machine instructions interspersed with source lines. This listing is displayed in the Command/Log Window. If a decimal line number is given, disassembly starts with the first line of code generated by or after that line. If expression is specified, the listing starts with the instruction at that address.

If * appears next to the instruction address, that instruction is the home position for the current frame. Use * as the expression|decimal_number to start disassembly at the home position instruction.

If an equals sign appears after the address, a breakpoint is at that instruction.

If [expression|decimal_number] is omitted, the listing begins with the line or instruction following the most recently l'd or li'd line or instruction or the home line or instruction if no l or li command has been given for this file.

The display contains program source lines interspersed among disassembled machine instructions. The first instruction is preceded by the source line that generated it except when no source is available or disassembly begins mid-statement.

The debugger does not, in one li command, disassemble across a source file boundary, no matter how many lines it is instructed to print. It stops the display at the source file boundary. The next li command with no parameters starts at the beginning of the next source file.

In Screen Mode

Precede this command with : and follow with Return. You can show disassembly in the upper window with Instruction and Source Sub-modes.

In screen mode, toggle the upper window (source window) to display either source code or disassembled machine instructions. The screen mode command, I (uppercase i), performs this toggling.

wi

List window of disassembled and original code

Syntax
Arguments
Description

The term "window" is used here to mean a section of source text. Do not confuse it with the windows of the debugger.

wi prints a window containing the specified number of lines including disassembled machine instructions interspersed with source lines. This window appears in the Command/Log Window. If a decimal line number is given (decimal_number), this line is at the center of the window. If expression is specified, the instruction at the address given by expression is at the center of the window.

If an equals sign appears after the address, a breakpoint is at that instruction.

If [expression|decimal_number] is omitted, the display is centered on the line or instruction following the most recent w'd or wi'd line or instruction or the home line or instruction if no w or wi command is given for this file. The home position is centered in the window if [expression|decimal_number] is *.

The display contains program source lines interspersed among disassembled machine instructions. The first instruction is preceded by the source line that generated it except when no source is available or disassembly begins mid statement.

The debugger does not, in one wi command, disassemble across a source file boundary, no matter how many lines it is instructed to print. It stops the display at the source file boundary.

In Screen Mode

Precede this command with : and follow with Return.

In screen mode, the upper window (source window) toggles to display either source code or disassembled machine instructions. The screen mode command, I, performs this toggling.


Setting Breakpoints at Instructions

If assembly code is displayed, entering the standard breakpoint commands have the effect of setting the breakpoint at the instruction level. You can also use the bi command in the Command Pane or non-GUI debugger to set a breakpoint at an instruction.


Stepping Machine-Code

All stepping commands available in source mode are also available in Assembly mode. These are as follows:

Table 16 Debugger Machine Code Stepping Commands
Operation
Command
Where
Step one machine instruction.
Debug > Step > Step Instruction
Execution > Step Instruction


si, ii
Editor
All debugger windows

Command Pane,
Command-Line interface

Step one machine instruction, stepping over called subprograms (Ada) or functions (C/C++).
Debug > Step Over Instruction
Execution > Step Over Instruction


oi
Editor
All debugger windows

Command Pane,
Command-Line interface


Register Operations

Apex offers the capability of displaying and modifying the contents of regular and floating point registers.

Obtaining Information from Registers

There are several ways to obtain information from registers. You can:

Displaying the Registers Window

The Registers window displays the current values of all the registers in the current context. When you change the context to a different task or frame, the registers for the specified frame are displayed. Each register name is followed by its hexadecimal value.

The Registers window, shown in Figure 6 , is platform-specific. This example is from a Sun SPARC. The entries shown in blue are registers whose values have changed with the last execution command given to the program.

Figure 6 Registers Window

There are several ways to display the Registers window. You can:

Displaying the Floating Point Registers Window

The Floating Point Registers window displays the current values of all the floating point registers in the current context. When you change the context to a different task or frame, the registers for the specified frame are displayed. Each register name is followed by its decimal value.

The Floating Point Registers window is platform-specific. The example shown is from a Sun SPARC

.

There are several ways to display the Floating Point Registers window. You can:

Displaying the Contents of a Single Register

In the Debugger window or the non-GUI debugger, you can display the contents of a register directly by entering p $register_name command.

You can also use the following steps to display the value of any register:

1 . Execute the Debug > Show... command from any debugger window or Control-Debug > Show from an editor window.

2 . When the Show Data dialog box appears, enter the name of the register you want to display. Note that register names must begin with a dollar sign ($).

3 . Click OK to close the Show Data dialog box.

reg

List the current machine register contents

Syntax
Arguments
Description

reg lists the contents of registers as they are when the program stops.

The command

lists the floating point coprocessor registers if the implementation supports a coprocessor.

On the SPARC, display floating point registers as single-precision floats using p $fnumber ($f2), as double-precision floats using p $dnumber and as extended reals using p $enumber.

Display individual registers using the p command with the name of the register preceded by a dollar sign ($).

For MIPS processors, single precision registers are displayed using p $fnumber ($f0), Double-precision registers are displayed using p $dnumber ($d0).

In Screen Mode

Precede this command with : and follow with Return.

Modifying the Value of a Register

To modify the value of a register, execute the Debug > Modify Register command from any debugger window. Apex opens the Modify Register dialog box.

After you execute this command, the name of the register and its new value are displayed in the Log area of the main window.

After you execute the Modify Register command, the old and new values are displayed in the log area. Note that the new value is listed first. The new value is also displayed in blue in the Registers window.

In the non-GUI debugger, or command pane, change the value of a register using an assignment statement described in Modifying Data Using Assignment Statements.


Memory Location Operations

Displaying Memory Locations

You can display the contents of memory information in several ways:

Displaying the Memory Window

To display the Memory window, execute the Windows > Memory command from any debugger window or execute the Debug > Window > Memory command from an editor window. When the Memory dialog box opens, no data is displayed because the debugger has not been instructed to display any particular range of memory locations.

When an empty Memory dialog box opens because no memory-display instructions have been issued, Apex also opens the Memory Bounds dialog box. You can then enter the beginning location, the range of the memory locations you want to display, and the bytes per unit to display.

The Memory window displays the contents of specific memory locations. On each line, the first entry is the memory address in hexadecimal. This entry is followed by the contents of memory starting at that address. The memory contents are displayed in hexadecimal notation. By default, 128 bytes are displayed, 16 bytes per line. An ASCII string is appended at the end of each line.

This display can be modified by using the View > Bounds command from the Memory window.

The Memory window displayed after entering a starting address is illustrated below.

Display Memory - Command Line Interface

The following syntaxes can be used to display the value of a memory location. If the debugger GUI is being used, enter these in the Command Pane.

Syntax
Arguments
Description

Use the p command to display memory. In this form of the p command, you supply an address on the left side of the : and a format on the right side. The optional number field is used to repeat that display at successive memory locations.

The address you supply can be a simple number (0123:LX), a variable name (name:m), or an expression ($pc + 4). The format can be one of those described below under display, or a typedef defined in your program. If you use a name, it is evaluated and the address of the named object is used.

The precedence of operators is that the C unary operators * and & have the highest precedence, followed by the : in display memory and then the binary operators. For example, if the source is C, the debugger evaluates p *address:display as p (*address):display. Use parentheses to establish a different precedence, p *(address:display).

For binary operators, p $pc + 4:m is evaluated, by default, as p $pc + (4:m). Use parentheses within binary expressions preceding the : to avoid ambiguity, p ($pc + 4):m.

display consists of a length character alone, a length character and a format character or a format character alone. The default is shown in brackets.

B
8-bit [default number base established by set obase]
D
64-bit floating point
E
largest size floating-point format available
F
32-bit floating point
I
Size of an integer type (32-bits)
L
Size of a long_integer type (64-bits or 32-bits)
W
16-bit [default number base established by set obase]
Q
64-bit [default number base established by set obase]

a
Show the address of the item
b
Display as bits
c
ASCII character
d
Decimal [32 bits]
f
Floating point [32 bits]
m
One line of Storage_Units, first in hexadecimal, then as ASCII characters
n
Like m but bytes are interpreted in reverse order
o
Octal [32 bits]
p
hexadecimal pointer [32 bits or 64-bits]
r
Reverse-map the address to a procedure name
s
Null-terminated (C-style) string
x
Hexadecimal [32 bits] Note that on 64-bit machines, this will be the same as using p.
z
Show the address of the dope vector for records and unconstrained arrays

You can enter number in either decimal or in hexadecimal with a leading 0. If the leading digit of a number is a zero, the debugger assumes it is a hexadecimal number (0123 or 0F2).

number determines how many values are displayed. The address is advanced by a number corresponding to the length specified. For example, to display 8 16-bit hexadecimal values starting at address 01A9A, type the following command:

Note: This is just an example address and may not be valid for your processor. It can be replaced by an address applicable to your system.

The debugger responds with this output:

The default length is 32 bits. The default format is either decimal, octal or hexadecimal, depending on the setting of the set obase number command. The default count is 1. Specifying an address of the form hexadecimal_number displays 32 bits in the current output base. The following command example displays two lines each, beginning at address 01A9A. Each line is displayed in hexadecimal format followed by an ASCII string:

The debugger responds with this output:

Even though they cannot be typed in directly by the user, the debugger can display bit addresses using the notation hex_byte_addr.bit_offset. For example, given the following declarations:

For Ada:

the following can be displayed:

For C/C++:

the following can be displayed:

The :a format is useful for finding the address of any name expression. For example, given the array My_Array, the command

displays the address of the first element. This is equivalent to typing p &My_Array. You can use the :a format for procedure names, simple variables, fields of a structure, etc

Note: Typing a plain decimal number moves the current position to that line number. Memory displays require the number to be followed by a colon and a display letter. The p command symbolically displays the value of variables or name expressions; a command consisting of only a name expression is a syntax error.

In addition to the lengths and formats of display listed above, the debugger can display memory at a given address using a type declared in the user Ada or C/C++ program. For example, if Task_Block is a complex structure, p 080040:TASK_BLOCK displays the entire structure at address 080040.

You can display the structure with a:

As another example, consider these Ada type declarations:

If the user is breakpointed in a subprogram where the register with the name rn holds a Queue_Ptr value, the following expressions can be typed:

Debugger Command
Value printed
> p $rn:queue_ptr
The access value in rn, i.e., an address
> p ($rn:queue_ptr).all
The object pointed to by the access in rn asType QUEUE
> p ($rn:queue_ptr).node
The access value of the node field
> p ($rn:queue_ptr).node.all
The task_block object pointed to by node

After an object is created using the p address:type syntax, use it in any expression where such an object is legal.

Note: First, the debugger checks the specified type against the debugger basic display values. If a match exists, it uses the basic value, even if the program contains a declared type of the same name. The debugger display values are listed above and are displayed as part of the diagnostic if an unrecognized value is used.

Applying a Type to an Address

The debugger also has the ability to display an object in memory when no visible variable points to that object.

There are times when debugging that you either have only the address of an object because you are debugging a machine code routine, or are in a location in your program where the debugger cannot determine with certainty where an object is. In the latter case, you can often determine the address of the object by examining the machine instructions and/or register contents. In addition, there is a convenient way for you to display your object using just its address and type mark.

The syntax of the debugger command is an extension of the syntax for examining memory. Instead of supplying a format specifier such as L or B, you supply the type mark (Ada) or name (C/C++), which must be visible according to the standard visibility rules. Consider the following Ada example:

Suppose you know that the address of an object of this type is 16#100A48#. To display the object you would simply enter the command:

Further, if the object is located at an offset of 16 off of register s0 (This is just an example register and may not be valid for your system but the process is the same on all systems), you could either get the address in register s0, add 16 then use the method above, or more simply type:

This expression is evaluated as follows:

$s0

value in register s0

$s0+16

add 16 to value in s0

*($s0+ 16) 

the * means "indirect", that is, read the memory whose address is $s0+16. The 32 bits of memory at that location are the address that is used to display dashboard.speedometer_t.

To display an object as another type, use the same command as above only substitute the name of the object for the address on the left. For example, if there is an object declared in the program as

and you want to display foo as type Miles_T, simply enter the command

and the debugger displays the object foo as type Miles_T.

Note: The "typecast" operation, :, binds most tightly. If you have an expression to the immediate left of the :, you must use parentheses to typecast the entire expression. For example, if you type

> sym + foo:newtype

foo is recast to newtype. To recast sym+foo, you must surround the expression with parentheses.

> (sym + foo):newtype

Typecasting is available in Native debuggers.

For example, in X-window applications, you may want to look at the fields of a widget. The type Widget is defined as:

Even though all the widget variables declared are used as though they are type Widget, in fact they are more complex structures.

For example, when a label widget is created, it returns a pointer to a Labelrec:

If a variable Label_W has been declared as

the debugger command

displays only the fields in Corepart of the widget. To display ALL the information about this label Widget, the variable can be typecast:

or

As with Ada typecasting, an address may be used instead of a variable name.

There are some special restrictions with C/C++ typecasting:

Modifying Contents of Memory Locations

To modify the data in a memory location, execute the Debug > Modify Memory command. Apex displays the Modify Memory dialog box.

Another way to modify the data in a memory location is to execute the Debug > Modify Data command from an editor window. When modifying the value of a memory location via Debug > Modify Data, the Memory dialog box is not updated automatically. To update the Memory window, click the View > Refresh command in the Memory window.

You can also modify memory through the Command Pane or non-GUI debugger by entering the memory address to be modified, then the new value. For example,


Rational Software Corporation 
http://www.rational.com
support@rational.com
techpubs@rational.com
Copyright © 1993-2002, Rational Software Corporation. All rights reserved.
TOC PREV NEXT INDEX DOC LIST MASTER INDEX TECHNOTES APEX TIPS