Windows2000/private/windbg64/langapi/debugger/orpc_dbg.c
2020-09-30 17:12:32 +02:00

641 lines
18 KiB
C

// ORPC_DBG.C (tabs 4)
// !!!!!!!!! !!!!!!!!! NOTE NOTE NOTE NOTE !!!!!!!!! !!!!!!!!!!
// SEND MAIL TO SANJAYS IF YOU MODIFY THIS FILE!
// WE MUST KEEP OLE AND LANGUAGES IN SYNC!
// !!!!!!!!! !!!!!!!!! NOTE NOTE NOTE NOTE !!!!!!!!! !!!!!!!!!!
// Created 08-Oct-1993 by Mike Morearty. The master copy of this file
// is in the LANGAPI project owned by the Languages group.
// Helper functions for OLE RPC debugging.
#include <windows.h>
#ifndef _CHICAGO_
#include <tchar.h>
#endif
#include "orpc_dbg.h"
static TCHAR tszAeDebugName[] = TEXT("AeDebug");
static TCHAR tszAutoName[] = TEXT("Auto");
static TCHAR tszOldAutoName[] = TEXT("OldAuto");
static TCHAR tszDebugObjectRpcEnabledName[] =
#ifdef _CHICAGO_
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\DebugObjectRPCEnabled";
#else
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\DebugObjectRPCEnabled");
#endif
// Emit the ORPC signature into the bytestream of the function
#define ORPC_EMIT_SIGNATURE() 'M', 'A', 'R', 'B',
// Emit a LONG into the bytestream
#define ORPC_EMIT_LONG(l) \
((l >> 0) & 0xFF), \
((l >> 8) & 0xFF), \
((l >> 16) & 0xFF), \
((l >> 24) & 0xFF),
// Emit a WORD into the bytestream
#define ORPC_EMIT_WORD(w) \
((w >> 0) & 0xFF), \
((w >> 8) & 0xFF),
// Emit a BYTE into the bytestream
#define ORPC_EMIT_BYTE(b) \
b,
// Emit a GUID into the bytestream
#define ORPC_EMIT_GUID(l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
ORPC_EMIT_LONG(l) \
ORPC_EMIT_WORD(w1) ORPC_EMIT_WORD(w2) \
ORPC_EMIT_BYTE(b1) ORPC_EMIT_BYTE(b2) \
ORPC_EMIT_BYTE(b3) ORPC_EMIT_BYTE(b4) \
ORPC_EMIT_BYTE(b5) ORPC_EMIT_BYTE(b6) \
ORPC_EMIT_BYTE(b7) ORPC_EMIT_BYTE(b8)
BYTE rgbClientGetBufferSizeSignature[] =
{
ORPC_EMIT_SIGNATURE()
ORPC_EMIT_GUID(0x9ED14F80, 0x9673, 0x101A, 0xB0, 0x7B,
0x00, 0xDD, 0x01, 0x11, 0x3F, 0x11)
ORPC_EMIT_LONG(0)
};
BYTE rgbClientFillBufferSignature[] =
{
ORPC_EMIT_SIGNATURE()
ORPC_EMIT_GUID(0xDA45F3E0, 0x9673, 0x101A, 0xB0, 0x7B,
0x00, 0xDD, 0x01, 0x11, 0x3F, 0x11)
ORPC_EMIT_LONG(0)
};
BYTE rgbClientNotifySignature[] =
{
ORPC_EMIT_SIGNATURE()
ORPC_EMIT_GUID(0x4F60E540, 0x9674, 0x101A, 0xB0, 0x7B,
0x00, 0xDD, 0x01, 0x11, 0x3F, 0x11)
ORPC_EMIT_LONG(0)
};
BYTE rgbServerNotifySignature[] =
{
ORPC_EMIT_SIGNATURE()
ORPC_EMIT_GUID(0x1084FA00, 0x9674, 0x101A, 0xB0, 0x7B,
0x00, 0xDD, 0x01, 0x11, 0x3F, 0x11)
ORPC_EMIT_LONG(0)
};
BYTE rgbServerGetBufferSizeSignature[] =
{
ORPC_EMIT_SIGNATURE()
ORPC_EMIT_GUID(0x22080240, 0x9674, 0x101A, 0xB0, 0x7B,
0x00, 0xDD, 0x01, 0x11, 0x3F, 0x11)
ORPC_EMIT_LONG(0)
};
BYTE rgbServerFillBufferSignature[] =
{
ORPC_EMIT_SIGNATURE()
ORPC_EMIT_GUID(0x2FC09500, 0x9674, 0x101A, 0xB0, 0x7B,
0x00, 0xDD, 0x01, 0x11, 0x3F, 0x11)
ORPC_EMIT_LONG(0)
};
// Macro to deal with assigning refiid for both C and C++.
#if defined(__cplusplus)
#define ASSIGN_REFIID(orpc_all, iid) ((orpc_all).refiid = &iid)
#else
#define ASSIGN_REFIID(orpc_all, iid) ((orpc_all).refiid = iid)
#endif
#pragma code_seg(".orpc")
// SzSubStr()
// Find str2 in str2
static LPTSTR SzSubStr(LPTSTR str1, LPTSTR str2)
{
CharLower(str1);
CharLower(str2);
#ifdef _CHICAGO_
return strstr(str1, str2);
#else
return _tcsstr(str1, str2);
#endif
}
// DebugORPCSetAuto()
// Sets the "Auto" value in the "AeDebug" key to "1", and saves info
// necessary to restore the previous value later.
BOOL WINAPI DebugORPCSetAuto(VOID)
{
HKEY hkey;
TCHAR rgtchDebugger[256]; // 256 is the length NT itself uses for this
TCHAR rgtchAuto[256];
TCHAR rgtchOldAuto[2]; // don't need to get the whole thing
// If the "DebugObjectRPCEnabled" key does not exist, then do not
// cause any notifications
if (RegOpenKey(HKEY_LOCAL_MACHINE, tszDebugObjectRpcEnabledName, &hkey))
return FALSE;
RegCloseKey(hkey);
// If the AeDebug debugger string does not exist, or if it contains
// "drwtsn32" anywhere in it, then don't cause any notifications,
// because Dr. Watson is not capable of fielding OLE notifications.
if (!GetProfileString(tszAeDebugName, TEXT("Debugger"), TEXT(""),
rgtchDebugger, sizeof(rgtchDebugger)) ||
SzSubStr(rgtchDebugger, TEXT("drwtsn32")) != NULL)
{
return FALSE;
}
// Must ensure that the "Auto" value in the AeDebug registry key
// is set to "1", so that the embedded INT 3 below will cause the
// debugger to be automatically spawned if it doesn't already
// exist.
// Get old "Auto" value
GetProfileString(tszAeDebugName, tszAutoName, TEXT(""),
rgtchAuto, sizeof(rgtchAuto));
// If "OldAuto" already existed, then it's probably left over from
// a previous invocation of the debugger, so don't overwrite it.
// Otherwise, copy "Auto" value to "OldAuto"
if (!GetProfileString(tszAeDebugName, tszOldAutoName, TEXT(""),
rgtchOldAuto, sizeof(rgtchOldAuto)))
{
if (!WriteProfileString(tszAeDebugName, tszOldAutoName, rgtchAuto))
return FALSE;
}
// Change "Auto" value to "1"
if (!WriteProfileString(tszAeDebugName, tszAutoName, TEXT("1")))
return FALSE;
return TRUE;
}
// DebugORPCRestoreAuto()
// Restores the previous value of the "Auto" value in the AeDebug key.
VOID WINAPI DebugORPCRestoreAuto(VOID)
{
TCHAR rgtchAuto[256];
// Restore old Auto value (or delete it if it didn't exist before).
// Very minor bug here: if "Auto" was previously "", then we will
// now delete it. That's not a big deal though, as an empty "Auto"
// and a nonexistent one have the same effect.
GetProfileString(tszAeDebugName, tszOldAutoName, TEXT(""),
rgtchAuto, sizeof(rgtchAuto));
WriteProfileString(tszAeDebugName, tszAutoName,
rgtchAuto[0] ? rgtchAuto : NULL);
// Delete OldAuto value
WriteProfileString(tszAeDebugName, tszOldAutoName, NULL);
}
// This pragma is necessary in case the compiler chooses not to inline these
// functions (e.g. in a debug build, when optimizations are off).
#pragma code_seg(".orpc")
__inline DWORD WINAPI OrpcBreakpointFilter(
LPEXCEPTION_POINTERS lpExcptPtr,
BOOL *lpAeDebugAttached ) \
{
BOOL fAeDebugAttached = FALSE;
DWORD dwRet;
if ( lpExcptPtr->ExceptionRecord->ExceptionCode == EXCEPTION_ORPC_DEBUG )
{
if ( UnhandledExceptionFilter(lpExcptPtr) == EXCEPTION_CONTINUE_SEARCH )
{
// It is important that we don't return EXCEPTION_CONTINUE_SEARCH.
// This is because there might an handler up the stack which could
// handle this exception. Just set the flag indicating that a
// debugger is now attached.
fAeDebugAttached = TRUE;
}
dwRet = EXCEPTION_EXECUTE_HANDLER;
}
else
{
// Not one of our exceptions.
dwRet = EXCEPTION_CONTINUE_SEARCH;
}
if ( lpAeDebugAttached != NULL )
(*lpAeDebugAttached) = fAeDebugAttached;
return dwRet;
}
ULONG WINAPI DebugORPCClientGetBufferSize(
RPCOLEMESSAGE * pMessage,
REFIID iid,
void * reserved,
IUnknown * pUnkProxyMgr,
LPORPC_INIT_ARGS lpInitArgs,
BOOL fHookEnabled)
{
ULONG cbBuffer = 0;
ORPC_DBG_ALL orpc_all = {0};
ORPC_DBG_ALL * lpOrpcAll = &orpc_all;
if (!fHookEnabled)
return 0; // We should be able to assert that this never happens.
orpc_all.pSignature = rgbClientGetBufferSizeSignature;
orpc_all.pMessage = pMessage;
orpc_all.reserved = reserved;
orpc_all.pUnkProxyMgr = pUnkProxyMgr;
orpc_all.lpcbBuffer = &cbBuffer;
ASSIGN_REFIID(orpc_all, iid);
if ( lpInitArgs == NULL || lpInitArgs->lpIntfOrpcDebug == NULL )
{
// Do Orpc debug notification using an exception.
__try
{
RaiseException(EXCEPTION_ORPC_DEBUG, 0, 1, (LPDWORD)&lpOrpcAll);
}
__except(OrpcBreakpointFilter(GetExceptionInformation(), NULL))
{
// this just goes down to the to the return.
}
}
else
{
IOrpcDebugNotify __RPC_FAR *lpIntf = lpInitArgs->lpIntfOrpcDebug;
// call the appropriate method in the registered interface
// ( this is typically used by in-proc debuggers)
#if defined(__cplusplus) && !defined(CINTERFACE)
lpIntf->ClientGetBufferSize(lpOrpcAll);
#else
lpIntf->lpVtbl->ClientGetBufferSize(lpIntf, lpOrpcAll);
#endif
}
return cbBuffer;
}
void WINAPI DebugORPCClientFillBuffer(
RPCOLEMESSAGE * pMessage,
REFIID iid,
void * reserved,
IUnknown * pUnkProxyMgr,
void * pvBuffer,
ULONG cbBuffer,
LPORPC_INIT_ARGS lpInitArgs,
BOOL fHookEnabled)
{
ORPC_DBG_ALL orpc_all = {0};
ORPC_DBG_ALL * lpOrpcAll = &orpc_all;
if (!fHookEnabled)
return; // We should be able to assert that this never happens
orpc_all.pSignature = rgbClientFillBufferSignature;
orpc_all.pMessage = pMessage;
orpc_all.reserved = reserved;
orpc_all.pUnkProxyMgr = pUnkProxyMgr;
ASSIGN_REFIID(orpc_all, iid);
orpc_all.pvBuffer = pvBuffer;
orpc_all.cbBuffer = cbBuffer;
if ( lpInitArgs == NULL || lpInitArgs->lpIntfOrpcDebug == NULL )
{
// Do Orpc debug notification using an exception.
__try
{
RaiseException(EXCEPTION_ORPC_DEBUG, 0, 1, (LPDWORD)&lpOrpcAll);
}
__except(OrpcBreakpointFilter(GetExceptionInformation(), NULL))
{
// this just returns.
}
}
else
{
IOrpcDebugNotify __RPC_FAR *lpIntf = lpInitArgs->lpIntfOrpcDebug;
// call the appropriate method in the registered interface
// ( this is typically used by in-proc debuggers)
#if defined(__cplusplus) && !defined(CINTERFACE)
lpIntf->ClientFillBuffer(lpOrpcAll);
#else
lpIntf->lpVtbl->ClientFillBuffer(lpIntf, lpOrpcAll);
#endif
}
}
// This special value is to ensure backward compatibility with VC 2.0.
// It is not exposed in the header files. The behavior if this is the value
// in the first four bytes of the debug packet, should be identical to
// ORPC_DEBUG_ALWAYS.
#define ORPC_COMPATIBILITY_CODE (0x4252414DL)
void WINAPI DebugORPCClientNotify(
RPCOLEMESSAGE * pMessage,
REFIID iid,
void * reserved,
IUnknown * pUnkProxyMgr,
HRESULT hresult,
void * pvBuffer,
ULONG cbBuffer,
LPORPC_INIT_ARGS lpInitArgs,
BOOL fHookEnabled)
{
ORPC_DBG_ALL orpc_all = {0};
ORPC_DBG_ALL * lpOrpcAll = &orpc_all;
BOOL fRethrow = FALSE;
// First check to see if the debugger on the other side
// wants us to notify this side if the hook is not enabled.
if (!fHookEnabled)
{
if (cbBuffer >= 4)
{
LONG orpcCode = *(LONG *)pvBuffer;
if ( orpcCode == ORPC_DEBUG_IF_HOOK_ENABLED)
return; // No notification in this case.
}
}
orpc_all.pSignature = rgbClientNotifySignature;
orpc_all.pMessage = pMessage;
orpc_all.reserved = reserved;
orpc_all.pUnkProxyMgr = pUnkProxyMgr;
orpc_all.hresult = hresult;
ASSIGN_REFIID(orpc_all, iid);
orpc_all.pvBuffer = pvBuffer;
orpc_all.cbBuffer = cbBuffer;
if ( lpInitArgs == NULL || lpInitArgs->lpIntfOrpcDebug == NULL )
{
if (DebugORPCSetAuto())
{
// Do Orpc debug notification using an exception.
__try
{
RaiseException(EXCEPTION_ORPC_DEBUG, 0, 1, (LPDWORD)&lpOrpcAll);
}
__except(OrpcBreakpointFilter(GetExceptionInformation(), &fRethrow))
{
// Fall through.
}
if (fRethrow)
{
// At this point we are sure that a debugger is attached
// so we raise this exception outside of a __try block.
RaiseException(EXCEPTION_ORPC_DEBUG, 0, 1, (LPDWORD)&lpOrpcAll);
}
DebugORPCRestoreAuto();
}
}
else
{
IOrpcDebugNotify __RPC_FAR *lpIntf = lpInitArgs->lpIntfOrpcDebug;
// call the appropriate method in the registered interface
// ( this is typically used by in-proc debuggers)
#if defined(__cplusplus) && !defined(CINTERFACE)
lpIntf->ClientNotify(lpOrpcAll);
#else
lpIntf->lpVtbl->ClientNotify(lpIntf, lpOrpcAll);
#endif
}
}
void WINAPI DebugORPCServerNotify(
RPCOLEMESSAGE * pMessage,
REFIID iid,
IRpcChannelBuffer * pChannel,
void * pInterface,
IUnknown * pUnkObject,
void * pvBuffer,
ULONG cbBuffer,
LPORPC_INIT_ARGS lpInitArgs,
BOOL fHookEnabled)
{
ORPC_DBG_ALL orpc_all = {0};
ORPC_DBG_ALL * lpOrpcAll = &orpc_all;
BOOL fRethrow = FALSE;
// First check to see if the debugger on the other side
// wants us to notify this side if the hook is not enabled.
if (!fHookEnabled)
{
if (cbBuffer >= 4)
{
LONG orpcCode = *(LONG *)pvBuffer;
if ( orpcCode == ORPC_DEBUG_IF_HOOK_ENABLED)
return; // No notification in this case.
}
}
orpc_all.pSignature = rgbServerNotifySignature;
orpc_all.pMessage = pMessage;
orpc_all.pChannel = pChannel;
orpc_all.pInterface = pInterface;
orpc_all.pUnkObject = pUnkObject;
ASSIGN_REFIID(orpc_all, iid);
orpc_all.pvBuffer = pvBuffer;
orpc_all.cbBuffer = cbBuffer;
if ( lpInitArgs == NULL || lpInitArgs->lpIntfOrpcDebug == NULL )
{
if (DebugORPCSetAuto())
{
// Do Orpc debug notification using an exception.
__try
{
RaiseException(EXCEPTION_ORPC_DEBUG, 0, 1, (LPDWORD)&lpOrpcAll);
}
__except(OrpcBreakpointFilter(GetExceptionInformation(), &fRethrow))
{
// Fall through
}
if (fRethrow)
{
// At this point we are sure that a debugger is attached
// so we raise this exception outside of a __try block.
RaiseException(EXCEPTION_ORPC_DEBUG, 0, 1, (LPDWORD)&lpOrpcAll);
}
DebugORPCRestoreAuto();
}
}
else
{
IOrpcDebugNotify __RPC_FAR *lpIntf = lpInitArgs->lpIntfOrpcDebug;
// call the appropriate method in the registered interface
// ( this is typically used by in-proc debuggers)
#if defined(__cplusplus) && !defined(CINTERFACE)
lpIntf->ServerNotify(lpOrpcAll);
#else
lpIntf->lpVtbl->ServerNotify(lpIntf, lpOrpcAll);
#endif
}
}
ULONG WINAPI DebugORPCServerGetBufferSize(
RPCOLEMESSAGE * pMessage,
REFIID iid,
IRpcChannelBuffer * pChannel,
void * pInterface,
IUnknown * pUnkObject,
LPORPC_INIT_ARGS lpInitArgs,
BOOL fHookEnabled)
{
ULONG cbBuffer = 0;
ORPC_DBG_ALL orpc_all = {0};
ORPC_DBG_ALL * lpOrpcAll = &orpc_all;
if (!fHookEnabled)
return 0; // We should be able to assert that this never happens.
orpc_all.pSignature = rgbServerGetBufferSizeSignature;
orpc_all.pMessage = pMessage;
orpc_all.pChannel = pChannel;
orpc_all.pInterface = pInterface;
orpc_all.pUnkObject = pUnkObject;
orpc_all.lpcbBuffer = &cbBuffer;
ASSIGN_REFIID(orpc_all, iid);
if ( lpInitArgs == NULL || lpInitArgs->lpIntfOrpcDebug == NULL )
{
// Do Orpc debug notification using an exception.
__try
{
RaiseException(EXCEPTION_ORPC_DEBUG, 0, 1, (LPDWORD)&lpOrpcAll);
}
__except(OrpcBreakpointFilter(GetExceptionInformation(), NULL))
{
// this just goes down to the return.
}
}
else
{
IOrpcDebugNotify __RPC_FAR *lpIntf = lpInitArgs->lpIntfOrpcDebug;
// call the appropriate method in the registered interface
// ( this is typically used by in-proc debuggers)
#if defined(__cplusplus) && !defined(CINTERFACE)
lpIntf->ServerGetBufferSize(lpOrpcAll);
#else
lpIntf->lpVtbl->ServerGetBufferSize(lpIntf, lpOrpcAll);
#endif
}
return cbBuffer;
}
void WINAPI DebugORPCServerFillBuffer(
RPCOLEMESSAGE * pMessage,
REFIID iid,
IRpcChannelBuffer * pChannel,
void * pInterface,
IUnknown * pUnkObject,
void * pvBuffer,
ULONG cbBuffer,
LPORPC_INIT_ARGS lpInitArgs,
BOOL fHookEnabled)
{
ORPC_DBG_ALL orpc_all = {0};
ORPC_DBG_ALL * lpOrpcAll = &orpc_all;
if (!fHookEnabled)
return; // We should be able to assert that this never happens.
orpc_all.pSignature = rgbServerFillBufferSignature;
orpc_all.pMessage = pMessage;
orpc_all.pChannel = pChannel;
orpc_all.pInterface = pInterface;
orpc_all.pUnkObject = pUnkObject;
ASSIGN_REFIID(orpc_all, iid);
orpc_all.pvBuffer = pvBuffer;
orpc_all.cbBuffer = cbBuffer;
if ( lpInitArgs == NULL || lpInitArgs->lpIntfOrpcDebug == NULL )
{
// Do Orpc debug notification using an exception.
__try
{
RaiseException(EXCEPTION_ORPC_DEBUG, 0, 1, (LPDWORD)&lpOrpcAll);
}
__except(OrpcBreakpointFilter(GetExceptionInformation(), NULL))
{
// this just returns.
}
}
else
{
IOrpcDebugNotify __RPC_FAR *lpIntf = lpInitArgs->lpIntfOrpcDebug;
// call the appropriate method in the registered interface
// ( this is typically used by in-proc debuggers)
#if defined(__cplusplus) && !defined(CINTERFACE)
lpIntf->ServerFillBuffer(lpOrpcAll);
#else
lpIntf->lpVtbl->ServerFillBuffer(lpIntf, lpOrpcAll);
#endif
}
}
// WARNING: there is no way to "pop" to the previously active code_seg:
// this will revert to what the code seg was when compilation began.
#pragma code_seg()