/*++ Copyright (c) 1992 Microsoft Corporation Module Name: Tunnel.c Abstract: WinDbg Extension Api Author: Dan Lovinger 2-Apr-96 Environment: User Mode. Revision History: --*/ #include "precomp.h" #pragma hdrstop // // printf is really expensive to iteratively call to do the indenting, // so we just build up some avaliable spaces to mangle as required // #define MIN(a,b) ((a) > (b) ? (b) : (a)) #define MAXINDENT 128 #define INDENTSTEP 2 #define MakeSpace(I) Space[MIN((I)*INDENTSTEP, MAXINDENT)] = '\0' #define RestoreSpace(I) Space[MIN((I)*INDENTSTEP, MAXINDENT)] = ' ' CHAR Space[MAXINDENT*INDENTSTEP + 1]; //#define SplitLI(LI) (LI).HighPart, (LI).LowPart #define SplitLL(LL) (ULONG)((LL) >> 32), (ULONG)((LL) & 0xffffffff) VOID DumpTunnelNode ( ULONG64 Node, ULONG Indent ) { WCHAR ShortNameStr[8+1+3] = {0}; WCHAR LongNameStr[64] = {0}; ULONG Flags; UNICODE_STRING ShortName, LongName; if (GetFieldValue(Node, "TUNNEL_NODE", "Flags", Flags)) { return; } InitTypeRead(Node, TUNNEL_NODE); ShortName.Length = (USHORT) ReadField(ShortName.Length); if (ShortName.Length >= sizeof(ShortNameStr)) { ShortName.Length = sizeof(ShortNameStr) - sizeof(WCHAR); } LongName.Length = (USHORT) ReadField(LongName.Length); if (LongName.Length >= sizeof(LongNameStr)) { LongName.Length = sizeof(LongNameStr) - sizeof(WCHAR); } // // Grab the strings from the debugee // if (!ReadMemory(ReadField(ShortName.Buffer), ShortNameStr, ShortName.Length, NULL)) { return; } if (!ReadMemory(ReadField(LongName.Buffer), LongNameStr, LongName.Length, NULL)) { return; } // // Modify the node in-place so we can use normal printing // LongName.Buffer = LongNameStr; ShortName.Buffer = ShortNameStr; MakeSpace(Indent); dprintf("%sNode @ %08x Cr %08x%08x DK %08x%08x [", Space, Node, SplitLL(ReadField(CreateTime)), SplitLL(ReadField(DirKey))); // // Must be kept in sync with flag usage in fsrtl\tunnel.c // if (Flags & 0x1) dprintf("NLA"); else dprintf("LA"); if (Flags & 0x2) dprintf(" KYS"); else dprintf(" KYL"); dprintf("]\n"); dprintf("%sP %08p R %08p L %08p Sfn/Lfn \"%wZ\"/\"%wZ\"\n", Space, ReadField(CacheLinks.Parent), ReadField(CacheLinks.RightChild), ReadField(CacheLinks.LeftChild), &ShortName, &LongName ); dprintf("%sF %08p B %08p\n", Space, ReadField(ListLinks.Flink), ReadField(ListLinks.Blink)); RestoreSpace(Indent); } VOID DumpTunnelNodeWrapper ( ULONG64 pCacheLinks, ULONG Indent ) { // TUNNEL_NODE Node, *pNode; static ULONG Off=0; if (!Off) { GetFieldOffset("TUNNEL_NODE", "CacheLinks", &Off); } DumpTunnelNode(pCacheLinks - Off, Indent); } VOID DumpTunnel ( ULONG64 pTunnel ) { ULONG64 pLink, pHead, NodeFlink=0, TimerQueueFlink, pNode; ULONG Indent = 0, EntryCount = 0, NumEntries, Offset, ListOffset; ULONG64 Cache; if (GetFieldValue(pTunnel, "TUNNEL", "NumEntries", NumEntries)) { dprintf("Can't read TUNNEL at %p\n", pTunnel); return; } GetFieldValue(pTunnel, "TUNNEL", "Cache", Cache); GetFieldValue(pTunnel, "TUNNEL", "TimerQueue.Flink", TimerQueueFlink); pLink = TimerQueueFlink; GetFieldOffset("TUNNEL", "TimerQueue", &Offset); dprintf("Tunnel @ %08x\n" "NumEntries = %ld\n\n" "Splay Tree @ %08x\n", pTunnel, NumEntries, Cache); EntryCount = DumpSplayTree(Cache, DumpTunnelNodeWrapper); if (EntryCount != NumEntries) { dprintf("Tree count mismatch (%d not expected %d)\n", EntryCount, NumEntries); } GetFieldOffset("TUNNEL_NODE", "ListLinks", &ListOffset); for (EntryCount = 0, pHead = pTunnel + Offset, pLink = TimerQueueFlink; pLink != pHead; pLink = NodeFlink, EntryCount++) { pNode = pLink - ListOffset; if (pLink == TimerQueueFlink) { dprintf("\nTimer Queue @ %08x\n", pHead); } if (GetFieldValue(pNode, "TUNNEL_NODE", "ListLinks.Flink", NodeFlink)) { dprintf("Can't read TUNNEL_NODE at %p\n", pNode); return; } DumpTunnelNode(pNode, 0); if ( CheckControlC() ) { return; } } if (EntryCount != NumEntries) { dprintf("Timer count mismatch (%d not expected %d)\n", EntryCount, NumEntries); } } DECLARE_API( tunnel ) /*++ Routine Description: Dump tunnel caches Arguments: arg -
Return Value: None --*/ { ULONG64 Tunnel = 0; RtlFillMemory(Space, sizeof(Space), ' '); Tunnel = GetExpression(args); if (Tunnel == 0) { // // No args // return E_INVALIDARG; } DumpTunnel(Tunnel); return S_OK; }