/*++ Copyright (c) 1995-1996 Microsoft Corporation Module Name: fcache.cxx Abstract: This module contains the cache-related ntsd debugger extensions for Internet Information Server Author: Keith Moore (keithmo) 12-Aug-1997 Revision History: --*/ #include "inetdbgp.h" // // Worker routines. // PSTR DemuxToString( IN ULONG Demux ) /*++ Routine Description: Converts the specified demux value to a printable string. Arguments: Demux - The demux value to map. Return Value: PSTR - The printable string. --*/ { switch( Demux ) { case RESERVED_DEMUX_START : return "RESERVED_DEMUX_START"; case RESERVED_DEMUX_DIRECTORY_LISTING : return "RESERVED_DEMUX_DIRECTORY_LISTING"; case RESERVED_DEMUX_ATOMIC_DIRECTORY_GUARD : return "RESERVED_DEMUX_ATOMIC_DIRECTORY_GUARD"; case RESERVED_DEMUX_OPEN_FILE : return "RESERVED_DEMUX_OPEN_FILE"; case RESERVED_DEMUX_URI_INFO : return "RESERVED_DEMUX_URI_INFO"; case RESERVED_DEMUX_PHYSICAL_OPEN_FILE : return "RESERVED_DEMUX_PHYSICAL_OPEN_FILE"; default : return "Unknown"; } } // DemuxToString PSTR SignatureToString( IN DWORD CurrentSignature, IN DWORD ValidSignature, IN DWORD FreedSignature ) /*++ Routine Description: Determines an appropriate display string for the given signature. If the current signature matches the expected valid signature, then the string "OK" is returned. If the current signature matches the freed signature, then "FREED" is returned. Otherwise, "INVALID" is returned. Arguments: CurrentSignature - The current signature as retrieved from the object/structure. ValidSignature - The expected signature for a valid, in-use object/structure. FreedSignature - The signature assigned to the object/structure just before it is freed. Return Value: PSTR - "OK", "FREED", or "INVALID" as appropriate. --*/ { if( CurrentSignature == ValidSignature ) { return "OK"; } if( CurrentSignature == FreedSignature ) { return "FREED"; } return "INVALID"; } // SignatureToString PSTR BoolToString( IN BOOL Flag ) /*++ Routine Description: Maps the given BOOL to a displayable string. Arguments: Flag - The BOOL flag to map. Return Value: PSTR - "TRUE", "FALSE", or "INVALID" as appropriate. --*/ { // // In general, explicit testing for TRUE is a Bad Thing, but in // this case, it's useful for catching invalid data. // if( Flag == TRUE ) { return "TRUE"; } if( Flag == FALSE ) { return "FALSE"; } return "INVALID"; } // BoolToString VOID DumpBlobHeader( IN PSTR Prefix, IN PBLOB_HEADER BlobHeader, IN ULONG ActualAddress ) /*++ Routine Description: Formats and dumps a specific BLOB_HEADER structure. Arguments: Prefix - The prefix to use before each printed line. This makes hierarchical object displays much prettier. BlobHeader - Points to a local copy of the structure. ActualAddress - The virtual address of the object in the debugee. Return Value: None. --*/ { ULONG offset; UCHAR symbol[MAX_PATH]; CHAR renderedSymbol[MAX_PATH]; GetSymbol( (PVOID)BlobHeader->pfnFreeRoutine, symbol, &offset ); if( symbol[0] == '\0' ) { renderedSymbol[0] = '\0'; } else if( offset == 0 ) { sprintf( renderedSymbol, " (%s)", symbol ); } else { sprintf( renderedSymbol, " (%s+0x%lx)", symbol, offset ); } dprintf( "%sBLOB_HEADER @ %08lx\n" "%s IsCached = %s\n" "%s pCache = %08lx\n" "%s PFList @ %08lx%s\n" "%s pfnFreeRoutine = %08lx%s\n" "\n", Prefix, ActualAddress, Prefix, BoolToString( BlobHeader->IsCached ), Prefix, BlobHeader->pCache, Prefix, ActualAddress + FIELD_OFFSET( BLOB_HEADER, PFList ), IS_LIST_EMPTY( BlobHeader, ActualAddress, BLOB_HEADER, PFList ) ? " (EMPTY)" : "", Prefix, BlobHeader->pfnFreeRoutine, renderedSymbol ); } // DumpBlobHeader VOID DumpOpenFileInfo( IN PSTR Prefix, IN LPTS_OPEN_FILE_INFO OpenFileInfo, IN ULONG ActualAddress ) /*++ Routine Description: Formats and dumps a specific TS_OPEN_FILE_INFO structure. Arguments: Prefix - The prefix to use before each printed line. This makes hierarchical object displays much prettier. OpenFileInfo - Points to a local copy of the structure. ActualAddress - The virtual address of the object in the debugee. Return Value: None. --*/ { dprintf( "%sTS_OPEN_FILE_INFO @ %08lx\n" "%s m_hOpeningUser = %08lx\n" "%s m_PhysFileInfo = %08lx\n" "%s m_FileInfo @ %08lx\n" "%s m_CastratedLastWriteTime @ %08lx\n", Prefix, ActualAddress, Prefix, OpenFileInfo->m_hOpeningUser, Prefix, OpenFileInfo->m_PhysFileInfo, Prefix, ActualAddress + FIELD_OFFSET( TS_OPEN_FILE_INFO, m_FileInfo ), Prefix, ActualAddress + FIELD_OFFSET( TS_OPEN_FILE_INFO, m_CastratedLastWriteTime ) ); dprintf( "%s m_achHttpInfo @ %08lx (%s)\n" "%s m_cchHttpInfo = %lu\n" "%s m_achETag @ %08lx (%s)\n" "%s m_cchETag = %lu\n" "%s m_ETagIsWeak = %s\n" "%s m_fIsCached = %s\n" "\n", Prefix, ActualAddress + FIELD_OFFSET( TS_OPEN_FILE_INFO, m_achHttpInfo ), OpenFileInfo->m_achHttpInfo, Prefix, OpenFileInfo->m_cchHttpInfo, Prefix, ActualAddress + FIELD_OFFSET( TS_OPEN_FILE_INFO, m_achETag ), OpenFileInfo->m_achETag, Prefix, OpenFileInfo->m_cchETag, Prefix, BoolToString( OpenFileInfo->m_ETagIsWeak ), Prefix, BoolToString( OpenFileInfo->m_fIsCached ) ); } // DumpOpenFileInfo VOID DumpUriInfo( IN PSTR Prefix, IN PW3_URI_INFO UriInfo, IN ULONG ActualAddress ) /*++ Routine Description: Formats and dumps a specific W3_URI_INFO structure. Arguments: Prefix - The prefix to use before each printed line. This makes hierarchical object displays much prettier. UriInfo - Points to a local copy of the structure. ActualAddress - The virtual address of the object in the debugee. Return Value: None. --*/ { CHAR name[MAX_PATH]; CHAR unmappedName[MAX_PATH]; if( UriInfo->pszName == NULL ) { strcpy( name, "" ); } else if( !ReadMemory( (ULONG)UriInfo->pszName, name, sizeof(name), NULL ) ) { strcpy( name, "" ); } if( UriInfo->pszUnmappedName == NULL ) { strcpy( unmappedName, "" ); } else if( !ReadMemory( (ULONG)UriInfo->pszUnmappedName, unmappedName, sizeof(unmappedName), NULL ) ) { strcpy( unmappedName, "" ); } dprintf( "%sW3_URI_INFO @ %08lx\n" "%s bFileInfoValid = %lu\n" "%s bIsCached = %s\n" "%s hFileEvent = %08lx\n" "%s pOpenFileInfo = %08lx\n", Prefix, ActualAddress, Prefix, UriInfo->bFileInfoValid, Prefix, BoolToString( UriInfo->bIsCached ), Prefix, UriInfo->hFileEvent, Prefix, UriInfo->pOpenFileInfo ); dprintf( "%s dwFileOpenError = %lu\n" "%s cchName = %lu\n" "%s pszName = %08lx (%s)\n" "%s pszUnmappedName = %08lx (%s)\n" "%s pMetaData = %08lx\n" "\n", Prefix, UriInfo->dwFileOpenError, Prefix, UriInfo->cchName, Prefix, UriInfo->pszName, name, Prefix, UriInfo->pszUnmappedName, unmappedName, Prefix, UriInfo->pMetaData ); } // DumpUriInfo VOID DumpPhysOpenFileInfo( IN PSTR Prefix, IN PPHYS_OPEN_FILE_INFO PhysOpenFileInfo, IN ULONG ActualAddress ) /*++ Routine Description: Formats and dumps a specific PHYS_OPEN_FILE_INFO structure. Arguments: Prefix - The prefix to use before each printed line. This makes hierarchical object displays much prettier. PhysOpenFileInfo - Points to a local copy of the structure. ActualAddress - The virtual address of the object in the debugee. Return Value: None. --*/ { dprintf( "%sPHYS_OPEN_FILE_INFO @ %08lx\n" "%s Signature = %08lx (%s)\n" "%s hOpenFile = %08lx\n" "%s hOpenEvent = %08lx\n", Prefix, ActualAddress, Prefix, PhysOpenFileInfo->Signature, SignatureToString( PhysOpenFileInfo->Signature, PHYS_OBJ_SIGNATURE, PHYS_OBJ_SIGNATURE_X ), Prefix, PhysOpenFileInfo->hOpenFile, Prefix, PhysOpenFileInfo->hOpenEvent ); dprintf( "%s OpenReferenceList @ %08lx%s\n" "%s fSecurityDescriptor = %s\n" "%s fIsCached = %s\n", Prefix, ActualAddress + FIELD_OFFSET( PHYS_OPEN_FILE_INFO, OpenReferenceList ), IS_LIST_EMPTY( PhysOpenFileInfo, ActualAddress, PHYS_OPEN_FILE_INFO, OpenReferenceList ) ? " (EMPTY)" : "", Prefix, BoolToString( PhysOpenFileInfo->fSecurityDescriptor ), Prefix, BoolToString( PhysOpenFileInfo->fIsCached ) ); dprintf( "%s dwLastError = %lu\n" "%s cbSecDescMaxSize = %lu\n" "%s abSecurityDescriptor = %08lx\n" "%s pOplock = %08lx\n" "\n", Prefix, PhysOpenFileInfo->dwLastError, Prefix, PhysOpenFileInfo->cbSecDescMaxSize, Prefix, PhysOpenFileInfo->abSecurityDescriptor, Prefix, PhysOpenFileInfo->pOplock ); } // DumpPhysOpenFileInfo VOID DumpOplockObject( IN PSTR Prefix, IN POPLOCK_OBJECT OplockObject, IN ULONG ActualAddress ) /*++ Routine Description: Formats and dumps a specific OPLOCK_OBJECT structure. Arguments: Prefix - The prefix to use before each printed line. This makes hierarchical object displays much prettier. OplockObject - Points to a local copy of the structure. ActualAddress - The virtual address of the object in the debugee. Return Value: None. --*/ { dprintf( "%sOPLOCK_OBJECT @ %08lx\n" "%s Signature = %08lx (%s)\n" "%s lpPFInfo = %08lx\n" "%s hOplockInitComplete = %08lx\n" "\n", Prefix, ActualAddress, Prefix, OplockObject->Signature, SignatureToString( OplockObject->Signature, OPLOCK_OBJ_SIGNATURE, OPLOCK_OBJ_SIGNATURE_X ), Prefix, OplockObject->lpPFInfo, Prefix, OplockObject->hOplockInitComplete ); } // DumpOplockObject VOID DumpOpenFileInfoBlob( IN PSTR Prefix, IN PBLOB_HEADER BlobHeader, IN ULONG ActualAddress ) /*++ Routine Description: Formats and dumps a TS_OPEN_FILE_INFO blob. Arguments: Prefix - The prefix to use before each printed line. This makes hierarchical object displays much prettier. BlobHeader - Points to a local copy of the blob. ActualAddress - The virtual address of the object in the debugee. Return Value: None. --*/ { TS_OPEN_FILE_INFO localOpenFileInfo; if( !ReadMemory( ActualAddress + sizeof(*BlobHeader), &localOpenFileInfo, sizeof(localOpenFileInfo), NULL ) ) { dprintf( "inetdbg: cannot read TS_OPEN_FILE_INFO @ %08lx\n", ActualAddress + sizeof(*BlobHeader) ); return; } DumpBlobHeader( Prefix, BlobHeader, ActualAddress ); DumpOpenFileInfo( Prefix, &localOpenFileInfo, ActualAddress + sizeof(*BlobHeader) ); } // DumpOpenFileInfoBlob VOID DumpUriInfoBlob( IN PSTR Prefix, IN PBLOB_HEADER BlobHeader, IN ULONG ActualAddress ) /*++ Routine Description: Formats and dumps a W3_URI_INFO blob. Arguments: Prefix - The prefix to use before each printed line. This makes hierarchical object displays much prettier. BlobHeader - Points to a local copy of the blob. ActualAddress - The virtual address of the object in the debugee. Return Value: None. --*/ { W3_URI_INFO localUriInfo; if( !ReadMemory( ActualAddress + sizeof(*BlobHeader), &localUriInfo, sizeof(localUriInfo), NULL ) ) { dprintf( "inetdbg: cannot read W3_URI_INFO @ %08lx\n", ActualAddress + sizeof(*BlobHeader) ); return; } DumpBlobHeader( Prefix, BlobHeader, ActualAddress ); DumpUriInfo( Prefix, &localUriInfo, ActualAddress + sizeof(*BlobHeader) ); } // DumpUriInfoBlob VOID DumpPhysOpenFileInfoBlob( IN PSTR Prefix, IN PBLOB_HEADER BlobHeader, IN ULONG ActualAddress ) /*++ Routine Description: Formats and dumps a PHYS_OPEN_FILE_INFO blob. Arguments: Prefix - The prefix to use before each printed line. This makes hierarchical object displays much prettier. BlobHeader - Points to a local copy of the blob. ActualAddress - The virtual address of the object in the debugee. Return Value: None. --*/ { PHYS_OPEN_FILE_INFO localPhysOpenFileInfo; if( !ReadMemory( ActualAddress + sizeof(*BlobHeader), &localPhysOpenFileInfo, sizeof(localPhysOpenFileInfo), NULL ) ) { dprintf( "inetdbg: cannot read PHYS_OPEN_FILE_INFO @ %08lx\n", ActualAddress + sizeof(*BlobHeader) ); return; } DumpBlobHeader( Prefix, BlobHeader, ActualAddress ); DumpPhysOpenFileInfo( Prefix, &localPhysOpenFileInfo, ActualAddress + sizeof(*BlobHeader) ); } // DumpPhysOpenFileInfo VOID DumpCacheObject( IN PSTR Prefix, IN PCACHE_OBJECT CacheObject, IN ULONG ActualAddress, IN BOOLEAN Verbose ) /*++ Routine Description: Formats and dumps a specific CACHE_OBJECT structure. Arguments: Prefix - The prefix to use before each printed line. This makes hierarchical object displays much prettier. CacheObject - Points to a local copy of the structure. ActualAddress - The virtual address of the object in the debugee. Verbose - If TRUE, then also dumps the blob associated with the object. Return Value: None. --*/ { BLOB_HEADER localBlob; CHAR path[MAX_PATH+1]; path[0] = '\0'; if( CacheObject->cchLength < MAX_PATH ) { ReadMemory( ActualAddress + FIELD_OFFSET( CACHE_OBJECT, szPath ), path, CacheObject->cchLength, NULL ); path[CacheObject->cchLength] = '\0'; } dprintf( "%sCACHE_OBJECT @ %08lx\n" "%s Signature = %08lx (%s)\n" "%s BinList @ %08lx%s\n" "%s MruList @ %08lx%s\n" "%s DirChangeList @ %08lx%s\n", Prefix, ActualAddress, Prefix, CacheObject->Signature, SignatureToString( CacheObject->Signature, CACHE_OBJ_SIGNATURE, CACHE_OBJ_SIGNATURE_X ), Prefix, ActualAddress + FIELD_OFFSET( CACHE_OBJECT, BinList ), IS_LIST_EMPTY( CacheObject, ActualAddress, CACHE_OBJECT, BinList ) ? " (EMPTY)" : "", Prefix, ActualAddress + FIELD_OFFSET( CACHE_OBJECT, MruList ), IS_LIST_EMPTY( CacheObject, ActualAddress, CACHE_OBJECT, MruList ) ? " (EMPTY)" : "", Prefix, ActualAddress + FIELD_OFFSET( CACHE_OBJECT, DirChangeList ), IS_LIST_EMPTY( CacheObject, ActualAddress, CACHE_OBJECT, DirChangeList ) ? " (EMPTY)" : "" ); dprintf( "%s pbhBlob = %08lx\n" "%s references = %lu\n" "%s TTL = %lu\n" "%s hash = %08lx\n", Prefix, CacheObject->pbhBlob, Prefix, CacheObject->references, Prefix, CacheObject->TTL, Prefix, CacheObject->hash ); dprintf( "%s cchLength = %lu\n" "%s iDemux = %08lx (%s)\n" "%s dwService = %08lx\n" "%s dwInstance = %08lx\n", Prefix, CacheObject->cchLength, Prefix, CacheObject->iDemux, DemuxToString( CacheObject->iDemux ), Prefix, CacheObject->dwService, Prefix, CacheObject->dwInstance ); dprintf( "%s pSecDesc = %08lx\n" "%s hLastSuccessAccessToken = %08lx\n" "%s fZombie = %s\n" "%s szPath = %s\n" "\n", Prefix, CacheObject->pSecDesc, Prefix, CacheObject->hLastSuccessAccessToken, Prefix, BoolToString( CacheObject->fZombie ), Prefix, path ); if( Verbose ) { CHAR prefix[80]; sprintf( prefix, " %s", Prefix ); if( !ReadMemory( (ULONG)CacheObject->pbhBlob, &localBlob, sizeof(localBlob), NULL ) ) { dprintf( "inetdbg: cannot read blob header @ %08lx\n", CacheObject->pbhBlob ); return; } switch( CacheObject->iDemux ) { case RESERVED_DEMUX_OPEN_FILE : DumpOpenFileInfoBlob( prefix, &localBlob, (ULONG)CacheObject->pbhBlob ); break; case RESERVED_DEMUX_URI_INFO : DumpUriInfoBlob( prefix, &localBlob, (ULONG)CacheObject->pbhBlob ); break; case RESERVED_DEMUX_PHYSICAL_OPEN_FILE : DumpPhysOpenFileInfoBlob( prefix, &localBlob, (ULONG)CacheObject->pbhBlob ); break; } } } // DumpCacheObject VOID DumpCacheObjectList( IN PSTR ListName, IN PLIST_ENTRY LocalListHead, IN PLIST_ENTRY RemoteListHead, IN BOOLEAN MruList, IN BOOLEAN Verbose ) /*++ Routine Description: Formats and dumps a linked list of CACHE_OBJECTs. Arguments: Prefix - The prefix to use before each printed line. This makes hierarchical object displays much prettier. LocalListHead - Points to a local copy of the linked list head. RemoteListHead - The virtual address of the linked list head in the debugee. MruList - TRUE if we're dumping the Mru list, FALSE if we're dumping the Bin list. Verbose - If TRUE, then be verbose. Return Value: None. --*/ { PLIST_ENTRY nextEntry; PCACHE_OBJECT cacheObject; CACHE_OBJECT localCacheObject; dprintf( "%s @ %08lx\n\n", ListName, RemoteListHead ); nextEntry = LocalListHead->Flink; while( nextEntry != RemoteListHead ) { if( CheckControlC() ) { break; } if( MruList ) { cacheObject = CONTAINING_RECORD( nextEntry, CACHE_OBJECT, MruList ); } else { cacheObject = CONTAINING_RECORD( nextEntry, CACHE_OBJECT, BinList ); } if( !ReadMemory( (ULONG)cacheObject, &localCacheObject, sizeof(localCacheObject), NULL ) ) { dprintf( "inetdbg: cannot read CACHE_OBJECT @ %08lx\n", cacheObject ); return; } DumpCacheObject( " ", &localCacheObject, (ULONG)cacheObject, Verbose ); if( MruList ) { nextEntry = localCacheObject.MruList.Flink; } else { nextEntry = localCacheObject.BinList.Flink; } } } // DumpCacheObjectList VOID DumpCacheTable( IN PCACHE_TABLE CacheTable, IN ULONG ActualAddress, IN BOOLEAN DumpBin, IN BOOLEAN DumpMru, IN BOOLEAN Verbose ) /*++ Routine Description: Formats and dumps the entire cache table. Arguments: CacheTable - Points to a local copy of the cache table. ActualAddress - The virtual address of the cache table in the debugee. DumpBin - If TRUE, then dump the bin lists hanging off the cache table. DumpMru - If TRUE, then dump the Mru list hanging off the cache table. Verbose - If TRUE, then be verbose. Return Value: None. --*/ { LONG i; // // Dump simple data. // dprintf( "CACHE_TABLE @ %08lx\n" " CriticalSection @ %08lx\n", ActualAddress, ActualAddress + FIELD_OFFSET( CACHE_TABLE, CriticalSection ) ); if( CacheTable->CriticalSection.LockCount == -1 ) { dprintf( " LockCount = NOT LOCKED\n" ); } else { dprintf( " LockCount = %lu\n", CacheTable->CriticalSection.LockCount ); } dprintf( " RecursionCount = %lu\n" " OwningThread = %08lx\n", CacheTable->CriticalSection.RecursionCount, CacheTable->CriticalSection.OwningThread ); // // Only display the non-empty bins. // for( i = 0 ; i < MAX_BINS ; i++ ) { CHAR tmp[sizeof("Items[1234567890]")]; if( !IS_LIST_EMPTY( CacheTable, ActualAddress, CACHE_TABLE, Items[i] ) ) { sprintf( tmp, "Items[%lu]", i ); dprintf( " %-18s @ %08lx\n", tmp, ActualAddress + FIELD_OFFSET( CACHE_TABLE, Items[i] ) ); } } dprintf( " MruList @ %08lx%s\n" " OpenFileInUse = %ld\n" " MaxOpenFileInUse = %ld\n" "\n", ActualAddress + FIELD_OFFSET( CACHE_TABLE, MruList ), IS_LIST_EMPTY( CacheTable, ActualAddress, CACHE_TABLE, MruList ) ? " (EMPTY)" : "", CacheTable->OpenFileInUse, CacheTable->MaxOpenFileInUse ); // // If requested, dump the individual entries in the bin & mru lists. // if( DumpBin ) { for( i = 0 ; i < MAX_BINS ; i++ ) { CHAR tmp[sizeof("Items[1234567890]")]; if( !IS_LIST_EMPTY( CacheTable, ActualAddress, CACHE_TABLE, Items[i] ) ) { sprintf( tmp, "Items[%lu]", i ); DumpCacheObjectList( tmp, &CacheTable->Items[i], (PLIST_ENTRY)( ActualAddress + FIELD_OFFSET( CACHE_TABLE, Items[i] ) ), FALSE, Verbose ); } } } if( DumpMru ) { if( !IS_LIST_EMPTY( CacheTable, ActualAddress, CACHE_TABLE, MruList ) ) { DumpCacheObjectList( "MruList", &CacheTable->MruList, (PLIST_ENTRY)( ActualAddress + FIELD_OFFSET( CACHE_TABLE, MruList ) ), TRUE, Verbose ); } } } // DumpCacheTable // // NTSD extension entrypoints. // DECLARE_API( fcache ) /*++ Routine Description: This function is called as an NTSD extension to format and dump the entire open file cache or a single cache object. Arguments: hCurrentProcess - Supplies a handle to the current process (at the time the extension was called). hCurrentThread - Supplies a handle to the current thread (at the time the extension was called). CurrentPc - Supplies the current pc at the time the extension is called. lpExtensionApis - Supplies the address of the functions callable by this extension. lpArgumentString - Supplies the asciiz string that describes the ansi string to be dumped. Return Value: None. --*/ { ULONG address; CACHE_OBJECT cacheObject; CACHE_TABLE cacheTable; BOOLEAN dumpBin; BOOLEAN dumpMru; BOOLEAN verbose; INIT_API(); // // Establish defaults. // dumpBin = FALSE; dumpMru = FALSE; verbose = FALSE; // // Skip any leading blanks. // while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; } // // Process switches. // while( *lpArgumentString == '-' ) { lpArgumentString++; while( *lpArgumentString != ' ' && *lpArgumentString != '\t' && *lpArgumentString != '\0' ) { switch( *lpArgumentString ) { case 'v' : case 'V' : verbose = !verbose; break; case 'b' : case 'B' : dumpBin = !dumpBin; break; case 'm' : case 'M' : dumpMru = !dumpMru; break; case '-' : // Set the switches the way I like them. --keithmo verbose = TRUE; dumpBin = TRUE; dumpMru = FALSE; break; default : dprintf( "use: inetdbg.fcache [options] [address]\n" ); return; } lpArgumentString++; } while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; } } if( *lpArgumentString != '\0' ) { // // Dump a single object. // address = GetExpression( lpArgumentString ); if( address == 0 ) { dprintf( "inetdbg: cannot evaluate \"%s\"\n", lpArgumentString ); return; } // // Read the cache object. // if( !ReadMemory( (ULONG)address, &cacheObject, sizeof(cacheObject), NULL ) ) { dprintf( "inetdbg: cannot read CACHE_OBJECT @ %lx\n", address ); return; } DumpCacheObject( "", &cacheObject, address, verbose ); return; } // // Dump the entire cache table. // address = GetExpression( "infocomm!CacheTable" ); if( address == 0 ) { dprintf( "inetdbg: cannot find infocomm!CacheTable\n" ); return; } if( !ReadMemory( (ULONG)address, &cacheTable, sizeof(cacheTable), NULL ) ) { dprintf( "inetdbg: cannot read CACHE_TABLE @ %08lx\n", address ); return; } DumpCacheTable( &cacheTable, address, dumpBin, dumpMru, verbose ); } // DECLARE_API( fcache ) DECLARE_API( open ) /*++ Routine Description: This function is called as an NTSD extension to format and dump a specific TS_OPEN_FILE_INFO structure. Arguments: hCurrentProcess - Supplies a handle to the current process (at the time the extension was called). hCurrentThread - Supplies a handle to the current thread (at the time the extension was called). CurrentPc - Supplies the current pc at the time the extension is called. lpExtensionApis - Supplies the address of the functions callable by this extension. lpArgumentString - Supplies the asciiz string that describes the ansi string to be dumped. Return Value: None. --*/ { ULONG address; TS_OPEN_FILE_INFO openFileInfo; INIT_API(); // // Skip any leading blanks. // while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; } if( *lpArgumentString == '\0' ) { dprintf( "use: inetdbg.open address\n" ); return; } address = GetExpression( lpArgumentString ); if( address == 0 ) { dprintf( "inetdbg: cannot evaluate \"%s\"\n", lpArgumentString ); return; } // // Read the object. // if( !ReadMemory( (ULONG)address, &openFileInfo, sizeof(openFileInfo), NULL ) ) { dprintf( "inetdbg: cannot read TS_OPEN_FILE_INFO @ %lx\n", address ); return; } DumpOpenFileInfo( "", &openFileInfo, address ); } // DECLARE_API( open ) DECLARE_API( uri ) /*++ Routine Description: This function is called as an NTSD extension to format and dump a specific W3_URI_INFO structure. Arguments: hCurrentProcess - Supplies a handle to the current process (at the time the extension was called). hCurrentThread - Supplies a handle to the current thread (at the time the extension was called). CurrentPc - Supplies the current pc at the time the extension is called. lpExtensionApis - Supplies the address of the functions callable by this extension. lpArgumentString - Supplies the asciiz string that describes the ansi string to be dumped. Return Value: None. --*/ { ULONG address; W3_URI_INFO uriInfo; INIT_API(); // // Skip any leading blanks. // while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; } if( *lpArgumentString == '\0' ) { dprintf( "use: inetdbg.uri address\n" ); return; } address = GetExpression( lpArgumentString ); if( address == 0 ) { dprintf( "inetdbg: cannot evaluate \"%s\"\n", lpArgumentString ); return; } // // Read the object. // if( !ReadMemory( (ULONG)address, &uriInfo, sizeof(uriInfo), NULL ) ) { dprintf( "inetdbg: cannot read W3_URI_INFO @ %lx\n", address ); return; } DumpUriInfo( "", &uriInfo, address ); } // DECLARE_API( uri ) DECLARE_API( phys ) /*++ Routine Description: This function is called as an NTSD extension to format and dump a specific PHYS_OPEN_FILE_INFO structure. Arguments: hCurrentProcess - Supplies a handle to the current process (at the time the extension was called). hCurrentThread - Supplies a handle to the current thread (at the time the extension was called). CurrentPc - Supplies the current pc at the time the extension is called. lpExtensionApis - Supplies the address of the functions callable by this extension. lpArgumentString - Supplies the asciiz string that describes the ansi string to be dumped. Return Value: None. --*/ { ULONG address; PHYS_OPEN_FILE_INFO physOpenFileInfo; INIT_API(); // // Skip any leading blanks. // while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; } if( *lpArgumentString == '\0' ) { dprintf( "use: inetdbg.phys address\n" ); return; } address = GetExpression( lpArgumentString ); if( address == 0 ) { dprintf( "inetdbg: cannot evaluate \"%s\"\n", lpArgumentString ); return; } // // Read the object. // if( !ReadMemory( (ULONG)address, &physOpenFileInfo, sizeof(physOpenFileInfo), NULL ) ) { dprintf( "inetdbg: cannot read PHYS_OPEN_FILE_INFO @ %lx\n", address ); return; } DumpPhysOpenFileInfo( "", &physOpenFileInfo, address ); } // DECLARE_API( phys ) DECLARE_API( oplock ) /*++ Routine Description: This function is called as an NTSD extension to format and dump a specific OPLOCK_OBJECT structure. Arguments: hCurrentProcess - Supplies a handle to the current process (at the time the extension was called). hCurrentThread - Supplies a handle to the current thread (at the time the extension was called). CurrentPc - Supplies the current pc at the time the extension is called. lpExtensionApis - Supplies the address of the functions callable by this extension. lpArgumentString - Supplies the asciiz string that describes the ansi string to be dumped. Return Value: None. --*/ { ULONG address; OPLOCK_OBJECT oplockObject; INIT_API(); // // Skip any leading blanks. // while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; } if( *lpArgumentString == '\0' ) { dprintf( "use: inetdbg.oplock address\n" ); return; } address = GetExpression( lpArgumentString ); if( address == 0 ) { dprintf( "inetdbg: cannot evaluate \"%s\"\n", lpArgumentString ); return; } // // Read the object. // if( !ReadMemory( (ULONG)address, &oplockObject, sizeof(oplockObject), NULL ) ) { dprintf( "inetdbg: cannot read OPLOCK_OBJECT @ %lx\n", address ); return; } DumpOplockObject( "", &oplockObject, address ); } // DECLARE_API( oplock ) DECLARE_API( blob ) /*++ Routine Description: This function is called as an NTSD extension to format and dump a specific BLOB_HEADER structure. Arguments: hCurrentProcess - Supplies a handle to the current process (at the time the extension was called). hCurrentThread - Supplies a handle to the current thread (at the time the extension was called). CurrentPc - Supplies the current pc at the time the extension is called. lpExtensionApis - Supplies the address of the functions callable by this extension. lpArgumentString - Supplies the asciiz string that describes the ansi string to be dumped. Return Value: None. --*/ { ULONG address; BLOB_HEADER blobHeader; INIT_API(); // // Skip any leading blanks. // while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; } if( *lpArgumentString == '\0' ) { dprintf( "use: inetdbg.blob address\n" ); return; } address = GetExpression( lpArgumentString ); if( address == 0 ) { dprintf( "inetdbg: cannot evaluate \"%s\"\n", lpArgumentString ); return; } // // Read the object. // if( !ReadMemory( (ULONG)address, &blobHeader, sizeof(blobHeader), NULL ) ) { dprintf( "inetdbg: cannot read BLOB_HEADER @ %lx\n", address ); return; } DumpBlobHeader( "", &blobHeader, address ); } // DECLARE_API( blob )