This chapter explains how to:
The chapter describes window actions and window menu choices, but you can perform most common debugger operations by choosing items from context-sensitive pop-up menus. To access these menus, click on MB3 while the mouse pointer is in the window area.
You can also enter commands at the command-entry prompt. For information about entering debugger commands, see Section 2.4.
By default, the debugger's Main Window displays the source code of your program (see Figure 4-1).
Whenever execution is suspended (at a breakpoint for example), the debugger updates the source display by displaying the code that surrounds the point at which execution is paused. The current- location pointer to the left of the source code marks the line whose code will execute next. (A source line corresponds to one or more programming-language statements, depending on the language and coding style.)
By default, the debugger displays line numbers to the left of the source code. These numbers help you identify breakpoints that are listed in the Breakpoint View (see Section 4.4.3). You can choose not to display line numbers. To hide or display line numbers, choose File:Display Line Numbers on the Main Window.
The current-location pointer is normally filled in as shown in Figure 4-1. The current-location pointer is cleared if the displayed code is not that of the routine in which execution is paused.
You can use the scroll bars to show more of the source code. However, you can scroll vertically through only one module of your program at a time.
The following sections explain how to display source code for other parts of your program so that you can set breakpoints in various modules. Section 4.1.2 explains what to do if the debugger cannot find source code for display. Section 4.6.1 explains how to display the source code associated with routines that are currently active on the call stack.
After you navigate the Main Window, you can redisplay the location at which execution is paused by clicking on the top item in the Call Stack menu.
If your program was optimized during compilation, the source code displayed might not reflect the actual contents of some program locations.
To display source code contained in another module or source file:
Section 4.6.1 describes an alternative way to display routine source code for routines currently active on the call stack using the Call Stack menu.
The Browse Source dialog box displays information in a hierarchical form about all the binary files in your application. For each binary file, it displays information about the modules contained in the binary. For each module, a list of routines in that module can be displayed.
You can manipulate the Browse Source display by clicking on menu items in the Browse Source pop-up menus.
In certain cases, the debugger cannot display source code. Possible causes are:
If the debugger cannot find source code for a display, it tries to display the source code for the next routine on the call stack for which source code is available. If the debugger can display source code for such a routine, the current-location pointer is cleared. The pointer then marks the source line to which execution returns in the calling routine.
Information about the characteristics and the location of source files is embedded in the debug symbol table of your program. If a source file has been moved to a different directory since compile time, the debugger might not find the file. To direct the debugger to your source files, enter the use [directory] command at the command-entry prompt.
The debugger provides a simple text editor you can use to edit your source files while debugging your program (Figure 4-3).
To invoke the editor, choose Commands:Edit File on the Main Window.
By default, the editor window displays an empty text buffer, called
dbg_editor_main
. However, if you are debugging a
program when you invoke the editor, the editor window displays this
program, names the filled text buffer with its file specification,
and places dbg_editor_main
on the buffer menu at the
upper right corner as an alternative text buffer.
The editor allows you to create any number of text buffers by choosing File:New (for empty text buffers) or File:Open (for existing files). The name of each text buffer appears in the buffer menu. You can cut, copy, and paste text across buffers by choosing items from the Edit menu and selecting buffers from the buffer menu.
You can perform forward and backward search and replace operations by entering strings in the Find text and Replace with entry boxes and clicking on a directional arrow.
If you continue to click on a directional arrow, or if you continue to press the Return key, a repeated search for the string occurs in the direction you indicate.
You can also continue a search by choosing the Edit:Find/Replace Next or Edit:Find/Replace Previous.
When you complete your edits, save these to your file by choosing the File:Save or File:Save As. Then recompile and relink your source file so the changes will take effect.
This section explains how to:
For information about rerunning your program or running another program from the current debugging session, see Section 3.4 and Section 3.5.
To determine where execution is currently paused within your program:
To start program execution or resume execution from the current location, click on the Continue button on the push-button panel (see Figure 2-4) or the Continue item in the pop-up menu on the window or view of your choice.
Once started, program execution continues until one of the following occurs:
Whenever the debugger suspends execution of the program, the source display display is updated and the current-location pointer marks the line whose code will execute next.
Letting your program run freely without debugger intervention is useful in situations such as the following:
If your program does not terminate and you suspect that it is looping, click on the Interrupt button. The source display will show where you interrupted program execution, and the Call Stack menu will identify the sequence of routine calls at that point (see Section 4.3.1).
To execute one source line of your program, click on the Next button on the push-button panel or the Next pop-up menu item in the window or view of your choice. Note that the Next button executes a routine call, but does not step into it.
After the line executes, the source display is updated and the current-location pointer marks the line whose code will execute next.
Executable lines have a toggle button to their left in the source pane.
Nonexecutable lines do not have a toggle button to their left in the source pane.
Keep in mind that if you optimized your code at compilation time, the source code displayed might not reflect the code that is actually executing (see Section 1.4).
When program execution is paused at a routine call statement, clicking on the Next push button executes the called routine in one step. The debugger suspends execution at the next source line in the calling routine (assuming no breakpoint was set within the called routine). "Stepping over" called routines lets you move through the code quickly without having to trace execution. Use the Next button to step over routines.
To "step into" a called routine so that you can execute it one line at a time:
Once execution is within the called routine, click on the Next push button to execute the routine line by line.
Clicking on the Step button when execution is not paused at a routine call statement is the same as clicking on the Next push button.
When execution is suspended within a called routine, you can execute your program directly to the end of that routine by clicking on the Return button on the push-button panel on the Main Window, returning you to the calling routine.
The Return button is particularly useful if you have inadvertently stepped into a routine that is out of the scope of the bug you are tracking.
A breakpoint is a location in your program at which you want execution to stop so that you can perform some action such as checking the current value of a variable, stepping into a routine, etc. When using the window interface, you can set breakpoints on:
A breakpoint with no condition associated with it can be set by using the Break menu, but it is often simpler to click on the toggle push button in the source display.
You can also qualify breakpoints as follows:
You can set a breakpoint that is both a conditional and an action breakpoint. The following sections explain these breakpoint options.
You can set a breakpoint on any source line that has a toggle button to its left in the source pane. These are the lines for which the compiler has generated executable code (for example, routine declarations, assignment statements).
To set a breakpoint on a source line:
The breakpoint is set when the button is filled in. The breakpoint is set at the start of the source line-that is, on the first machine-code instruction associated with that line.
Figure 4-4 shows that a breakpoint has been set on the start of line 14.
To set a breakpoint in the Instruction View:
The Browse Source dialog box displays hierarchical information about all the binary files in your application. For each binary file, it displays information about the modules contained in the binary. For each module, you can display a list of routines in that module.
Setting a breakpoint on a routine enables you to move execution directly to the routine and inspect the local environment.
To set a breakpoint on a routine:
Either of these actions sets a breakpoint at the start of the routine (directly after any prolog code).
In the source pane, the toggle button to the left of the source line that contains the start of the routine is now filled in, confirming that the breakpoint is set. (If the Instruction Window is open, the breakpoint will also display for the corresponding instruction.)
There are two ways to determine which breakpoints are currently set:
Double clicking on an entry in the Breakpoint View expands the one-line entry into a description of the action and condition (if any) that are currently associated with the breakpoint, whether or not the breakpoint is active or deactivated (see Figure 4-6).
After a breakpoint is set, you can deactivate, activate, or delete it.
Deactivating a breakpoint causes the debugger to ignore the breakpoint during program execution. However, the debugger keeps the breakpoint listed in the Breakpoint View so that you can activate it at a later time, for example, when you rerun the program (see Section 3.4). The following are procedures to deactivate or activate breakpoints:
In the Breakpoint View, you can also choose Break:Toggle or press MB3, if the breakpoint is currently activated.
When you delete a breakpoint, it is no longer listed in the Breakpoint View so that later you cannot activate it from that list. You would have to reset the breakpoint as explained in Section 4.4.1 and Section 4.4.2. The following are procedures to delete breakpoints:
A conditional breakpoint suspends execution only when a specified expression is evaluated as true. For example, you can specify that a breakpoint take effect when the value of a variable in your program is 4. The breakpoint is ignored if the value is other than 4.
The debugger evaluates the conditional expression when the breakpoint triggers during execution of your program.
To set a conditional breakpoint:
at line 10 in factorial.c in routine seven at address 0x01024b
The following procedure modifies a conditional breakpoint; it can be used to change the location or condition associated with an existing conditional breakpoint, or to change an unqualified breakpoint into a conditional breakpoint:
When an action breakpoint triggers, the debugger suspends execution and then executes a specified list of commands.
To set an action breakpoint:
at line 10 in factorial.c in routine seven at address 0x01024b
The following procedure modifies an action breakpoint; that is, it can be used to change the command associated with an existing action breakpoint, or to change an unqualified breakpoint into an action breakpoint:
This section explains how to:
Table 4-1 describes options available for selecting and changing variables and values.
Option | Attributes |
---|---|
Local Variables View |
|
Print button |
|
Monitor View |
|
Print Dialog Box | Allows for typecasting. |
Assign Dialog Box | Allows for typecasting. |
Use the following techniques to select variable names from windows.
When selecting names, follow the syntax of the source programming language:
Select character strings from windows in one of the following ways:
For example, suppose the source display contains the character string arr2[m], then:
You can display the current value of a variable or expression as described in Table 4-1.
The following sections describe these methods.
In the Local Variables View, you can monitor the values of all local variables and parameters passed to a routine, as shown in Figure 4-9.
The debugger automatically displays these values. It checks and updates them whenever the debugger regains control from your program (for example, after a step or at a breakpoint).
To monitor a local variable or parameter using the Local Variables View, select Views:Local Variables View or select Views:Manage Views and toggle the Local Variables View button on the Main or Optional Views Window.
The debugger automatically lists all local variable and parameter names (in the Monitor Expression column) and current values (in the Value/Assign column).
You cannot add or remove an entry to the local variables and parameters list. The debugger automatically removes previous entries and adds new entries when a new routine appears at the top of the Call Stack.
To monitor a global variable, use the Monitor View (see Section 4.5.3.3). Section 4.5.3.3 also explains how to monitor an aggregate variable and a pointer variable. The technique is the same whether you use the Monitor View or the Local Variables View.
To display the current value of a variable using the Print button:
When you monitor a variable, the debugger displays the value in the Monitor View and automatically checks and updates the displayed value whenever the debugger regains control from your program (for example, after a step or at a breakpoint).
To monitor a variable or expression with the Monitor View:
If you select the name of an aggregate variable such as an array or structure (record) and click on the Monitor push button, the debugger displays the full type name of the aggregate in the Value /Assign column of the Monitor View. To display the values of all elements (components) of an aggregate variable, double click on the variable name in the Monitor Expression column.
The displayed element names are indented relative to the parent name (see Figure 4-11). If an element is also an aggregate, you can double click on its name to display its elements.
To collapse an expanded display so that only the aggregate parent name is shown in the Monitor View, double click on the name in the Monitor Expression column.
If you have selected a component of an aggregate variable, and the component expression is itself a variable, the debugger monitors the component that was active when you made the selection. For example, if you select the array component arr[i] and the current value of i is 9, the debugger monitors arr[9] even if the value of i subsequently changes to 10.
If the aggregate is a local variable, you can also use the Local Variables View to monitor the aggregate.
If you select the name of a pointer (access) variable and click on the Monitor push button, the debugger displays the address and value of the referenced object in the Value/Assign column of the Monitor View (see Figure 4-12).
If a referenced object is an aggregate, you can double click on its name to display its elements.
If the pointer is local, you can also use the Local Variables View to monitor the pointer.
The Print dialog box allows you to request typecasting or an altered output radix in the displayed result.
To display the current value with the Print dialog box, select the variable or expression using the method described in Section 4.5.2 and click on Print or:
The debugger displays the variable or expression and its current value in the Command Message View.
Your echoed command and the current value appear in the Command Message View.
Figure 4-13 shows a typecast to int for the variable length.
The debugger displays your echoed command and the variable or expression and its current value in the Command Message View.
You can change the value of a variable with either of the following methods:
To change a value monitored within the Local Variables View or Monitor View (see Figure 4-14):
To cancel a text entry and dismiss the text edit box, click on X (Cancel).
You can change the value of only one component of an aggregate variable at a time (such as an array or structure). To change the value of an aggregate variable component (see Figure 4-15):
To change the value of a variable with the Assign dialog box:
Figure 4-16 shows a new value and input radix for the variable prime.
You can also display the Assign dialog box by clicking MB3 in the source pane and selecting Assign from the pop-up menu.
This section provides some general information about accessing program variables while debugging.
If your program was optimized during compilation, you might not have access to certain variables while debugging. When you compile a program for debugging, it is best to disable optimization if possible (see Section 1.4).
Before you check on the value of a variable, always execute the program beyond the point where the variable is declared and initialized. The value contained in any uninitialized variable should be considered invalid.
In most cases, the debugger resolves symbol ambiguities automatically, using the scope and visibility rules of the source programming language. For more information about resolving symbol ambiguities, see Chapter 8.
While debugging a routine in your program, you might want to set the current scope to a calling routine (a routine down the stack from the routine in which execution is currently paused). This enables you to:
The Call Stack menu, shown in Figure 4-17 lists the names of the routines of your program that are currently active on the stack, up to the maximum number of lines that can be displayed on your screen.
The numbers on the left side of the menu indicate the level of each routine on the stack relative to level 0, which denotes the routine in which execution is paused.
To set the current scope to a particular routine on the stack, choose the routine's name from the Call Stack menu; for example, 1:trycol in Figure 4-17. This causes the following to occur:
When you set the scope to a calling routine, the current-location pointer (which is cleared) marks the source line to which execution will return in that routine. Depending on the source language and coding style used, this might be the line that contains the call statement or some subsequent line.
Symbol ambiguities can occur when a symbol is defined in more than one routine or other program unit.
In most cases, the debugger automatically resolves symbol ambiguities. First, it uses the scope and visibility rules of the currently set language. The debugger uses the ordering of routine calls on the call stack to resolve symbol ambiguities.
In some cases, however, the debugger might respond as follows when you specify a symbol that is defined multiple times:
To resolve such problems, you must specify a scope where the debugger searches for the declaration of the symbol you want:
(ladebug) examine swap\x
The Register View displays the current contents of all machine registers (see Figure 2-7).
To display the Register View, choose Views:Register View or Views:Manage Views... and toggle the Register View button. The Register View appears in the Optional Views Window.
By default, the Register View automatically displays the register values associated with the routine in which execution is currently paused. Any values that change as your program executes are highlighted whenever the debugger regains control from your program.
To display the register values associated with any routine on the call stack, choose its name from the Call Stack menu on the Main Window (see Section 4.6.1).
To change the value stored in a register:
The text edit box is removed and replaced by the new value, indicating that the register now contains that value.
To cancel a text entry and dismiss the text edit box, click on X (Cancel).
You can also change the radix for modifying values stored in a register as follows:
The Instruction View displays the decoded instruction stream of your program: the code that is actually executing (see Figure 4-19). This is useful if the program you are debugging has been optimized by the compiler. This means that the information in the Main Window does not exactly reflect the code that is executing (see Section 1.4).
To display the Instruction View, choose Views:Instruction View or Views:Manage Views... and toggle the Instruction View button on the Main or Optional Views Window.
By default, the Instruction View automatically displays the decoded instruction stream of the routine in which execution is currently paused. The current location pointer (to the left of the instructions) marks the instruction that will execute next.
By default, the debugger displays line numbers to the left of the instructions with which they are associated. You can choose not to display these line numbers so that more space is devoted to showing instructions. To hide or display line numbers, choose File:Show Instruction Addresses on the Instruction View.
To copy memory addresses or instructions into a command you are entering at the command-entry prompt, select text and choose Edit:Copy in the Instruction View. Then position your mouse pointer at the command you have entered and choose Edit:Paste on the Main Window. (You can also select instruction text to be used with a push-button command you click in the push-button panel of the Main Window.)
To set breakpoints from the Instruction View, toggle the breakpoint button next to the instruction of interest. The breakpoint is set in the source display, instruction display (if the Instruction View is open), and Breakpoint View (if the Breakpoint View is open). Information on the breakpoint is continuously updated in the source display, and in the Instruction View and Breakpoint View if they are open.
You can also set breakpoints and change breakpoint status by pulling down the Break menu from the Optional Views Window.
After navigating through the Instruction View, to redisplay the location at which execution is paused, click on the Call Stack menu.
To display the instruction stream of any routine on the call stack, choose the routine's name from the Call Stack menu on the Main Window (see Section 4.6.1).
You can customize the debugger's window interface in two ways:
Table 4-2 shows the methods you use to customize parameters.
Use This Method | To Change These Parameters |
---|---|
Customize... dialog box |
|
Edit debugger (ladebugresource) resource file |
|
The following sections discuss using these methods to customize the debugger window interface.
To define the startup configuration of the debugger windows and views:
When you later start the debugger, the new configuration appears automatically. Adding views to the startup configuration increases the startup time accordingly.
The source pane displays source line numbers by default at debugger startup. To hide (or display) line numbers at debugger startup:
When you later start the debugger, line numbers are either displayed or hidden accordingly.
The push buttons on the push-button panel are associated with debugger commands. You can:
To save these modifications for subsequent debugger sessions, choose Options:Save Options on the Main Window or an optional view. This creates a new version of the debugger resource file with the new definitions.
The following sections explain how to customize push buttons interactively through the window interface. You can also customize push buttons by editing the resource file (see Section 4.9.4).
To change a button's label or the debugger command associated with a push button:
If the command is to operate on a name or language expression selected in a window, include %s in the command name. For example, the following command displays the current value of the variable that is currently selected:
print %s
If the command is to operate on a name that has a percent sign (%) as the first character, specify two percent signs.
To add a new button to the push-button panel and assign a debugger command to that push button:
To remove a push button:
To resequence a button:
The debugger is installed on your system with a debugger resource file (ladebugresource) that defines startup defaults.
When you first choose Options:Save Options on the Main or Optional Views Window, the debugger creates your own local debugger resource file in your home directory.
When you subsequently start the debugger, it uses the settings defined in your local resource file (such as window configuration) and uses the system default resource file for the other settings (such as character fonts). Whenever you choose Save Window Configuration, a new version of your local resource file is created.
Using the system default file as reference, you can add customized resource settings to your own local file. When you subsequently choose Options:Save Options, the debugger automatically copies these added settings to the new version of your local file.