═══ 1. Special Notices ═══ References in this tutorial to IBM products, programs, or services do not imply that IBM intends to make these available in all countries in which IBM operates. Any reference to an IBM licensed program in this online information is not intended to state or imply that only IBM's licensed program may be used. Any functionally equivalent product, program or service that does not infringe any of IBM's intellectual property rights may be used instead of the IBM product, program, or service. Evaluation and verification of operation in conjunction with other products, except those expressly designated by IBM, is the user's responsibility. IBM may have patents or pending patent applications covering subject matter in this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries, in writing, to the IBM Director of Commercial Relations, IBM Corporation, Purchase, NY 10577. This online information could contain technical inaccuracies or typographical errors. This tutorial may contain examples of data and reports used in daily business operations. To illustrate them as completely as possible, the examples may include names of individuals, companies, brands, and products. All of these names are fictitious and any similarity to the names and addresses used by an actual business enterprise is entirely coincidental. ═══ 1.1. Trademarks and Service Marks ═══ The following terms, denoted by an asterisk (*) in this online information, are trademarks of the IBM Corporation in the United States and/or other countries: C Set ++ IBM OS/2 Operating System/2 Presentation Manager WorkFrame/2. ═══ 2. Start Here ═══ The IBM* C/C++ Debugger uses Presentation Manager* (PM) window services to help detect and diagnose errors in code developed in IBM 32-bit C/C++. The debugger has a graphical user interface and debugs PM and non-PM (single or multi-threaded) applications. It also features a number of C++-related debugging features. You will interact directly with the debugger while viewing this tutorial. To continue, click on the Forward push button. ═══ 2.1. About This Tutorial ═══ This tutorial guides you through three sample debugging sessions. The series of steps in these debugging sessions do not necessarily represent the most efficient way to debug any of the sample programs. However, the main objective of this tutorial is to show you how to use as many of the debugger features as possible. Work through the lessons in the tutorial in the correct order. Do not skip any steps; each step builds on the work you do in the previous steps. This tutorial is organized into two main parts: Debugger Features for C Programming This part contains Lesson 1, which takes you through a sample debugging session using the program DPMLINES. The code in this program has an error. You will use the debugger tutorial to locate the error in the program. Debugger Features for C++ Programming This part contains Lesson 2 and is used to introduce you to the C++ features. Lesson 2 uses the sample programs MCELCV and NEST. There is one error in NEST that you will learn how to fix. This tutorial takes approximately 2 hours to complete. Select Navigating in the Tutorial for information on how to navigate through the tutorial, ═══ Navigating in the Tutorial ═══ There are several ways to navigate through the tutorial. You can use the push buttons, scroll bars, and keyboard keys. The push buttons at the bottom of this window allow you to navigate within the tutorial. Previous Takes you to the window you saw before the current one. You may have gotten here by pressing Forward, Backward, or you may have gotten there from a link, such as an index entry. You can also do this with the Esc key. Print Prints the tutorial if your system is attached to a printer. Back Moves backward one page in sequential order, regardless of how you got to the current page. Forward Moves forward one page in sequential order. For more information on using this Help facility, select Using Help from the Help menu in this window. ═══ 2.2. Finding the Sample Programs ═══ You can find the sample programs in the following subdirectories: DPMLINES IBMCPP\TUTORIAL\DEBUGGER\DPMLINES MCELCV IBMCPP\TUTORIAL\DEBUGGER\MCELCV NEST IBMCPP\TUTORIAL\DEBUGGER\NEST ═══ 2.3. What Is New in Version 2.0 ═══ If you are already familiar with the previous version of the debugger, you may be interested in a quick overview of what is new in this version. The debugger now supports the C++ language. A summary of the new features added to support C++ are as follows: Template support Allows you to debug template functions. When an action is ambiguous, the IBM C/C++ Debugger prompts you for the correct instance of a function. Inheritance view Displays class hierarchy in a graphical format. Class details view Displays information about a class. This information includes type information for data members, member functions and parameters, access information and relationship data. Expression evaluation Evaluates expressions that use the new C++ operators for reference and scope. Full casting is supported for C++. In addition to the features supporting C++, there are also many other new and enhanced features. Descriptions of these features are as follows: Window analysis Displays PM windows in a three-dimensional view. Window characteristics and window relationship data are also displayed. Message queue monitor Monitors PM messages that are related to specific PM windows. Include file support Debugs include files that contain executable code. You can browse the source code of an include file and set breakpoints. Exception handling Displays options when an exception occurs during execution of your program. Jump to location Resets the extended instruction pointer (EIP) to a location in your program without executing any statements. Buttons in the title bar Provides quick access to step commands and various utility windows. Breakpoints Manipulates breakpoints using a notebook format. This allows easier access to different types of breakpoints. Stack Views a more complete picture of the stack. Debug Session Control Displays a hierarchical representation of the relationships among all components, such as executable files, object files, and functions. Default data representation Allows you to change the default representation of data. For example, integers can be displayed as either decimal or hexadecimal. Locate function Displays source code for a given function. The IBM C/C++ Debugger lists overloaded functions and lets you choose the correct function. Register Views and alters the individual flags in the processor's EFLAGS register, coprocessor floating point control word, and floating point status word registers. ═══ 2.4. Using Help in the Debugger ═══ There are several ways to get help within the debugger. Tutorial You can access this tutorial from the Help menu in the Debug Session Control window or from the Help menu in any of the program view windows (Source, Disassembly, or Mixed). Help on a Window To see help for a particular debugger window, select General Help from the Help menu (Help  General Help) or press the F1 key in any window. Some windows also have a Help push button. Help on a Menu Choice While a menu is displayed, use the arrow keys to select a choice and press the F1 key. ═══ 2.5. Using the Default Session Settings ═══ The tutorial assumes that all of your debugger session settings are set to their default values. Otherwise, some events may not happen exactly as stated. To reset all your session settings to their default values, delete the IPMD.@2S file from the debugger directory. Note: This step is mandatory if any of the defaults have been changed. See Customizing the Debugger Environment to explore the options you can change in the debugger session settings. ═══ 2.6. Customizing the Debugger Environment ═══ Before you begin a debugging session, you can select the options (session settings) that define your debugging environment. If you have not changed any of the debugger default session settings, then the steps outlined in the next two panels are optional and are included only to show you the different session settings that are available. ═══ 2.6.1. Setting Source Window Properties ═══ Note: These steps are mandatory if any of the defaults have been changed, or if the IPMD.@2S debugger settings file has not been deleted. You can set the New view priority to control how your program view windows are initially displayed, and how they are handled when they halt or are no longer active. To set a new view priority: 1. From the Options menu in the Source window, select Session settings Source window properties. 2. At the bottom of the New view priority group heading, select the Icon push button to set the views in the list to icons. This is the default. 3. To change the order of the icons, use mouse button two to press and drag the disassembly icon above the source icon and then release mouse button two. The icons are displayed in a new order with the disassembly icon first and the source icon second. 4. Press and drag the source icon over the disassembly icon and release mouse button two. The icons are reordered so that the source icon is first and the disassembly icon is second. When the program starts, it is displayed in the Source window. Note: For the tutorial, the Source window should be the first view opened for new programs. Several other settings involving the program view windows can be set from this window as well. For example: 5. From the Old source disposition group heading, enable the Discard radio button. 6. From the Display at stop entry field, enable the Only stopping thread radio button. 7. To save these selections for the next debugging session, select Save session settings. This is the default. 8. Select the OK push button to accept the information that you entered and to close the Source Window Properties action window. For more information about these settings or any of the other settings you can choose from this window, select the General help choice from the Help pull-down in the Debug Session Control window. ═══ 2.6.2. Setting Monitor Properties ═══ You can set the default options for the variable monitors, and save them with the session settings. This feature allows you to use the same monitor settings for each debugging session. When you double-click on a variable name in your source file, that variable and its current value are added to a Monitor window, and the value is updated as needed. The Monitor Properties action window lets you choose which type of monitor window is used to hold the value for those variables: o A data pop-up, a single small window for each variable monitored. o One of the monitor windows, such as Program Monitor or Private Monitor, which gathers several variables to monitor in the same place. The next few steps show you how you can change the default so that variables are monitored in various monitor windows. Note: This tutorial assumes you have the default condition of having the variables added to the Program Monitor action window in effect. 1. From the Options menu in the Source window, select Session settings  Monitor properties. The Monitor Properties action window is displayed. 2. Under the Monitor location group heading, select Program monitor. 3. Select Save session settings to save your selections for the next debugging session. This is the default. 4. Select the OK push button to save your selections for the next debugging session and to close the Monitor Properties action window. If you would like to change to a different monitor location, you may want to try selecting Popup. You may then see the results by double-clicking on a variable in the Source window. It appears in a data pop-up instead of in the Program Monitor action window. Be sure to change back to the Program monitor window to monitor variables for the rest of the tutorial. ═══ 3. Before You Begin ═══ This topic is divided as follows: Getting Ready to Use the Debugger Explains how to prepare your program for use with the debugger. Starting the C/C++ Debugger Explains how to start the debugger from WorkFrame/2* and the OS/2* prompt. Introducing the Main Debugger Windows Introduces the main debugger windows and the buttons on the title bar. Customizing Your Environment Instructs you to resize the Tutorial window and change the PM debugging mode to asynchronous. ═══ 3.1. Getting Ready to Use the Debugger ═══ Before you can run the debugger on your program, you will need to know: o How to writing code that the IBM* C/C++ Tools Debugger supports o How to compile and link your program to generate debugging information o How to set debugger search path information. Click on the Forward pushbutton to learn how to perform these tasks. ═══ 3.1.1. Writing Code that the IBM C/C++ Debugger Supports ═══ When you write your code, put each statement on a separate line. Multiple C statements on the same line are difficult to debug. These multiple statements cannot be accessed easily when you set breakpoints and do not allow you to single-step through each statement. ═══ 3.1.2. Compiling and Linking Your Program ═══ When you compile and link your program, you will need to specify options so that debugging information is generated. Optimized or inlined code cannot be debugged, so do not set options that turn optimization and inlining on. Use the following options when compiling and linking code to be debugged: Compile Options: /Ti+ Compiles your program with debugging information (same as /Ti). /O- Compiles your program with optimization off (this is the default). /Oi- Compiles your program with inlining off (this is the default). Link Options: /Debug or /De Links your program to produce an executable file that includes line number information and a symbol table, in addition to the executable code. For example, to compile a file for debugging, type: icc /Ti myfile.c When this option is turned on, the compiler and linker generates debugging information that the debugger is able to access. ═══ 3.1.3. Search Path Information ═══ The search path tells the debugger where to find the source file. The debugger searches for the source files in the following order: 1. The path where the object file was compiled. 2. The path where the executable file is located. 3. The path defined by the PMDPATH environment variable, if specified. 4. The current path. 5. The path defined in the INCLUDE environment variable. Using the Environment Variables The debugger uses two environment variables: PMDPATH and PMDOVERRIDE. To set the PMDPATH environment variable, do the following: Set PMDPATH=path;path where path is the location of your source files. To override the normal search order, use the PMDOVERRIDE environment variable, as follows: Set PMDOVERRIDE=path;path where path is the location of your source files. If the source file is not found in the defined override path, the debugger uses the normal search order. ═══ 3.2. Starting the C/C++ Debugger ═══ There are two ways to start the debugger, from WorkFrame/2* or from the OS/2* prompt. ═══ 3.2.1. Starting the Debugger from WorkFrame/2 ═══ Before you start the debugger from the WorkFrame/2* environment, you need to create a project for the program you want to debug. To be able to compile and link a target program with debugging information, you need to set the debugger options that the WorkFrame/2 environment uses for creating a project. For information on creating a project, setting options, and starting the debugger, refer to the IBM WorkFrame/2: Introduction. or the WorkFrame/2 online help. ═══ 3.2.2. Starting the Debugger from the OS/2 Prompt ═══ To start the debugger from an OS/2* prompt, type the following command and parameters, in the order they are listed: ipmd myprog You may want to specify debugger parameters (/n, /i) when you start up the debugger. ═══ Using Debugger Parameters ═══ When you start the debugger from an OS/2* prompt, you can specify debugger parameters to specify information that would otherwise be entered in the Startup Information window: /n Do not use any restart information that was saved from a previous debugging session for this program. /i Start the debugger in the system initialization routine so that you can debug initialization code. Place these parameters before your program name. For example, ipmd /n myprog You can also start the debugger by simply typing ipmd Then once the debugger has started, you can load a program by selecting Startup from the File pull-down in the Debug Session Control window, the first window that appears when you start the debugger. ═══ 3.3. Introducing the Main Debugger Windows ═══ This topic covers the Debug Session Control window and the various program view windows. These are the main debugger windows. From these windows you control the debugger and have access to all of the debugging features. A new feature of the debugger is the buttons in the title bar. These buttons allow you to quickly access often-used menu choices. You will use these buttons to access debugger features later on in the tutorial. ═══ 3.3.1. Introducing the Debug Session Control Window ═══ The Debug Session Control window is the control window of the debugger and is displayed during the entire debugging session. This window displays the threads and components for the program you are debugging. From this window, you can enable or disable threads and select program components for viewing. Selecting program components for viewing provides you with the capability to access any part of your program. This window is divided in two list boxes: o The Threads list box shows the state of the threads in your program. o The Components list box contains executable files (EXEs) or dynamic-link libraries (DLLs) for the program you are debugging. Use the Components list box to: - Generate a list of object files for an executable file (select the plus icon to the left of the executable file name). - Open a program view of an object file (double-click on the object file name). - Generate a list of functions for a specific object file (select the plus icon to the left of the object file name). - Open a program view for the object file that contains the function (double-click on the function name). The program view window is opened to the first line of the function that you selected. Note: For C++ programs, the function name includes the class name and parameters. ═══ 3.3.2. Introducing the Program View Windows ═══ Using the program view windows, you can monitor the execution of your program, among other things. There are three program view windows: Source The original source file. Disassembly The assembler instructions produced by the compiler. Mixed Source lines and the corresponding assembler instructions. As you run or step through the program, the program view window of the component that is currently executing is displayed. During stepping, the executing line is highlighted. If your program has include files, those source files are available for debugging in the notebook format of the Source window. You can disable the notebook format by selecting View  Notebook from the File pull-down in the program view window to toggle the Notebook option. Each program view window has buttons in the title bar. ═══ 3.3.3. Introducing the Buttons on the Title Bar ═══ The buttons on the title bar in all of the program view windows give you quick access to often-used functions. The step and run buttons appear in the title bar in the same order as the step and run functions in the Run menu to make it easier for you to remember. Step over Executes the current or highlighted line in the program, but the debugger does not enter any called function, even though the code is executed. Thus you step to the next sequential instruction in the source file you are viewing without jumping to the source for a called function. Step into Executes the current or highlighted line in the program. The debugger steps into any called program or function as well. Step debug Executes the current or highlighted line in the program. The debugger steps over any function for which debugging information is not available (for example, library and system routines), and steps into any function for which debugging information is available. Step return Automatically executes the lines of code up to, and including, the return statement of the current function. Run Runs the program, executing all enabled threads. While running, the button turns red. Pushing the button again stops the program and the button turns green. View Changes the current view to one of the other windows: Source, Disassembly, or Mixed windows. Stack Displays the Stack window, which lists all of the active functions for a thread in the order that they were called. Register Displays the Register window, which lists all the processor and coprocessor registers for a thread. Program monitor Displays the Program Monitor action window for viewing and changing your program variables. Storage Displays the Storage window, which shows the addresses and contents of a portion of memory. Debug session control Displays the Debug Session Control window. ═══ 3.4. Customizing Your Environment ═══ Before continuing with the tutorial, you may want to resize the tutorial window and set the debugging mode. The following panels explain how to do these tasks. ═══ 3.4.1. Resizing the Tutorial Window ═══ If you plan to work with the debugger while viewing this tutorial, you may want to resize the IBM C/C++ Debugger Tutorial window to occupy about half of your screen, saving the other half for performing the debugger tasks. A good size is just wide enough so that the push buttons at the bottom of the tutorial window fit on a single line. You may also need to re-organize the screen locations when you open new windows so that both the tutorial and the debugger windows are visible. ═══ 3.4.2. Selecting the PM Debugging Mode ═══ Note: This step is mandatory to insure uninterrupted viewing of the tutorial. When you set the mode of the debugger to asynchronous or synchronous, you determine how PM messages are processed while the debugger has control. In asynchronous mode, you are allowed to do other things on your desktop while the debugger is running, such as viewing the tutorial. In synchronous mode, only the debugger windows are active. If your program uses PM messages, some PM messages may not be answered correctly. To set the debugging mode to asynchronous: 1. From the Options menu in the Source window, select Session settings  PM debugging mode. 2. Under Debugging mode, select the Asynchronous radio button. 3. Select Save session settings to save the mode you have selected for the next debugging session. 4. Select the OK push button. ═══ 4. Debugger Features for C Programming ═══ This section guides you through a sample debugging session using the sample program DPMLINES. In this section, you will learn how to: o Load and run the DPMLINES program o Use the step commands o Manipulate breakpoints o Monitor the stack and registers o Locate functions and search for text strings o Use the monitor windows o Change the storage address o Monitor messages o Use the window analysis windows. ═══ 4.1. Lesson 1: Loading DPMLINES ═══ To start this lesson, you will need to load the DPMLINES program: 1. Select Startup from the File pull-down in the Debug Session Control window. 2. In the Program entry field, type: IBMCPP\TUTORIAL\DEBUGGER\DPMLINES\DPMLINES.EXE Ensure that the Debug program initialization check box is not selected, otherwise, the next window to display is the DOSCALL program in the Disassembly window. 3. Select the OK push button. The program view window appears showing the source file. Note: If you are starting the debugger for the first time, you may see the Change Location window. See the Debug Session Control window for more information on this. ═══ 4.2. About the DPMLINES Program ═══ Before beginning the debugging process, run the program to verify that the error exists. DPMLINES is a PM program that runs in the first thread and displays a PM window with simple menus. It creates the second thread to draw lines in the window. The color or the line changes every few seconds. You can change the background color by double-clicking with mouse button 2 anywhere in the window. This program was modified to display text that names the active line color in the lower left-hand corner of the window after the first color change. The displayed text should be: Color Value: active_line_color_code The code that was added to modify the program, however, has an error in it, and the active_line_color_code (which is a number) does not display. ═══ 4.2.1. Running the DPMLINES Program ═══ To start the debugging process at the beginning of the DPMLINES program, you need to restart the program from the debugger: Note: If you have not set the debugging mode to asynchronous, you need to do this now. 1. Select the Run button in the title bar. The DPMLINES window is opened behind the debugger windows. Run executes the program, including all enabled threads, from the current line until a breakpoint is reached or the program is terminated. 2. Select the DPMLINES window to make it active and display it in front of the debugger windows. You can see that the DPMLINES program continually draws lines in the DPMLINES window. The color of these lines changes every few seconds. 3. Look at the lower left-hand corner of the DPMLINES window. The text Color value: is displayed, but the active_line_color_code is not. 4. From the Exit menu in the DPMLINES window, select Exit DPMLINES. The DPMLINES window is closed and the Program Terminated window is displayed. 5. In the Program Terminated window, answer No to the prompt: Do you want to save restart information? The DPMLINES program is ended, the Source window closes, and the Debug Session Control window is left as the only debugger window. ═══ 4.2.2. Starting the DPMLINES Again ═══ To continue with the debugging session, start the DPMLINES program again as follows: 1. From the File menu in the Debug Session Control window, select Startup. The Startup Information action window is displayed. 2. In the Program entry field, leave the default program path name. The default path name is the path name of the DPMLINES program. 3. Select the OK push button to accept the information and to close the Startup Information window. The DPMLINES program is started for debugging and the Source window is displayed. ═══ 4.3. Stepping through the Program ═══ You can step through the program, a line at a time, in several different ways. This lesson explains basic stepping and introduces the step buttons, the first four buttons in the title bar. ═══ 4.3.1. Understanding Basic Stepping ═══ The easiest way to single-step your program is to press mouse button two anywhere in the Source window. This does a step over, which executes the current, highlighted line of code. However, the debugger does not step into any called function, although the code is executed. Step over can also be executed by: o Selecting Step over from the Run menu in the program view windows. o Pressing the O key. o Pressing the Step over button in the title bar. Try it now. You should be at the top of the DPMLINES program and stepping a few lines does not affect the next activity. The other stepping commands are described next. ═══ 4.3.2. Using the Step Commands ═══ The following summarizes the 4 step commands. Step over Executes the current or highlighted line of code, but the debugger does not step into a called function. The called program, if any, is executed and execution stops at the next line in the current program. The debugger stops in a called function if it encounters a breakpoint there. Step into Executes the current or highlighted line of code, but the debugger does step into a called function if necessary. Step debug Executes the current or highlighted line of code. The debugger steps over any function for which debugging information is not available, such as library and system routines, and steps into any function for which debugging information is available. Step return Automatically executes the lines of code up to, and including, the return statement of the current function. ═══ 4.4. Setting Breakpoints ═══ Breakpoints stop the execution of your program at preset points. During a debugging session, you can set as many breakpoints as you want. Breakpoints can be set in the Source window, the Disassembly window, or the Mixed window. When you set a breakpoint in one program view window, it is shown in all program view windows. When the program encounters the breakpoint, it stops before the line is executed and highlights the line. Breakpoints set in the Source window stop execution before the line of source code is executed. Breakpoints set in the Disassembly window or the Mixed window stop execution before the assembler instruction is executed. ═══ 4.4.1. Setting a Simple Line Breakpoint ═══ The simplest breakpoint is a line breakpoint. A line breakpoint is set by double-clicking in the prefix area or on the line number of the source statement. This area turns red, indicating that the breakpoint has been set. Double-clicking on the area again turns off the breakpoint. Breakpoints can only be set on executable lines, which are shown in blue. Non-executable lines, such as comments, are shown in black. Clicking on or selecting the prefix area highlights it or turns it gray. Try it on one or more lines now, watching the prefix area turn red. Be sure to turn the breakpoints off when you are finished. ═══ 4.4.2. Using the Breakpoints Action Window ═══ The Breakpoints window is used to set and list several kinds of breakpoints in a program. From the Breakpoints window, you can: o Set a line breakpoint. o Set a function breakpoint. o Set an address breakpoint. o Set a change address breakpoint. o Set a load occurrence breakpoint. o List the breakpoints that have been set. o Delete one or all of the breakpoints that have been set. You can set five types of breakpoints in all or one of the active threads. The execution of the program halts at a breakpoint when the conditions you have specified (in this window) are met. By setting a breakpoint, you can work with the section of code that contains the error. The section of code that was added to the DPMLINES program starts at line 564. To set a line breakpoint at line 567, which contains the ptlt.x = 1: expression: 1. Scroll to line 567 in the Source window. 2. Highlight line 567 by selecting the prefix area. The prefix area turns gray. 3. From the Breakpoints menu, select Line. This displays the Breakpoints action window, which is in a notebook format. 4. In the Line number entry field, 567 should already be filled in for you. 5. Set the Frequency entry fields as follows: a. Change the From entry field to 100. b. In the To entry field, replace the current value with 200. c. In the Every entry field, change the current value to 10. d. Select the Set push button to set the breakpoint at line 567 of the DPMLINES program. The following appears at the bottom of the notebook page: Breakpoint has been set. The Breakpoints action window is left open. ═══ 4.4.3. Listing the Breakpoint ═══ The breakpoints that have been set in a program can be listed. To list the breakpoints, do the following: 1. Select the List tab at the bottom of the Breakpoints action window. Each breakpoint entry displayed in the List Breakpoint window includes information on the type, location, and any conditions under which the breakpoint is activated. You can modify, delete, or sort the list of breakpoints from this window. 2. View the breakpoint entries in the List action window. You may need to use the scroll bars to view all the information. 3. If you set any additional breakpoints earlier, you need to delete them now. To delete the additional breakpoints, highlight the line and then select the Delete push button. Note: Be sure to leave only the breakpoint on line 567. 4. Select the OK push button to close the Breakpoint action window. ═══ 4.4.4. Running the Program to Reach the Breakpoint ═══ Note: If you have not set the PM debugging mode to asynchronous, you will receive unpredictable results. To run the program and reach the breakpoint you have just set, select the Run button in the title bar. When the breakpoint is encountered, the program stops and the Source window for thread 2 is opened. The current line, which is where the breakpoint was set, is displayed at the top of the Source window for thread 2. The section of code that contains the error is in thread 2. ═══ 4.5. Monitoring the Stack ═══ You can monitor the stack to find the function name that started thread 2, which is where the error is located. The Stack window lists all of the functions in the call stack for a particular thread. Any calls that have been made are included in the stack and each thread has a call stack. You can use the Display Style action window to select the parameters that control how items on the stack are displayed. From this action window, you can select the descriptive information you want displayed for all of the call stack items and whether you want the active function to be displayed at the top or the bottom of the stack. By default, active functions are displayed at the top of the stack. ═══ 4.5.1. Select the Display Style Format for the Stack Items ═══ To select the display style for the stack items: 1. To open the Stack window, select the Stack button in the title bar. The Stack window is displayed. 2. From the Options menu in the Stack window, select Window settings  Display style. The Display Style window is displayed. 3. Under the Items group heading, enable the Entry number, Function, Source, and Recursion level check boxes to display all of the available information for each stack entry. 4. For Growth direction , select the Up radio button to display the most recently called items at the top of the stack. This is the default. 5. The Save window settings check box should be checked, so your selections are saved for the next debugging session. This is the default. 6. Select the OK push button to accept the information you have entered and to close the Display Style window. 7. Resize the Stack window, if necessary, to display the four columns of information. ═══ 4.5.2. Review the Items in the Stack Window ═══ Review the items in the Stack window. The first entry in the Function column is DrawingThread. The DrawingThread function started thread 2 and is used to find the source for this function in the next step. Close the Stack window after you have examined the information. ═══ 4.6. Locating Functions ═══ Now that you have set a breakpoint, you can step through the code to see what happens when the next few statements execute. Here, you will learn how to find the section of code that starts thread 2. You can then review the logic of the function that starts thread 2 up to where the new section of code was added. There are several ways to find the DrawingThread function, which starts thread 2: o Using the Components list box in the Debug Session Control window o Using Locate Function option. Click on the Forward push button to learn how to locate a function using these methods. ═══ 4.6.1. Using the Components List Box ═══ These steps demonstrate the usage of the Components list box to locate a function: 1. From the Debug Session Control window, select 2 from the Threads list box to highlight thread 2. 2. Expand DPMLINES.EXE from the Components list box by selecting the plus icon. 3. To find the DrawingThread function, double-click on the plus icon next to the DPMLINES object file to expand it. 4. Double-click on the DrawingThread function to open the Source window. The Source window displays the DrawingThread function. A separate Source window can be displayed for each thread created by your program, so more than one view of the same source file may be displayed. ═══ 4.6.2. Using the Locate Function Action Window ═══ The DrawingThread function is a static function, which means it is local to the DPMLINES.EXE. The debugger needs more information when searching for static functions than is needed to find global functions. To demonstrate: 1. In the Source window, select Where from the File menu to locate the current execution line. 2. Select Locate function from the File menu. The Locate Function action window is displayed. 3. Type the following in the Function entry field and press the OK push button. DrawingThread Since this is a static function, the following message is displayed: No matching functions found. Desired function could be static. If you want to use Locate Function to find a static function, you need to specify which executable file and object file to search. 4. Select OK to remove the message box. 5. Disable the All executables check box and select DPMLINES.EXE from the Executable drop-down list box. 6. Ensure that the Debug data only check box is enabled (restricting the search to only files that were compiled with debugging information) and select DPMLINES from the Source list box. DPMLINES should appear in this entry field now. 7. In the Function entry field, ensure that the following is displayed: DrawingThread Note: Disable the Case sensitive check box if you want it to search without sensitivity to upper and lower case characters. 8. Select the OK push button to find the function. This tells the debugger to search for the function within a certain executable and object file. Now you can review the lines of the code that lead up to the new section of code by scrolling in the Source window. The first line in the new section of code can be identified by the breakpoint that you set earlier at line 567. The prefix area is highlighted in red where breakpoints are set. ═══ 4.6.3. Searching for a Text String ═══ You can also search for text strings in a source file. For example, to search for the occurrence of the Fcolour text string, do the following: 1. From the Edit menu in the Source window, select Search. The Search action window is displayed. 2. In the Enter search text entry field, type the following: Fcolour Note: The search is not case sensitive unless you enable the Case sensitive check box. 3. Select the OK push button to accept the information that you entered and to close the Search action window. The text in the Source window scrolls to the first occurrence of the text string and highlights Fcolour in gray. 4. To find the next occurrence of Fcolour, select Find next from the Edit menu in the Source window while the Source window is selected. The next occurrence of the text string is highlighted. When you are finished using Search, go to the Debug Session Control window and double-click on the DrawingThread function to return to its definition in the Source window. ═══ 4.6.4. Using Where To Locate the Next Line ═══ Use the Where choice to locate the next line in your program to be executed. To do this, complete the following: 1. In the Source window for thread 2, select Where from the File menu to quickly locate line 567, the next line to be executed in the thread. This is where you set the breakpoint, and where the program is currently stopped. 2. Select the Step over button to execute the current line. Line number 567 is executed, and the current line moves from line 567 to line 568. 3. Select Step over two more times. The current line should now be 570. 4. Double-click on line 571 to set a line breakpoint. 5. Notice that the line that executes next depends on the result of the expression in line 571. Line 571 displays as: if (oldFcolour != lFcolour) { The code between lines 571 and 594 is executed only if the oldFcolour variable is not equal to the lFcolour variable. 6. Select the Run button to reach line 571. ═══ 4.6.5. Monitoring an Expression ═══ You can monitor expressions from your program, or expressions that are not in your program. To verify that the oldFcolour variable is equal to the lFcolour variable: 1. Highlight the expression on line 571 by pressing and dragging the mouse pointer over the following expression: (oldFcolour != lFcolour) 2. From the Variable pull-down, select Monitor expression. The Monitor Expression action window is displayed and the expression you highlighted is inserted in the Expression entry field. 3. Select the Monitor properties push button. The Monitor Properties action window is displayed. This shows information about the Monitor Expression action window. Its location is in the Program Monitor action window by default. 4. Select the Cancel push button to exit the Monitor Properties action window, since you do not want to make any changes at this time. 5. Select the OK push button to close the Monitor Expression action window. The (oldFcolour != lFcolour) expression is displayed in the Program Monitor action window. You may have to resize this window to see the entire expression. Note: A plus icon at the end of the expression indicates that there is more of the expression to display than fits in the window. The value of the expression is 0, which means that these variables are equal. A value of 1 would indicate that the expression was true and that the variables were not equal. 6. To close the Program Monitor action window, select Close from its system menu. ═══ 4.6.6. Locating the Error ═══ The program error may be apparent to you if you read the next few lines of code after line 571. The DPMLINES program periodically changes the color of the lines that are being drawn. The lFcolour variable is updated with the new color only when the color of the line changes. When we reach line 571, the lFcolour and oldFcolour variables are equal, so the section of code between lines 571 and 594 is not executed. This is why the color number is never written on the screen. ═══ 4.7. Monitoring the Registers ═══ The Register window displays the processor registers and flags, including the coprocessor information. You will learn how to change the EAX register contents in the next few panels. To display the contents of EAX register: 1. Select the Register button in the title bar. The Register window is displayed. 2. Review the contents of the EAX register. ═══ 4.7.1. Executing the Current Line to Update the EAX Register ═══ To execute the current line: 1. Select the View button in the title bar of the Source window twice. The Mixed window is displayed. The first assembler instruction for the current line is highlighted in black in the Mixed window. You can see the instruction that loads the EAX register with the contents of one of the variables in line 571. 2. Place your mouse pointer inside the Mixed window and press mouse button two. The debugger executes the current line of code, which is the MOV instruction and is the first assembler statement for line 571. 3. Review the contents of the EAX register. The EAX register has been updated with the contents of the lFcolour variable. ═══ 4.7.2. Changing the Contents on the EAX Register ═══ You can change the contents of the EAX register before executing line 571. However, when you execute 571, the contents returns to 00000001. To do this, complete the following: 1. Delete the breakpoint on the assembler instruction that follows the source instruction on line 571. 2. Return to the MOV instruction after line 571 by highlighting the prefix area of the line. 3. Select Jump to Location from the Run menu. 4. Typeover the current EAX register contents, 00000001, with the following and press Enter: 00000000 5. Step over the MOV instruction by selecting the button to execute it again. The EAX register value is set back to 1. 6. Close the Register window. ═══ 4.8. Using the Monitor Windows ═══ There are two monitor windows: Private Monitor and Program Monitor. The Private Monitor window displays the variables or expressions that are relative to a component or thread. This window closes when its associated program view window closes. You can bring up this window by selecting Private monitor from the Windows pull-down in the program view windows. Close the Private Monitor window before continuing. The Program Monitor action window is usually used to display the global variables used in your program. This next panel shows you how to change the value of a variable and monitor their values as they change. ═══ 4.8.1. Changing the Value of a Variable ═══ You can influence the way your program executes by changing the value of a variable. For example, if you change the value of oldFcolour to make it the same as lFcolour, then the IF statement on line 571 will not cause the section of code between lines 571 and 594 to be skipped. If you were viewing assembler instructions in the Mixed window, return to the Source window by pressing the View button . now. To view the values of those variables in a monitor window: 1. To display the Program Monitor action window, select Program monitor from the Windows pull-down in the program view windows or the Debug Session Control window. 2. Double-click on the oldFcolour and lFcolour variables to place them in the Program Monitor action window. 3. Change one of the values so that they are not equal. For example, change the value of oldFcolour to 2 by typing over the old value. 4. If you are not already there, step or run to line 571. If you step one more time, line 572 becomes the current line because the expression in 571 is true. ═══ 4.8.2. Monitoring More Variables ═══ You probably already have at least oldFcolour and lFcolour displayed in the Program Monitor action window. These variables were placed in the Program Monitor action window when you double-clicked on their names in the Source window. The value of a variable as shown in the monitor window changes as the value of the variable changes. If you want to have the value of oldFcolour displayed but not changed, do the following: 1. Select the oldFcolour variable in the monitor window. 2. From the Options menu in the monitor window, select Disable to disable the monitored variable. The displayed value of this variable is not updated as the program executes. Now you can learn how to display an expression in a monitor window. Highlight the expression &ptlt on line 586 by dragging the mouse to include the &, then double-clicking on it. This adds the expression to the monitor window. ═══ 4.8.3. Using the Local Variables Monitor Window ═══ You can also monitor all the local variables in your program with the Local Variables window. Select Local variables from the Windows menu to display the Local Variables window. It contains all the variables local to the currently executing program. If you have many local variables, this window may take more room to display than the Program Monitor action window. However, this window shows all the variables from the current stack frame. Close the Local Variables window. ═══ 4.8.4. Displaying Contextual Information for Monitored Variables ═══ The same variable can be used in many places in a program. The value of a variable shown in a monitor is specific to the location in which it is selected for monitoring. Since it is easy to forget where the variable that you are monitoring is located. You should display the contextual information. Contextual information consists of the source file, line number, and thread. To display the contextual information: 1. Select one or more of the variable monitors in the Program Monitor action window, by clicking on the names (not the area containing the values). 2. From the Options menu in the Program Monitor action window, select Show context. 3. If all the contextual information is not displayed, resize the Program Monitor action window. ═══ 4.8.5. Changing the Representation of a Variable in the Monitor ═══ In any of the monitor windows, you can also change how a particular variable is displayed. To change how a variable is displayed: 1. Select one of the variable monitors in the Program Monitor action window, by clicking on the name (not the area containing the value). When a monitor is selected, it is highlighted. 2. From the Options menu in the Program Monitor action window, select Representation and select one of the valid representations listed. For example, for an integer you can pick either Decimal or Hexadecimal. 3. The representation of the selected variable is changed. 4. Close the Program Monitor action window. ═══ 4.8.6. Reviewing the Contents of the Variables ═══ Review the contents of the variables you have displayed, and any others you like, to see if you can determine the location of the error. Your review of the contents of the variables could lead you along several paths of investigation. The following information is important at this point: o The values of oldFcolour and lFcolour are equal at line 571. You already knew these variables were equal from a previous step. Because the variables are equal, the line color does not change during this pass through thread 2. If you had not run the program in Run the Program, you might think this is the reason that the text is not displayed. In fact, the text is never displayed. o The value of the lBcolour variable on line 575 and line 585 is the same. The contents of the lBcolour variable does not change between these lines. The fact that the value of the lBcolour variable does not change is not surprising since the background color changes only when you double-click mouse button two in the DPMLINES window. If you understand the PM function calls, however, you may realize at this point that the statement on line 585 sets the color in which the text string is to be written. o The p variable is a pointer that points to the contents of the buffer variable. The value of the buffer variable. is an ASCII character string with the value of 1. Monitoring the value of the p variable shows that the contents of the variable lFcolour has been successfully converted to an ASCII text string by the program. The next panel shows you how to find the contents of the buffer variable by monitoring storage. ═══ 4.9. Monitoring Storage ═══ The Storage window monitors the storage being used by your program. You can open several windows to monitor different areas of storage at the same time. As the program state changes (when it executes and data is updated), the data displayed in the storage windows is updated to reflect these changes. You can change data in storage by typing over the storage values. Data in other affected windows, such as variable monitors, changes to reflect the new value. You can also change the data that is displayed in the Storage window by typing over the address of a variable. The Storage window is updated with the data at the new address. This part of the tutorial shows you how to check the contents of storage for the value of the buffer variable. The buffer variable holds the number of the current color of the line being drawn as a text string. ═══ 4.9.1. Locating the Address of a Variable ═══ These steps show you how to use the address to view the contents of buffer variable in storage. To locate the address of the buffer variable: 1. From the Variable menu in the Source window, select Monitor expression. The Monitor Expression action window is displayed. 2. In the Expression entry field, type the following: &buffer 3. Select the OK push button to accept the information you have entered and to close the Monitor Expression action window. The buffer variable address appears in the monitor window. 4. To monitor the value of the buffer variable as well, double-click on the buffer variable in line 578. Now you are monitoring both the value and the address of the buffer variable. ═══ 4.9.2. Changing the Storage Address Style ═══ To change the storage address style: 1. Open the Storage window by selecting Storage from the Windows menu in the Source window. The Storage window is displayed. 2. Select Window settings  Address style from the Options menu in the Storage window. The Storage Address Style action window is displayed. 3. Select the arrow to the right of the Style list box to display a list of address styles. 4. Select the Flat address style from the list box. The Style list box closes. 5. Select the OK push button to accept this selection and to close the Storage Address Style action window. ═══ 4.9.3. Verifying the Contents of a Variable in Storage ═══ To verify the contents of the buffer variable in storage: 1. Make sure you can see all of the information in the Storage window. Resize it if necessary. 2. Type over the Flat address field and enter the address of the &buffer variable shown by the pointer in the monitor window. The contents of the window are updated one second after the last keystroke. The the display is updated incrementally as you type. When you are finished, the contents of the address is updated and the Storage window is scrolled to the appropriate address. 3. Review the first line of characters in the Character column. The first character is a 1, which is the value of the buffer variable. 4. Review the first line of hexadecimal values displayed in the HEX field. The first two numbers are the hexadecimal representation of 1 in the ASCII character set. 5. Close the Storage window and Program Monitor window. ═══ 4.10. Understanding Window Analysis ═══ The Window Analysis window gives you an understanding of PM application windows. It presents both graphical and textual information about your application windows and lets you observe the relationship between windows. You can view an image of your desktop with each of your program windows outlined. This helps to visually distinguish the different windows in your application. You can select any one of these windows and view another three-dimensional breakdown of that individual program window and the windows that make it up. These three-dimensional views also have an added benefit in that hidden details of a window structure can be revealed. For example, windows may exist that are not visible because they are obscured by other windows. By highlighting any of the representations of your program windows in any of these three Window Analysis windows, you can immediately see the related information in the other windows. ═══ 4.10.1. Viewing the Window Analysis Window ═══ You will need to stop your program before the Window Analysis windows can be displayed. To display the main Window Analysis window, select Windows  Window Analysis from the Source window or Debug Session Control window. The Window Analysis window is displayed. ═══ 4.10.2. About the Window Analysis Window ═══ The Window Analysis window is shown in a notebook format. You are viewing the primary page, which is a view of the desktop window, with an outline of your programs windows shown. This primary page has a large notebook tab at the bottom of the notebook window named Desktop. The other tabs, along the right side of the Window Analysis window, represent the regular pages. Each regular page shows an image of one of your program windows. To select one of your program windows, double-click on its image on the desktop page. The regular page showing this window is displayed. Notice that you can also select it with the notebook tab, once you know which tab corresponds to each window. ═══ 4.10.3. Selecting Pages and Windows in the Window Analysis Window ═══ You can select individual windows with the mouse or with the Tab key. Selecting a window makes it available for other analysis functions, which will be described in the next few panels of the tutorial. For example, you can see the names and attributes of each selected window in another window. Select a window by clicking with the mouse. The window is highlighted. You can also select a window by pressing the Tab key. Repeatedly pressing the Tab key cycles through the windows; the Back-Tab key cycles through the windows in the opposite direction. In cases where there are many windows that are difficult to visually separate, the Tab keys can be helpful to individually select the windows. ═══ 4.10.4. Rotating Images ═══ Another way to visually separate the different windows in your program is to rotate the windows in the Window Analysis window. This makes the windows easier to see and select individually, often allowing you to see details that might be obscured by other windows from other perspectives. This is especially useful when there are a large number of overlapping windows. To rotate the windows, use one or both of the: o Horizontal scroll bar to rotate around the y-axis. o Vertical scroll bar to rotate around the x-axis. Note: You can see a sideways view of your program by scrolling all the way to the left or right with the horizontal scroll bar. In addition, two options from the Options menu allow you to rotate windows to predetermined positions: Rotate to center Shows a face-on view as your window appears to the program. Rotate to default Places the window at a convenient three dimensional angle for viewing the separate windows within your programs window, at approximately a 30-45 degree angle. ═══ 4.10.5. Using Window Characteristics ═══ Use the Window Characteristics to see a list of textual information about a particular window. This includes all the names and attributes within that window. Selecting them visually with the mouse highlights the corresponding items in the Window Characteristics window. Now that you can select individual windows in several different ways, you can view information about each of the windows selected: 1. Select the image of the main DPMLINES window in the Window Analysis window. 2. Select the tab D1 directly. If you do not see D1, you need to disable the Bitmaps choice from the Options menu in the Window Analysis window. 3. Select Window Characteristics from the Details menu in the Window Analysis window. Note that this window is a secondary window to the Window Analysis window, and thus always displays in front of the Window Analysis window. It is also automatically closed if the Window Analysis window is closed. As you select the individual windows in the Window Analysis window, note how the class names and other information is highlighted in the Window Characteristics window. Each row in the Window Characteristics window represents one window in the Window Analysis window. ═══ 4.10.6. Adding Additional Window Characteristics ═══ To add a column of information to the Window Characteristics window and show more information for each window, use the Display style choice. To do this: 1. Select Options  Display style from the Window Characteristics window. 2. Choose Text and Visible by selecting these keywords from the Visible characteristics scroll box. 3. Select the OK push button to return to the Window Characteristics window with your selections. Two columns, entitled Text and Visible, are added to the window. You may have to resize the window to see the additional columns and information. The text displayed in the Text column shows the relationship of your program windows and how your program windows are displayed when the program is running. The Visible column should also show you why the Window Analysis windows show more buttons defined in this window than the OK push button that you can see. The other buttons are not visible. ═══ 4.10.7. Displaying the Parent and Z-Order tree ═══ The Parent and Z-Order Tree window displays a list of the parents and children of each window in your program, in a hierarchical tree. It also indicates the Z-order, which windows are displayed in front of or behind other windows. This window shows a list of the parents and children of the window displayed, as well as the Z-order. The Z-Order is the back-to-front stacking of the windows, which indicates which windows are displayed in front of other windows. To display the Parent and Z-Order Tree window, select Details  Parent and Z-Order Tree from the Window Analysis window. Like the Window Characteristics window, the Parent and Z-Order Tree window is a secondary window to the Window Analysis window, so it always displays in front of it, and is closed when the Window Analysis window is closed. Within the Parent and Z-Order Tree window, you can expand and collapse the tree that shows the parent-child relationships among the windows using the plus and minus icons, respectively. ═══ 4.10.8. Reflecting Window Information ═══ Notice than whenever you select a window in any of the three window analysis windows, it is reflected, or highlighted in the other two windows as well. By using the three window analysis windows, you can see the graphical placement of a window while seeing the names of its parts and its relationship to the other views. Now close the Window Analysis window. The other two windows close also. ═══ 4.11. Monitoring Messages in the Message Queue Monitor Window ═══ The Message Queue Monitor window displays PM messages associated with a PM program. It presents the messages in a list as they occur. Using the message queue monitor, you can control: o What is displayed for each message o How the message parameters are formatted o Which messages are monitored o Which windows have their messages monitored o Which message queues have their messages monitored o New messages that you define. ═══ 4.11.1. Selecting Messages to Monitor ═══ To select the messages you want to have monitored: 1. Select Message queue monitor from the Windows pull-down in the program view window or Debug Session Control window. The Message Queue Monitor window appears. 2. In the Message Queue Monitor window, select Monitor messages from the Options pull-down. 3. In the Monitor Messages action window, scroll within the Defined Message IDs list box. 4. Highlight only the WM_COMMAND message. You need to deselect any other messge IDs that are highlighted, such as WM_CHAR and WM_CLOSE. 5. Select the highlighted IDs to remove the highlighting. Leave the WM_COMMAND message highlighted. This is the only message that is monitored. 6. Scroll to the end and remove the highlighting from the rest of the WM_ messages. 7. Select the OK push button to accept the information you have entered and close this window. ═══ 4.11.2. Selecting the Message Display Style ═══ Select a PM message parameter to monitor: 1. Select Display Style from the Options pull-down. 2. Highlight MP 1 in the Columns list box. (Make sure that only three items are highlighted in this list box: CLASS, MESSAGE, and the MP 1 that you added.) 3. Select the OK push button to accept the information you have entered and close this window. ═══ 4.11.3. Selecting the Format of Message Parameters ═══ You can select the format of the MP 1 messages by doing the following: 1. Select Format Parameters from the Options pull-down to display the Format Parameters window. 2. Within this window, find WM_COMMAND in the Message list box, and highlight it. 3. Under the Parameter formatting group heading, 2 16-bit unsigned integers is selected by default for the MP 1 entry field. Open the MP1 entry field by selecting the down arrow and select 32-bit unsigned integer from the list box. You may have to scroll up in the list box to find it. (The format for MP 2 does not matter since you are not monitoring that message parameter). 4. Select the OK push button to accept the information you have entered and close this window. ═══ 4.11.4. Selecting Which Windows to Monitor ═══ To set the debugger to monitor the messages from the DPMLINES windows: 1. In the Message Queue Monitor window, select Monitor Windows from the Options pull-down. 2. Enable the Monitor all windows check box. 3. Select the OK push button to accept the information you have entered and close this window. ═══ 4.11.5. Run the Program and Watch the Monitored Messages ═══ Run the program to see the messages that are displayed in the Message Queue Monitor window. 1. Run the program by selecting the Run button in the title bar of the Source window. While it waits for input, it displays a clock icon in place of the mouse pointer. 2. In the program window, you can see the program continually draws lines in DPMLINES window. The color of these lines changes every few seconds. 3. In the Message Queue Monitor window, you may have to expand the window to see all the columns. 4. In the DPMLINES window, select Help  Instructions to observe which messages are monitored. 5. From the Exit menu in the DPMLINES window, select Exit DPMLINES. 6. Close the Message Queue Monitor window. ═══ 4.12. Fixing DPMLINES ═══ Note: Before you edit the DPMLINES program to correct the error, copy it to a new directory so others can use the tutorial after you are finished. Do not edit the copy of the DPMLINES program that is shipped with the product. ═══ 4.12.1. Correcting the Error ═══ The error in the DPMLINES code occurs at line 585, which appears as GpiSetColor ( hps, lBcolour); This statement sets the color of the text that is to be displayed when the color changes. The text string is correctly written by the statement in line 586, but it is invisible since it is set to be written in the same color as the background. Now, edit the DPMLINES program to correct the error: Change the lBcolour variable in line 585 with the color CLR_BLACK. After you have edited the program, compile and link it, then run the program as described under Run the Program. Notice that the active_line_color_code is now visible in the lower left-hand corner of the DPMLINES window. ═══ 4.13. Closing the DPMLINES Program ═══ Now that you have completed Lesson 1, you'll need to close the DPMLINES program. To close the program, do the following: 1. From the Exit menu in the DPMLINES window, select Exit DPMLINES. The DPMLINES window is closed and the Program Terminated window is displayed. 2. In the Program Terminated window, answer No to the prompt: Do you want to save restart information? The DPMLINES program is ended, the Source window closes, and the Debug Session Control window is left as the only debugger window. ═══ 5. Debugger Features for C++ Programming ═══ This part of the tutorial contains two lessons that show you how to perform debugging tasks specific to C++ programs. These lessons repeat some information from Lesson 1 of this tutorial, but also shows you how the debugger displays and handles C++ classes and templates. If you have not already done so, resize the Tutorial window to occupy about half of your screen, allowing the other half to perform the following debugging lessons: o The First C++ Sample Program: MCELCV introduces the debugger features that show class inheritance, class details, overloaded functions, and C++ expressions. This program does not contain an error. o The Second C++ Sample Program: NEST introduces the debugger features that show template functions. This program contains an exception handling error. ═══ 5.1. Lesson 2: Loading MCELCV ═══ This lesson shows you how to: o Set function breakpoints o Locate the source for a particular function o Find overloaded functions o Use breakpoints o Use the Inheritance View and Class Details windows. The C++ program, MCELCV, includes classes, static data members, and reference variables. To load MCELCV, do the following: 1. From the Debug Session Control window, select Startup from the File menu. 2. In the Program entry field, type the following: IBMCPP\TUTORIAL\DEBUGGER\MCELCV\MCELCV.EXE Note: Make sure the Debug program initialization check box is not enabled. 3. Select OK to load the program. The Debug Session Control window and the Source window are displayed. You can monitor the execution of your program from the Source window. ═══ 5.1.1. Setting Function Breakpoints ═══ In the next few steps, you can learn how to do use the Debug Session Control window to set function breakpoints: 1. Go to the Debug Session Control window and expand the MCELCV.EXE executable by selecting the plus icon. The object files that make up the executable are displayed. 2. Select the plus icon beside the AMCELCV.OBJ object file to expand it. 3. Double-click on the following function: ApushButtonHandler::command(ICommandEvent&) The source code at that entry point is displayed. 4. Set a function breakpoint by highlighting the following line in the Debug Session Control window: ApushButtonHandler::command(ICommandEvent&) 5. Select the Breakpoints menu and then select the Function choice. The Breakpoints action window is displayed with the function name already filled in for you. 6. In the Breakpoints action window, disable the All executables check box in the Executable entry field. This causes the following to be displayed in the Executable entry field: MCELCV.EXE and the following to display in the Source entry field: AMCELCV The Source entry field indicates the object file. 7. Select OK to set the breakpoint at the function in AMCELCV. The Breakpoints action window closes. Note: If you want to confirm that the breakpoint is set, look at the ApushButtonHandler::Command(ICommandEvent&) line of the AMCELCV.CPP source file, which is highlighted red. 8. In the Source window, select Where from the File menu to locate the current execution line. ═══ 5.1.2. Locating Source Code for a Function ═══ This step shows you how to locate the source code for a function. Here, you will find the command function: 1. Select the Debug Session Control window. 2. From the File pull-down, select Locate Function. The Locate Function window is displayed. 3. Disable the All executables check box. 4. Type the following in the Executable entry field or select it from the Executable list box: MCELCV.EXE 5. Type the following in the Source entry field or select it from the Source list box: AMCELCV 6. Type the following in the Function entry field: Command 7. Select OK to accept the changes. The Source window is displayed at the same point of the source code before you used the Where choice. ═══ 5.1.3. Finding Overloaded Functions ═══ In this panel, you can learn how to locate overloaded functions and select the appropriate function. To do this: 1. Go to the Debug Session Control window. 2. Highlight the following function: IMessageBox::Style::Style(unsigned long) 3. Fron the Breakpoints menu, select the Function choice. The Breakpoints window is displayed with the function name already filled in. 4. In the Breakpoints action window, disable the All executables box in the Executable entry field. This causes the following to be displayed in the Executable entry field: MCELCV.EXE and the following to be displayed in the Source entry field: AMCELCV 5. Select the OK push button. The Overloaded Function action window is displayed with two functions. 6. Highlight the following function: IMessageBox::Style::Style(unsigned long) This causes a function breakpoint to be set for that function. 7. Select OK to accept the changes and close the window. 8. To confirm that the breakpoint is set, select the Breakpoints menu and then the List choice. The IMessageBox::Style::Style(unsigned long) function is displayed. 9. Select the Delete button to delete this function breakpoint. 10. Select OK to accept the changes and close the window. ═══ 5.1.4. Using Breakpoints and Stepping through the Program ═══ In this step, you will learn how to expand objects to see what they contain. To expand the objects: Note: If you have not set the debugging mode to asynchronous, you'll need to do so now. 1. In the Source window, double-click on line 124 in AMCELCV.CPP. The line prefix area turns red to indicate that the breakpoint was set. 2. Single-step using mouse button two until the program reaches line 45. You have not encountered the breakpoint yet. 3. Select the Run button in the title bar. The Debug Appl window is displayed. 4. Select the Read push button. 5. Select the Run button to run the program again. The next breakpoint should be encountered at line 134. 6. Select the Run button again. The next breakpoint should be encountered at line 124. 7. Double-click on line 123 on the str1 object. The Program Monitor action window for the object displays. The str1 object is displayed. 8. Close the Monitor window. ═══ 5.1.5. Viewing the Inheritance View and Class Details Windows ═══ The Inheritance View is a graphical picture of the relationship of the classes in an object file (OBJ). In this case, the graphical picture shows the inheritance relationships between the classes in MCELCV. To do this: 1. From the Windows pull-down in the Source window, select Inheritance view to show the Inheritance View window for the classes in the MCELCV program. Use the scroll bars in the Inheritance View window to scroll within it. A list on the right side of the picture lists the classes; you may select a class name either in this list or in the graphical picture. You can also display a hierarchical tree of the derived and base classes in this class list. 2. Use the Options menu option to control the Classes box: a. Select Derived to base class tree from the Options pull-down to display the classes box in a hierarchical tree listing the classes alphabetically. Click on the plus icon next to any class name to expand it into its base classes. b. Select Base to derived class tree from the Options pull-down to display the classes box as a hierarchical tree listing the classes alphabetically. Click on the plus icon next to any class name to expand it into its derived classes. c. Select Class list from the Options pull-down to return to the simple or non-expandable class list display. 3. To display class details for any class, select the IHandler class by double-clicking on the box for IHandler in either the graph or the list box. This displays the Class Details window for the IHandler class. 4. To show the class information, such as data members, member functions, base classes, derived classes, class friends, and friend functions, scroll through the pages of the Class Details window. 5. Close the Class Details window. ═══ 5.1.6. Viewing the Inheritance Overview ═══ From the File pull-down in the Inheritance View window, select Overview. The Overview window, which appears, gives a small view of the portion of the class hierarchy that is shown in the Inheritance View window within the overall Inheritance View. To create a smaller or larger view in the Inheritance View window, use mouse button 2 to drag an edge of the box in the Overview window. For example, you can make a larger window to include more classes in the Inheritance View window. Move the Overview window by dragging the center of the box with mouse button two. This moves the portion of the Inheritance View window within the other window. Close the Inheritance View window. The Overview window closes as well. ═══ 5.1.7. Summary of Lesson 2 ═══ This lesson showed you how to: o Set function breakpoints o Locate the source for a particular function o Find overloaded functions o Use breakpoints o Use the Inheritance View and Class Details windows. ═══ 5.2. Lesson 3: Loading NEST ═══ In this lesson the debugger is used to: o Examine template functions o Set ambiguous breakpoints for overloaded entries o Handle exceptions It uses the sample program NEST. To load the NEST program: 1. Select Startup from the File pull-down in the Debug Session Control window. 2. In the Program entry field of the Startup window, type: IBMCPP\TUTORIAL\DEBUGGER\NEST\NEST.EXE 3. Select the OK push button to load the program. The Source window is displayed. ═══ 5.2.1. Showing Include Files in the Source Window ═══ The Source window contains the source for the executable file you are debugging. Note that the notebook format is available whenever there is executable code in include files, such as in our NEST program. The notebook format is useful for quick access to other files that contain source for the object file (OBJ), such as include files. ═══ 5.2.2. Displaying the Include Files ═══ To display an include file from one of the program view windows, select a notebook tab at the bottom of the notebook. For example, select the NESTTPL.CPP tab to see the source code. ═══ 5.2.3. Setting Breakpoints for all Template Functions ═══ Now you will learn how to set breakpoints for all instances of a template function, and for a specific instance of a template function. To set a breakpoint for all instances of a template function, double-click on the line 3. The prefix area turns red, indicating that the breakpoint has been set. There are several ways to see where the breakpoints have been set: 1. Select List from the Breakpoints pull-down in the Source window. The List action window shows that the breakpoint is set in two places, once for each instance of the template function. Close the List action window. 2. Select the View button from the title bar until the Mixed window is displayed. In the Mixed window, the template function disassembled code is listed twice, once for each instance of the template function. ═══ 5.2.4. Setting a Breakpoint for one Template Function ═══ To set a breakpoint for a specific instance of a template function: 1. Set a breakpoint at line 9 by highlighting the prefix area. The prefix area turns gray. Note: If you double-click on the line number prefix, as in the previous example, a breakpoint is set for all instances of the template function. 2. From the Breakpoints pull-down, select Line. The Breakpoints notebook is displayed for a Line Breakpoint, with the Line tab already selected, and Line 9 already filled in. 3. Select the OK push button to set the breakpoint on line 9. The Ambiguous Line action window appears, allowing you to select which template function to set a breakpoint for. 4. Select the function for outer::inner::hello(int,char*). You can select the Set push button to set more breakpoints. 5. Press the OK push button in the Ambiguous Line window to set the breakpoint and exit the Ambiguous Line and Breakpoints windows. In the Source window, you can see that the prefix area on line 9 is now red, indicating that a breakpoint has been set there. ═══ 5.2.5. Listing Breakpoints ═══ To view the breakpoints you have just set: 1. From the Breakpoints pull-down in the Source window, select List. Note that the breakpoint on line 3 is set in two places for each of the function entries. The breakpoint on line 9 is set for the single function that you selected. 2. Press the OK push button to exit the Breakpoints list. ═══ 5.2.6. Using a Variable Monitor within a Template Function ═══ This step teaches you how to monitor a variable within a template function. 1. From the Source window, double-click on the e variable on line 6. A Program Monitor action window is opened for the e variable. Note: If you have a qualified variable name, such as one of the following: abc::xyz a.b a[5] you will need to highlight the specific variable name and then double-click on it. The highlighted variable is the on that is used. After you double-click on the e variable, the Select Function for Expression action window is displayed, showing a list of template functions. 2. Select the following entry: outer::hello(int) 3. Select the OK push button. The Program Monitor action window for e appears with the value Not Allocated. 4. Close the Program Monitor window. ═══ 5.2.7. Using Where to Find the Current Line ═══ You can run the program from the beginning of the NESTTPL.CPP source file, or you can go back to the current line and start it from there. 1. To find the current execution point in the thread, select Where from the File menu in the Source window. The current line is highlighted. 2. Run the program by selecting the Run button in the title bar. The breakpoint is encountered at line 3 in the NESTTPL.CPP include file. This line is highlighted. ═══ 5.2.8. Looking at the Stack ═══ To verify that the correct breakpoint was encountered: Select the Stack button in the title bar of the Source window. The top item should be the outer::hello(int) function. The breakpoint was encountered at line 3 in NESTTPL.CPP. Select the Run button twice. The breakpoint on line 9 is encountered in file NESTTPL.C. You are now at the outer::inner::hello(int,char*) instance of the template function shown at the top of the Stack window. Now close the Stack window. ═══ 5.2.9. Viewing Template Functions in the Mixed Window ═══ To see how the different template functions display in the assembler code, change to the Mixed window: Select the View button in the title bar until the Mixed window is displayed. In the Mixed window you can see how the different template functions are implemented in machine code. The source line for each template function is listed with the disassembled code beneath it. Then, the source is duplicated, along with the associated disassembled code for each instance of the template. To change the view to Source window, select the View button in the title bar until the Source window is displayed. ═══ 5.3. Handling Exceptions ═══ This step demonstrates how the debugger deals with exception handling and shows you how to fix the error in the NEST program: 1. Select the NEST.CPP tab at the bottom of the notebook. Notice that the NEST program at line 22 attempts to divide by zero. 2. Select the Run button to continue the running of the NEST program. 3. Select Run until it causes the program to run to the error. The OS/2 Application Exception Action window appears. indicating that the exception that occurred was an integer divide by zero error. You can select from the following options: o Examine/Retry o Step Exception o Run Exception 4. Select Examine/Retry to examine the source code that caused the exception. The Source window is displays at the line containing the error. 5. To continue past the error, change the value of j to a nonzero value, so that a divide-by-zero error does not occur. To do this, double-click on the variable j in the Source window, to bring up the Program Monitor action window. Change the value for j to another value, such as 1. 6. Continue to step or run. The program terminates normally. ═══ 5.3.1. Summary of Lesson 3 ═══ This concludes lesson 3 of the tutorial. You have learned how to: o Set breakpoints in template functions and indicate which instance of a template function to set the breakpoint at. o Display the stack to see which instance of a template function is being executed. o View the assembler instructions for the different instances of a template function in the Mixed window. This concludes the portion of the debugger tutorial that deals with debugging tasks specific to C++ programming. ═══ 6. Customizing a Debugger Session ═══ This section shows you how to set the debugger session settings to customize your debugger sessions. You will learn how to: o Set the default data representation o Set the animation rate o Set initial window placement and size o Select the font for the source window. ═══ 6.1. Setting Default Data Representation ═══ You can change the way certain types of variables are displayed in the monitor windows. For example, you might want integers to display as hexadecimal. To do this: 1. From the Options menu, select Session settings  Default data representation  C. The Default Representation window is displayed. 2. From Integer, select Hexadecimal. 3. Select the OK push button. Default data representation changes only take effect for variables put in monitor windows after the default is changed. ═══ 6.2. Set the Animation Rate ═══ When you select Animate, either from the Run menu, or by pressing the A key, the debugger automatically steps over commands to execute your code one line at a time. The animation rate specifies the rate at which the debugger automatically executes the commands. To change the animation rate: 1. From the Options menu, select Session settings  Animation rate. Note: You can select this from the Source view window or the Debug Session Control window. 2. Set the speed of execution by positioning the slider bar between the slow and fast limits, or by entering a number in the entry field. For example, you might move the slider bar to the right or select the arrow on the right until 16 is displayed in the entry field. The numbers 1 to 20 are for reference purposes only. The true speed of animation depends on the processor speed, the number of open windows, and the type of instruction being executed. 3. Select the Save session settings check box to save your selection for the next debugging session. 4. Select the OK push button to continue. To stop the animation, select Animate using the A key or pressing the SysRq key. ═══ 6.3. Set Initial Window Placement and Size ═══ The debugger has an Initial Window Placement action window that you can use to set the position and size of the debugger windows when they are first opened. The windows that you can edit in this way are: o Debug Session Control o Program view windows (Source, Disassembly or Mixed) o Local Variables o Parent and Z-Order Tree o Program Monitor o Register o Stack o Storage o Window Analysis o Window Characteristics Using the Initial Window Placement action window, you can change the initial opening position and initial opening size window characteristics. ═══ 6.3.1. Changing the Initial Opening Positions ═══ To change the opening position of the Stack window: 1. From the Options menu in the Source window, select Session settings  Initial window placement. The Initial Window Placement action window is displayed. The debugger windows are displayed under the Window group heading. The rectangular area inside the Window box represents your screen. The Width and Height of the representational screen are shown under the Screen size group heading. The lower left-hand corner of the screen has coordinates 0,0. Note: The full title of each window may not be displayed. 2. Under the Window group heading, select the Stack window with your mouse. It may be hidden behind other windows, so you may have look for it. The entry field at the bottom of the Window area is updated with the title Stack. 3. Placing the mouse on the title bar to select the Stack window, move the window horizontally until it is almost touching the Register window. The new X (horizontal axis) and Y (vertical axis) coordinate data are displayed under the Placement Values group heading. ═══ 6.3.2. Changing the Initial Opening Sizes ═══ To change the opening size of the Register window: 1. In the Initial window placement window, select the Register window under the Window group heading. The list box at the bottom of the Window entry field is updated with the title Register. 2. Placing the mouse pointer on the right edge of the Register window (a double arrow is shown when it is positioned correctly), drag and release the edge of the window until the full title is displayed. The new Height and Width values are displayed under the Placement Values group heading. 3. Select Save session setting to save your selections for the next debugging session. This is the default. 4. Select the OK push button to select the information that you have entered and to close the action window. The initial opening positions and sizes of the windows you inidcated are set. The new size and position are applied the next time you open the affected window. ═══ 6.4. Selecting the Font for the Source Window ═══ You can change the font that is used for the text displayed in a debugger window. To select the new font: 1. From the Options menu in the Source window, select Fonts. The Font Selection window displays the font that is currently being used in that window and allows you to make changes. 2. If you would like to change the font, in the Name scroll box, highlight a font (for example, the Courier font). In the Style scroll box, highlight a font style (such as bold, italic, or normal). A sample of the font is displayed in the Sample field. The default is Courier, font size 10. Note: Your system might use different fonts. 3. Select the OK push button to select the information that you entered and close the Font window. If you made a change, the text in the Source window is now displayed in the new font. ═══ 7. The End ═══ You have now reached the end of this tutorial, having learned all the major functions and features of the IBM C/C++ Debugger. Experiment with other functions of the debugger using the sample programs or a program of your own. Use the on-line help to obtain more information about a debugger feature. ═══ ═══ Trademark of IBM Corporation ═══ ═══ Session settings contain the profile information for your debugger session that are set up when you choose Options  Session Settings from the Debug Session Control window or any of the program view windows. This includes information such as: o Source window properties o Monitor properties o PM debugging mode o Default data representation o Animation rate o Initial window placement. ═══ ═══ The step commands execute a single line of code at a time. ═══ ═══ Restart information can be stored for each program that you debug. This information is used to restore all the windows and breakpoints as they were during a previous debugging session on the same program when the debugger starts up. One restart information file is saved per program. For example, the restart information is stored in the PROG.@2R file for PROG program. For executable files and pre-loaded DLLs, only information relating to the primary thread is restored. ═══ ═══ If you are starting the debugger for the first time, the Change Location action window is displayed, prompting you to type the location where the session settings and restart information files should be stored. The session settings information file, which is called IPMD.@2S, is created and stored in the directory that you specified. The Change Location action window is displayed only once. It reappears if the IPMD.@2S file is erased. ═══ ═══ There are two wait states in the debugger: o When the debugger is busy doing something, it displays a clock icon. This icon will disappear when the wait is over (for example, loading a program into the debugger). o When your program is running, the debugger displays a clock icon with a rectangle behind it. This means that your program is waiting for input. If so, select your program window (if necessary) and provide it with the input it needs.