Chapter 1. Getting Started with the WorkShop Debugger

The WorkShop Debugger is a UNIX source-level debugging tool that provides special windows (views) for displaying program data and execution status. These views update as the program executes. This chapter presents an overview of the WorkShop Debugger and is divided into these sections:

Typical Debugger Usage

This section provides a general description of debugging software with WorkShop. It covers these topics:

Starting and Exiting the Debugger

To start the Debugger, you use the following syntax:

cvd [-pid pid] [-host host] [executable [corefile]] [&]

The -pid option lets you attach the Debugger to a running process. You can use this to determine why a live process is in a loop.

The argument executable is the name of the executable file for the process you want to run. It is optional; you can invoke the Debugger first and specify the executable later.

You can also invoke the Debugger and specify a core file (with its executable) to try to determine why a program crashed.

To exit the Debugger, select "Exit" from the Admin menu in the Main View window. You have two other options: you can type quit at the Debugger command line or press <Ctrl-c> where you first entered cvd into a terminal. You can also double-click the window system menu, or select its "Quit" entry.

Using the Debugger From a Remote Host

The -host option lets you specify a remote host on which the target executable will be run; the Debugger runs locally. This option is useful if

  • you don't want the Debugger windows to interfere with the application you are debugging

  • you are supporting an application remotely

  • you don't want to use the Debugger on the target machine for some other reason

Using Main View

Starting the Debugger with an executable brings up the Main View window, loaded with the source code, and ready to run the process with any specified arguments. You perform most of your work in Main View, which provides

  • a menu bar for performing Main View functions and for accessing other views

  • a control panel for specifying and controlling the process to be debugged

  • a source code display area for inspecting the source code

  • a status line for viewing the state of the program

  • the Debugger command line for entering special debugging commands (see "Debugger Command Line" for the syntax)

The major areas of the Main View window are shown in Figure 1-1.

Figure 1-1. Major Areas of the Main View Window

Figure 1-1 Major Areas of the Main View Window

Setting Traps

A major part of the debugging process is inspecting data at points during execution. A trap is a mechanism for gathering this data. A stop trap halts the process so that you can manually examine data. A sample trap collects specified performance data without stopping.

The Debugger lets you set traps:

  • at a line in a file (breakpoint)

  • at an instruction address

  • on entry to or exit from a function

  • when a signal is received

  • when a system call is made, at either the entry or exit point

  • when a given variable or address is written to, read from, or executed (watchpoint)

  • at set time intervals (pollpoint)

For more information on traps, refer to Chapter 4, "Setting Traps."

Inspecting Debugger Data

When you stop the process, you then have a number of options for examining the data. You can inspect

  • the call stack at the breakpoint (using Call Stack)

  • the value of specified expressions (using Expression View)

  • the values, types, or addresses of variables (using Variable Browser)

  • data structures (using Structure Browser)

  • the values of an array variable (using Array Browser)

  • values in specified memory locations (using Memory View) or registers (using Register View)

  • the disassembled code (using Disassembly View)

For more information on the standard Debugger views, refer to Chapter 6, "Examining Debugger Data."

Changing Source Code

To change your source code and recompile, follow these steps:

  1. Switch to a text editor ("Fork Editor" selection in Source menu) or edit in Main View ("Make Editable" in Source menu).

    If you are using a configuration management system, then you can check out the source code, by selecting "Versioning" from the Source menu and accessing the source through the configuration management shell.

  2. Make any changes and save them. In the Main View, pull down the Source menu and select "Save..."

  3. In the Main View, pull down the Source menu and select "Recompile."

    The Build View window displays and lets you start the compile. Any compile errors are listed in the window, and you can access the related source code by clicking the errors. For more information on the Build Manager, refer to Appendix B, "Using the Build Manager."

    When the code is rebuilt successfully, the new executable reattaches automatically to the Debugger and Static Analyzer. Previously set traps are intact unless you have traps triggered at line numbers and have changed the line count.

Updating and Saving Views

Updating and saving view data is done through the Admin menu in the particular view (see Figure 1-2).

Figure 1-2. Admin Menu in Debugger Views

Figure 1-2 Admin Menu in Debugger Views

Typically, you display the WorkShop views of interest when you are stopped at a trap and leave them on the screen as you run the process.

"Active"  

Updates the view each time the process stops or if the context is changed in the Call Stack View window. The active state is the default.

"Clone" 

Makes a duplicate, inactive copy of the view, allowing you to save current information for future reference.

"Save As Text..." 


Lets you save the data currently displayed in a view to a text file. Note that not all views have the "Save as Text..." option.

"Close" 

Closes the window of the view.

Integration With Other WorkShop Tools

The WorkShop tools are designed so that you can move easily between them in a work session.

Accessing the Performance Analyzer From Main View

You can switch to the Performance Analyzer at any time while debugging. Selecting "Performance Task..." from the Admin menu lets you enable data collection for your experiment. A performance task must be specified before the process is run; this enables the correct data collection. If you are in the middle of a run, you must terminate it, select a task, and restart the target to collect the data. Selecting "Performance Analyzer" from the "Launch Tool" submenu displays the main Performance Analyzer for analyzing the experiment results.

Accessing the Static Analyzer From Main View

You can access the Static Analyzer from the "Launch Tool" submenu, if desired. The Static Analyzer displays source information from Main View, making it easy to set traps in source code located by the Static Analyzer. Note that the Query menu enables you to conduct some of the same queries as in the Static Analyzer.

Accessing Editors From Main View

After you solve a problem with the WorkShop tools, you may wish to make the change in Source View (or your preferred editor) and then recompile.

Accessing Configuration Management Tools

If you use ClearCaseÔ (available from Silicon Graphics), RCS, or SCCS for configuration management, you can integrate the tool into the WorkShop environment by typing

cvconfig [clearcase | rcs | sccs] 

This enables the "Versioning" in the Source menu, which provides selections for checking files in and out.

Recompiling From Main View or Source View

To access the Build View window (which lets you start the compile), in the Main View, pull down the Source menu and select "Recompile." To examine the build dependencies, in the Main View, pull down the Admin menu and select "Build Analyzer." For more information on the Build Manager tools, see Appendix B, "Using the Build Manager."

Debugging with Fix+Continue

Fix and Continue is integrated with the Debugger. You issue Fix and Continue commands graphically from the Fix+Continue pulldown menu of the Debugger main window. You may also issue Fix and Continue commands from the Debugger command line (cvd>).

Redefining Functions Using Fix and Continue

Fix and Continue gives you the ability to make changes to a program you are debugging without having to recompile and link the entire program, and then continue debugging the code. With Fix and Continue, you can edit a function, parse the new function, and continue execution of the program being debugged. Fix and Continue enables you to speed up your development cycle significantly.

Table 1-1 compares the cycle time in seconds between a full rebuild and a Fix and Continue for three typical programs.

Table 1-1. Fix and Continue Compile Time Cycle

Example

Time to Rebuild

Time to Fix+Continue

Program A

0:06

0:02

Program B

0:33

0:06

Program C

5:24

0:49


Fix and Continue Functionality

Fix and Continue lets you:

  • Redefine existing function definitions

  • Disable, re-enable, save, and delete redefinitions

  • Set breakpoints in and single-step within redefined code

  • View the status of changes

  • Examine differences between original and redefined functions

The basic cycle of using Fix and Continue is shown in Figure 1-3.

Figure 1-3. Fix and Continue Cycle

Figure 1-3 Fix and Continue Cycle

A typical session would be the following:

  1. Using the Fix and Continue commands, you redefine a function. When you continue executing the program, the Debugger attempts to call the redefined function. If it cannot, an information popup appears, and the redefined function will be executed the next time the program calls that function.

  2. You redefine other functions, alternating between debugging, disabling, re-enabling, and deleting redefinitions. You might save function redefinitions to their own files, or save files to a different name, to be used later with the present or with other programs.

Frequently during debugging you can review the status of changes by listing them, showing specific changes, or looking at the Fix and Continue Status View. You can compare changes to an individual function or to an entire file with the compiled versions. When satisfied with the behavior of your application, you save the file, replacing the compiled source.

Fix and Continue/WorkShop Integration

Using Fix and Continue affects these WorkShop tools:

  • The WorkShop Debugger Main View, the Source View, and the Fix and Continue Status window make a clear distinction between compiled and redefined code, and allow editing only in redefined code.

  • The different WorkShop views that are knowledgeable about redefined code:

    • Call Stack

    • Trap Manager

    • Debugger command-line

How Redefined Code Is Distinguished From Compiled Code

Redefined functions have an identification number and special line numbers, and in the Debugger views are color-coded according to their state (edited, parsed, and so on).

Line numbers in the compiled file stay the same, no matter how redefined functions change. However, when you begin editing a function, the line numbers of the function body are represented in decimal notation (n.1, n.2, ..., n.m). n is the compiled line number where the function body begins. m is the line number relative to the beginning of the function body, starting with 1.

Figure 1-4 shows two redefined functions. Function 1 replaces lines 8-15. Function 2 replaces lines 18-20. Although its three lines are now one, the following line number is still 21.

Figure 1-4. Line Numbers in Decimal Notation

Figure 1-4 Line Numbers in Decimal Notation

The Call Stack and Trap Manager both use function-relative decimal notation when referring to a line number within the body of a redefined function.

The Debugger command line reports ongoing status. In addition to providing the same commands available from the menu, edit commands allow you to add, replace, or delete lines from files. You can easily operate on several files at once.

Restrictions on Fix and Continue

Fix and Continue has the following restrictions when you fix a function in which you have stopped:

  • You may not add, delete, or reorder the local variables in a function.

  • You may not change the type of a local variable.

  • You may not change a local variable to be a register variable, and vice- versa.

  • You may not add any function calls that increase the size of the parameter area.

  • You may not add an alloca function to a frame that did not previously use an alloca.

  • Both the old and new functions must be compiled with -g.

    In other words, the layout of the stack frames of both the old and new functions must be identical for you to continue execution in the function that is being modified. If not, execution of the old function continues, and the new function is executed the next time it is called.

  • If you redefine functions which are in but not on top of the call stack, the modified code will not be executed when they combine. Modified functions will be executed only on their next call or on a re-run.

    For example, consider the following call stack:

    foo()
    bar()
    foobar()
    main()

    1. If you redefine foo(), you can continue execution provided the layout of the stack frames are same.

    2. If you redefine bar() [or foobar()], the new code will not be executed when foo() returns. The code will be executed only on the next call of bar() [or foobar()].

    3. If you redefine main() after you have run, it will be executed only when you re-run.

The Fix and Continue Environment

The interface to Fix and Continue is through the Fix+Continue menu and its associated windows: Status, Message, and Build Environment. These windows are completely dependent on Fix and Continue, and do not operate unless it is installed.

For more complete information on all of the Fix and Continue menus, windows, and functions, see "Fix+Continue Windows".

Debugger With Fix and Continue Support

Without Fix and Continue, the Debugger source views are Read-Only by default. That is so you can examine your files with no risk of changing them. When you select "Edit" from the Fix+Continue menu, the Debugger source code status indicator (in the lower-right corner of the Debugger window—see Figure A-1) remains Read-Only. Fix and Continue edits are saved in an intermediate state and must be explicitly written with the "Save File+Fixes As..." option to be saved.

When you edit a function, it is color-highlighted. Then, if you switch to the compiled version, the color changes to show that there is a redefinition. If you try to edit the compiled version, the Debugger beeps, indicating it is Read-Only.

When you have completed your edits and wish to see the results, click "Parse and Load." When the Parse and Load has executed successfully, the color changes again. If the color doesn't change, there may be errors, and you should check your "Message Window..." view.

GUI Debugger Command Line

Just as you can enter any dbx command at the Debugger command line, you can enter Fix and Continue commands there.

Change ID, Build Path, and Other Concepts

The Fix and Continue methods for accessing functions through ID numbers, finding files, and so forth, are discussed below.

  • Each redefined function is numbered with a change ID. Its status is redefined, enabled, disabled, deleted, or detached.

  • Fix and Continue needs to know where to find include files and other parameters specified by compiler build flags (compiler options). You can set the build environment for all files or for a specific file. You can display the current build environment from the Fix+Continue pulldown menu, the command line, or the Fix and Continue Status Window. When you finish a Fix and Continue session, you can unset the build environment.

A successful run results in output in the Execution View. This functionality is the same as it is in the Debugger without Fix and Continue.

Debugging with the X/Motif Analyzer

The X/Motif analyzer is integrated with the Debugger. You issue X/Motif analyzer commands graphically from the X/Motif analyzer subwindow of the main Debugger window (see Figure 1-5). To access the subwindow, you must pull down the Views menu and select "X/Motif Analyzer"

Figure 1-5. Launching the X/Motif Analyzer

Figure 1-5 Launching the X/Motif Analyzer

Special Libraries

When you first bring up the X/Motif Analyzer, it may ask you if you want to change $LD_LIBRARY_PATH to include /usr/lib/WorkShop/Motif. In that directory are instrumented versions of the Silicon Graphics Xlib, Xt, and Xm libraries. These versions include debugging symbols and special support for X/Motif Analyzer functions.

It is strongly recommended that you click OK to the dialog and use these libraries. Doing so enables all of the features of the X/Motif Analyzer. These libraries are identical in functionality to the libraries shipped with IRIX 5.3. The analyzer uses the Silicon Graphics enhanced version of these libraries. There are no instrumented MIPS/ABI versions of the libraries.

Using the X/Motif Analyzer

The X/Motif Analyzer provides specific debugging support for X/Motif applications. There are various examiners for different X/Motif objects (for example, widgets and X graphics contexts) that are normally difficult or impossible to inspect using ordinary debugger functionality. Also, you can set widget-level breakpoints and collect X event history information (in the same manner as xscope).

Examiners Overview

When you first bring up the X/Motif Analyzer, you see the Widget examiner. It may be blank or displaying a Widget that it found on the callstack if you have a stopped process. Most of the examiners in the X/Motif Analyzer try to detect interesting objects from the callstack and offer to display them for you, automatically.

At the bottom of the X/Motif Analyzer is a tab panel showing the current set of examiners. Besides the Widget examiner, the Breakpoints, Tree, and Trace examiners are available by default. These four tabs are always present.

To bring up new examiners, use the Examine menu and select one from below the separator. Some examiners (for example, the Callback examiner) cannot be manually selected—they appear only when the callstack context is appropriate. In the case of the Callback examiner, it appears only when the process is stopped somewhere in a widget callback.

To remove an examiner from the tab panel, put the pointer over the tab, click the right button of your mouse, and select 'Remove Examiner' from the popup menu. The tab disappears.

Examiners and Selections

If you select text in one examiner and then choose another using the Examine menu, the new examiner is brought up and the text is used as an expression for it. If you selected text that evaluated to an inappropriate object for the new examiner, an error is generated.

Alternatively, you can select text, pull down the Examine menu, and choose "Selection." The X/Motif Analyzer attempts to select an appropriate examiner for the type of the selected text. If the type of the text is unknown, the error Couldn't examine selection in more detail is generated. Otherwise, the appropriate examiner is chosen and the text is evaluated.

You can accomplish the same thing by triple-clicking the line of text. If the type of the text is unknown, nothing happens. Otherwise, the appropriate examiner is chosen and the text is evaluated.

Inspecting Data

X/Motif applications consist of collections of objects (Motif widgets) and make extensive use of X resources such as windows, graphics context, and so on. The construction model of an X window system hinders you from inspecting the internal structures of widgets and X resources because you are presented with ID values. The X/Motif Analyzer provides inspection capability for you to see into the data structures behind the ID values.

Inspecting the Control Flow

Traditional debuggers enable you to set breakpoints only in source lines or functions. With the X/Motif Analyzer, you can set breakpoints for specific widgets or widget classes, for specific control flow constructs like callbacks or event handlers, and (at a lower level) for specific X events or requests.

Tracing the Execution

The X/Motif Analyzer can trace Xlib-level server events and client requests, Xt-level event dispatching information, widget life cycle, and widget status information.

Restrictions and Limitations

Due to implementation details, there are several nuisances that currently pose some restrictions to the X/Motif Analyzer:

  • The Breakpoints area is active only after you've stopped the process once, and if you've changed $LD_LIBRARY_PATH.

  • Sometimes, gadget names may be unavailable and are displayed as <object>.You can minimize this condition by getting the widget tree beforehand.

  • editres-type requests (widget selection and widget tree) work only if the process is running or if the process is stopped outside of a system call. This can be annoying when the process is stopped in select(), waiting for an X server event.

  • The process state and appearance of the cvd Main View flickers while the X/Motif Analyzer tries to complete an editres request when the process is stopped.

  • editres requests may be unreliable if the process is stopped.

Customizing the Debugger

If there are Debugger commands or combinations of Debugger commands that you use frequently, you may find it convenient to create a script composed of Debugger commands. Debugger scripts are ASCII files containing one Debugger command with its arguments per line. A Debugger script can in turn call other Debugger scripts. There are three general methods for running scripts:

  • Entering the source command and the filename at the Debugger command line—this is useful for scripts that you need only occasionally.

  • Including the script in a startup file—this is useful for scripts that you want implemented every time you use the Debugger.

  • Defining a button in the graphical interface to run the script—use this method for scripts that you use frequently but apply only at specific times in a debugging session

Using a Startup File

The startup file feature lets you preload your favorite buttons and aliases in a file that runs when cvd is invoked. It's also useful if you have traps that you set the same way each time. The suggested name for the startup file is .cvdrc; you can supply a different name as long as you specify its path in the environment variable CVDINIT. The steps in the algorithm that cvd follows when looking for a startup file are:

  1. Check the environment variable CVDINIT.

  2. Check for the file .cvdrc in the current directory.

  3. Check for the file .cvdrc in the user's home directory.

Implementing User-Defined Buttons

If there are Debugger commands or combinations of Debugger commands that you use frequently, you may find it convenient to define a button for the graphical interface. You can implement buttons by providing a special Debugger startup file or by creating them on the fly within a debugging session. Buttons appear in order of implementation in a row at the bottom of the control panel area. Currently, you can define only one row of custom buttons. Figure 1-6 is a typical example of Main View with user-defined buttons. The definitions for the user-defined buttons display in the Debugger command line area.

Figure 1-6. User-Defined Button Example

Figure 1-6 User-Defined Button Example

The syntax for creating a button is

button label command [$sel]

The syntax for creating a multiple-command button is

button label {command1 [$sel]; command2 [$sel]; ...}

where

button is the Debugger command for defining buttons. It can be applied at the Debugger command line or in a startup file.

label is the name appearing on the button. Button labels should be kept short since there is only room for a single row of buttons. There can be no spaces in a label.

command is one of the the Debugger commands, which are entered at the command line at the bottom of Main View. See "Debugger Command Line".

$sel is a substitute for the current cursor selection and should be appropriate as an argument to the selected command.

command1, command2 (and any additional commands) are Debugger commands to be applied in order. They must be separated by semicolons (;) and enclosed by braces ({}). The multiple-command button is a powerful feature; it lets you write a short script to be executed when you click the button.

The following syntax

button 

displays a list of all currently defined buttons.

The syntax

unbutton label

deletes the button corresponding to the label. You might use this if you needed room to implement different buttons. The effect of unbutton is temporary so that subsequently running the startup file reactivates the button.

The syntax

button label

displays the button's definition if it exists. If the button does not exist, an error message displays along with the standard usage syntax for button.