CPGuide - Debugging
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
Debugging is the process of detecting, diagnosing, and eliminating errors in programs. A debugger application is designed to interact with and control the application that it is debugging. Because of the protected mode architecture of OS/2, special steps must be taken to enable a debugger application to perform its functions in the application being debugged (for example, to examine and manipulate memory locations in the address space of another process).
The following topic is related to the information in this chapter:
- Program execution and control
About Debugging
DosDebug enables one application to control the execution of another application for debugging purposes.
An application is selected for debugging when it is started. DosExecPgm and DosStartSession both have flags that can be used to specify that the application being started is to be controlled by the starting application.
DosExecPgm starts an application within a new process. DosStartSession starts a new session within which one or more processes can be executing. See DosStartSession and DosExecPgm for details on how to start an application for debugging purposes. For information on processes and sessions, see Program Execution Control in this book.
Once a process has been selected for debugging, DosDebug is used to control its execution and to examine and manipulate its variables.
DosDebug provides a full set of debugging commands, including execution control commands-like single stepping and setting watchpoints-and commands to examine and manipulate the memory and registers of the process being debugged. The debugger process can access specific threads within a process being debugged and specific processes within a session being debugged.
DosDebug also has a rich set of notification messages to keep the debugger application informed of activities occurring during the execution of the application being debugged.
The debugger application can use the session and process control functions described in Program Execution Control to control the child process or session being debugged. For example, the debugger can use DosSelectSession to switch itself, or the session being debugged, to the foreground.
Using the Debugging Function
DosDebug provides a set of commands that permit one process to control another process for debugging.
In the following code fragment, the calling process uses DosDebug to modify a word in a controlled process. All the necessary steps have already been taken so that the calling process controls the second process-the process identifier of the controlled process has been placed into PID, the address of the word to be modified in the controlled process has been placed into Addr, and the value to be substituted in the controlled process has been placed into Value.
(Due to the size of the debug_buffer data structure, the code fragment has been divided into two figures. If you were actually entering this into a program, the information would be together as if it were all one figure.)
- Note
- In the example code fragments that follow, error checking was left out to conserve space. Applications should always check the return code that the functions return. Control Program functions return an APIRET value. A return code of 0 indicates success. If a non-zero value is returned, an error occurred.
#define INCL_DOSPROCESS /* Process and thread values */ #include <os2.h> #include <stdio.h> struct debug_buffer { ULONG Pid; /* Debuggee Process ID */ ULONG Tid; /* Debuggee Thread ID */ LONG Cmd; /* Command or Notification */ LONG Value; /* Generic Data Value */ ULONG Addr; /* Debuggee Address */ ULONG Buffer; /* Debugger Buffer Address */ ULONG Len; /* Length of Range */ ULONG Index; /* Generic Identifier Index */ ULONG MTE; /* Module Table Entry Handle */ ULONG EAX; /* Register Set */ ULONG ECX; ULONG EDX; ULONG EBX; ULONG ESP; ULONG EBP; ULONG ESI; ULONG EDI; ULONG EFlags; ULONG EIP; ULONG CSLim; /* Byte Granular Limits */ ULONG CSBase; /* Byte Granular Base */ UCHAR CSAcc; /* Access Bytes */ UCHAR CSAtr; /* Attribute Bytes */ USHORT CS; ULONG DSLim; ULONG DSBase; UCHAR DSAcc; UCHAR DSAtr; USHORT DS; ULONG ESLim; ULONG ESBase; UCHAR ESAcc; UCHAR ESAtr; USHORT ES; ULONG FSLim; ULONG FSBase; UCHAR FSAcc; UCHAR FSAtr; USHORT FS; ULONG GSLim; ULONG GSBase; UCHAR GSAcc; UCHAR GSAtr; USHORT GS; ULONG SSLim; ULONG SSBase; UCHAR SSAcc; UCHAR SSAtr; USHORT SS; }; struct debug_buffer DbgBuf; /* Debug buffer */ ULONG ulPID; /* Process ID of the controlled process */ ULONG ulAddr; /* Address in the controlled process */ LONG lValue; /* Value to be substituted in the */ /* controlled process */ APIRET ulrc; /* Return code */ DbgBuf.Cmd = DBG_C_WriteMem; /* Indicate that a Write Word */ /* command is requested */ DbgBuf.Pid = ulPID; /* Place PID of controlled process */ /* into the debug buffer */ DbgBuf.Addr = ulAddr; /* Place the word address (within the */ /* controlled process) into the debug */ /* buffer */ DbgBuf.Value = lValue; /* Place the value to be updated into */ /* the specified word of the controlled */ /* process */ ulrc = DosDebug(&DbgBuf); if (ulrc != 0) { printf("DosDebug error: return code = %ld", ulrc); return; } /* Be sure to check DbgBuf.Cmd for the notification returned by DosDebug */
The Cmd field in the debug buffer is used for two purposes. On input, the Cmd field is used to pass the commands that direct DosDebug's activities. On output, the Cmd field is used by DosDebug to return a notification indicating the events and activities that occurred during the call.
If DosDebug returns no error, a notification resides in the Cmd field of the debug buffer. The data returned with the notification varies, depending on the command passed in the Cmd field of the debug buffer data structure when DosDebug was called.
Not all fields in the debug buffer have to be defined on every DosDebug command. The same field can have a different meaning in different DosDebug commands.
Some notifications (such as DBG_N_ModuleLoad and DBG_N_NewProc) might require multiple returns to the debugger. These additional, pending notifications will be returned before the process being debugged is permitted to execute any more user code, and will be returned on the Go, Single Step, or Stop commands.
Additional notifications can be pending at any time, so a debugger must be ready to handle any notification any time a Go, Single Step, or Stop command is called.