ICAT: The New Remote Source-code Debugger for OS/2

Written by Chris Matthews and Dave Evans

Introduction
There's great news for all of you OS/2 developers! We are proud to introduce a new remote debugger for you to debug source-level code for your OS/2 Warp device drivers, installable file system (IFS) binaries, and applications - all to increase your productivity during debug time. This might sound familiar if you subscribed to DevCon. We previously ran an article about ICAT when we shipped the original debugger on DevCon 11 and 12 around the release of Warp 4.0 and Warp 4.0 Server SMP, but a lot has changed since then.

The new debugging environment is the Remote Interactive Code Analysis Tool (Remote ICAT) for OS/2, which you can install from the Toolkit category of the Developer Connection catalog or from the ICAT home page off the DDK (Device Driver Developer Kit) Area. Remote ICAT is a two-system setup that piggybacks on the kernel debugger (KDB) and works on these versions of the target machine: OS/2 Warp 4.0 Version 4, Warp Server 4.0 SMP Version, and OS/2 Warp Version 3.0 at FixPak 24 or later. Remote ICAT lets you debug a target OS/2 system from a remote host with the familiar IPMD/ICSDEBUG debugger interface. This makes it easier to debug VIO and PM applications, IFS binaries, and device drivers, especially drivers using the new adapter device driver (ADD) and graphics ADD (GRADD) modules written in C. Here are some of the features of the new debugger:


 * Source-Code Support
 * Remote ICAT supports 16- and 32-bit C, C++, and assembler language for debugging source. It supports both the High-Level Language (HLL) debug format used by IBM Visual Age C++ and the CodeView (CV) debug format used by Microsoft's assembler, C, and C++ environments.


 * Stack Unwind
 * Remote ICAT provides the ability to unwind stacks across 16- and 32-bit C, C++, and assembler routines. It also provides the ability to unwind the stacks through ring transitions (for example, from ring 0 to ring 3) and thunks.


 * I/O Breakpoints
 * This is a new feature added to support breakpoints on I/O ports. It is a feature supported on the Pentium and Pentium Pro processor and some stepping levels of the 486 processor. This feature has also been added to KDB.


 * Passthru
 * The Remote ICAT's Passthru feature lets you access KDB while working in the source-code debugger. This is handy for retrieving information that might be easier to obtain through KDB (for example, by using the DG and LG commands).

Note: The Passthru option can be dangerous if you modify the memory or register (state) on the target machine. Remote ICAT assumes that state is not changed while it has control. Therefore when you do make changes to the target machine state with the Passthru window, ensure that you select the Resync push button before Remote ICAT's next run or step directive. Even with the Resync option, it is safest to request information with the Passthru window as opposed to altering state.
 * Higher Baud Rates
 * With this new version of OS/2 Warp, the source-code debugger and KDB can operate at speeds up to 57,600 bps (115,200 bps if you use the special com.sys drivers of OS/2 Warp Version 4 on the host system). The default for the debuggers is 9,600 bps, but this rate can be changed to the higher rates in the setup file for Remote ICAT or by using the KDB .b command.


 * Floating Point Support
 * ICAT allows you to view the floating point registers for an IFS, Device Driver, etc. This is not possible today using KDB.


 * Many Other Enhancements
 * See the ICAT home page in the DDK area for a more complete list of features, FAQS, etc.

Operation of the Debugger
In the initial setup of the remote debugger, the target machine contains any of your IFS, physical device driver (PDD), virtual device driver (VDD), or application code to be debugged. These must be compiled and linked using debug flags (the specific flags depend on your compiler and linker). If file size is a problem, you can strip debug information from the binaries before putting them on the target machine, but they must be generated with the debug information initially.



The real debugging work is done on the host machine connected to the remote target machine through the COMx port (the same setup that KDB already uses). The host machine maintains the unstripped version of the debug binary files and the source used for building the binaries. The Remote ICAT debugger depends on the host machine's environment variables to access the directories that contain the debug binaries and source files. This allows Remote ICAT to debug device drivers, IFS binaries, or applications at the source level.

Once the initial setup of the target and host system is completed, the debugger environment is created to establish communication information, source and binary paths, module list selection, and other Remote ICAT options. Then Remote ICAT can be started. It takes a few seconds for Remote ICAT to initialize communication with the target system, but once the communication is established, the following initialization dialog is displayed. Select Attach to complete the connection.



Note: If you experience a communication problem, check to make sure that there is not a terminal emulator program running that competes for the COMx port. Also check to see if you can bring up KDB under a terminal emulator program (without Remote ICAT running) and communicate successfully. Don't forget to shut this terminal emulator down before retrying the Remote ICAT connection.

When the connection is complete, the debugger opens a Debugger Session Control (DSC) window. This window displays a list of Slots (process and thread IDs) along with the modules that are being debugged.

Note: If you do not see your module in the list, it may mean that the module was not compiled with the debug flags, the module was not found in Remote ICAT's binary search path, or that the target module was excluded due to an environment variable.

Notice that all the processes running in the system are displayed in the process list. This is because the source-code debugger piggybacks on KDB so that it comes in at the supervisor level just as KDB does. This gives the source-code debugger the flexibility to do things like debug an application and device driver in the same debug session at the source-code level with the same tool. You can watch your application call into your device driver and debug the device driver as the call enters the strategy routine. It also allows you to switch context between applications on the fly. These are things you can only do with KDB.

Once the kernel attachment is complete, you can select a module from the module list in the DSC window and then select the source code for the function you want to debug. Then you can set a breakpoint and let Remote ICAT run. When the breakpoint is hit, you can unwind the stack, look at storage, monitor properties of a variable, and so forth. At any time during the debug session, you can use the Passthru window to look at things like the global descriptor table (GDT), local descriptor table (LDT), and so forth.



What about Network debugging ?
Well this is something new we have added to ICAT. The network solution we have today is a three-tiered solution. It still needs a COM port connection to the target machine but requires a mediator (bridge) system between the host and the target system. The mediator (bridge) system can be OS/2 or NT (see the illustration below). For more information on how to set up the connection see the ICAT home page off the DDK (Device Driver Developer Kit) Area.



We have also provided a remote console monitor. The remote console monitor allows you to monitor a series of systems throughout your network and notify you of problems as they occur. It communicates directly with the mediator (bridge) daemon for status information. We are revamping the monitor into a more upscale GUI monitor, but we have a lightweight version available now.

Where are we going ?
You probably guessed it. We would like to get to an OS/2 point-to-point network debugging solution for ICAT and kernel debugger. This would remove the requirement for the mediator system and allow a direct debug connection from host to target over the network, but we are not sure when this will be available. If and when it is available, we will announce it on the ICAT home page or on EDM/2. See the illustration below for more information on future plans of OS/2 point-to-point debugging.



Helpful Remote ICAT Debugging Tips
The following are some Remote ICAT debugging tips that can be helpful for both novices and more advanced users.


 * Debugging Init Routines
 * Here are some ways of debugging an init routine for your device driver, DLL, or other modules using the source-code debugger.

Place a breakpoint interrupt (Int 3) in the beginning of your module's init routine. When the init routine is hit, the interrupt causes KDB to stop. When this happens, attach to the kernel with the Remote ICAT debugger. The program counter (PC) register should now point to the source for the init routine. From here, you can continue to step through your code, set breakpoints, or run. This guarantees that your module's page has been loaded. Note: Don't forget to release the KDB terminal emulator before attaching with the Remote ICAT debugger. Otherwise, a COMx port conflict might occur. Attach to the kernel when the system is coming up and KDB has already been loaded on the target machine. At this point, you can set your breakpoint in the appropriate location and run. This method is risky because the init routine might not have been loaded or paged in yet. Hence, the breakpoint might not be valid for the routine selected. It is possible to use the Passthru into the kernel in order to prefault the page (using the .i command) if the module has already been loaded, but this is not certain. You will get more consistent results with the pre-embedded Int 3 technique.
 * Disassembling a Raw Storage Location
 * At times you might find yourself debugging code placed in a raw storage location. This can happen if your application uses run-time generated instructions that are built into memory. To debug this code with the Remote ICAT debugger, you can modify the EIP register to point to the raw storage offset and let the Remote ICAT disassembler display the generated assembler information in the disassembly window.


 * Viewing Registers
 * Remote ICAT maintains a PC register, which is the linear address of the current execution point for the slot in question; that is PC == %(CS:EIP) in KDB debugger parlance. The EIP register is shown under the General registers heading. The CS register is shown under the Segment registers heading.

Note: Almost every window on ICAT has an Options->Display style that has unique display information for each window; e.g., stacks, registers, storage, etc.
 * Ring-3 Debugging
 * You can debug applications (.EXE and .DLL files) at ring 3 with Remote ICAT. The application's modules will be displayed in the DSC window, and you can click on these modules to show their constituent parts. Note that you need to be in the context of your application when you bring up its source under Remote ICAT. By context, we mean the active thread must be one of your application's threads (slots). If not, then you are mapping source for (say) app1.exe on top of (say) app2.exe's address space. You don't run into this problem with device drivers or IFS binaries because they are mapped into the global address space.

The simplest way to establish this correct context is to look in ICAT's DSC window and select the appropriate process and/or slot number for your application on the left hand side. The context with be switched automatically to this process. You can also select threads/ processes from the DSC window and hit the accelerator key to display the current stack, storage, registers, etc. for that given context.

Conclusion
You should now be on your way to successful remote source-code debugging of system-level binaries. We will continue to provide quality enhancements and features to the debugger, and your feedback is always welcome! Please send your comments to Chris Matthews or Dave Evans.