/*++ Copyright (c) 2000 Microsoft Corporation Module Name: RpcDbg.cxx Abstract: RPC Extended Debugging Utility Author: Kamen Moutafov (kamenm) 11-30-99 Revision History: --*/ #include #include // Usage const char *USAGE = "-s -p -C -I \n" "-N -P -L \n" "-E -T -r -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 ] [-I ] [-N ] [-P ]\n" "-l -P -L \n" "-e [-E ]\n" "-t -P [-T ]\n" "-a [-C ] [-I ] [-N ] [-P ]\n" "-s, -p and -r are independent to the other options. -r affects\n" "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': // Requires a parameter. if (fMissingParm) { break; } CallID = strtoul(*argv, &Ignored, radix); argc--; argv++; break; case 'p': // Requires a parameter. if (fMissingParm) { break; } 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': // Requires a parameter. if (fMissingParm) { break; } NetworkAddr = *argv; argc--; argv++; break; case 'I': // Requires a parameter. if (fMissingParm) { break; } IfStart = strtoul(*argv, &Ignored, radix); argc--; argv++; break; case 'N': // Requires a parameter. if (fMissingParm) { break; } ProcNum = strtoul(*argv, &Ignored, radix); argc--; argv++; break; case 'L': // Requires a parameter. if (fMissingParm) { break; } 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': // Requires a parameter. if (fMissingParm) { break; } EndpointName = *argv; argc--; argv++; break; case 'T': // Requires a parameter. if (fMissingParm) { break; } ThreadID = strtoul(*argv, &Ignored, radix); argc--; argv++; break; case 'P': // Requires a parameter. if (fMissingParm) { break; } 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': // Requires a parameter. if (fMissingParm) { break; } radix = atoi(*argv); argc--; argv++; break; default: fMissingParm = 0; printf("Usage: %s: %s\n", Name, USAGE); exit(2); break; } if (fMissingParm) { printf("Switch %s, missing required parameter\n", *(argv-1)); 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); }