Format of Debug Information

This section discusses the format of the debug information which the debugger puts into the buffer in the DebugORPCClientFillBuffer and DebugORPCServerFillBuffer calls. The structure of this data is as follows, here specified in an IDL-like manner.27. For historical reasons, this structure has 1-byte alignment of its internal members. Again, for historical reasons, the data is always transmitted in little-endian byte order.


#pragma pack(1) // this structure defined with 1-byte packing alignment
struct {
    DWORD   alwaysOrSometimes;  // controls spawning of debugger
    BYTE    verMajor;           // major version
    BYTE    verMinor;           // minor version
    DWORD   cbRemaining;        // inclusive of byte count itself
    GUID    guidSemantic;       // semantic of this packet
    [switch_is(guidSemantic)] union { // semantic specific information
    
    // case "step" semantic, guid = 9CADE560-8F43-101A-B07B-00DD01113F11
        BOOL    fStopOnOtherSide;   // should single step or not?

    // case "general" semantic, guid = D62AEDFA-57EA-11ce-A964-00AA006C3706
        USHORT  wDebuggingOpCode;   // should single step or not, etc.
        USHORT  cExtent;            // offset=28
        BYTE    padding[2];         // offset=30, m.b.z.
        [size_is(cExtent)] struct {
            ULONG cb;               // offset=32
            GUID  guidExtent;       // the semantic of this extent
            [size_is(cb)] BYTE  *rgbData;   
            };
      };                  
   }

The first DWORD in the debug packet has a special meaning assigned to it. The rest of the debug packet is treated as a stream of bytes by COM and is simply passed across the channel to the debugger on the other side. If the first DWORD contains the value ORPC_DEBUG_ALWAYS (this is a manifest constant defined in the header files), then COM will always raise the notification on the other side (use of the four bytes "MARB" is for historical reasons synonymous with use of ORPC_DEBUG_ALWAYS). If the first DWORD in the debug packet contains the value ORPC_DEBUG_IF_HOOK_ENABLED, then the notification is raised on the other side of the channel only if COM debugging has been enabled in that context; that is only if DllDebugObjectRPCHook has been called in that process with fTrace = TRUE. It is the debugger's responsibility to include enough memory for the first DWORD in its response to the DebugOrpcClientGetBufferSize or DebugOrpcServerGetBufferSize notifications.

The two bytes immediately following the initial DWORD contain the major and minor version numbers of the data format specification.

For packets in the format of the current major version, this is followed by:

Semantic

Meaning

Step

This semantic indicates that the single stepping is to be performed or not. The GUID of this semantic is 9CADE560-8F43-101A-B07B-00DD01113F11. The data of this semantic consists of a Boolean value which indicates in the "step out of a server" case whether execution should continue once the other side is reached or one should remain stopped.

General

This semantic, which has GUID D62AEDFA-57EA-11ce-A964-00AA006C3706, allows for series of tagged bags of data to be passed. Each is byte counted, and has associated with it a GUID. wDebuggingOpCode allows for one of a series of operations to be specified. Existing-defined op-codes are as follows. Future op-codes are to be allocated by a central coordinating body.28.


Op-code

Meaning

0x0000

No operation

0x0001

Single step, stop on the other side, as in the "Step" semantic.


Extents presently defined for use in the General semantic are as follows:

Extent

Meaning

Interface pointer

This semantic has GUID 53199051-57EB-11ce-A964-00AA006C3706.

The contents of rgbData for this extent is simply an OBJREF, which is the data structure which describes a marshaled interface pointer, the data that results from calling CoMarshalInterface (OBREFs are described later in this specification). Usually, this OBJREF is either the self-enclosed LONGOBJREF variation or a custom-marshaled variation, but this is not required. The LONGOBJREF usually contains a reference count of zero, allowing this information to be freely discarded without a leakage of state. Remember that OBJREFs are always in little-endian byte order. An OBJREF is converted into its corresponding interface pointer using CoUnmarshalInterface.


With the Interface Pointer extent, an object can be created in the source debugger's space that relates to the call being made. It can then be marshaled, again, in the source debugger's process, not the source debuggee; this yields an OBJREF. The OBJREF is then transmitted in the course of the call as an extent in the passed debug information. On the destination side, it is conveyed to the destination debugger, who unmarshals it in its process. The result is a COM remoting connection from the source debuggers process to the destination debugger's process that is semantically tied to a particular COM call that needs to be debugged. (TBD) Interfaces on this object can be then be used to provide stack walk-backs, remote memory manipulation, or other debugging functionality.