/*++ Copyright (c) 2000 Microsoft Corporation Module Name: CellDef.hxx Abstract: The header file which contains the common definitions for the cell debugging facilities. Author: Kamen Moutafov (kamenm) Dec 99 - Feb 2000 Revision History: Data Structures: The cells are kept in the so called cell heap. The cell heap can allocate, free and relocate cells. Here's the relation b/n them: ///////////////// // CellHeap // ///////////////// | | 1 | : | N V ================= 1:N \\\\\\\\\\\\\\\\ == CellSection ==-------->\\ Cells \\ ================= \\\\\\\\\\\\\\\\ There is only one cell heap per process. Each cell section is a DACL protected, read-only from outside the process shared memory section. It starts with one committed page, and will commit more, if necessary. Pages are never decommitted from a section. We keep one cached section. If a whole section becomes unused, we make it the cached section. If the number of free cells in a section drops below a threshold, we free the cached section. Each section has a small header with information maintained by the cell heap manager. The allocator is tuned to pick up new cells from the first avaialble sections, which should preserve good locality and minimize long term memory pressure. The cell is 32 bytes big in both 32 and 64 bit versions. The fixed length simplifies and speeds up the operations of the allocator. All cells must start with the same Type byte in the same position - this is how code outside the process knows what cell is what. DebugCellID: There is the important concept of a debug cell id. A debug cell id is a unique identified of a cell, which is valid across processes. Thus, if you reference once cell from another, you should use the debug cell id, instead of the pointer. --*/ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #ifndef __CELLDEF_H__ #define __CELLDEF_H__ #ifndef __DBGCOMN_HXX__ #include #endif #ifndef __DbgIdl_h__ #include #endif #define _NOT_COVERED_ (0) // forwards class CellSection; typedef int CellTag; // temporary cells can be dctInvalid when the caller gets them and // starts initializing them const int dctFirstEntry = dctInvalid; const int dctLastEntry = dctUsedGeneric; typedef enum tagCallStatus { csAllocated, csActive, csDispatched } CallStatus; const int CallStatusFirst = csAllocated; const int CallStatusLast = csDispatched; #define DBGCELL_CACHED_CALL 0x00000001 #define DBGCELL_ASYNC_CALL 0x00000002 #define DBGCELL_PIPE_CALL 0x00000004 #define DBGCELL_LRPC_CALL 0x00000008 #define DBGCELL_VALID_CALL_FLAGS 0x00000015 typedef struct tagDebugCallInfo { union { struct { BYTE Type; // chosen from the CallStatus enum BYTE Status; USHORT ProcNum; }; DWORD TypeHeader; }; DWORD InterfaceUUIDStart; DebugCellID ServicingTID; // 1 - cached if set // 2 - async if set // 3 - pipe if set // 4 - set if this is an LRPC call - otherwise its OSF // the others are not used DWORD CallFlags; DWORD CallID; DWORD LastUpdateTime; union { // valid for OSF only DebugCellID Connection; // valid for LRPC only union { struct { USHORT PID; USHORT TID; }; // used for fast zeroing out of PID/TID pair DWORD FastInit; }; }; DWORD Reserved; } DebugCallInfo; #define DBGCELL_AUTH_SVC_NTLM 16 #define DBGCELL_AUTH_SVC_KERB 32 #define DBGCELL_AUTH_SVC_OTHER 48 const int ConnectionAuthLevelMask = 14; const int ConnectionAuthLevelShift = 1; const int ConnectionAuthServiceMask = 48; const int ConnectionAuthServiceShift = 4; typedef struct tagDebugConnectionInfo { union { struct { BYTE Type; // 1 - exclusive if set // 2,3,4 - auth level // 5,6 - auth service encoded as follows: // 0 - none // 1 - NTLM // 2 - Kerberos/Snego // 3 - other // 7,8 - reserved BYTE Flags; USHORT LastTransmitFragmentSize; }; DWORD TypeHeader; }; DebugCellID Endpoint; // switch for union type is made based on the // protseq type in the endpoint HANDLE ConnectionID[2]; DWORD LastSendTime; DWORD LastReceiveTime; #ifndef _WIN64 DWORD Reserved[2]; #endif } DebugConnectionInfo; typedef enum tagDebugThreadStatus { dtsProcessing, dtsDispatched, dtsAllocated, dtsIdle } DebugThreadStatus; typedef struct tagDebugThreadInfo { union { struct { BYTE Type; BYTE Reserved; // picked from the DebugThreadStatus enum USHORT Status; }; DWORD TypeHeader; }; DWORD LastUpdateTime; DebugCellID Endpoint; // something else? USHORT TID; // if LRPC thread, the address it is listening on. If remote // worker thread, 0 USHORT Reserved2; DWORD Reserved3[4]; } DebugThreadInfo; typedef enum tagDebugEndpointStatus { desAllocated, desActive, desInactive } DebugEndpointStatus; const int DebugEndpointNameLength = 28; typedef struct tagDebugEndpointInfo { union { struct { BYTE Type; BYTE ProtseqType; // chosen from the DebugEndpointStatus enum BYTE Status; BYTE Reserved; }; DWORD TypeHeader; }; // this string is *not* NULL terminated - use with care char EndpointName[DebugEndpointNameLength]; } DebugEndpointInfo; const int ClientCallEndpointLength = 12; typedef struct tagDebugClientCallInfo { union { struct { BYTE Type; BYTE Reserved; USHORT ProcNum; }; DWORD TypeHeader; }; DebugCellID ServicingThread; DWORD IfStart; DWORD CallID; DebugCellID CallTargetID; // Note - this string is not zero terminated char Endpoint[ClientCallEndpointLength]; } DebugClientCallInfo; const int TargetServerNameLength = 24; typedef struct tagDebugCallTargetInfo { union { struct { BYTE Type; BYTE Reserved; USHORT ProtocolSequence; }; DWORD TypeHeader; }; DWORD LastUpdateTime; // Note - this string is not zero terminated char TargetServer[TargetServerNameLength]; } DebugCallTargetInfo; typedef struct tagDebugFreeCell { union { struct { BYTE Type; BYTE Reserved; USHORT Reserved2; }; DWORD TypeHeader; }; #ifdef _WIN64 DWORD Reserved3[1]; #endif CellSection *pOwnerSection; LIST_ENTRY FreeCellsChain; #ifndef _WIN64 DWORD Reserved3[4]; #endif } DebugFreeCell; typedef struct tagDebugCellGeneric { union { struct { BYTE Type; BYTE ProtseqType; USHORT Reserved; }; DWORD TypeHeader; }; } DebugCellGeneric; typedef struct tagDebugCellUnion { union { DebugCallInfo callInfo; DebugThreadInfo threadInfo; DebugEndpointInfo endpointInfo; DebugClientCallInfo clientCallInfo; DebugConnectionInfo connectionInfo; DebugCallTargetInfo callTargetInfo; DebugFreeCell freeCell; DebugCellGeneric genericCell; }; } DebugCellUnion; // forward class CellHeap; // 32 bytes for 32 bit systems, 64 bytes for 64 bit systems class CellSection { public: friend CellHeap; friend void RPC_ENTRY I_RpcDoCellUnitTest(IN OUT void *p); void CompleteSectionInitialization(void); void PrepareSectionForCleanup(void); void CellAllocated(void); void CellFreed(void); static CellSection *AllocateCellSection(OUT RPC_STATUS *Status, IN BOOL fFirstSection, IN SECURITY_DESCRIPTOR *pSecDescriptor, IN CellHeap *pCellHeap); #if DBG void AssertValid(CellHeap *pCellHeap); #endif private: // ownership of hNewFileMapping passes to the CellSection CellSection(IN OUT RPC_STATUS *Status, IN OUT HANDLE hNewFileMapping, IN CellHeap *pCellHeap, IN DWORD *pRandomNumbers); void Free(void); // always must be called within the CellHeap mutex RPC_STATUS ExtendSection(IN CellHeap *pCellHeap); void InitializeNewPage(PVOID NewPage); USHORT Signature; // set during section creation public: USHORT LastCommittedPage; // the index of the last committed page // pages never get decommitted - only a whole // section can get freed. Therefore this // number only grows. It's protected by the // CellHeapMutex and is 1 based short SectionID; // the key for this section in the section // dictionary. private: USHORT NumberOfUsedCells; // the number of cells used in the section // protected by the CellHeap lock public: DWORD NextSectionId[2]; // two DWORDs that uniquely identify the next // section name. On the cached section, they // identify this section's name private: DebugFreeCell *pFirstFreeCell; // first free cell from this section // protected by the CellHeap lock HANDLE hFileMapping; // the handle of the section LIST_ENTRY SectionListEntry;// placeholder to chain the sections #if defined(_WIN64) DWORD Reserved[4]; #endif }; // all of these functions are in the debug library // enumeration handles typedef void * ServerEnumerationHandle; typedef void * CellEnumerationHandle; typedef void * RPCSystemWideCellEnumerationHandle; typedef void * CallInfoEnumerationHandle; typedef void * EndpointInfoEnumerationHandle; typedef void * ThreadInfoEnumerationHandle; typedef void * ClientCallInfoEnumerationHandle; #define RPCDBG_NO_PROCNUM_SPECIFIED (~(USHORT)0) // section manipulation functions void GenerateSectionName(OUT RPC_CHAR *Buffer, IN int BufferLength, IN DWORD ProcessID, IN DWORD *pSectionNumbers OPTIONAL); RPC_STATUS OpenDbgSection(OUT HANDLE *pHandle, OUT PVOID *pSection, IN DWORD ProcessID, IN DWORD *pSectionNumbers OPTIONAL); void CloseDbgSection(IN HANDLE SecHandle, IN PVOID SecPointer); // server manipulation functions RPC_STATUS StartServerEnumeration(OUT ServerEnumerationHandle *pHandle); RPC_STATUS OpenNextRPCServer(IN ServerEnumerationHandle Handle, OUT CellEnumerationHandle *pHandle); void ResetServerEnumeration(IN ServerEnumerationHandle Handle); void FinishServerEnumeration(IN OUT ServerEnumerationHandle *pHandle); DWORD GetCurrentServerPID(IN ServerEnumerationHandle Handle); // utility functions DWORD GetPageSize(void); RPC_STATUS InitializeDbgLib(void); // cell enumeration functions // enumerating a particular server RPC_STATUS OpenRPCServerDebugInfo(IN DWORD ProcessID, OUT CellEnumerationHandle *pHandle); DebugCellUnion *GetNextDebugCellInfo(IN CellEnumerationHandle Handle, OUT DebugCellID *CellID); void ResetRPCServerDebugInfo(IN CellEnumerationHandle Handle); void CloseRPCServerDebugInfo(IN OUT CellEnumerationHandle *pHandle); // enumerating all servers RPC_STATUS OpenRPCSystemWideCellEnumeration(OUT RPCSystemWideCellEnumerationHandle *pHandle); RPC_STATUS GetNextRPCSystemWideCell(IN RPCSystemWideCellEnumerationHandle handle, OUT DebugCellUnion **NextCell, OUT DebugCellID *CellID, OUT DWORD *ServerPID OPTIONAL); DebugCellUnion *GetRPCSystemWideCellFromCellID(IN RPCSystemWideCellEnumerationHandle handle, IN DebugCellID CellID); void FinishRPCSystemWideCellEnumeration(IN OUT RPCSystemWideCellEnumerationHandle *pHandle); RPC_STATUS ResetRPCSystemWideCellEnumeration(IN RPCSystemWideCellEnumerationHandle handle); // enumerating calls RPC_STATUS OpenRPCDebugCallInfoEnumeration(IN DWORD CallID OPTIONAL, IN DWORD IfStart OPTIONAL, IN int ProcNum OPTIONAL, IN DWORD ProcessID OPTIONAL, OUT CallInfoEnumerationHandle *pHandle); RPC_STATUS GetNextRPCDebugCallInfo(IN CallInfoEnumerationHandle handle, OUT DebugCallInfo **NextCall, OUT DebugCellID *CellID, OUT DWORD *ServerPID); void FinishRPCDebugCallInfoEnumeration(IN OUT CallInfoEnumerationHandle *pHandle); RPC_STATUS ResetRPCDebugCallInfoEnumeration(IN CallInfoEnumerationHandle handle); // enumerating endpoints RPC_STATUS OpenRPCDebugEndpointInfoEnumeration(IN char *Endpoint OPTIONAL, OUT EndpointInfoEnumerationHandle *pHandle); RPC_STATUS GetNextRPCDebugEndpointInfo(IN CallInfoEnumerationHandle handle, OUT DebugEndpointInfo **NextEndpoint, OUT DebugCellID *CellID, OUT DWORD *ServerPID); void FinishRPCDebugEndpointInfoEnumeration(IN OUT EndpointInfoEnumerationHandle *pHandle); RPC_STATUS ResetRPCDebugEndpointInfoEnumeration(IN EndpointInfoEnumerationHandle handle); // enumerating threads RPC_STATUS OpenRPCDebugThreadInfoEnumeration(IN DWORD ProcessID, IN DWORD ThreadID OPTIONAL, OUT ThreadInfoEnumerationHandle *pHandle); RPC_STATUS GetNextRPCDebugThreadInfo(IN ThreadInfoEnumerationHandle handle, OUT DebugThreadInfo **NextThread, OUT DebugCellID *CellID, OUT DWORD *ServerPID); void FinishRPCDebugThreadInfoEnumeration(IN OUT ThreadInfoEnumerationHandle *pHandle); RPC_STATUS ResetRPCDebugThreadInfoEnumeration(IN ThreadInfoEnumerationHandle handle); // enumerating client calls RPC_STATUS OpenRPCDebugClientCallInfoEnumeration(IN DWORD CallID OPTIONAL, IN DWORD IfStart OPTIONAL, IN int ProcNum OPTIONAL, IN DWORD ProcessID OPTIONAL, OUT ClientCallInfoEnumerationHandle *pHandle); RPC_STATUS GetNextRPCDebugClientCallInfo(IN ClientCallInfoEnumerationHandle handle, OUT DebugClientCallInfo **NextCall, OUT DebugCallTargetInfo **NextCallTarget, OUT DebugCellID *CellID, OUT DWORD *ServerPID); void FinishRPCDebugClientCallInfoEnumeration(IN OUT ClientCallInfoEnumerationHandle *pHandle); RPC_STATUS ResetRPCDebugClientCallInfoEnumeration(IN CallInfoEnumerationHandle handle); // retrieving a cell by the cell id DebugCellUnion *GetCellByDebugCellID(IN CellEnumerationHandle CellEnumHandle, IN DebugCellID CellID); RPC_STATUS GetCellByDebugCellID(IN DWORD ProcessID, IN DebugCellID CellID, DebugCellUnion *Container); // print function prototype typedef VOID (__cdecl *PRPCDEBUG_OUTPUT_ROUTINE)(PCSTR lpFormat, ...); // format and print functions void PrintCallInfoHeader(PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void PrintCallInfoBody(IN DWORD ProcessID, IN DebugCellID CellID, IN DebugCallInfo *CallInfo, PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void GetAndPrintCallInfo(IN DWORD CallID OPTIONAL, IN DWORD IfStart OPTIONAL, IN int ProcNum OPTIONAL, IN DWORD ProcessID OPTIONAL, PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void PrintDbgCellInfo(IN DebugCellUnion *Container, IN DebugCellUnion *EndpointContainer OPTIONAL, PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void GetAndPrintDbgCellInfo(DWORD ProcessID, DebugCellID CellID, PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void PrintEndpointInfoHeader(PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void PrintEndpointInfoBody(IN DWORD ProcessID, IN DebugCellID CellID, IN DebugEndpointInfo *EndpointInfo, PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void GetAndPrintEndpointInfo(IN char *Endpoint OPTIONAL, PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void PrintThreadInfoHeader(PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void PrintThreadInfoBody(IN DWORD ProcessID, IN DebugCellID CellID, IN DebugThreadInfo *ThreadInfo, PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void GetAndPrintThreadInfo(DWORD ProcessID, DWORD ThreadID OPTIONAL, PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void PrintClientCallInfoHeader(PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void PrintClientCallInfoBody(IN DWORD ProcessID, IN DebugCellID CellID, IN DebugClientCallInfo *ClientCallInfo, IN DebugCallTargetInfo *CallTargetInfo, PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); void GetAndPrintClientCallInfo(IN DWORD CallID OPTIONAL, IN DWORD IfStart OPTIONAL, IN int ProcNum OPTIONAL, IN DWORD ProcessID OPTIONAL, PRPCDEBUG_OUTPUT_ROUTINE PrintRoutine); #define RPC_S_DBG_NOT_AN_RPC_SERVER 1 #define RPC_S_DBG_ENUMERATION_DONE 2 #endif __CELLDEF_H__