CPGuide - Debugging: Difference between revisions
Line 174: | Line 174: | ||
::This command allows attaching to a currently running task. | ::This command allows attaching to a currently running task. | ||
:;Note | |||
::A DBG_C_Connect does not need to be issued because DBG_C_Attach will perform the connection. Also, because the debugger did not start the task, it will not have a parent/child relationship as in a DBG_C_Connect. | |||
DosDebug generates the following notifications: | ::DosDebug generates the following notifications: | ||
:::1.DBG_N_ModuleLoad notifications for all loaded modules | |||
:::2.DBG_N_ThreadCreate notifications for all active threads in task | |||
:;Note | |||
:: Unlike DBG_C_Connect, there will not be any DBG_N_ModuleInit notifications because the task is most likely already in _main. | |||
:;b.DBG_C_Detach | |||
::This debug command has the following parameters: | |||
; | |||
b.DBG_C_Detach: This debug command has the following parameters: | |||
PID Process ID of debuggee | PID Process ID of debuggee | ||
Line 201: | Line 201: | ||
;Note: This is the only call that will cleanly turn off debugging and resume the specified task. DBG_C_Term will kill the task whether it was connected or attached. | ;Note: This is the only call that will cleanly turn off debugging and resume the specified task. DBG_C_Term will kill the task whether it was connected or attached. | ||
3.PowerPC-specific notifications: are as follows: | ;3.PowerPC-specific notifications | ||
: are as follows: | |||
a.DBG_N_ModuleInit: Module initialization routine about to run. This notification is the same format as DBG_N_ModuleLoad. | a.DBG_N_ModuleInit: Module initialization routine about to run. This notification is the same format as DBG_N_ModuleLoad. | ||
Line 216: | Line 217: | ||
Value Process ID of debuggee | Value Process ID of debuggee | ||
4.DBG_C_Go and DBG_C_SStep: will stop and return any pending notifications. | ;4.DBG_C_Go and DBG_C_SStep | ||
: will stop and return any pending notifications. | |||
5.Serialization of command execution: All notifications other than DBG_N_Success and DBG_N_Error must be acknowledged through DBG_C_Continue before processing resumes or another notification can be grabbed. Thus, only GO/SStep and Stop (to prevent retrieving a pending notification) will be prevented from running. All other subcommands can be executed. | ;5.Serialization of command execution | ||
: All notifications other than DBG_N_Success and DBG_N_Error must be acknowledged through DBG_C_Continue before processing resumes or another notification can be grabbed. Thus, only GO/SStep and Stop (to prevent retrieving a pending notification) will be prevented from running. All other subcommands can be executed. | |||
DosDebug informs the debugger that a notification has been returned, but not acknowledged. If you issue a Go/SStep/Stop and get the following synchronous notification, then you must issue a DBG_C_Continue before resuming execution. | DosDebug informs the debugger that a notification has been returned, but not acknowledged. If you issue a Go/SStep/Stop and get the following synchronous notification, then you must issue a DBG_C_Continue before resuming execution. | ||
rc = DosDebug() = 0; | rc = DosDebug() = 0; | ||
puDB->Cmd = DBG_N_Error; | puDB->Cmd = DBG_N_Error; | ||
puDB->Value = ERROR_INVALID_FUNCTION; | puDB->Value = ERROR_INVALID_FUNCTION; | ||
The following code segments illustrate the use of various commands: | The following code segments illustrate the use of various commands: | ||
Line 277: | Line 278: | ||
</PRE> | </PRE> | ||
6.Per task serialization of all DosDebug subcommands: A debugger can be multi-threaded. If the debugger issues subcommands for different tasks they can run concurrently. If the debugger issues subcommands for the same task they will be serialized. | ;6.Per task serialization of all DosDebug subcommands: A debugger can be multi-threaded. If the debugger issues subcommands for different tasks they can run concurrently. If the debugger issues subcommands for the same task they will be serialized. | ||
;7.Breakpoint exceptions (trap word instruction): Debugger must increment IP to next instruction (+4) whenever a breakpoint exception occurs. | |||
;8.DBG_N_Exception notification: Returns Thread ID of thread taking exception in debug_buffer->TID field. When responding to exception notifications use the proper Thread ID in the DBG_C_Continue call. | |||
;9.Unsupported or not working for the PowerPC: | |||
:a.Calls to these commands will result in a DBG_C_Null: | |||
::*DBG_C_XchngOpcode | |||
::*DBG_C_RangeStep | |||
::*DBG_C_MapRWAlias | |||
::*DBG_C_UnMapAlias | |||
::*DBG_C_MapROAlias | |||
::*DBG_C_LinToSel | |||
::*DBG_C_SelToLin | |||
:b.Global scope watchpoints: Watchpoint effective in the context of any task currently not allowed. | |||
:c.Descendant (task or session) debugging not working. | |||
::1.EXEC_ASYNCRESULTDB: Tasking flag will act like EXEC_TRACE | |||
::2.SSF_TRACEOPT_TRACEALL: Session flag will act like SSF_TRACEOPT_TRACE | |||
::3.DBG_N_ProcNew notification never sent | |||
c.Descendant (task or session) debugging not working. | |||
1.EXEC_ASYNCRESULTDB: Tasking flag will act like EXEC_TRACE | |||
2.SSF_TRACEOPT_TRACEALL: Session flag will act like SSF_TRACEOPT_TRACE | |||
3.DBG_N_ProcNew notification never sent | |||
;10.DBG_C_NumToAddr and DBG_AddrToNum | ;10.DBG_C_NumToAddr and DBG_AddrToNum |
Revision as of 16:11, 29 February 2020
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.
Debugging on OS/2 Warp (PowerPC Edition)
The following are the specific features available for debugging for OS/2 Warp (PowerPC Edition):
- 1.PowerPC-specific debug buffer
- The debug buffer is specified in the value field of DBG_C_Connect command as follows:
- Intel:
DBG_L_386
This is not defined in bsedos.h.
- PowerPC:
DBG_L_PPC
This is defined in bsedos.h.
- 2.PowerPC-specific functions
-
- a.DBG_C_ATTACH
- This debug command has the following parameters:
- PID
- Process ID of debuggee
- CMD
- DBG_C_Attach
- VALUE
- DBG_L_PPC
- This command is defined as follows:
- For clients in bsedos.h
- For servers in server\include\debug_types.h as follows:
#define DBG_L_PPC 2
- This command returns:
- DBG_N_Success Attachment made
- DBG_N_Error Any OS/2-defined error
- This command allows attaching to a currently running task.
- This command returns:
- Note
- A DBG_C_Connect does not need to be issued because DBG_C_Attach will perform the connection. Also, because the debugger did not start the task, it will not have a parent/child relationship as in a DBG_C_Connect.
- DosDebug generates the following notifications:
- 1.DBG_N_ModuleLoad notifications for all loaded modules
- 2.DBG_N_ThreadCreate notifications for all active threads in task
- DosDebug generates the following notifications:
- Note
- Unlike DBG_C_Connect, there will not be any DBG_N_ModuleInit notifications because the task is most likely already in _main.
- b.DBG_C_Detach
- This debug command has the following parameters:
PID Process ID of debuggee
CMD DBG_C_Detach
This command returns:
DBG_N_Success Attachment made
DBG_N_Error Any OS/2-defined error
This command detaches from attached and connected tasks. The specified task is resumed and all debugging hooks are removed.
- Note
- This is the only call that will cleanly turn off debugging and resume the specified task. DBG_C_Term will kill the task whether it was connected or attached.
- 3.PowerPC-specific notifications
- are as follows:
a.DBG_N_ModuleInit: Module initialization routine about to run. This notification is the same format as DBG_N_ModuleLoad. CMD DBG_N_ModuleInit
Value MTE (module handle)
Addr 0 b.DBG_N_ReadyToRunMain: Debuggee thread 1 ready to run _start. Issued after all import DLL Init/Term routines have completed. This allows the debugger to know that the debugged task has finished loading and is ready to run.
Note: For descendant debuggee tasks, DBG_N_NewProc will be sent instead. CMD DBG_N_ReadyToRunMain
Value Process ID of debuggee
- 4.DBG_C_Go and DBG_C_SStep
- will stop and return any pending notifications.
- 5.Serialization of command execution
- All notifications other than DBG_N_Success and DBG_N_Error must be acknowledged through DBG_C_Continue before processing resumes or another notification can be grabbed. Thus, only GO/SStep and Stop (to prevent retrieving a pending notification) will be prevented from running. All other subcommands can be executed.
DosDebug informs the debugger that a notification has been returned, but not acknowledged. If you issue a Go/SStep/Stop and get the following synchronous notification, then you must issue a DBG_C_Continue before resuming execution.
rc = DosDebug() = 0; puDB->Cmd = DBG_N_Error; puDB->Value = ERROR_INVALID_FUNCTION;
The following code segments illustrate the use of various commands:
/*********************************************************************/ /* Connect and grab all pending DBG_N_ThreadCreate, DBG_N_ModuleInit */ /* and DBG_N_ModuleLoad notifications. Note, Stop returns */ /* DBG_N_Success when there are no more notifications. */ /*********************************************************************/ DBG_C_Connect DBG_C_Stop while ( puDB->Cmd != DBG_N_Success ) { DBG_C_Continue w XCPT_CONTINUE_STOP DBG_C_Stop } /**********************************************************************/ /* Go until certain notification occurs. This loop will also grab any */ /* pending notifications that are outstanding since DBG_C_Go won't */ /* execute if any notifications are pending. */ /**********************************************************************/ DBG_C_Go while (debug_buffer->Cmd != Notification your looking for) { DBG_C_Continue w XCPT_CONTINUE_STOP DBG_C_GO } /*********************************************************************/ /* Clear all pending notifications and acknowledge each notification */ /*********************************************************************/ DBG_C_STOP while (debug_buffer->Cmd != DBG_N_Success) { DBG_C_Continue w XCPT_CONTINUE_STOP DBG_C_STOP }
- 6.Per task serialization of all DosDebug subcommands
- A debugger can be multi-threaded. If the debugger issues subcommands for different tasks they can run concurrently. If the debugger issues subcommands for the same task they will be serialized.
- 7.Breakpoint exceptions (trap word instruction)
- Debugger must increment IP to next instruction (+4) whenever a breakpoint exception occurs.
- 8.DBG_N_Exception notification
- Returns Thread ID of thread taking exception in debug_buffer->TID field. When responding to exception notifications use the proper Thread ID in the DBG_C_Continue call.
- 9.Unsupported or not working for the PowerPC
- a.Calls to these commands will result in a DBG_C_Null:
- DBG_C_XchngOpcode
- DBG_C_RangeStep
- DBG_C_MapRWAlias
- DBG_C_UnMapAlias
- DBG_C_MapROAlias
- DBG_C_LinToSel
- DBG_C_SelToLin
- b.Global scope watchpoints: Watchpoint effective in the context of any task currently not allowed.
- c.Descendant (task or session) debugging not working.
- 1.EXEC_ASYNCRESULTDB: Tasking flag will act like EXEC_TRACE
- 2.SSF_TRACEOPT_TRACEALL: Session flag will act like SSF_TRACEOPT_TRACE
- 3.DBG_N_ProcNew notification never sent
- 10.DBG_C_NumToAddr and DBG_AddrToNum
- these functions are not fully supported on the PowerPC as there meaning differs between Intel and PowerPC architectures. The following has been observed:
- a.On Intel, this should be data segment. It appears to be data segment on the PowerPC:
PBuf->Cmd = DBG_C_NumToAddr; PBuf->Value = 1;
- b.On Intel, this should be a code segment. On the PowerPC, this is invalid:
PBuf->Cmd = DBG_C_NumToAddr; PBuf->Value = 2;
- c.On Intel, this should be invalid. On the PowerPC, this appears to be code segment:
PBuf->Cmd = DBG_C_NumToAddr; PBuf->Value = 0;