Getting the Bugs Out with IPMD

From EDM2
Jump to: navigation, search

by Patrick Gerstle

I enjoy creating software products! After I get a program working correctly, it never wears out, burns out, overheats, gets out of tolerance, breaks, has cold solder joints, or gets eaten by the dog. The key phrase in this statement, however, is "get working correctly", a task which has often made me reconsider my choice of a career. After all the top-down designing, structured programming, and code inspections are through, I am always left with my buggy software and a tool known as a debugger. Debugging can be the hardest part of a software project, but the right tool and a collection of tips and techniques can make the job a lot more pleasant. This article presents several of the tips I have found useful when debugging in the IBM C Set++ environment.

The debugger that installs with the C Set++ product is IPMD. IPMD exploits the Presentation Manager user interface to provide an efficient source-level debugging environment. IPMD also excels in the debugging of Presentation Manager applications. In addition to the standard features a developer expects in a state-of-the-art debugger (such as execution control, breakpoints, data monitors, register, storage, and stack display), IPMD has been enhanced to give you advanced features such as automatic multithread support, a PM message queue monitor, exception handling, graphical window analysis, template support, class hierarchy and details, and expression evaluation.

The current version of IPMD (the C Set++ 2.0/2.1 version) can debug C code produced by the C Set/2 product, C/C++ code from the C Set++ product, and 16-bit code containing Microsoft Codeview format debug information.

As mentioned above, IPMD has some great features; however, it is not always obvious how to use them to get the bugs out in the most efficient manner. The following are some of the less obvious, but extremely useful, hints for better debugging with IPMD.

Debugging Child Processes

DosExecPgm lets your program request that another program execute as a child process. With a simple change to the parent program, you can start an instance of IPMD to independently debug the child process. The following code segment demonstrates using DosExecPgm to start the program, "t.exe":

int i;
char LoadError[100];
RESULTCODES rcodes;
i = DosExecPgm(LoadError,
sizeof(LoadError),
EXEC_SYNC,
NULL,
NULL,
&rcodes,
"t.exe");

Changing the DosExecPgm call to:

i = DosExecPgm(LoadError,
sizeof(LoadError),
EXEC_SYNC,
"ipmd.exe\0-n t.exe\0\0",
NULL,
&rcodes,
"ipmd.exe");

causes IPMD to start debugging "t.exe".

The -n is one of the optional command-line parameters to IPMD that indicates that restart information is not to be used. The only restriction in this comes from DosExecPgm - you may not use DosExecPgm to start a process that is of a different type than the starting (parent) process. Because IPMD (the child) is a PM program, the parent also must be PM. This is accomplished by using the /PM:PM switch when linking the parent.

Performing Typecasting

The Monitor Expression dialog lets you enter expressions for evaluation and monitoring. If you need the address of variable &parray, you enter &parray in the Monitor Expression dialog; the address appears in a monitor window. The expression evaluator ports a subset of the C/C++ language.

One of the major functional enhancements in the C++ release of IPMD is the ability to perform user typecasting in the Monitor Expression dialog. To use complex typecasting, your application must be compiled using the C++ front-end (rather than the C front-end). This is, of course, automatic for C++ programs and can be requested for C programs with the /Tdp compiler switch.

A very common use for such typecasting is to provide for the display of dynamically allocated arrays. Consider the following program:

#include <malloc.h>
int main(int argc, char **argv,char **envp)
{
int i = 500;
int * iarray = (int *) malloc(i * sizeof(int));
iarray[0] = 10;
iarray[25] = 20;
}

The standard method for displaying a variable with IPMD is to place the mouse pointer on the variable name and double-click mouse button 1. If such an action is performed on the variable iarray, the program monitor window displays only the first element of iarray (as shown on the top line of the Program Monitor window in Figure 1). You can look at individual elements by typing iarray[10], for example, in the Monitor expression dialog, or you can determine the address of the array and use the storage window to view the contents.

There is an easy way, however, to display the entire array in the monitor window. If you enter the following expression in the Monitor Expression dialog, any number of the array elements will appear in the Program Monitor window (after the representation is changed to Array):

*(int(*)[n])iarray

where n is the number of elements you want to see. Figure 1 shows the dialog and the resulting monitor display.

GettingBugs-Fig-1.gif

Figure 1. Monitor Expression Dialog and display

Debugging PM Applications

When debugging a PM application, IPMD functions precisely as it would in debugging any OS/2 application, and no additional preparation is necessary on the part of the user. The debugger automatically detects that the application is a PM application. However, the following are a few additional concepts of which you should be aware.

Presentation Manager is a message-based system. As program events are encountered by PM programs, the programs communicate with each other by passing messages and by receiving user input through input messages. When a PM program encounters an enabled breakpoint, the input queue can become blocked and, as a result, dependent program events, or processes, can also become blocked. For example, the input queue can become blocked when your program is halted at a breakpoint that has been triggered by an input event. The PM debugging option of IPMD is built around two distinct ways of managing these dependencies.

IPMD provides two modes of operation - synchronous and asynchronous - which refer to different means by which synchronous message dependencies are handled when the debugger has control (for example, the application is at a breakpoint, stepping, and so forth).

In synchronous mode, the synchronous dependencies are held for all applications except the debugger. More precisely, the keyboard and mouse messages for the debugger are processed, but those for other applications are not. Thus, all other PM applications, though still processing generally, will freeze when a synchronous dependency is hit. In particular, these applications will not respond to mouse and keyboard messages as long as the debugger has control.

When the debugger has control in asynchronous mode, it responds to all messages on behalf of the application in a default fashion. Thus, all other applications will behave normally. However, because the program being debugged is suspended and because the debugger is providing a default response to messages, the user cannot effectively operate on the application's windows while the debugger has control. If you want to look at the window your application is executing in, uncovering it by moving other windows won't help. Since no repaint messages are being processed, you are left with a copy of the moved windows on top of your application's window! To view the application's window when the application is stopped, position it so that it is not covered whe n IPMD gets control.

Do not operate the debugger in asynchronous mode if the PM application that you are debugging requires the appropriate response to its messages. For example, a dynamic data exchange (DDE) message would require the appropriate response.

The PM Debugging mode selection dialog is accessed from the Session settings menu under the Options pull-down.

Debugging REXX DLLs

You can easily debug DLLs called by REXX programs. Start IPMD with the following syntax:

IPMD CMD.EXE /K <your REXX.cmd>

When IPMD displays the disassembly code for CMD.EXE, set a load type breakpoint to stop on the load of the DLL you want to debug. Tell IPMD to Run. At the popup indicating your DLL has loaded, set any necessary breakpoints in the DLL's functions.

Conclusion

Writing programs should be fun, however, debugging can take out all the fun. I hope that these few helpful tips will put the fun back into your programming. Let us know what you think - we'll be watching the forums!