449 lines
9.2 KiB
C
449 lines
9.2 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1992 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
FileLock.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
WinDbg Extension Api
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Dan Lovinger 12-Apr-96
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
User Mode.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
//
|
||
|
// Common node type codes
|
||
|
//
|
||
|
|
||
|
#define NTFS_NTC_SCB_DATA 0x705
|
||
|
#define FAT_NTC_FCB 0x502
|
||
|
|
||
|
//
|
||
|
// dprintf 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];
|
||
|
|
||
|
__inline VOID CheckForBreak()
|
||
|
/*++
|
||
|
|
||
|
Purpose:
|
||
|
|
||
|
Encapsulate control c checking code
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return:
|
||
|
|
||
|
None, raises if break is needed
|
||
|
--*/
|
||
|
{
|
||
|
if ( CheckControlC() ) {
|
||
|
|
||
|
RaiseException(0, EXCEPTION_NONCONTINUABLE, 0, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Helper macros for printing 64bit quantities
|
||
|
//
|
||
|
|
||
|
#define SplitLI(LI) (LI).HighPart, (LI).LowPart
|
||
|
|
||
|
VOID
|
||
|
DumpFileLockInfo(
|
||
|
ULONG64 pFileLockInfo,
|
||
|
ULONG Indent
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Purpose:
|
||
|
|
||
|
Dump the local internal FILE_LOCK_INFO structure
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pFileLock - debugger address of FILE_LOCK_INFO to dump
|
||
|
|
||
|
Return:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
MakeSpace(Indent);
|
||
|
|
||
|
InitTypeRead(pFileLockInfo, FILE_LOCK_INFO);
|
||
|
dprintf("%sStart = %08I64x Length = %08I64x End = %08I64x (%s)\n"
|
||
|
"%sKey = %08x FileOb = %08p ProcId = %08p\n",
|
||
|
Space,
|
||
|
ReadField(StartingByte),
|
||
|
ReadField(Length),
|
||
|
ReadField(EndingByte),
|
||
|
(ReadField(ExclusiveLock) ? "Ex":"Sh"),
|
||
|
Space,
|
||
|
(ULONG) ReadField(Key),
|
||
|
ReadField(FileObject),
|
||
|
ReadField(ProcessId));
|
||
|
|
||
|
RestoreSpace(Indent);
|
||
|
}
|
||
|
|
||
|
__inline
|
||
|
ULONG64
|
||
|
ExLockAddress(
|
||
|
ULONG64 ExLockSplayLinks
|
||
|
)
|
||
|
{
|
||
|
static ULONG Off=0, GotOff=0;
|
||
|
|
||
|
if (!GotOff) {
|
||
|
if (!GetFieldOffset("nt!_EX_LOCK", "Links", &Off))
|
||
|
GotOff = TRUE;
|
||
|
}
|
||
|
return ExLockSplayLinks ?
|
||
|
( ExLockSplayLinks - Off ) : 0;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DumpExclusiveNode(
|
||
|
ULONG64 ExclusiveNodeSplayLinks,
|
||
|
ULONG Indent
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Purpose:
|
||
|
|
||
|
Dump an exclusive lock node
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ExclusiveNodeSplayLinks - splay links of an exclusive node
|
||
|
|
||
|
Indent - indent level to use
|
||
|
|
||
|
Return:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG64 Parent, pExLock;
|
||
|
ULONG Off;
|
||
|
|
||
|
pExLock = ExLockAddress(ExclusiveNodeSplayLinks);
|
||
|
|
||
|
if (GetFieldValue(pExLock, "nt!_EX_LOCK", "Links.Parent", Parent)) {
|
||
|
dprintf("Cannot read nt!_EX_LOCK at %p.\n", pExLock);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
MakeSpace(Indent);
|
||
|
|
||
|
InitTypeRead(pExLock, EX_LOCK);
|
||
|
dprintf("%sLock @ %08x ("
|
||
|
"P = %08x R = %08x L = %08x)\n",
|
||
|
Space,
|
||
|
pExLock,
|
||
|
ExLockAddress(Parent),
|
||
|
ExLockAddress(ReadField(Links.RightChild)),
|
||
|
ExLockAddress(ReadField(Links.LeftChild)));
|
||
|
|
||
|
RestoreSpace(Indent);
|
||
|
|
||
|
GetFieldOffset("nt!_EX_LOCK", "LockInfo", &Off);
|
||
|
DumpFileLockInfo(pExLock + Off, Indent);
|
||
|
}
|
||
|
|
||
|
__inline
|
||
|
ULONG64
|
||
|
LockTreeAddress(
|
||
|
ULONG64 LockTreeSplayLinks
|
||
|
)
|
||
|
{
|
||
|
static ULONG Off=0, GotOff=0;
|
||
|
|
||
|
if (!GotOff) {
|
||
|
if (GetFieldOffset("nt!_LOCKTREE_NODE", "Links", &Off))
|
||
|
GotOff = TRUE;
|
||
|
}
|
||
|
return LockTreeSplayLinks ?
|
||
|
( LockTreeSplayLinks - Off ) : 0;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DumpSharedNode(
|
||
|
ULONG64 SharedNodeSplayLinks,
|
||
|
ULONG Indent
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Purpose:
|
||
|
|
||
|
Dump a shared lock node
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
SharedNodeSplayLinks - splay links of an exclusive node
|
||
|
|
||
|
Indent - indent level to use
|
||
|
|
||
|
Return:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG64 pLockTreeNode;
|
||
|
ULONG64 pShLock;
|
||
|
ULONG64 pLink, Next;
|
||
|
ULONG Off, LockInfoOff;
|
||
|
|
||
|
pLockTreeNode = LockTreeAddress(SharedNodeSplayLinks);
|
||
|
|
||
|
if (GetFieldValue(pLockTreeNode, "nt!_LOCKTREE_NODE", "Locks.Next", Next)) {
|
||
|
dprintf("Cannot read nt!_LOCKTREE_NODE at %p\n", pLockTreeNode);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
MakeSpace(Indent);
|
||
|
|
||
|
InitTypeRead(pLockTreeNode, nt!_LOCKTREE_NODE);
|
||
|
dprintf("%sLockTreeNode @ %08p ("
|
||
|
"P = %08p R = %08p L = %08p)%s\n",
|
||
|
Space,
|
||
|
pLockTreeNode,
|
||
|
LockTreeAddress(ReadField(Links.Parent)),
|
||
|
LockTreeAddress(ReadField(Links.RightChild)),
|
||
|
LockTreeAddress(ReadField(Links.LeftChild)),
|
||
|
(ReadField(HoleyNode) ? " (Holey)" : ""));
|
||
|
|
||
|
RestoreSpace(Indent);
|
||
|
|
||
|
GetFieldOffset("nt!_SH_LOCK", "Link", &Off);
|
||
|
GetFieldOffset("nt!_SH_LOCK", "LockInfo", &LockInfoOff);
|
||
|
for (pLink = Next;
|
||
|
pLink;
|
||
|
pLink = Next) {
|
||
|
|
||
|
CheckForBreak();
|
||
|
|
||
|
pShLock = ( pLink - Off);
|
||
|
|
||
|
if (GetFieldValue(pShLock, "nt!_SH_LOCK", "Link.Next", Next)) {
|
||
|
dprintf("Cannot read nt!_SH_LOCK AT %p.\n", pShLock);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
MakeSpace(Indent);
|
||
|
|
||
|
dprintf("%sLock @ %08p\n", Space, pShLock);
|
||
|
|
||
|
RestoreSpace(Indent);
|
||
|
|
||
|
DumpFileLockInfo(pShLock + LockInfoOff, Indent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DumpFileLock(
|
||
|
ULONG64 pFileLock
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Purpose:
|
||
|
|
||
|
Dump the fsrtl FILE_LOCK structure at debugee
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pFileLock - debugee address of FILE_LOCK
|
||
|
|
||
|
Return:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG64 pFileLockInfo;
|
||
|
ULONG64 pLockInfo;
|
||
|
ULONG Count;
|
||
|
ULONG64 LastReturnedLock, LockInformation, LowestLockOffset;
|
||
|
ULONG64 SharedLockTree, ExclusiveLockTree;
|
||
|
|
||
|
if (GetFieldValue(pFileLock, "FILE_LOCK", "LastReturnedLock", LastReturnedLock)) {
|
||
|
dprintf("Cannot read FILE_LOCK at %p\n", pFileLock);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
InitTypeRead(pFileLock, FILE_LOCK);
|
||
|
dprintf("FileLock @ %08p\n"
|
||
|
"FastIoIsQuestionable = %c\n"
|
||
|
"CompletionRoutine = %08p\n"
|
||
|
"UnlockRoutine = %08p\n"
|
||
|
"LastReturnedLock = %08p\n",
|
||
|
pFileLock,
|
||
|
ReadField(FastIoIsQuestionable) ? 'T':'F',
|
||
|
ReadField(CompleteLockIrpRoutine),
|
||
|
ReadField(UnlockRoutine),
|
||
|
LastReturnedLock);
|
||
|
|
||
|
LockInformation = ReadField(LockInformation);
|
||
|
|
||
|
if (LastReturnedLock != 0) {
|
||
|
ULONG Off;
|
||
|
|
||
|
//
|
||
|
// We never reset the enumeration info, so it can be out of date ...
|
||
|
//
|
||
|
|
||
|
GetFieldOffset("FILE_LOCK", "LastReturnedLockInfo", &Off);
|
||
|
dprintf("LastReturnedLockInfo:\n");
|
||
|
DumpFileLockInfo(pFileLock + Off, 0);
|
||
|
}
|
||
|
|
||
|
if (LockInformation == 0) {
|
||
|
|
||
|
dprintf("No Locks\n");
|
||
|
return;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
if (GetFieldValue(LockInformation, "nt!_LOCK_INFO", "LowestLockOffset", LowestLockOffset)) {
|
||
|
dprintf("Canot read nt!_LOCK_INFO at %p\n", LockInformation);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dprintf("LowestLockOffset = %08p\n\n", LowestLockOffset);
|
||
|
|
||
|
GetFieldValue(LockInformation, "nt!_LOCK_INFO", "LockQueue.SharedLockTree", SharedLockTree);
|
||
|
GetFieldValue(LockInformation, "nt!_LOCK_INFO", "LockQueue.ExclusiveLockTree", ExclusiveLockTree);
|
||
|
|
||
|
Count = DumpSplayTree(SharedLockTree, DumpSharedNode);
|
||
|
|
||
|
if (!Count) {
|
||
|
|
||
|
dprintf("No Shared Locks\n");
|
||
|
}
|
||
|
|
||
|
dprintf("\n");
|
||
|
|
||
|
Count = DumpSplayTree(ExclusiveLockTree, DumpExclusiveNode);
|
||
|
|
||
|
if (!Count) {
|
||
|
|
||
|
dprintf("No Exclusive Locks\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
DECLARE_API( filelock )
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Dump file locks
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
arg - <Address>
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG64 FileLock = 0;
|
||
|
CSHORT NodeType = 0;
|
||
|
CSHORT FileType = 0;
|
||
|
ULONG64 FsContext = 0;
|
||
|
ULONG Offset;
|
||
|
|
||
|
RtlFillMemory(Space, sizeof(Space), ' ');
|
||
|
|
||
|
|
||
|
if ((FileLock = GetExpression(args)) == 0) {
|
||
|
|
||
|
//
|
||
|
// No args
|
||
|
//
|
||
|
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We raise out if the user whacketh control-c
|
||
|
//
|
||
|
|
||
|
__try {
|
||
|
|
||
|
//
|
||
|
// Test for fileobject
|
||
|
//
|
||
|
|
||
|
GetFieldValue( FileLock, "nt!_FILE_OBJECT", "Type", FileType );
|
||
|
|
||
|
if (FileType == IO_TYPE_FILE) {
|
||
|
|
||
|
//
|
||
|
// its really a fileobject so grab the fscontext
|
||
|
//
|
||
|
|
||
|
if (!GetFieldValue( FileLock, "nt!_FILE_OBJECT", "FsContext", FsContext )) {
|
||
|
GetFieldValue( FsContext, "nt!_FSRTL_COMMON_FCB_HEADER", "NodeTypeCode", NodeType );
|
||
|
|
||
|
dprintf( "%x\n", NodeType );
|
||
|
|
||
|
if (NodeType == NTFS_NTC_SCB_DATA) {
|
||
|
GetFieldValue( FsContext, "ntfs!_SCB", "ScbType.Data.FileLock", FileLock );
|
||
|
} else if (NodeType == FAT_NTC_FCB) {
|
||
|
GetFieldOffset( "fastfat!_FCB", "Specific", &Offset );
|
||
|
dprintf( "Offset: 0x%x\n", Offset );
|
||
|
FileLock = FsContext + Offset;
|
||
|
} else {
|
||
|
dprintf( "Unknown fscontext - you'll have to find the filelock within the fileobject manually\n" );
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FileLock == 0) {
|
||
|
dprintf( "There is no filelock in this fileobject\n" );
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DumpFileLock(FileLock);
|
||
|
|
||
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
|
||
|
NOTHING;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|