Jump to content

Debug Notifications

From EDM2

DBG_N_SUCCESS

Debug Notification 0 - Success Notification

This notification returns:

  • Cmd= DBG_N_Success

The DosDebug command was successful. Returned values depend on the command just executed.

DBG_N_ERROR

Debug Notification -1 - Error Notification

This notification returns:

  • Cmd= DBG_N_Error
  • Value= Any standard error code

An error was detected while attempting a DosDebug command.

Error codes are returned from DosDebug in different ways:

  1. Errors can be returned via the standard method (EAX = ERROR_CODE).
    This is only done when the DosDebug command failed to execute at all. An example of this would be ERROR_INTERRUPT when the debugger receives a signal. If DosDebug returns a nonzero value in the EAX register, the returned Debug buffer is invalid.
  2. Errors are also returned via the DBG_N_Error notification.
    This is used when the DosDebug command was attempted, but failed due to some internal DosDebug failure. Examples of error codes returned via this interface are ERROR_INVALID_PROCID and ERROR_INVALID_DATA. Generally, these errors are detected while in the context of the debuggee process, and may include ERROR_INTERRUPT.

DBG_N_ProcTerm

Debug Notification -6 - Process Termination Notification

This notification returns:

  • Cmd= DBG_N_ProcTerm
  • Value= Process Exit Code
  • Index= Process Exit Type
  • Addr= 0

The debuggee process is about to terminate.

The debugger is still allowed to examine the debuggee's final register and memory contents at this time. Note that when the debugger has completed this examination, it should finish terminating the debuggee process with a final DBG_C_Go, DBG_C_SStep, or DBG_C_Term command.

Value and Index contain the same information as that returned via a subsequent DosWaitChild call. The act of collecting this information does not terminate the process.

DBG_N_Exception

Debug Notification -7 - General Exception Notification

This notification returns:

For the pre-first chance for a breakpoint exception:

  • Cmd= DBG_N_Exception
  • Value= 0 (DBG_X_PRE_FIRST_CHANCE)
  • Addr= Linear address of breakpoint
  • Buffer= Exception number (XCPT_BREAKPOINT) (0xC000009F)

For the pre-first chance for a single-step exception:

  • Cmd= DBG_N_Exception
  • Value= 0 (DBG_X_PRE_FIRST_CHANCE)
  • Addr= Linear address of instruction after Single Step
  • Buffer= Exception number (XCPT_SINGLE_STEP) (0xC00000A0)

For the first chance for all exceptions:

  • Cmd= DBG_N_Exception
  • Value= 1 (DBG_X_FIRST_CHANCE)
  • Addr= Linear address of exception
  • Buffer= Pointer to Exception Report Record in debuggee's context
  • Len= Pointer to Exception Context Record in debuggee's context

For the last chance for all exceptions:

  • Cmd= DBG_N_Exception
  • Value= 2 (DBG_X_LAST_CHANCE)
  • Addr= Linear address of exception
  • Buffer= Pointer to Exception Report Record in debuggee's context
  • Len= Pointer to Exception Context Record in debuggee's context

For an invalid stack notification:

  • Cmd= DBG_N_Exception
  • Value= 3 (DBG_X_STACK_INVALID)
  • Addr= Linear address of exception
  • Buffer= Exception number

The scenarios under which a debug exception is reported are pre-first, first, and last chance, and invalid stack notification. The Value field of the user debug buffer indicates the scenario.

DosDebug has detected an exception (a trap or a fault) at the specified address. The exception number in the exception structure identifies the exception that was detected.

Exception notifications are always returned from the context of the thread that detected the exception. That is, the exception structure reflects the state of the thread that caused the exception, at the time the exception was detected.

The debugger is given a maximum of two chances to handle exceptions other than single-step or breakpoint exceptions, which have a maximum of three chances. The order of operations for handling an exception is as follows:

  1. Debugger has the pre-first chance to handle the exception (for breakpoint and single-step exceptions).
  2. Debugger has the first chance to handle the exception, or to invoke an exception handler if it is present.
  3. Debugger has the last chance to handle the exception, or to invoke an exception handler if it is present.

An exception notification is returned for all exceptions, including those raised by the user via DosRaiseException.

An exception can have an informational, warning, or fatal severity. The severity is coded in the high-order three bits of the exception number for user-raised and system exceptions.

The debugger may dismiss the exception by returning XCPT_CONTINUE_EXECUTION, so that the user's context is restored, and execution continues at the point where the exception occurred. Otherwise, the debugger may return XCPT_CONTINUE_SEARCH. This causes the exception to be passed to the user's exception handlers (after the debugger's first chance), or causes the default action for the exception to occur (after the debugger's last chance).

For performance reasons, the single-step and breakpoint exceptions cause a "pre-first" notification. This is faster than the ordinary first exception notification. At the time of the notification, the debugger may decide if the single-step or breakpoint exception was an anticipated event. If it was anticipated, the debugger may return XCPT_CONTINUE_EXECUTION, as for an ordinary first notification. If it was not anticipated, the debugger may return XCPT_CONTINUE_SEARCH in order to raise an ordinary first notification for the single-step or breakpoint exception. With the second notification, this allows a maximum of three notifications for the single-step and breakpoint exceptions.

For breakpoint exceptions, the instruction pointer (EIP) of the debuggee is decremented to point to the breakpoint instruction.

Note
Do not confuse the family of floating point exceptions with the DBG_N_CoError error notification.
Restrictions
The error code may not be reliable in some situations for the page fault exception, due to hardware errors.

DBG_N_ModuleLoad

Debug Notification -8 - Module Load Notification

This notification returns:

  • Cmd= DBG_N_ModuleLoad
  • Value= MTE (Module Table Entry) handle of newly attached module
  • Addr= 0

A module has just been loaded. This occurs either at program startup, or during a call to DosLoadModule.

The newly attached module's handle is returned via Value. You can use this handle with DosQueryModuleName, or with the Debug DBG_C_NumToAddr command, for symbolic debugging. A debugger should save these handles for future reference.

There may be many module attachments done at one time, but DosDebug is only able to communicate a single load during any one notification. In this case, the additional library load notifications become pending. The debugger should issue repeated DBG_C_Stop commands to be notified of these additional library loads, until Success is returned from the DBG_C_Stop command. If the DBG_C_Go, DBG_C_SStep, or DBG_C_RangeStep commands are issued instead of the DBG_C_Stop command, the pending notifications will be returned immediately, until there are no further notifications.

DBG_N_CoError

Debug Notification -9 - Coprocessor Error Notification

This notification returns:

  • Cmd= DBG_N_CoError
  • Value= Any standard Error Code

An error was detected while attempting a DosDebug command that attempted to access a Coprocessor.

DBG_N_CoError is similar to the DBG_N_Error notification, but is returned only after attempting an access to the coprocessor registers.

DBG_N_CoError is returned if any one of the following occurs:

  • The debuggee process is emulating the coprocessor.
  • The specified debuggee thread has not yet attempted to use the coprocessor.
  • The wrong coprocessor type is used.
  • The requested coprocessor type is not supported or available.

This notification should not be confused with any of the floating point exception notifications.

DBG_N_ThreadTerm

Debug Notification -10 - Thread Termination Notification

This notification returns:

  • Cmd= DBG_N_ThreadTerm
  • Value= Thread's proposed return code (from DosExit)
  • Addr= 0

A debuggee thread is about to terminate.

DosExitList processing has not yet been started.

The debugger is still allowed to examine the debuggee thread' signal register contents at this time. When the debugger has completed this examination, it should finish terminating the debuggee thread with a final DBG_C_Go or DBG_C_SStep command.

Value contains the return code from the thread. This is only a proposed return code passed from DosExit. Only when the process actually terminates is the return code that is passed to DosWaitChild finally known.

DBG_N_AsyncStop

Debug Notification -11 - Asynchronous Stop Notification

This notification returns:

  • Cmd= DBG_N_AsyncStop
  • Value= 0
  • Addr= 0

An Asynchronous Stop request has been detected.

The asynchronous stop command is used to get the attention of some debuggee thread, so that the debugger can again control the process. Because any notification results in the debuggee's coming under control of the debugger again, the asynchronous stop notification becomes redundant in that case, and is not returned.

The asynchronous stop request will be overridden and ignored if another notification can be performed instead, at the same time. An asynchronous stop notification never becomes a "pending" notification, in the sense that a library load notification becomes pending.

DBG_N_NewProc

Debug Notification -12 - New Process Notification

This notification returns:

  • Cmd= DBG_N_NewProc
  • Value= Process ID of the new process
  • Addr= 0

The debuggee process has just started a child process, and that child process needs to be debugged.

Note
This notification occurs only if descendant debugging was specified in the DosExecPgm call that started the process tree in which the debuggee is executing.

DBG_N_AliasFree

Debug Notification -13 - Alias Free Notification

This notification returns:

  • Cmd= DBG_N_AliasFree
  • Buffer= 32-bit offset to debugger alias region
  • Addr= 0

An object that contains an aliased region is about to be freed by the debuggee. This can also occur if the underlying memory object is about to be shrunk such that the alias would span memory outside the resultant object.

The alias region must be unmapped before the debugger may execute the debuggee again.

The DBG_C_UnMapAlias command is the proper response to an alias free notification.

If a debugger creates an alias to memory in another debugger, and that memory is itself an alias to the second debugger's debuggee, then the first debugger will not receive an alias free notification when the memory of the second debugger's debuggee is freed. The alias will be freed automatically. The second debugger will receive an alias free notification.

DBG_N_Watchpoint

Debug Notification -14 - Watchpoint Hit Notification

This notification returns:

  • Cmd= DBG_N_Watchpoint
  • Addr= Linearized instruction pointer of watchpoint hit
  • Value= Process ID of process that hit the watchpoint
  • Len= Thread ID of thread that hit the watchpoint
  • MTE= Module Table Entry handle of process that hit the watchpoint
  • Index= Watchpoint ID number

A watchpoint has been hit. The Watchpoint ID number identifies the watchpoint that was hit.

Multiple watchpoint hits become pending notifications that are returned on subsequent DBG_C_Stop, DBG_C_Go, or DBG_C_SStep commands. A watchpoint may be hit at any time, and more than one watchpoint may be hit at the same time.

If a watchpoint notification is pending, the resources used by the watchpoint will not be freed until the watchpoint notification is complete, or the watchpoint is cleared.

A watchpoint notification is not always returned by the same thread that caused the hit. A watchpoint may be hit by one thread, but another thread may return the notification. The thread ID of the thread that hit the watchpoint is not necessarily the value passed in the Tid field.

Data Watchpoint hits are treated as faults, rather than as traps, by the 80386 processor. Therefore, the linearized instruction pointer may not point to the exact instruction that caused the fault.

If a watchpoint is hit at interrupt time, the Value, Addr, MTE, and Len fields are all returned as zero.

DBG_N_ThreadCreate

Debug Notification -15 - Thread Creation Notification

This notification returns:

  • Cmd= DBG_N_ThreadCreate
  • Tid= Thread ID of new thread
  • Addr= 0

A debuggee thread has just been created.

The new thread has not executed any user code yet.

DBG_N_RangeStep

Debug Notification -17 - Range Step Notification

This notification returns:

  • Cmd= DBG_N_RangeStep
  • Addr= Linearized instruction pointer at exception
  • Value= Linearized instruction pointer of last user instruction executed

The debuggee stopped range-stepping because its linearized instruction pointer was outside the original range, or because the current linearized instruction pointer is equal to the linearized instruction pointer of the previous user instruction.

The DBG_N_RangeStep notification is returned independently of the DBG_N_Watchpoint notification, even though the Watchpoint fault and the RangeStep may have occurred at the exact same time.