Chapter 8. Debugging with Fix+Continue

Fix+Continue allows you to make changes to a C++ program you are debugging without having to recompile and link the entire program. With Fix+Continue you can edit a function, parse the new function, and continue execution of the program being debugged.

Fix+Continue is an integral part of the Debugger. You issue Fix+Continue commands graphically from the Fix+Continue submenu of the Main View window, or from the cvd command line prompt in the Command/Message pane of the Main View window.

This chapter provides an introduction to the Fix+Continue functionality as well as a tutorial to demonstrate many of the Fix+Continue functions.

Fix+Continue Functionality

Fix+Continue lets you perform the following activities:

  • Redefine existing function definitions.

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

  • Set breakpoints in redefined code.

  • Single-step within redefined code.

  • View the status of changes.

  • Examine differences between original and redefined functions.

A typical Fix+Continue cycle proceeds as follows:

  1. You redefine a function with Fix+Continue. When you continue executing the program, the Debugger attempts to call the redefined function. If it cannot, an information pop-up window appears and the redefined function is 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.

During debugging you can review the status of changes by listing them, showing specific changes, or looking at the Fix+Continue Status View. You can compare changes to an individual function or to an entire file with the compiled versions. When you are satisfied with the behavior of your application, save the changed file as a replacement for the compiled source.

Fix+Continue Integration with Debugger Views

Fix+Continue interacts with the following Views:

  • The Views main view, the Source View, and Fix+Continue Status windows distinguish between compiled and redefined code, and allow editing in redefined code.

  • The following status windows elements work with redefined code:

    • Call Stack window

    • Trap Manager

    • Debugger command line

How Redefined Code Is Distinguished from Compiled Code

Redefined functions have an identification number and special line numbers. They are color-coded according to their state (that is, 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), where n is the compiled line number where the function body begins, and m is the line number relative to the beginning of the function body, starting with the number 1.

The Call Stack window and the Trap Manager functions 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. Therefore, you can operate on several files at once.

The Fix+Continue Interface

You can access Fix+Continue through the Fix+Continue menu. It includes three supporting windows: Status, Message, and Build Environment. These windows are part of Fix+Continue, and do not operate unless it is installed.

Debugger with Fix+Continue Support

Without Fix+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) remains Read-Only. This is because edits made using Fix+Continue are saved in an intermediate state. Instead, you must choose Save File -> Fixes As to save your edits.

When you edit a function, it is highlighted in color; and if you switch to the compiled version of your code, the color changes to show that the function has been redefined. If you try to edit the compiled version of your code, the Debugger beeps indicating Read-Only status.

When you have completed your edits and want to see the results, select Parse and Load. When the parse and load has executed successfully, the color changes again. If the color does not change, there may be errors: check the Message Window.

Change ID, Build Path, and Other Concepts

The Fix+Continue features finding files and accessing functions through ID numbers as follows:

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

  • Fix+Continue needs to know the location of include files and other parameters specified by compiler build flags. 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 menu, the command line, or the Fix+Continue Status Window. When you finish a Fix+Continue session, you can unset the build environment.

  • Output from a successful run is displayed in the Execution View. This functionality is the same as it is in the Debugger without Fix+Continue.

Restrictions on Fix+Continue

Fix+Continue has the following restrictions:

  • When you work with C code, you must use the -o32 compiler option.

  • Fix+Continue does not support C++ templates.

  • You may not add, delete, or reorder 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 function.

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

    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 the function is called.

  • If you redefine functions that are in but not on top of the call stack, the modified code is not executed when they combine. Modified functions are executed only on their next call or on a rerun.

    For example, consider the following call stack:

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

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

    • If you redefine main() after you have begun execution, the redefined main() is executed only when you rerun.

    • If you redefine bar() or foobar(), the new code is not executed when foo() returns. It is executed only on the next call of bar() or foobar().

Fix+Continue Tutorial

This tutorial illustrates several features of Fix+Continue. The demo files included in /usr/demos/WorkShop/time1 contain the complete C++ source code for the program time1. Use this program for your tutorial. Here you see how Fix+Continue can modify functions without recompiling and linking the entire program.

This section contains the following subsections:

Setting up the Sample Session

For this tutorial, use the demo files in the /usr/demos/WorkShop/time1 directory that contains the complete source code for the C++ application time1. To prepare for the session, you must create the fileset and launch Fix+Continue from the Debugger as shown below:

  1. Enter the following commands:

    % cd demos
    % mkdir time1
    % cd time1
    % cp /usr/demos/WorkShop/time1/* .
    % make time1
    % cvd time1 &

    The cvd command brings up the Debugger, from which you can use the Fix+Continue utility. The Execution View icon and the Main View window appear. Note that the Debugger shows a source code status indicator of (Read Only).

  2. Open the Execution View window and position it next to the Main View window.

  3. Click Run to run time1.

    The Execution View shows the program output (see Figure 8-1).

    Figure 8-1. Program Results in Execution View

    Program Results in Execution View

Redefining a Function: time1 Program

In this section, you will do the following in the time1 program:

  • Edit a C/C++ function.

  • Change the code of an existing C/C++ function and then parse and load the function, rebuilding your program to see the effect of your changes on program output (without recompiling).

  • Save the changed function to its own separate file.

Editing a Function

Perform the following in the Debugger Main View window (the time1 program should be displayed) to edit a function:

  1. Select Display ->  Show Line Numbers from the Main View window menu bar to show line numbers.

  2. Click on the source annotation column to the left of line 17 to set a breakpoint at that point.

  3. Set a breakpoint at line 20 from the cvd command line as follows:

    cvd> stop at 20

  4. Click on the Run button to execute the program.

    The following output appears in the Execution View window:

    First printing of time:
    
    08:20:50
    ***************
    

  5. Enter the following at the cvd command line to choose a class member function to edit (in this case, printTime, a C++ member function of class Time):

    cvd> func Time::printTime

    This command opens the time1/time1.c file, which contains the implementation of class Time. The cursor is placed at the beginning of the printTime function. See Figure 8-2. The syntax of the func command is as follows:

    • For C++ class member functions:

      cvd> func className::classMemberFunction

    • For all other C/C++ functions:

      cvd> func functionName

    Figure 8-2. Selecting a Function for Redefinition

    Selecting a Function for Redefinition

  6. Select Fix+Continue -> Edit from the menu bar to highlight the function to be edited. You can also use Alt-Ctrl-e to do this.

    Note the results as shown in Figure 8-3. Line numbers changed to a decimal notation based on the first line number of the function body. The function body highlights to show that it is being edited. The line numbers of the rest of the file are not affected.

    Figure 8-3. Redefined Function

    Redefined Function

Changing Code

  1. To change the time output as shown in Step 5 in “Editing a Function”, delete the 0 from "0" in line 23.2.

  2. Select Fix+Continue -> Parse And Load from the menu bar to parse the modified function and load it for execution.

    An icon for the Fix+Continue Error Messages window displays and the following message appears in the cvd window:

    Change id: 1 modified

    If there are errors:

    1. Go to the error location(s) by double-clicking the related message line in the Fix+Continue Error Messages window.

    2. Correct the errors.

    3. Repeat steps 1 and 2.

    Continue to step 3 when you see the change ID and the following messages:

    Change id: 1 redefined
    Change id: 1 saved func
    Change id: 1 file not saved
    Change id: 1 modified

    The new function value is not active until the function is called.

  3. Click on the Continue button to continue program execution.

    The following output appears in the Execution View window:

    Second printing of time:
    
    8:20:50
    ***************

    Notice how the time printout has changed from 08:20:50 to 8:20:50.

Deleting Changed Code

To cancel any of your changes, you must bring up the source file in which the change was made and perform the following steps:

  1. Enter the following at the cvd command line:

    cvd> func Time::printTime

  2. Select Fix+Continue ->  Delete Edits from the menu bar to delete your changes.

    The Verify before deleting dialog displays.

  3. Click OK in the Verify before deleting dialog.

    Your deletion is complete.

Changing Code from the Debugger Command Line

You can redefine a C++ class member function from the Debugger command line as follows:

  1. Click on the Kill button in the Main View window.

  2. Click on the Run button to re-run the program.

  3. Choose a class member function (in this case, printTime) to edit by entering the following at the cvd command line:

    cvd> func Time::printTime

  4. Use the redefine command to edit the function:

    cvd> redefine Time::printTime

    Note the results as shown in Figure 8-3. Here, line numbers have changed to decimal notation based on the first line number of the function body. Note also that the command line prompt has changed.

  5. Enter the following at the prompt:

    "/path/name/time1.C":23.1> .

  6. Change the function source by entering the following at the command line:

    cvd> replace_source "time1.C":23.2
    "time1.C:23.2> cout << (hour < 10 ? "" : "") << hour << ":"
    "time1.C:23.3> .

    Parse and Load is executed at this point. You exit out of the function edit mode are return to the main source code. The following messages appear in the command/message pane:

    Change id: 2 redefined
    Change id: 2 save func
    Change id: 2 file not saved
    Change id: 2 modified
    Change id: 2 , build results:
           2     enabled .../time1.C Time::printTime(void)


    Note: 2 in these messages is the redefined function ID. You use this ID in the procedure in “Switching between Compiled and Redefined Code”. The new function value is not active until the function is called.


  7. Continue execution by entering the following command at the cvd command line:

    cvd> continue

    The following displays in the Execution View window:

    Second printing of time:
    
    8:20:50
    ***************

If you prefer to use the command line, experiment with add_source and other commands that give you the same functionality described for the menu commands. For details on each command, see the ProDev WorkShop: Debugger Reference Manual.

Saving Changes

Your original source files are not updated until the changed source file is saved. You could save redefined function changes to the time1.C file. However, if you did, the file would not match the tutorial. So perform the following steps:

  1. Enter the following command:

    cvd> func Time::printTime

  2. Select Fix+Continue ->  Save As from the menu bar.

    A file_name dialog box opens.

  3. The dialog box enables you to save your file changes back to the original source files or save them to a different file. However, since you do not want to save your changes, press the Cancel button on the bottom of the dialog box.


Note: You should wait until you are finished with Fix+Continue before you save your changes. In addition to the method described above, you can also save your changes by selecting Fix+Continue ->  Save All Files.


Setting Breakpoints in Redefined Code

To see how the Debugger works with traps in redefined code, this section shows you how to set breakpoints, run the Debugger, and view the results.

  1. Reset to the beginning of program execution by entering the following at the cvd command line:

    cvd> kill
    cvd> run   

  2. Bring up the time1.C source file by entering the following at the cvd command line:

    cvd> func Time::printTime

  3. Select Fix+Continue ->  Edit from the menu bar. You can also use the Alt-Ctrl-e accelerator to do this.

  4. Enter the following after line 23.4 in the source pane of the Main View window:

    cout << " AM"<< endl;

  5. Select Fix+Continue ->  Parse And Load from the menu bar.

  6. Bring up the time1.C source file again by entering the following command at the cvd command line:

    cvd> func Time::printTime

  7. Set a breakpoint at line 23.6 by entering the following message at the cvd command line:

    cvd> stop at 23.6

    The following message appears in the Command/Message pane:

    [2] Stop at file /path/name/time1.C line 23.6

  8. Click on the Cont button in the Main View window.

  9. Select the following from the menu bar to see the results of continuing to the breakpoint: Views ->  Call Stack.

  10. Select the following from the menu bar to view the locations of the breakpoints: Views ->  Trap Manager.

  11. Remove the breakpoint by clicking on the source annotation column to the right of line 23.6.

To view status, select the following from the menu bar: Fix+Continue -> View -> Status Window. The Fix+Continue Status window opens.

Comparing Original and Redefined Code

You can use Fix+Continue to compare original code with and modified code. This section shows you several ways to view your changes.

Switching between Compiled and Redefined Code

Follow these steps to see how the redefined code affects your executable:

  1. Click the Run button to view your redefined code. If you are following procedures in order in this section, you should see the following display:

    8:20:50 AM

  2. Enter the following at the cvd command line:

    cvd> func Time::printTime

  3. Select Fix+Continue ->  Parse and Load from the menu bar.

  4. Select Fix+Continue ->  Edited<-->Compiled from the menu bar to disable your changes.

  5. Click the Continue button to see the printing of Time as in the original executable. The following displays:

    08:20:50

  6. Re-enter the following at the cvd command line:

    cvd> func Time::printTime

  7. Select Fix+Continue ->  Edited<-->Compiled from the menu bar to re-enable your changes.

  8. Click on the Run button to see the changed printout of Time. The following displays:

    08:20:50 AM

Comparing Function Definitions

  1. Place the cursor in the time1.C function.

  2. Select Fix+Continue ->  Show Difference -> For Function from the menu bar.

    A window opens to display an xdiff comparison of the files as follows:

    Figure 8-4. Comparing Compiled and Redefined Function Code

    Comparing Compiled and Redefined Function Code

    You can get the same result by entering the show_diff # command from the Debugger command line, where # is the redefined function ID.

    If you do not like xdiff, you can change the comparison tool by selecting Fix+Continue -> Show Difference ->  Set Diff Tool from the menu bar.

Comparing Source Code Files

If you have made several redefinitions to a file, you may need a side-by-side comparison of the entire file. To see how changes to the entire file look, select Fix+Continue -> Show Difference ->  For File from the menu bar. This opens an xdiff window that displays the entire file rather than just the function.

You can get the same comparison results from the Debugger command line if you enter the following command:

show_diff -file time1.C

Ending the Session

Exit the Debugger by selecting Admin ->  Exit from the menu bar.