1199 lines
38 KiB
C++
1199 lines
38 KiB
C++
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
RpcDbg.cxx
|
|
|
|
Abstract:
|
|
|
|
RPC Extended Debugging Utility
|
|
|
|
Author:
|
|
|
|
Kamen Moutafov (kamenm) 11-30-99
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <sysinc.h>
|
|
|
|
#include <CellDef.hxx>
|
|
|
|
// Usage
|
|
|
|
const char *USAGE = "-s <server> -p <protseq> -C <CallID> -I <IfStart>\n"
|
|
"-N <ProcNum> -P <ProcessID> -L <CellID1.CellID2>\n"
|
|
"-E <EndpointName> -T <ThreadID> -r <radix> -c -l -e -t -a\n"
|
|
"Exactly one of -c, -l, -e, -t, or -a have to be specified.\n"
|
|
"The valid combinations are:\n"
|
|
"-c [-C <CallID>] [-I <IfStart>] [-N <ProcNum>] [-P <ProcessID>]\n"
|
|
"-l -P <ProcessID> -L <CellID1.CellID2>\n"
|
|
"-e -E <EndpointName>\n"
|
|
"-t -P <ProcessID> [-T <ThreadID>]\n"
|
|
"-a [-C <CallID>] [-I <IfStart>] [-N <ProcNum>] [-P <ProcessID>]\n"
|
|
"-s, -p and -r are independent to the other options. -r affects"
|
|
"only options after it on the command line. Default is 16 (hex)";
|
|
|
|
|
|
// Error stuff
|
|
|
|
#define CHECK_RET(status, string) if (status)\
|
|
{ printf("%s failed -- %lu (0x%08X)\n", string,\
|
|
(unsigned long)status, (unsigned long)status);\
|
|
return (status); }
|
|
|
|
DWORD CallID = 0;
|
|
DWORD IfStart = 0;
|
|
DWORD ProcNum = RPCDBG_NO_PROCNUM_SPECIFIED;
|
|
DWORD ProcessID = 0;
|
|
DebugCellID CellID = {0, 0};
|
|
char *EndpointName = NULL;
|
|
DWORD ThreadID = 0;
|
|
char *Protseq = "ncacn_np";
|
|
char *NetworkAddr = NULL;
|
|
int radix = 16;
|
|
char *BindingEndpoint = 0;
|
|
|
|
enum tagChosenDebugAction
|
|
{
|
|
cdaInvalid,
|
|
cdaCallInfo,
|
|
cdaDebugCellInfo,
|
|
cdaEndpointInfo,
|
|
cdaThreadInfo,
|
|
cdaClientCallInfo
|
|
} ChosenDebugAction;
|
|
|
|
int Action = cdaInvalid;
|
|
|
|
BOOL CheckForCellID(void)
|
|
{
|
|
if ((CellID.SectionID != 0) || (CellID.CellID != 0))
|
|
{
|
|
printf("A cell ID cannot be specified for this action\n");
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CheckForEndpointName(void)
|
|
{
|
|
if (EndpointName)
|
|
{
|
|
printf("An endpoint name cannot be specified for this action\n");
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CheckForThreadID(void)
|
|
{
|
|
if (ThreadID)
|
|
{
|
|
printf("A thread ID cannot be specified for this action\n");
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CheckForCallID(void)
|
|
{
|
|
if (CallID)
|
|
{
|
|
printf("A call ID cannot be specified for this action\n");
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CheckForIfStart(void)
|
|
{
|
|
if (IfStart)
|
|
{
|
|
printf("An interface UUID start cannot be specified for this action\n");
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CheckForProcNum(void)
|
|
{
|
|
if (ProcNum != RPCDBG_NO_PROCNUM_SPECIFIED)
|
|
{
|
|
printf("A procedure number cannot be specified for this action\n");
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CheckForProcessID(void)
|
|
{
|
|
if (ProcessID)
|
|
{
|
|
printf("A process ID cannot be specified for this action\n");
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
void __cdecl DumpToConsole(PCSTR lpFormat, ...)
|
|
{
|
|
va_list arglist;
|
|
|
|
va_start(arglist, lpFormat);
|
|
vfprintf(stdout, lpFormat, arglist);
|
|
va_end(arglist);
|
|
}
|
|
|
|
|
|
void __RPC_FAR * __RPC_API MIDL_user_allocate(size_t Size)
|
|
{
|
|
void PAPI * pvBuf;
|
|
|
|
pvBuf = new char [Size];
|
|
|
|
return(pvBuf);
|
|
}
|
|
|
|
void __RPC_API MIDL_user_free (void __RPC_FAR *Buf)
|
|
{
|
|
delete (Buf);
|
|
}
|
|
|
|
const char *ValidProtocolSequences[] = {"ncacn_np", "ncacn_ip_tcp"};
|
|
const char *ValidEnpoints[] = {"epmapper", "135"};
|
|
|
|
#define ARRAY_SIZE_OF(a) (sizeof(a) / sizeof(a[0]))
|
|
|
|
void ParseArgv(int argc, char **argv)
|
|
{
|
|
int fMissingParm = 0;
|
|
char *Name = *argv;
|
|
char option;
|
|
char *TempString;
|
|
char *Delimiter;
|
|
char *Ignored;
|
|
BOOL fInvalidArg;
|
|
int i;
|
|
|
|
argc--;
|
|
argv++;
|
|
while(argc)
|
|
{
|
|
if (**argv != '/' &&
|
|
**argv != '-')
|
|
{
|
|
printf("Invalid switch: %s\n", *argv);
|
|
argc--;
|
|
argv++;
|
|
}
|
|
else
|
|
{
|
|
option = argv[0][1];
|
|
argc--;
|
|
argv++;
|
|
|
|
// Most switches require a second command line arg.
|
|
if (argc < 1)
|
|
fMissingParm = 1;
|
|
|
|
switch(option)
|
|
{
|
|
case 'C':
|
|
CallID = strtoul(*argv, &Ignored, radix);
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 'p':
|
|
Protseq = *argv;
|
|
for (i = 0; i < ARRAY_SIZE_OF(ValidProtocolSequences); i ++)
|
|
{
|
|
if (_strcmpi(Protseq, ValidProtocolSequences[i]) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i < ARRAY_SIZE_OF(ValidProtocolSequences))
|
|
{
|
|
BindingEndpoint = (char *) ValidEnpoints[i];
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
printf("Invalid protocol sequence: %s\n", Protseq);
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
}
|
|
case 's':
|
|
NetworkAddr = *argv;
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 'I':
|
|
IfStart = strtoul(*argv, &Ignored, radix);
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 'N':
|
|
ProcNum = strtoul(*argv, &Ignored, radix);
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 'L':
|
|
TempString = *argv;
|
|
Delimiter = strchr(TempString, '.');
|
|
if (Delimiter == NULL)
|
|
{
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
}
|
|
*Delimiter = 0;
|
|
Delimiter ++;
|
|
CellID.SectionID = (unsigned short)strtoul(TempString, &Ignored, radix);
|
|
CellID.CellID = (unsigned short)strtoul(Delimiter, &Ignored, radix);
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 'E':
|
|
EndpointName = *argv;
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 'T':
|
|
ThreadID = strtoul(*argv, &Ignored, radix);
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 'P':
|
|
ProcessID = strtoul(*argv, &Ignored, radix);
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 'c':
|
|
if (Action != cdaInvalid)
|
|
{
|
|
printf("The action to be performed can be specified only once on the command line\n");
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
}
|
|
Action = cdaCallInfo;
|
|
fMissingParm = 0;
|
|
break;
|
|
case 'l':
|
|
if (Action != cdaInvalid)
|
|
{
|
|
printf("The action to be performed can be specified only once on the command line\n");
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
}
|
|
Action = cdaDebugCellInfo;
|
|
fMissingParm = 0;
|
|
break;
|
|
case 'e':
|
|
if (Action != cdaInvalid)
|
|
{
|
|
printf("The action to be performed can be specified only once on the command line\n");
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
}
|
|
Action = cdaEndpointInfo;
|
|
fMissingParm = 0;
|
|
break;
|
|
case 't':
|
|
if (Action != cdaInvalid)
|
|
{
|
|
printf("The action to be performed can be specified only once on the command line\n");
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
}
|
|
Action = cdaThreadInfo;
|
|
fMissingParm = 0;
|
|
break;
|
|
case 'a':
|
|
if (Action != cdaInvalid)
|
|
{
|
|
printf("The action to be performed can be specified only once on the command line\n");
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
}
|
|
Action = cdaClientCallInfo;
|
|
fMissingParm = 0;
|
|
break;
|
|
case 'r':
|
|
radix = atoi(*argv);
|
|
fMissingParm = 0;
|
|
break;
|
|
default:
|
|
fMissingParm = 0;
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
break;
|
|
}
|
|
|
|
if (fMissingParm)
|
|
{
|
|
printf("Invalid switch %s, missing required parameter\n", *argv);
|
|
exit(2);
|
|
}
|
|
}
|
|
} // while argc
|
|
|
|
// verify that the options are consistent
|
|
fInvalidArg = FALSE;
|
|
switch (Action)
|
|
{
|
|
case cdaInvalid:
|
|
printf("The action to be performed should be specified exactly once on the command line\n");
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
|
|
case cdaCallInfo:
|
|
case cdaClientCallInfo:
|
|
fInvalidArg = CheckForCellID();
|
|
fInvalidArg |= CheckForEndpointName();
|
|
fInvalidArg |= CheckForThreadID();
|
|
|
|
if (fInvalidArg)
|
|
{
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
}
|
|
break;
|
|
|
|
case cdaDebugCellInfo:
|
|
if ((CellID.SectionID == 0) && (CellID.CellID == 0))
|
|
{
|
|
printf("A cell ID must be specified for this action\n");
|
|
fInvalidArg = TRUE;
|
|
}
|
|
|
|
if (ProcessID == 0)
|
|
{
|
|
printf("A process ID must be specified for this action\n");
|
|
fInvalidArg = TRUE;
|
|
}
|
|
|
|
fInvalidArg |= CheckForEndpointName();
|
|
fInvalidArg |= CheckForThreadID();
|
|
fInvalidArg |= CheckForCallID();
|
|
fInvalidArg |= CheckForIfStart();
|
|
fInvalidArg |= CheckForProcNum();
|
|
|
|
if (fInvalidArg)
|
|
{
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
}
|
|
break;
|
|
|
|
case cdaEndpointInfo:
|
|
|
|
fInvalidArg |= CheckForCellID();
|
|
fInvalidArg |= CheckForThreadID();
|
|
fInvalidArg |= CheckForCallID();
|
|
fInvalidArg |= CheckForIfStart();
|
|
fInvalidArg |= CheckForProcNum();
|
|
fInvalidArg |= CheckForProcessID();
|
|
|
|
if (fInvalidArg)
|
|
{
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
}
|
|
break;
|
|
|
|
case cdaThreadInfo:
|
|
if (ProcessID == 0)
|
|
{
|
|
printf("A process ID must be specified for this action\n");
|
|
fInvalidArg = TRUE;
|
|
}
|
|
|
|
fInvalidArg |= CheckForCellID();
|
|
fInvalidArg |= CheckForCallID();
|
|
fInvalidArg |= CheckForIfStart();
|
|
fInvalidArg |= CheckForProcNum();
|
|
if (fInvalidArg)
|
|
{
|
|
printf("Usage: %s: %s\n", Name, USAGE);
|
|
exit(2);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
printf("Internal error. Chosen action is %d\n", Action);
|
|
exit(2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
RPC_STATUS DoRpcBindingSetAuthInfo(handle_t Binding)
|
|
{
|
|
if (AuthnLevel != RPC_C_AUTHN_LEVEL_NONE)
|
|
return RpcBindingSetAuthInfo(Binding,
|
|
NULL,
|
|
AuthnLevel,
|
|
ulSecurityPackage,
|
|
NULL,
|
|
RPC_C_AUTHZ_NONE);
|
|
else
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
unsigned long Worker(unsigned long l)
|
|
{
|
|
unsigned long status;
|
|
unsigned long Test;
|
|
unsigned long ClientId;
|
|
unsigned long InSize, OutSize;
|
|
unsigned long Time, Calls;
|
|
char __RPC_FAR *pBuffer;
|
|
char __RPC_FAR *stringBinding;
|
|
handle_t binding;
|
|
RPC_STATUS RpcErr;
|
|
int Retries;
|
|
|
|
pBuffer = MIDL_user_allocate(128*1024L);
|
|
if (pBuffer == 0)
|
|
{
|
|
PrintToConsole("Out of memory!");
|
|
return 1;
|
|
}
|
|
|
|
status =
|
|
RpcStringBindingComposeA(0,
|
|
Protseq,
|
|
NetworkAddr,
|
|
Endpoint,
|
|
0,
|
|
&stringBinding);
|
|
CHECK_RET(status, "RpcStringBindingCompose");
|
|
|
|
status =
|
|
RpcBindingFromStringBindingA(stringBinding, &binding);
|
|
CHECK_RET(status, "RpcBindingFromStringBinding");
|
|
|
|
status =
|
|
DoRpcBindingSetAuthInfo(binding);
|
|
CHECK_RET(status, "RpcBindingSetAuthInfo");
|
|
|
|
RpcStringFreeA(&stringBinding);
|
|
|
|
Retries = 15;
|
|
|
|
do
|
|
{
|
|
status = BeginTest(binding, &ClientId, &Test, &InSize, &OutSize);
|
|
|
|
if (status == PERF_TOO_MANY_CLIENTS)
|
|
{
|
|
PrintToConsole("Too many clients, I'm exiting\n");
|
|
goto Cleanup ;
|
|
}
|
|
|
|
Retries --;
|
|
if ((status == RPC_S_SERVER_UNAVAILABLE) && (Retries > 0))
|
|
{
|
|
PrintToConsole("Server too busy - retrying ...\n");
|
|
}
|
|
}
|
|
while ((status == RPC_S_SERVER_UNAVAILABLE) && (Retries > 0));
|
|
|
|
CHECK_RET(status, "ClientConnect");
|
|
|
|
if (InSize > IN_ADJUSTMENT)
|
|
{
|
|
InSize -= IN_ADJUSTMENT;
|
|
}
|
|
else
|
|
{
|
|
InSize = 0;
|
|
}
|
|
|
|
if (OutSize > OUT_ADJUSTMENT)
|
|
{
|
|
OutSize -= OUT_ADJUSTMENT;
|
|
}
|
|
else
|
|
{
|
|
OutSize = 0;
|
|
}
|
|
|
|
gInSize = InSize;
|
|
gOutSize = OutSize;
|
|
|
|
PrintToConsole("Client %ld connected\n", ClientId);
|
|
|
|
Retries = 15;
|
|
|
|
do
|
|
{
|
|
RpcTryExcept
|
|
{
|
|
RpcErr = RPC_S_OK;
|
|
|
|
Time = GetTickCount();
|
|
|
|
Calls = ( (TestTable[Test])(binding, ClientId, pBuffer) );
|
|
|
|
Time = GetTickCount() - Time;
|
|
|
|
Dump("Completed %d calls in %d ms\n"
|
|
"%d T/S or %3d.%03d ms/T\n\n",
|
|
Calls,
|
|
Time,
|
|
(Calls * 1000) / Time,
|
|
Time / Calls,
|
|
((Time % Calls) * 1000) / Calls
|
|
);
|
|
}
|
|
RpcExcept(1)
|
|
{
|
|
RpcErr = (unsigned long)RpcExceptionCode();
|
|
PrintToConsole("\nException %lu (0x%08lX)\n",
|
|
RpcErr, RpcErr);
|
|
}
|
|
RpcEndExcept
|
|
Retries --;
|
|
if ((RpcErr == RPC_S_SERVER_UNAVAILABLE) && (Retries > 0))
|
|
{
|
|
PrintToConsole("Server too busy - retrying ...\n");
|
|
}
|
|
}
|
|
while ((RpcErr == RPC_S_SERVER_UNAVAILABLE) && (Retries > 0));
|
|
|
|
Cleanup:
|
|
RpcBindingFree(&binding);
|
|
return status;
|
|
}
|
|
*/
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
/// Local representation to wire representation translation routines
|
|
////////////////////////////////////////////////////////////////////
|
|
BOOL TranslateRemoteCallInfoToLocalCallInfo(IN RemoteDebugCallInfo *RemoteCallInfo,
|
|
OUT DebugCallInfo *LocalDebugInfo)
|
|
{
|
|
LocalDebugInfo->Type = RemoteCallInfo->Type;
|
|
LocalDebugInfo->Status = RemoteCallInfo->Status;
|
|
LocalDebugInfo->ProcNum = RemoteCallInfo->ProcNum;
|
|
LocalDebugInfo->InterfaceUUIDStart = RemoteCallInfo->InterfaceUUIDStart;
|
|
LocalDebugInfo->ServicingTID = RemoteCallInfo->ServicingTID;
|
|
LocalDebugInfo->CallFlags = RemoteCallInfo->CallFlags;
|
|
LocalDebugInfo->CallID = RemoteCallInfo->CallID;
|
|
LocalDebugInfo->LastUpdateTime = RemoteCallInfo->LastUpdateTime;
|
|
if (RemoteCallInfo->ConnectionType == crtLrpcConnection)
|
|
{
|
|
ASSERT(LocalDebugInfo->CallFlags & DBGCELL_LRPC_CALL);
|
|
LocalDebugInfo->Connection = RemoteCallInfo->connInfo.Connection;
|
|
}
|
|
else if (RemoteCallInfo->ConnectionType == crtOsfConnection)
|
|
{
|
|
LocalDebugInfo->PID = RemoteCallInfo->connInfo.Caller.PID;
|
|
LocalDebugInfo->TID = RemoteCallInfo->connInfo.Caller.TID;
|
|
}
|
|
else
|
|
{
|
|
PrintToConsole("Invalid type for call info connection type: %d\n",
|
|
RemoteCallInfo->ConnectionType);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void TranslateRemoteEndpointInfoToLocalEndpointInfo(IN RemoteDebugEndpointInfo *RemoteEndpointInfo,
|
|
OUT DebugEndpointInfo *LocalDebugInfo)
|
|
{
|
|
LocalDebugInfo->Type = RemoteEndpointInfo->Type;
|
|
LocalDebugInfo->ProtseqType = RemoteEndpointInfo->ProtseqType;
|
|
LocalDebugInfo->Status = RemoteEndpointInfo->Status;
|
|
|
|
if (RemoteEndpointInfo->EndpointName)
|
|
{
|
|
memcpy(LocalDebugInfo->EndpointName,
|
|
RemoteEndpointInfo->EndpointName,
|
|
DebugEndpointNameLength);
|
|
MIDL_user_free(RemoteEndpointInfo->EndpointName);
|
|
RemoteEndpointInfo->EndpointName = 0;
|
|
}
|
|
else
|
|
LocalDebugInfo->EndpointName[0] = 0;
|
|
}
|
|
|
|
void TranslateRemoteThreadInfoToLocalThreadInfo(IN RemoteDebugThreadInfo *RemoteThreadInfo,
|
|
OUT DebugThreadInfo *LocalDebugInfo)
|
|
{
|
|
LocalDebugInfo->Type = RemoteThreadInfo->Type;
|
|
LocalDebugInfo->Status = RemoteThreadInfo->Status;
|
|
LocalDebugInfo->LastUpdateTime = RemoteThreadInfo->LastUpdateTime;
|
|
LocalDebugInfo->TID = RemoteThreadInfo->TID;
|
|
LocalDebugInfo->Endpoint = RemoteThreadInfo->Endpoint;
|
|
}
|
|
|
|
void TranslateRemoteClientCallInfoToLocalClientCallInfo(IN RemoteDebugClientCallInfo *RemoteClientCallInfo,
|
|
OUT DebugClientCallInfo *LocalDebugInfo)
|
|
{
|
|
LocalDebugInfo->Type = RemoteClientCallInfo->Type;
|
|
LocalDebugInfo->ProcNum = RemoteClientCallInfo->ProcNum;
|
|
LocalDebugInfo->ServicingThread = RemoteClientCallInfo->ServicingThread;
|
|
LocalDebugInfo->IfStart = RemoteClientCallInfo->IfStart;
|
|
LocalDebugInfo->CallID = RemoteClientCallInfo->CallID;
|
|
LocalDebugInfo->CallTargetID = RemoteClientCallInfo->CallTargetID;
|
|
|
|
if (RemoteClientCallInfo->Endpoint)
|
|
{
|
|
memcpy(LocalDebugInfo->Endpoint,
|
|
RemoteClientCallInfo->Endpoint,
|
|
ClientCallEndpointLength);
|
|
MIDL_user_free(RemoteClientCallInfo->Endpoint);
|
|
RemoteClientCallInfo->Endpoint = 0;
|
|
}
|
|
else
|
|
LocalDebugInfo->Endpoint[0] = 0;
|
|
}
|
|
|
|
void TranslateRemoteConnectionInfoToLocalConnectionInfo(IN RemoteDebugConnectionInfo *RemoteConnectionInfo,
|
|
OUT DebugConnectionInfo *LocalDebugInfo)
|
|
{
|
|
LocalDebugInfo->Type = RemoteConnectionInfo->Type;
|
|
LocalDebugInfo->Flags = RemoteConnectionInfo->Flags;
|
|
LocalDebugInfo->LastTransmitFragmentSize =
|
|
RemoteConnectionInfo->LastTransmitFragmentSize;
|
|
LocalDebugInfo->Endpoint = RemoteConnectionInfo->Endpoint;
|
|
LocalDebugInfo->ConnectionID[0] = ULongToPtr(RemoteConnectionInfo->ConnectionID[0]);
|
|
LocalDebugInfo->ConnectionID[1] = ULongToPtr(RemoteConnectionInfo->ConnectionID[1]);
|
|
LocalDebugInfo->LastSendTime = RemoteConnectionInfo->LastSendTime;
|
|
LocalDebugInfo->LastReceiveTime = RemoteConnectionInfo->LastReceiveTime;
|
|
}
|
|
|
|
void TranslateRemoteCallTargetInfoToLocalCallTargetInfo(IN RemoteDebugCallTargetInfo *RemoteCallTargetInfo,
|
|
OUT DebugCallTargetInfo *LocalDebugInfo)
|
|
{
|
|
LocalDebugInfo->Type = RemoteCallTargetInfo->Type;
|
|
LocalDebugInfo->ProtocolSequence = RemoteCallTargetInfo->ProtocolSequence;
|
|
LocalDebugInfo->LastUpdateTime = RemoteCallTargetInfo->LastUpdateTime;
|
|
|
|
if (RemoteCallTargetInfo->TargetServer)
|
|
{
|
|
memcpy(LocalDebugInfo->TargetServer, RemoteCallTargetInfo->TargetServer,
|
|
TargetServerNameLength);
|
|
MIDL_user_free(RemoteCallTargetInfo->TargetServer);
|
|
RemoteCallTargetInfo->TargetServer = 0;
|
|
}
|
|
}
|
|
|
|
BOOL TranslateRemoteDebugCellInfoToLocalDebugCellInfo(RemoteDebugCellUnion *RemoteCellInfo,
|
|
DebugCellUnion *Container)
|
|
{
|
|
switch (RemoteCellInfo->UnionType)
|
|
{
|
|
case dctCallInfo:
|
|
return TranslateRemoteCallInfoToLocalCallInfo(&RemoteCellInfo->debugInfo.callInfo,
|
|
&Container->callInfo);
|
|
break;
|
|
|
|
case dctThreadInfo:
|
|
TranslateRemoteThreadInfoToLocalThreadInfo(&RemoteCellInfo->debugInfo.threadInfo,
|
|
&Container->threadInfo);
|
|
break;
|
|
|
|
case dctEndpointInfo:
|
|
TranslateRemoteEndpointInfoToLocalEndpointInfo(&RemoteCellInfo->debugInfo.endpointInfo,
|
|
&Container->endpointInfo);
|
|
break;
|
|
|
|
case dctClientCallInfo:
|
|
TranslateRemoteClientCallInfoToLocalClientCallInfo(&RemoteCellInfo->debugInfo.clientCallInfo,
|
|
&Container->clientCallInfo);
|
|
break;
|
|
|
|
case dctConnectionInfo:
|
|
TranslateRemoteConnectionInfoToLocalConnectionInfo(&RemoteCellInfo->debugInfo.connectionInfo,
|
|
&Container->connectionInfo);
|
|
break;
|
|
|
|
case dctCallTargetInfo:
|
|
TranslateRemoteCallTargetInfoToLocalCallTargetInfo(&RemoteCellInfo->debugInfo.callTargetInfo,
|
|
&Container->callTargetInfo);
|
|
break;
|
|
|
|
default:
|
|
PrintToConsole("Invalid debug cell type: %d\n", RemoteCellInfo->UnionType);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// Helper routines for enumerating remote information
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void GetAndPrintRemoteCallInfo(IN handle_t Binding)
|
|
{
|
|
RemoteDebugCallInfo *RemoteCallInfo;
|
|
DebugCellID CellID;
|
|
DbgCallEnumHandle rh;
|
|
DebugCallInfo LocalCallInfo;
|
|
RPC_STATUS Status;
|
|
|
|
RemoteCallInfo = NULL;
|
|
DumpToConsole("Getting remote call info ...\n");
|
|
|
|
RpcTryExcept
|
|
{
|
|
Status = RemoteOpenRPCDebugCallInfoEnumeration(Binding, &rh, CallID, IfStart, ProcNum, ProcessID);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
DumpToConsole("RemoteOpenRPCDebugCallInfoEnumeration failed: %d\n", Status);
|
|
return;
|
|
}
|
|
|
|
PrintCallInfoHeader(DumpToConsole);
|
|
do
|
|
{
|
|
RemoteCallInfo = NULL;
|
|
RpcTryExcept
|
|
{
|
|
Status = RemoteGetNextRPCDebugCallInfo(rh, &RemoteCallInfo, &CellID, &ProcessID);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
TranslateRemoteCallInfoToLocalCallInfo(RemoteCallInfo, &LocalCallInfo);
|
|
MIDL_user_free(RemoteCallInfo);
|
|
PrintCallInfoBody(ProcessID, CellID, &LocalCallInfo, DumpToConsole);
|
|
}
|
|
}
|
|
while (Status == RPC_S_OK);
|
|
|
|
if (Status != RPC_S_DBG_ENUMERATION_DONE)
|
|
{
|
|
DumpToConsole("Enumeration aborted with error %d\n", Status);
|
|
}
|
|
|
|
RpcTryExcept
|
|
{
|
|
RemoteFinishRPCDebugCallInfoEnumeration(&rh);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
}
|
|
|
|
void GetAndPrintRemoteEndpointInfo(IN handle_t Binding)
|
|
{
|
|
DWORD CurrentPID;
|
|
RPC_STATUS Status;
|
|
DebugEndpointInfo EndpointInfo;
|
|
RemoteDebugEndpointInfo *RemoteEndpointInfo;
|
|
DbgEndpointEnumHandle rh;
|
|
DebugCellID CellID;
|
|
|
|
DumpToConsole("Getting remote endpoint info ...\n");
|
|
RpcTryExcept
|
|
{
|
|
Status = RemoteOpenRPCDebugEndpointInfoEnumeration(Binding, &rh,
|
|
(EndpointName != NULL) ? (strlen(EndpointName) + 1) : 0,
|
|
(unsigned char *) EndpointName);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
DumpToConsole("RemoteOpenRPCDebugEndpointInfoEnumeration failed: %d\n", Status);
|
|
return;
|
|
}
|
|
|
|
PrintEndpointInfoHeader(DumpToConsole);
|
|
do
|
|
{
|
|
RemoteEndpointInfo = NULL;
|
|
RpcTryExcept
|
|
{
|
|
Status = RemoteGetNextRPCDebugEndpointInfo(rh, &RemoteEndpointInfo, &CellID, &CurrentPID);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
TranslateRemoteEndpointInfoToLocalEndpointInfo(RemoteEndpointInfo, &EndpointInfo);
|
|
MIDL_user_free(RemoteEndpointInfo);
|
|
PrintEndpointInfoBody(CurrentPID, CellID, &EndpointInfo, DumpToConsole);
|
|
}
|
|
}
|
|
while (Status == RPC_S_OK);
|
|
|
|
if (Status != RPC_S_DBG_ENUMERATION_DONE)
|
|
{
|
|
DumpToConsole("Enumeration aborted with error %d\n", Status);
|
|
}
|
|
|
|
RpcTryExcept
|
|
{
|
|
RemoteFinishRPCDebugEndpointInfoEnumeration(&rh);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
}
|
|
|
|
void GetAndPrintRemoteThreadInfo(IN handle_t Binding)
|
|
{
|
|
RPC_STATUS Status;
|
|
DbgThreadEnumHandle rh;
|
|
RemoteDebugThreadInfo *RemoteThreadInfo;
|
|
DebugThreadInfo LocalThreadInfo;
|
|
DebugCellID CellID;
|
|
DWORD CurrentPID;
|
|
|
|
DumpToConsole("Getting remote thread info ...\n");
|
|
RpcTryExcept
|
|
{
|
|
Status = RemoteOpenRPCDebugThreadInfoEnumeration(Binding, &rh, ProcessID, ThreadID);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
DumpToConsole("RemoteOpenRPCDebugThreadInfoEnumeration failed: %d\n", Status);
|
|
return;
|
|
}
|
|
|
|
PrintThreadInfoHeader(DumpToConsole);
|
|
do
|
|
{
|
|
RemoteThreadInfo = NULL;
|
|
RpcTryExcept
|
|
{
|
|
Status = RemoteGetNextRPCDebugThreadInfo(rh, &RemoteThreadInfo, &CellID, &CurrentPID);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
TranslateRemoteThreadInfoToLocalThreadInfo(RemoteThreadInfo, &LocalThreadInfo);
|
|
MIDL_user_free(RemoteThreadInfo);
|
|
PrintThreadInfoBody(CurrentPID, CellID, &LocalThreadInfo, DumpToConsole);
|
|
}
|
|
}
|
|
while (Status == RPC_S_OK);
|
|
|
|
if (Status != RPC_S_DBG_ENUMERATION_DONE)
|
|
{
|
|
DumpToConsole("Enumeration aborted with error %d\n", Status);
|
|
}
|
|
|
|
RpcTryExcept
|
|
{
|
|
RemoteFinishRPCDebugThreadInfoEnumeration(&rh);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
}
|
|
|
|
void GetAndPrintRemoteClientCallInfo(IN handle_t Binding)
|
|
{
|
|
DWORD CurrentPID;
|
|
DebugCellID CellID;
|
|
|
|
DebugClientCallInfo LocalClientCall;
|
|
DebugCallTargetInfo LocalCallTarget;
|
|
|
|
RemoteDebugClientCallInfo *RemoteClientCallInfo;
|
|
RemoteDebugCallTargetInfo *RemoteCallTargetInfo;
|
|
|
|
RPC_STATUS Status;
|
|
DbgClientCallEnumHandle rh;
|
|
|
|
DumpToConsole("Getting remote call info ...\n");
|
|
RpcTryExcept
|
|
{
|
|
Status = RemoteOpenRPCDebugClientCallInfoEnumeration(Binding, &rh, CallID, IfStart, ProcNum, ProcessID);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
DumpToConsole("RemoteOpenRPCDebugClientCallInfoEnumeration failed: %d\n", Status);
|
|
return;
|
|
}
|
|
|
|
PrintClientCallInfoHeader(DumpToConsole);
|
|
do
|
|
{
|
|
RemoteClientCallInfo = NULL;
|
|
RemoteCallTargetInfo = NULL;
|
|
|
|
RpcTryExcept
|
|
{
|
|
Status = RemoteGetNextRPCDebugClientCallInfo(rh, &RemoteClientCallInfo, &RemoteCallTargetInfo,
|
|
&CellID, &CurrentPID);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
if ((RemoteCallTargetInfo != NULL) && (RemoteCallTargetInfo->Type != dctCallTargetInfo))
|
|
{
|
|
DumpToConsole("Inconsistent information detected - skipping ...\n");
|
|
MIDL_user_free(RemoteClientCallInfo);
|
|
MIDL_user_free(RemoteCallTargetInfo);
|
|
continue;
|
|
}
|
|
|
|
TranslateRemoteClientCallInfoToLocalClientCallInfo(RemoteClientCallInfo, &LocalClientCall);
|
|
MIDL_user_free(RemoteClientCallInfo);
|
|
TranslateRemoteCallTargetInfoToLocalCallTargetInfo(RemoteCallTargetInfo, &LocalCallTarget);
|
|
MIDL_user_free(RemoteCallTargetInfo);
|
|
PrintClientCallInfoBody(CurrentPID, CellID, &LocalClientCall, &LocalCallTarget,
|
|
DumpToConsole);
|
|
}
|
|
}
|
|
while (Status == RPC_S_OK);
|
|
|
|
if (Status != RPC_S_DBG_ENUMERATION_DONE)
|
|
{
|
|
DumpToConsole("Enumeration aborted with error %d\n", Status);
|
|
}
|
|
|
|
RpcTryExcept
|
|
{
|
|
RemoteFinishRPCDebugClientCallInfoEnumeration(&rh);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
}
|
|
|
|
int __cdecl
|
|
main (int argc, char **argv)
|
|
{
|
|
unsigned long Status, i;
|
|
unsigned char *StringBinding;
|
|
handle_t Binding;
|
|
RemoteDebugCellUnion *RemoteDebugCell;
|
|
DebugCellUnion Container;
|
|
DebugCellUnion EndpointContainer;
|
|
DebugCellUnion *EndpointContainerPointer;
|
|
BOOL fResult;
|
|
|
|
ParseArgv(argc, argv);
|
|
|
|
// by now, we must have all valid arguments. Depending on local/remote
|
|
// case and on action chosen, we actually do the work
|
|
if (NetworkAddr == NULL)
|
|
{
|
|
// in local case, just do the work
|
|
switch (Action)
|
|
{
|
|
case cdaCallInfo:
|
|
GetAndPrintCallInfo(CallID, IfStart, ProcNum, ProcessID, DumpToConsole);
|
|
break;
|
|
|
|
case cdaClientCallInfo:
|
|
GetAndPrintClientCallInfo(CallID, IfStart, ProcNum, ProcessID, DumpToConsole);
|
|
break;
|
|
|
|
case cdaDebugCellInfo:
|
|
GetAndPrintDbgCellInfo(ProcessID, CellID, DumpToConsole);
|
|
break;
|
|
|
|
case cdaEndpointInfo:
|
|
GetAndPrintEndpointInfo(EndpointName, DumpToConsole);
|
|
break;
|
|
|
|
case cdaThreadInfo:
|
|
GetAndPrintThreadInfo(ProcessID, ThreadID, DumpToConsole);
|
|
break;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = RpcStringBindingComposeA(0, (unsigned char *)Protseq,
|
|
(unsigned char *)NetworkAddr, (unsigned char *)BindingEndpoint, 0, &StringBinding);
|
|
CHECK_RET(Status, "RpcStringBindingCompose");
|
|
|
|
Status = RpcBindingFromStringBindingA(StringBinding, &Binding);
|
|
CHECK_RET(Status, "RpcBindingFromStringBinding");
|
|
|
|
RpcStringFreeA(&StringBinding);
|
|
|
|
Status = RpcBindingSetAuthInfo(Binding, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_GSS_NEGOTIATE,
|
|
NULL, RPC_C_AUTHZ_NONE);
|
|
CHECK_RET(Status, "RpcBindingSetAuthInfo");
|
|
|
|
// in remote case, call the remote RPCSS
|
|
switch (Action)
|
|
{
|
|
case cdaCallInfo:
|
|
GetAndPrintRemoteCallInfo(Binding);
|
|
break;
|
|
|
|
case cdaClientCallInfo:
|
|
GetAndPrintRemoteClientCallInfo(Binding);
|
|
break;
|
|
|
|
case cdaDebugCellInfo:
|
|
RemoteDebugCell = NULL;
|
|
DumpToConsole("Getting remote cell info ...\n");
|
|
RpcTryExcept
|
|
{
|
|
Status = RemoteGetCellByDebugCellID(Binding, ProcessID, CellID, &RemoteDebugCell);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
DumpToConsole("Remote call failed with error %d\n", Status);
|
|
break;
|
|
}
|
|
|
|
// get back the idl representation into a DbgCell representation
|
|
fResult = TranslateRemoteDebugCellInfoToLocalDebugCellInfo(RemoteDebugCell, &Container);
|
|
|
|
MIDL_user_free(RemoteDebugCell);
|
|
|
|
// if FALSE is returned, error info should have already been printed out
|
|
if (!fResult)
|
|
break;
|
|
|
|
if (Container.genericCell.Type == dctConnectionInfo)
|
|
{
|
|
RemoteDebugCell = NULL;
|
|
|
|
DumpToConsole("Getting remote endpoint info for connection ...\n");
|
|
|
|
RpcTryExcept
|
|
{
|
|
Status = RemoteGetCellByDebugCellID(Binding, ProcessID,
|
|
Container.connectionInfo.Endpoint, &RemoteDebugCell);
|
|
}
|
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
}
|
|
RpcEndExcept
|
|
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
DumpToConsole("Remote call failed with error %d\n", Status);
|
|
break;
|
|
}
|
|
|
|
fResult = TranslateRemoteDebugCellInfoToLocalDebugCellInfo(RemoteDebugCell,
|
|
&EndpointContainer);
|
|
|
|
MIDL_user_free(RemoteDebugCell);
|
|
|
|
if (!fResult)
|
|
break;
|
|
|
|
EndpointContainerPointer = &EndpointContainer;
|
|
}
|
|
else
|
|
EndpointContainerPointer = NULL;
|
|
|
|
PrintDbgCellInfo(&Container, EndpointContainerPointer, DumpToConsole);
|
|
break;
|
|
|
|
case cdaEndpointInfo:
|
|
GetAndPrintRemoteEndpointInfo(Binding);
|
|
break;
|
|
|
|
case cdaThreadInfo:
|
|
GetAndPrintRemoteThreadInfo(Binding);
|
|
break;
|
|
|
|
}
|
|
|
|
RpcBindingFree(&Binding);
|
|
}
|
|
|
|
/*
|
|
PrintToConsole("Authentication Level is: %s\n", AuthnLevelStr);
|
|
|
|
if (Options[0] < 0)
|
|
Options[0] = 1;
|
|
|
|
pClientThreads = MIDL_user_allocate(sizeof(HANDLE) * Options[0]);
|
|
|
|
for(i = 0; i < (unsigned long)Options[0]; i++)
|
|
{
|
|
pClientThreads[i] = CreateThread(0,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)Worker,
|
|
0,
|
|
0,
|
|
&status);
|
|
if (pClientThreads[i] == 0)
|
|
ApiError("CreateThread", GetLastError());
|
|
}
|
|
|
|
|
|
status = WaitForMultipleObjects(Options[0],
|
|
pClientThreads,
|
|
TRUE, // Wait for all client threads
|
|
INFINITE);
|
|
if (status == WAIT_FAILED)
|
|
{
|
|
ApiError("WaitForMultipleObjects", GetLastError());
|
|
}
|
|
*/
|
|
return(0);
|
|
}
|
|
|