Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

846 lines
23 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
irp.c
Abstract:
WinDbg Extension Api
Author:
Ramon J San Andres (ramonsa) 5-Nov-1993
Environment:
User Mode.
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
typedef struct _POOL_BLOCK_HEAD {
POOL_HEADER Header;
LIST_ENTRY List;
} POOL_BLOCK_HEAD, *PPOOL_BLOCK_HEADER;
typedef struct _POOL_HACKER {
POOL_HEADER Header;
ULONG Contents[8];
} POOL_HACKER;
#define TAG 0
#define NONPAGED_ALLOC 1
#define NONPAGED_FREE 2
#define PAGED_ALLOC 3
#define PAGED_FREE 4
#define NONPAGED_USED 5
#define PAGED_USED 6
VOID
DumpIrp(
PVOID IrpToDump,
BOOLEAN FullOutput
);
BOOLEAN
CheckSingleFilter (
PCHAR Tag,
PCHAR Filter
);
#if 0
VOID
DumpIrpZone(
IN ULONG Address,
IN BOOLEAN FullOutput
);
VOID
DumpIrpRegion(
IN ULONG Address,
IN BOOLEAN FullOutput
);
#endif
DECLARE_API( irp )
/*++
Routine Description:
Dumps the specified Irp
Arguments:
args - Address
Return Value:
None
--*/
{
ULONG irpToDump;
char buf[128];
buf[0] = '\0';
if (!*args) {
irpToDump = EXPRLastDump;
} else {
sscanf(args, "%lx %s", &irpToDump, buf);
}
DumpIrp((PUCHAR)irpToDump, (BOOLEAN) (buf[0] != '\0'));
}
DECLARE_API( irpzone )
/*++
Routine Description:
Dumps both the small irp zone and the large irp zone. Only irps that
are currently allocated are dumped. "args" controls the type of dump.
If "args" is present then the Irp is sent to the DumpIrp routine to be
disected. Otherwise, only the irp, its thread and the driver holding the
irp (i.e. the driver of the last stack) is printed.
Arguments:
args - a string pointer. If anything is in the string it indicates full
information (i.e. call DumpIrp).
Return Value:
None.
--*/
{
ULONG listAddress;
BOOLEAN fullOutput = FALSE;
dprintf("irpzone is no longer supported. Use irpfind to search " \
"nonpaged pool for active Irps\n");
#if 0
if (args) {
if (*args) {
fullOutput = TRUE;
}
}
listAddress = GetExpression( "IopSmallIrpList" );
if ( listAddress ) {
dprintf("Small Irp region\n");
DumpIrpRegion(listAddress, fullOutput);
} else {
dprintf("Cannot find Small Irp list\n");
}
dprintf("\n");
listAddress = GetExpression( "IopLargeIrpList" );
if ( listAddress ) {
dprintf("Large Irp region\n");
DumpIrpRegion(listAddress, fullOutput);
} else {
dprintf("Cannot find Large Irp list\n");
}
#endif
}
VOID
DumpIrp(
PVOID IrpToDump,
BOOLEAN FullOutput
)
/*++
Routine Description:
This routine dumps an Irp. It does not check to see that the address
supplied actually locates an Irp. This is done to allow for dumping
Irps post mortem, or after they have been freed or completed.
Arguments:
IrpToDump - the address of the irp.
Return Value:
None
--*/
{
IO_STACK_LOCATION irpStack;
PCHAR buffer;
ULONG irpStackAddress;
ULONG result;
IRP irp;
CCHAR irpStackIndex;
if ( !ReadMemory( (DWORD) IrpToDump,
&irp,
sizeof(irp),
&result) ) {
dprintf("%08lx: Could not read Irp\n", IrpToDump);
return;
}
if (irp.Type != IO_TYPE_IRP) {
dprintf("IRP signature does not match, probably not an IRP\n");
return;
}
dprintf("Irp is active with %d stacks %d is current\n",
irp.StackCount,
irp.CurrentLocation);
if ((irp.MdlAddress != NULL) && (irp.Type == IO_TYPE_IRP)) {
dprintf(" Mdl = %08lx ", irp.MdlAddress);
} else {
dprintf(" No Mdl ");
}
if (irp.AssociatedIrp.MasterIrp != NULL) {
dprintf("%s = %08lx ",
(irp.Flags & IRP_ASSOCIATED_IRP) ? "Associated Irp" :
(irp.Flags & IRP_DEALLOCATE_BUFFER) ? "System buffer" :
"Irp count",
irp.AssociatedIrp.MasterIrp);
}
dprintf("Thread %08lx: ", irp.Tail.Overlay.Thread);
if (irp.StackCount > 15) {
dprintf("Too many Irp stacks to be believed (>15)!!\n");
return;
} else {
if (irp.CurrentLocation > irp.StackCount) {
dprintf("Irp is completed. ");
} else {
dprintf("Irp stack trace. ");
}
}
if (irp.PendingReturned) {
dprintf("Pending has been returned\n");
} else {
dprintf("\n");
}
if (FullOutput)
{
dprintf("Flags = %08lx\n", irp.Flags);
dprintf("ThreadListEntry.Flink = %08lx\n", irp.ThreadListEntry.Flink);
dprintf("ThreadListEntry.Blink = %08lx\n", irp.ThreadListEntry.Blink);
dprintf("IoStatus.Status = %08lx\n", irp.IoStatus.Status);
dprintf("IoStatus.Information = %08lx\n", irp.IoStatus.Information);
dprintf("RequestorMode = %08lx\n", irp.RequestorMode);
dprintf("Cancel = %02lx\n", irp.Cancel);
dprintf("CancelIrql = %lx\n", irp.CancelIrql);
dprintf("ApcEnvironment = %02lx\n", irp.ApcEnvironment);
dprintf("UserIosb = %08lx\n", irp.UserIosb);
dprintf("UserEvent = %08lx\n", irp.UserEvent);
dprintf("Overlay.AsynchronousParameters.UserApcRoutine = %08lx\n", irp.Overlay.AsynchronousParameters.UserApcRoutine);
dprintf("Overlay.AsynchronousParameters.UserApcContext = %08lx\n", irp.Overlay.AsynchronousParameters.UserApcContext);
dprintf(
"Overlay.AllocationSize = %08lx - %08lx\n",
irp.Overlay.AllocationSize.HighPart,
irp.Overlay.AllocationSize.LowPart);
dprintf("CancelRoutine = %08lx\n", irp.CancelRoutine);
dprintf("UserBuffer = %08lx\n", irp.UserBuffer);
dprintf("&Tail.Overlay.DeviceQueueEntry = %08lx\n", &irp.Tail.Overlay.DeviceQueueEntry);
dprintf("Tail.Overlay.Thread = %08lx\n", irp.Tail.Overlay.Thread);
dprintf("Tail.Overlay.AuxiliaryBuffer = %08lx\n", irp.Tail.Overlay.AuxiliaryBuffer);
dprintf("Tail.Overlay.ListEntry.Flink = %08lx\n", irp.Tail.Overlay.ListEntry.Flink);
dprintf("Tail.Overlay.ListEntry.Blink = %08lx\n", irp.Tail.Overlay.ListEntry.Blink);
dprintf("Tail.Overlay.CurrentStackLocation = %08lx\n", irp.Tail.Overlay.CurrentStackLocation);
dprintf("Tail.Overlay.OriginalFileObject = %08lx\n", irp.Tail.Overlay.OriginalFileObject);
dprintf("Tail.Apc = %08lx\n", irp.Tail.Apc);
dprintf("Tail.CompletionKey = %08lx\n", irp.Tail.CompletionKey);
}
irpStackAddress = (ULONG)IrpToDump + sizeof(irp);
buffer = LocalAlloc(LPTR, 256);
if (buffer == NULL) {
dprintf("Can't allocate 256 bytes\n");
return;
}
dprintf(" cmd flg cl Device File Completion-Context\n");
for (irpStackIndex = 1; irpStackIndex <= irp.StackCount; irpStackIndex++) {
if ( !ReadMemory( (DWORD) irpStackAddress,
&irpStack,
sizeof(irpStack),
&result) ) {
dprintf("%08lx: Could not read IrpStack\n", irpStackAddress);
goto exit;
}
dprintf("%c%3x %2x %2x %08lx %08lx %08lx-%08lx %s %s %s %s\n",
irpStackIndex == irp.CurrentLocation ? '>' : ' ',
irpStack.MajorFunction,
irpStack.Flags,
irpStack.Control,
irpStack.DeviceObject,
irpStack.FileObject,
irpStack.CompletionRoutine,
irpStack.Context,
(irpStack.Control & SL_INVOKE_ON_SUCCESS) ? "Success" : "",
(irpStack.Control & SL_INVOKE_ON_ERROR) ? "Error" : "",
(irpStack.Control & SL_INVOKE_ON_CANCEL) ? "Cancel" : "",
(irpStack.Control & SL_PENDING_RETURNED) ? "pending" : "");
if (irpStack.DeviceObject != NULL) {
dprintf("\t ");
DumpDevice(irpStack.DeviceObject, FALSE);
}
if (irpStack.CompletionRoutine != NULL) {
GetSymbol((LPVOID)irpStack.CompletionRoutine, buffer, &result);
dprintf("\t%s\n", buffer);
} else {
dprintf("\n");
}
dprintf("\t\t\tArgs: %08lx %08lx %08lx %08lx\n",
irpStack.Parameters.Others.Argument1,
irpStack.Parameters.Others.Argument2,
irpStack.Parameters.Others.Argument3,
irpStack.Parameters.Others.Argument4);
irpStackAddress += sizeof(irpStack);
if (CheckControlC()) {
goto exit;
}
}
exit:
LocalFree(buffer);
}
#if 0
VOID
DumpIrpZone(
IN ULONG Address,
IN BOOLEAN FullOutput
)
/*++
Routine Description:
Dumps an Irp zone. This routine is used by bandDumpIrpZone and does
not know which zone is being dumped. The information concerning the
Irp Zone comes from the zone header supplied. No checks are made to
insure that the zone header is in fact a zone header, that is up to
the caller.
Arguments:
Address - the address for the zone header.
FullOutput - If TRUE then call DumpIrp to print the Irp.
Return Value:
None
--*/
{
PIRP irp;
ULONG i;
ULONG offset;
PVOID zoneAddress;
ULONG irpAddress;
ULONG result;
ULONG totalcount = 0;
ULONG activecount = 0;
ZONE_HEADER zoneHeader;
PZONE_SEGMENT_HEADER irpZone;
PIO_STACK_LOCATION irpSp;
if ( !ReadMemory( (DWORD)Address,
&zoneHeader,
sizeof(zoneHeader),
&result) ) {
dprintf("%08lx: Could not read Irp list\n", Address);
return;
}
zoneAddress = (PVOID)zoneHeader.SegmentList.Next;
irpZone = LocalAlloc(LPTR, zoneHeader.TotalSegmentSize);
if (irpZone == NULL) {
dprintf("Could not allocate %d bytes for zone\n",
zoneHeader.TotalSegmentSize);
return;
}
//
// Do the zone read in small chunks so the rest of the debugger
// doesn't get upset.
//
offset = 0;
while (offset < zoneHeader.TotalSegmentSize) {
i = zoneHeader.TotalSegmentSize - offset;
if (i > 1024) {
i = 1024;
}
if ( !ReadMemory( (DWORD)((PCH)zoneAddress + offset),
(PVOID)((PCH)irpZone + offset),
i,
&result) ) {
dprintf("%08lx: Could not read zone for size %d\n",
zoneAddress,
zoneHeader.TotalSegmentSize);
LocalFree(irpZone);
return;
}
if (CheckControlC()) {
break;
}
offset += i;
}
irp = (PIRP)((PCH)irpZone + sizeof(ZONE_SEGMENT_HEADER));
irpAddress = (ULONG)((PCH)zoneAddress + sizeof(ZONE_SEGMENT_HEADER));
for (i = sizeof(ZONE_SEGMENT_HEADER);
i <= zoneHeader.TotalSegmentSize;
i += zoneHeader.BlockSize, irpAddress += zoneHeader.BlockSize) {
totalcount++;
if (irp->Type == IO_TYPE_IRP) {
activecount++;
if (FullOutput) {
DumpIrp((PUCHAR)irpAddress, FALSE);
dprintf("\n");
} else {
irpSp = (PIO_STACK_LOCATION)
(((PCH) irp + sizeof(IRP)) +
((irp->CurrentLocation - 1) * sizeof(IO_STACK_LOCATION)));
dprintf("%08lx Thread %08lx ",
irpAddress,
irp->Tail.Overlay.Thread);
if (irp->CurrentLocation > irp->StackCount) {
dprintf("Irp is complete");
} else {
dprintf("current stack belongs to ");
DumpDevice(irpSp->DeviceObject, FALSE);
}
dprintf("\n");
}
}
if (CheckControlC()) {
break;
}
irp = (PIRP)((PCH)irp + zoneHeader.BlockSize);
}
LocalFree(irpZone);
if (totalcount != 0) {
dprintf("%lx active, %lx total\n", activecount, totalcount);
}
}
VOID
DumpIrpRegion(
IN ULONG Address,
IN BOOLEAN FullOutput
)
/*++
Routine Description:
Dumps an Irp region. This routine is used by bandDumpIrpZone and does
not know which region is being dumped. The information concerning the
Irp Zone comes from the region header supplied. No checks are made to
insure that the region header is in fact a region header, that is up to
the caller.
Arguments:
Address - the address for the region header.
FullOutput - If TRUE then call DumpIrp to print the Irp.
Return Value:
None
--*/
{
PIRP irp;
ULONG i;
ULONG offset;
PVOID regionAddress;
ULONG irpAddress;
ULONG result;
ULONG totalcount = 0;
ULONG activecount = 0;
REGION_HEADER regionHeader;
PIO_STACK_LOCATION irpSp;
PREGION_SEGMENT_HEADER irpRegion;
if ( !ReadMemory( (DWORD)Address,
&regionHeader,
sizeof(regionHeader),
&result) ) {
dprintf("%08lx: Could not read Irp region\n", Address);
return;
}
regionAddress = (PVOID)regionHeader.FirstSegment;
irpRegion = LocalAlloc(LPTR, regionHeader.TotalSize);
if (irpRegion == NULL) {
dprintf("Could not allocate %d bytes for region\n",
regionHeader.TotalSize);
return;
}
//
// Do the zone read in small chunks so the rest of the debugger
// doesn't get upset.
//
offset = 0;
while (offset < regionHeader.TotalSize) {
i = regionHeader.TotalSize - offset;
if (i > 1024) {
i = 1024;
}
if ( !ReadMemory( (DWORD)((PCH)regionAddress + offset),
(PVOID)((PCH)irpRegion + offset),
i,
&result) ) {
dprintf("%08lx: Could not read region for size %d\n",
regionAddress,
regionHeader.TotalSize);
LocalFree(irpRegion);
return;
}
if (CheckControlC()) {
break;
}
offset += i;
}
irp = (PIRP)((PCH)irpRegion + sizeof(REGION_SEGMENT_HEADER));
irpAddress = (ULONG)((PCH)regionAddress + sizeof(REGION_SEGMENT_HEADER));
for (i = sizeof(REGION_SEGMENT_HEADER);
i <= regionHeader.TotalSize;
i += regionHeader.BlockSize, irpAddress += regionHeader.BlockSize) {
totalcount++;
if (irp->Type == IO_TYPE_IRP) {
activecount++;
if (FullOutput) {
DumpIrp((PUCHAR)irpAddress, FALSE);
dprintf("\n");
} else {
irpSp = (PIO_STACK_LOCATION)
(((PCH) irp + sizeof(IRP)) +
((irp->CurrentLocation - 1) * sizeof(IO_STACK_LOCATION)));
dprintf("%08lx Thread %08lx ",
irpAddress,
irp->Tail.Overlay.Thread);
if (irp->CurrentLocation > irp->StackCount) {
dprintf("Irp is complete (CurrentLocation %d > StackCount %d)",
irp->CurrentLocation,
irp->StackCount);
} else {
dprintf("current stack belongs to ");
DumpDevice(irpSp->DeviceObject, FALSE);
}
dprintf("\n");
}
}
if (CheckControlC()) {
break;
}
irp = (PIRP)((PCH)irp + regionHeader.BlockSize);
}
LocalFree(irpRegion);
if (totalcount != 0) {
dprintf("%lx active, %lx total for region\n", activecount, totalcount);
}
}
#endif
DECLARE_API(irpfind)
/*++
Routine Description:
finds Irps in non-paged pool
Arguments:
args -
Return Value:
None
--*/
#define IRPBUFSIZE (sizeof(IRP) + (5 * sizeof(IO_STACK_LOCATION)))
{
PPOOL_TRACKER_TABLE PoolTrackTable;
POOL_TRACKER_TABLE Tags;
ULONG result;
ULONG PoolTag;
ULONG Flags;
ULONG Result;
PVOID PoolPage;
PVOID StartPage;
PUCHAR Pool;
POOL_HACKER PoolBlock;
ULONG Previous;
PCHAR PoolStart;
PCHAR PoolEnd;
ULONG TagName;
CHAR TagNameX[4] = {' ',' ',' ',' '};
PIO_STACK_LOCATION irpSp;
PIRP Irp;
ULONG irpAddress;
UCHAR turn;
UCHAR turnTable[] = {'|', '/', '-', '\\'};
BOOLEAN fullOutput = FALSE;
ULONG activeCount = 0;
if (args) {
if (*args) {
fullOutput = TRUE;
}
}
Flags = 0;
TagName = ' prI';
Irp = malloc(IRPBUFSIZE);
if(Irp == NULL) {
dprintf("Unable to allocate irp sized buffer\n");
return;
}
PoolStart = (PCHAR)GetUlongValue ("MmNonPagedPoolStart");
PoolEnd = (PCHAR) PoolStart + GetUlongValue ("MmMaximumNonPagedPoolInBytes");
dprintf("\nSearching %s pool (%lx : %lx) for Tag: %c%c%c%c\n\n",
(Flags == 0) ? "NonPaged" : "Paged",
PoolStart, PoolEnd,
TagName,
TagName >> 8,
TagName >> 16,
TagName >> 24);
PoolTrackTable = (PPOOL_TRACKER_TABLE)GetUlongValue ("PoolTrackTable");
PoolPage = (PVOID)PoolStart;
while (PoolPage < (PVOID)PoolEnd) {
Pool = (PUCHAR)PAGE_ALIGN (PoolPage);
StartPage = (PVOID)Pool;
Previous = 0;
while ((PVOID)PAGE_ALIGN(Pool) == StartPage) {
if ( !ReadMemory( (DWORD)Pool,
&PoolBlock,
sizeof(POOL_HACKER),
&Result) ) {
break;
}
#ifdef SHOW_PROGRESS
dprintf("\b");
#endif
if (((PoolBlock.Header.BlockSize << POOL_BLOCK_SHIFT) > POOL_PAGE_SIZE) ||
(PoolBlock.Header.BlockSize == 0) ||
(PoolBlock.Header.PreviousSize != Previous)) {
break;
}
PoolTag = PoolBlock.Header.PoolTag;
if ((PoolBlock.Header.PoolType & POOL_QUOTA_MASK) == 0) {
if (PoolBlock.Header.AllocatorBackTraceIndex != 0 &&
PoolBlock.Header.AllocatorBackTraceIndex & POOL_BACKTRACEINDEX_PRESENT
) {
if ( !ReadMemory( (DWORD)&PoolTrackTable[ PoolBlock.Header.PoolTagHash&~(PROTECTED_POOL >> 16) ],
&Tags,
sizeof(Tags),
&result) ) {
PoolTag = 0;
} else {
PoolTag = Tags.Key;
}
if (PoolBlock.Header.PoolTagHash & (PROTECTED_POOL >> 16)) {
PoolTag |= PROTECTED_POOL;
}
}
}
if ((PoolBlock.Header.PoolType != 0) &&
(CheckSingleFilter ((PCHAR)&PoolTag, (PCHAR)&TagName))) {
irpAddress = (ULONG) Pool + (ULONG) sizeof(POOL_HEADER);
if(ReadMemory(irpAddress,
Irp,
sizeof(DWORD),
&result)) {
if(Irp->Type == IO_TYPE_IRP) {
activeCount++;
if (fullOutput) {
dprintf("%08lx: ", irpAddress);
DumpIrp((PUCHAR)irpAddress, FALSE);
dprintf("\n");
} else {
if(ReadMemory(irpAddress,
Irp,
PoolBlock.Header.BlockSize <<
POOL_BLOCK_SHIFT,
&result)) {
irpSp = (PIO_STACK_LOCATION)
(((PCHAR) Irp + sizeof(IRP)) +
(Irp->CurrentLocation - 1) *
sizeof(IO_STACK_LOCATION));
dprintf("%08lx Thread %08lx ", irpAddress,
Irp->Tail.Overlay.Thread);
if(Irp->CurrentLocation > Irp->StackCount) {
dprintf("Irp is complete (CurrentLocation "
"%d > StackCount %d)",
Irp->CurrentLocation,
Irp->StackCount);
} else {
dprintf("current stack belongs to ");
DumpDevice(irpSp->DeviceObject, FALSE);
}
dprintf("\n");
}
}
} else {
// dprintf("%08lx (size %04lx) uninitialized or overwritten IRP\n",
// irpAddress,
// PoolBlock.Header.BlockSize << POOL_BLOCK_SHIFT);
}
} else {
dprintf("Possible IRP @ %lx - unable to read addr\n", irpAddress );
}
} else {
#ifdef SHOW_PROGRESS
dprintf("%c", turnTable[turn]);
turn = (turn + 1) % 4;
#endif
}
Previous = PoolBlock.Header.BlockSize;
Pool += (Previous << POOL_BLOCK_SHIFT);
if ( CheckControlC() ) {
dprintf("\n...terminating - searched pool to %lx\n",
PoolPage);
dprintf("%d active irps\n", activeCount);
return;
}
}
PoolPage = (PVOID)((PCHAR)PoolPage + PAGE_SIZE);
if ( CheckControlC() ) {
dprintf("\n...terminating - searched pool to %lx\n",
PoolPage);
dprintf("%d active irps\n", activeCount);
return;
}
}
dprintf("%d active irps\n", activeCount);
return;
}
#if 0
BOOLEAN
CheckSingleFilter (
PCHAR Tag,
PCHAR Filter
)
{
ULONG i;
CHAR tc;
CHAR fc;
for ( i = 0; i < 4; i++ ) {
tc = *Tag++;
fc = *Filter++;
if ( fc == '*' ) return TRUE;
if ( fc == '?' ) continue;
if ( tc != fc ) return FALSE;
}
return TRUE;
}
#endif