1060 lines
30 KiB
C
1060 lines
30 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
irp.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
WinDbg Extension Api
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User Mode.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
//#include "irpverif.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
typedef
|
|||
|
BOOLEAN
|
|||
|
(WINAPI *IRP_FILTER_ROUTINE)(
|
|||
|
ULONG64 Irp,
|
|||
|
PVOID FilterContext
|
|||
|
);
|
|||
|
|
|||
|
typedef struct _IRP_FILTER {
|
|||
|
IRP_FILTER_ROUTINE FilterRoutine;
|
|||
|
PVOID FilterContext;
|
|||
|
} IRP_FILTER, *PIRP_FILTER;
|
|||
|
|
|||
|
typedef struct _SEARCH_CONTEXT {
|
|||
|
ULONG FirstTime;
|
|||
|
IRP_FILTER Filter;
|
|||
|
} SEARCH_CONTEXT, *PSEARCH_CONTEXT;
|
|||
|
|
|||
|
#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(
|
|||
|
ULONG64 IrpToDump,
|
|||
|
ULONG DumpLevel
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterUserEvent(
|
|||
|
ULONG64 Irp,
|
|||
|
PVOID FilterContext
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterDevice(
|
|||
|
ULONG64 Irp,
|
|||
|
PVOID FilterContext
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterFileObject(
|
|||
|
ULONG64 Irp,
|
|||
|
PVOID FilterContext
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterThread(
|
|||
|
ULONG64 Irp,
|
|||
|
PVOID FilterContext
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterMdlProcess(
|
|||
|
ULONG64 Irp,
|
|||
|
PVOID FilterContext
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterArg(
|
|||
|
ULONG64 Irp,
|
|||
|
PVOID FilterContext
|
|||
|
);
|
|||
|
|
|||
|
DECLARE_API( irp )
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Dumps the specified Irp
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
args - Address
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG64 irpToDump;
|
|||
|
ULONG dumpLevel = 0 ;
|
|||
|
char irpExprBuf[256] ;
|
|||
|
char dumpLevelBuf[256] ;
|
|||
|
|
|||
|
if (!*args) {
|
|||
|
irpToDump = EXPRLastDump;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// !Irp IrpAddress DumpLevel
|
|||
|
// where IrpAddress can be an expression
|
|||
|
// and DumpLevel is a decimal level of any non-decimal string for 1
|
|||
|
irpExprBuf[0] = '\0' ;
|
|||
|
dumpLevelBuf[0] = '\0' ;
|
|||
|
|
|||
|
if (!sscanf(args, "%s %s", irpExprBuf, dumpLevelBuf)) {
|
|||
|
irpExprBuf[0] = '\0' ;
|
|||
|
dumpLevelBuf[0] = '\0' ;
|
|||
|
}
|
|||
|
|
|||
|
if (irpExprBuf) {
|
|||
|
|
|||
|
if (IsHexNumber(irpExprBuf)) {
|
|||
|
|
|||
|
irpToDump = GetExpression( irpExprBuf ) ;
|
|||
|
} else {
|
|||
|
|
|||
|
irpToDump = GetExpression( irpExprBuf ) ;
|
|||
|
if (irpToDump==0) {
|
|||
|
|
|||
|
dprintf("An error occured trying to evaluate the expression\n") ;
|
|||
|
return E_INVALIDARG ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (IsDecNumber(dumpLevelBuf)) {
|
|||
|
|
|||
|
if (!sscanf(dumpLevelBuf, "%d", &dumpLevel) ) {
|
|||
|
dumpLevel = 0;
|
|||
|
}
|
|||
|
} else if (dumpLevelBuf[0]) {
|
|||
|
|
|||
|
dumpLevel = 1 ;
|
|||
|
} else {
|
|||
|
|
|||
|
dumpLevel = 0 ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (irpToDump == 0) {
|
|||
|
|
|||
|
dprintf("Free build - use !irpfind to scan memory for any active IRPs\n") ;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DumpIrp(irpToDump, (ULONG) dumpLevel);
|
|||
|
}
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
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");
|
|||
|
|
|||
|
return S_OK;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DumpIrp(
|
|||
|
ULONG64 IrpToDump,
|
|||
|
ULONG DumpLevel
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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.
|
|||
|
DumpLevel - 0 Summary
|
|||
|
1 Extended information
|
|||
|
2 Debug tracking info iff available
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCHAR buffer;
|
|||
|
ULONG64 irpStackAddress;
|
|||
|
ULONG64 result64=0;
|
|||
|
ULONG result;
|
|||
|
// IRP irp;
|
|||
|
CCHAR irpStackIndex;
|
|||
|
LARGE_INTEGER runTime ;
|
|||
|
#if DBG
|
|||
|
// PIOV_REQUEST_PACKET irpTrackingData ;
|
|||
|
#endif
|
|||
|
BOOLEAN delayed ;
|
|||
|
ULONG Type=0, StackCount=0, CurrentLocation=0, Flags=0, PendingReturned=0;
|
|||
|
ULONG Io_Status=0, Cancel=0, CancelIrql=0, ApcEnvironment=0, Overlay_Alloc_High=0;
|
|||
|
ULONG Overlay_Alloc_Low=0, RequestorMode=0, IrpSize;
|
|||
|
ULONG64 Tail_Overlay_CurrStack=0, MdlAddress=0, Associated_MasterIrp=0;
|
|||
|
ULONG64 ThreadListEntry_Flink=0, ThreadListEntry_Blink=0, Io_Information=0;
|
|||
|
ULONG64 CancelRoutine=0, UserIosb=0, UserEvent=0, UserBuffer=0, Overlay_Async_UserApcRoutine=0;
|
|||
|
ULONG64 Overlay_Async_UserApcContext=0, Tail_Overlay_Thread=0, Tail_Overlay_AuxBuffer=0;
|
|||
|
ULONG64 Tail_Overlay_List_Flink=0, Tail_Overlay_List_Blink=0, Tail_Overlay_OrigFile=0;
|
|||
|
ULONG64 Tail_CompletionKey=0;
|
|||
|
BYTE Tail_Apc[100]={0};
|
|||
|
UCHAR IrpType[]= "nt!_IRP";
|
|||
|
|
|||
|
if ( (GetFieldValue(IrpToDump, IrpType, "Type", Type)) ) {
|
|||
|
dprintf("%08p: Could not read Irp\n", IrpToDump);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
GetFieldValue(IrpToDump, IrpType, "StackCount", StackCount);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "CurrentLocation", CurrentLocation);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Tail.Overlay.CurrentStackLocation", Tail_Overlay_CurrStack);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "MdlAddress", MdlAddress);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "AssociatedIrp.MasterIrp", Associated_MasterIrp);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Flags", Flags);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "RequestorMode", RequestorMode);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "PendingReturned", PendingReturned);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "ThreadListEntry.Flink", ThreadListEntry_Flink);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "ThreadListEntry.Blink", ThreadListEntry_Blink);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "IoStatus.Status", Io_Status);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "IoStatus.Information", Io_Information);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Cancel", Cancel);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "CancelIrql", CancelIrql);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "CancelRoutine", CancelRoutine);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "ApcEnvironment", ApcEnvironment);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "UserIosb", UserIosb);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "UserEvent", UserEvent);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "UserBuffer", UserBuffer);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Overlay.AsynchronousParameters.UserApcRoutine", Overlay_Async_UserApcRoutine);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Overlay.AsynchronousParameters.UserApcContext", Overlay_Async_UserApcContext);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Overlay.AllocationSize.High", Overlay_Alloc_High);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Overlay.AllocationSize.Low", Overlay_Alloc_Low);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Tail.Overlay.Thread", Tail_Overlay_Thread);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Tail.Overlay.AuxiliaryBuffer", Tail_Overlay_AuxBuffer);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Tail.Overlay.ListEntry.Flink", Tail_Overlay_List_Flink);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Tail.Overlay.ListEntry.Blink", Tail_Overlay_List_Blink);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Tail.Overlay.OriginalFileObject", Tail_Overlay_OrigFile);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Tail.Apc", Tail_Apc);
|
|||
|
GetFieldValue(IrpToDump, IrpType, "Tail.CompletionKey", Tail_CompletionKey);
|
|||
|
IrpSize = GetTypeSize("nt!_IRP");
|
|||
|
|
|||
|
if (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 (= %#08p)\n",
|
|||
|
StackCount,
|
|||
|
CurrentLocation,
|
|||
|
Tail_Overlay_CurrStack);
|
|||
|
|
|||
|
if ((MdlAddress != 0) && (Type == IO_TYPE_IRP)) {
|
|||
|
dprintf(" Mdl = %08p ", MdlAddress);
|
|||
|
} else {
|
|||
|
dprintf(" No Mdl ");
|
|||
|
}
|
|||
|
|
|||
|
if (Associated_MasterIrp != 0) {
|
|||
|
dprintf("%s = %08p ",
|
|||
|
(Flags & IRP_ASSOCIATED_IRP) ? "Associated Irp" :
|
|||
|
(Flags & IRP_DEALLOCATE_BUFFER) ? "System buffer" :
|
|||
|
"Irp count",
|
|||
|
Associated_MasterIrp);
|
|||
|
}
|
|||
|
|
|||
|
dprintf("Thread %08p: ", Tail_Overlay_Thread);
|
|||
|
|
|||
|
if (StackCount > 30) {
|
|||
|
dprintf("Too many Irp stacks to be believed (>30)!!\n");
|
|||
|
return;
|
|||
|
} else {
|
|||
|
if (CurrentLocation > StackCount) {
|
|||
|
dprintf("Irp is completed. ");
|
|||
|
} else {
|
|||
|
dprintf("Irp stack trace. ");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (PendingReturned) {
|
|||
|
dprintf("Pending has been returned\n");
|
|||
|
} else {
|
|||
|
dprintf("\n");
|
|||
|
}
|
|||
|
|
|||
|
if (DumpLevel>0) {
|
|||
|
dprintf("Flags = %08lx\n", Flags);
|
|||
|
dprintf("ThreadListEntry.Flink = %08p\n", ThreadListEntry_Flink);
|
|||
|
dprintf("ThreadListEntry.Blink = %08p\n", ThreadListEntry_Blink);
|
|||
|
dprintf("IoStatus.Status = %08lx\n", Io_Status);
|
|||
|
dprintf("IoStatus.Information = %08p\n", Io_Information);
|
|||
|
dprintf("RequestorMode = %08lx\n", RequestorMode);
|
|||
|
dprintf("Cancel = %02lx\n", Cancel);
|
|||
|
dprintf("CancelIrql = %lx\n", CancelIrql);
|
|||
|
dprintf("ApcEnvironment = %02lx\n", ApcEnvironment);
|
|||
|
dprintf("UserIosb = %08p\n", UserIosb);
|
|||
|
dprintf("UserEvent = %08p\n", UserEvent);
|
|||
|
dprintf("Overlay.AsynchronousParameters.UserApcRoutine = %08p\n", Overlay_Async_UserApcRoutine);
|
|||
|
dprintf("Overlay.AsynchronousParameters.UserApcContext = %08p\n", Overlay_Async_UserApcContext);
|
|||
|
dprintf(
|
|||
|
"Overlay.AllocationSize = %08lx - %08lx\n",
|
|||
|
Overlay_Alloc_High,
|
|||
|
Overlay_Alloc_Low);
|
|||
|
dprintf("CancelRoutine = %08p\n", CancelRoutine);
|
|||
|
dprintf("UserBuffer = %08p\n", UserBuffer);
|
|||
|
dprintf("&Tail.Overlay.DeviceQueueEntry = %08p\n", 0);// &Tail_Overlay_DeviceQueueEntry);
|
|||
|
dprintf("Tail.Overlay.Thread = %08p\n", Tail_Overlay_Thread);
|
|||
|
dprintf("Tail.Overlay.AuxiliaryBuffer = %08p\n", Tail_Overlay_AuxBuffer);
|
|||
|
dprintf("Tail.Overlay.ListEntry.Flink = %08p\n", Tail_Overlay_List_Flink);
|
|||
|
dprintf("Tail.Overlay.ListEntry.Blink = %08p\n", Tail_Overlay_List_Blink);
|
|||
|
dprintf("Tail.Overlay.CurrentStackLocation = %08p\n", Tail_Overlay_CurrStack);
|
|||
|
dprintf("Tail.Overlay.OriginalFileObject = %08p\n", Tail_Overlay_OrigFile);
|
|||
|
dprintf("Tail.Apc = %08lx\n", *((PULONG) &Tail_Apc));
|
|||
|
dprintf("Tail.CompletionKey = %08p\n", Tail_CompletionKey);
|
|||
|
}
|
|||
|
|
|||
|
irpStackAddress = (ULONG64) IrpToDump + GetTypeSize("nt!_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; (ULONG) irpStackIndex <= StackCount; irpStackIndex++) {
|
|||
|
ULONG MajorFunction=0, MinorFunction=0, Flags=0, Control=0, irpStackSize;
|
|||
|
ULONG64 DeviceObject=0, FileObject=0, CompletionRoutine=0, Context=0;
|
|||
|
ULONG64 Others_Argument1=0, Others_Argument2=0, Others_Argument3=0, Others_Argument4=0;
|
|||
|
UCHAR IOStack[] = "nt!_IO_STACK_LOCATION";
|
|||
|
|
|||
|
if ( GetFieldValue(irpStackAddress, IOStack, "MajorFunction", MajorFunction)) {
|
|||
|
dprintf("%p: Could not read IrpStack\n", irpStackAddress);
|
|||
|
goto exit;
|
|||
|
}
|
|||
|
|
|||
|
irpStackSize = GetTypeSize(IOStack);
|
|||
|
GetFieldValue(irpStackAddress, IOStack, "MinorFunction", MinorFunction);
|
|||
|
GetFieldValue(irpStackAddress, IOStack, "Flags", Flags);
|
|||
|
GetFieldValue(irpStackAddress, IOStack, "DeviceObject", DeviceObject);
|
|||
|
GetFieldValue(irpStackAddress, IOStack, "FileObject", FileObject);
|
|||
|
GetFieldValue(irpStackAddress, IOStack, "CompletionRoutine", CompletionRoutine);
|
|||
|
GetFieldValue(irpStackAddress, IOStack, "Context", Context);
|
|||
|
GetFieldValue(irpStackAddress, IOStack, "Control", Control);
|
|||
|
GetFieldValue(irpStackAddress, IOStack, "Parameters.Others.Argument1",Others_Argument1);
|
|||
|
GetFieldValue(irpStackAddress, IOStack, "Parameters.Others.Argument2",Others_Argument2);
|
|||
|
GetFieldValue(irpStackAddress, IOStack, "Parameters.Others.Argument3",Others_Argument3);
|
|||
|
GetFieldValue(irpStackAddress, IOStack, "Parameters.Others.Argument4",Others_Argument4);
|
|||
|
|
|||
|
|
|||
|
dprintf("%c[%3x,%2x] %2x %2x %08p %08p %08p-%08p %s %s %s %s\n",
|
|||
|
(ULONG) irpStackIndex == CurrentLocation ? '>' : ' ',
|
|||
|
MajorFunction,
|
|||
|
MinorFunction,
|
|||
|
Flags,
|
|||
|
Control,
|
|||
|
DeviceObject,
|
|||
|
FileObject,
|
|||
|
CompletionRoutine,
|
|||
|
Context,
|
|||
|
(Control & SL_INVOKE_ON_SUCCESS) ? "Success" : "",
|
|||
|
(Control & SL_INVOKE_ON_ERROR) ? "Error" : "",
|
|||
|
(Control & SL_INVOKE_ON_CANCEL) ? "Cancel" : "",
|
|||
|
(Control & SL_PENDING_RETURNED) ? "pending" : "");
|
|||
|
|
|||
|
if (DeviceObject != 0) {
|
|||
|
dprintf("\t ");
|
|||
|
DumpDevice(DeviceObject, 0, FALSE);
|
|||
|
}
|
|||
|
|
|||
|
if (CompletionRoutine != 0) {
|
|||
|
|
|||
|
GetSymbol(CompletionRoutine, buffer, &result64);
|
|||
|
dprintf("\t%s\n", buffer);
|
|||
|
} else {
|
|||
|
dprintf("\n");
|
|||
|
}
|
|||
|
|
|||
|
dprintf("\t\t\tArgs: %08p %08p %08p %08p\n",
|
|||
|
Others_Argument1,
|
|||
|
Others_Argument2,
|
|||
|
Others_Argument3,
|
|||
|
Others_Argument4);
|
|||
|
irpStackAddress += irpStackSize;
|
|||
|
if (CheckControlC()) {
|
|||
|
goto exit;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (DumpLevel>=2) {
|
|||
|
|
|||
|
dprintf("Extra information not available.\n") ;
|
|||
|
}
|
|||
|
|
|||
|
exit:
|
|||
|
LocalFree(buffer);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+---------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: CheckForIrp
|
|||
|
//
|
|||
|
// Synopsis: Matches pool chunk against an irp
|
|||
|
//
|
|||
|
// Arguments: [Tag] --
|
|||
|
// [Filter] --
|
|||
|
// [Flags] -- 0 nonpaged pool 1 paged pool 2 special pool 4 dump irp
|
|||
|
// [PoolTrackTable] --
|
|||
|
// [PoolHeader] --
|
|||
|
// [BlockSize] --
|
|||
|
// [Data] --
|
|||
|
//
|
|||
|
// Returns:
|
|||
|
//
|
|||
|
// History: 7-28-1999 benl Created
|
|||
|
//
|
|||
|
// Notes:
|
|||
|
//
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
BOOLEAN WINAPI CheckForIrp(
|
|||
|
PCHAR Tag,
|
|||
|
PCHAR Filter,
|
|||
|
ULONG Flags,
|
|||
|
ULONG64 PoolHeader,
|
|||
|
ULONG BlockSize,
|
|||
|
ULONG64 Data,
|
|||
|
PVOID Context
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG64 Irp = Data;
|
|||
|
ULONG Result;
|
|||
|
ULONG64 irpSp;
|
|||
|
// MDL Mdl;
|
|||
|
PSEARCH_CONTEXT SearchContext = (PSEARCH_CONTEXT)Context;
|
|||
|
ULONG PoolType, SizeOfIRP;
|
|||
|
|
|||
|
// dprintf("Call Hdr %p, Data %p \n", PoolHeader, Data);
|
|||
|
if (PoolHeader) {
|
|||
|
if (GetFieldValue(PoolHeader, "nt!_POOL_HEADER", "PoolType", PoolType)) {
|
|||
|
dprintf("Unable to read nt!_POOL_HEADER type.\n");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (((PoolHeader == 0) ||
|
|||
|
(Flags & 0x2) ||
|
|||
|
(PoolType != 0)) &&
|
|||
|
(CheckSingleFilter (Tag, Filter))) {
|
|||
|
|
|||
|
ULONG Type=0, CurrentLocation, StackCount, MajorFunction, MinorFunction;
|
|||
|
ULONG64 Thread, DeviceObject, MdlAddress;
|
|||
|
|
|||
|
if (!GetFieldValue(Irp, "nt!_IRP", "Type", Type)) {
|
|||
|
|
|||
|
if (Type == IO_TYPE_IRP) {
|
|||
|
|
|||
|
SizeOfIRP = GetTypeSize("nt!_IRP");
|
|||
|
|
|||
|
if (Flags & 0x4) {
|
|||
|
if (SearchContext->FirstTime) {
|
|||
|
|
|||
|
dprintf(" Irp [ Thread ] irpStack: (Mj,Mn) DevObj [Driver]\n");
|
|||
|
SearchContext->FirstTime = FALSE;
|
|||
|
}
|
|||
|
dprintf("%08p: ", Data);
|
|||
|
DumpIrp(Data, 0);
|
|||
|
dprintf("\n");
|
|||
|
} else {
|
|||
|
if ((SearchContext->Filter.FilterRoutine == NULL) ||
|
|||
|
(SearchContext->Filter.FilterRoutine(Irp, SearchContext->Filter.FilterContext))) {
|
|||
|
|
|||
|
if (SearchContext->FirstTime) {
|
|||
|
|
|||
|
dprintf(" Irp [ Thread ] irpStack: (Mj,Mn) DevObj [Driver]\n");
|
|||
|
SearchContext->FirstTime = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
GetFieldValue(Irp, "nt!_IRP", "CurrentLocation", CurrentLocation);
|
|||
|
GetFieldValue(Irp, "nt!_IRP", "StackCount", StackCount);
|
|||
|
GetFieldValue(Irp, "nt!_IRP", "MdlAddress", MdlAddress);
|
|||
|
GetFieldValue(Irp, "nt!_IRP", "Tail.Overlay.Thread",
|
|||
|
Thread);
|
|||
|
|
|||
|
irpSp = Irp + SizeOfIRP +
|
|||
|
(CurrentLocation - 1)*GetTypeSize("nt!_IO_STACK_LOCATION");
|
|||
|
|
|||
|
dprintf("%08p [%08p] ", Data, Thread);
|
|||
|
|
|||
|
|
|||
|
if (CurrentLocation > StackCount) {
|
|||
|
dprintf("Irp is complete (CurrentLocation "
|
|||
|
"%d > StackCount %d)",
|
|||
|
CurrentLocation,
|
|||
|
StackCount);
|
|||
|
} else {
|
|||
|
|
|||
|
GetFieldValue(irpSp, "nt!_IO_STACK_LOCATION", "MajorFunction", MajorFunction);
|
|||
|
GetFieldValue(irpSp, "nt!_IO_STACK_LOCATION", "MinorFunction", MinorFunction);
|
|||
|
GetFieldValue(irpSp, "nt!_IO_STACK_LOCATION", "DeviceObject", DeviceObject);
|
|||
|
|
|||
|
dprintf("irpStack: (%2x,%2x)",
|
|||
|
MajorFunction,
|
|||
|
MinorFunction);
|
|||
|
|
|||
|
dprintf(" %08p [", DeviceObject);
|
|||
|
DumpDevice(DeviceObject, 0, FALSE);
|
|||
|
dprintf("]");
|
|||
|
}
|
|||
|
|
|||
|
if (MdlAddress) {
|
|||
|
ULONG64 Process;
|
|||
|
|
|||
|
if (!GetFieldValue(MdlAddress,
|
|||
|
"nt!_MDL",
|
|||
|
"Process",
|
|||
|
Process)) {
|
|||
|
dprintf( " 0x%p", Process );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
dprintf("\n");
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
// dprintf("%08lx (size %04lx) uninitialized or overwritten IRP\n",
|
|||
|
// irpAddress,
|
|||
|
// PoolBlock.Header.BlockSize << POOL_BLOCK_SHIFT);
|
|||
|
}
|
|||
|
} else {
|
|||
|
dprintf("Possible IRP @ %p - unable to read addr/type\n", Data );
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
} else {
|
|||
|
#ifdef SHOW_PROGRESS
|
|||
|
dprintf("%c", turnTable[turn]);
|
|||
|
turn = (turn + 1) % 4;
|
|||
|
#endif
|
|||
|
}
|
|||
|
return FALSE;
|
|||
|
} // CheckForIrp
|
|||
|
|
|||
|
DECLARE_API(irpfind)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
finds Irps in non-paged pool
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
args -
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
{
|
|||
|
ULONG Flags = 0;
|
|||
|
ULONG64 RestartAddr = 0;
|
|||
|
ULONG TagName;
|
|||
|
UCHAR Field[20];
|
|||
|
ULONG64 Match=0;
|
|||
|
SEARCH_CONTEXT Context;
|
|||
|
|
|||
|
Context.FirstTime = TRUE;
|
|||
|
Context.Filter.FilterRoutine = NULL;
|
|||
|
Field[0] = '\0';
|
|||
|
if (args) {
|
|||
|
PCHAR pc;
|
|||
|
ULONG64 tmp;
|
|||
|
|
|||
|
if (GetExpressionEx(args, &tmp, &args)) {
|
|||
|
Flags = (ULONG) tmp;
|
|||
|
if (GetExpressionEx(args, &RestartAddr, &args)) {
|
|||
|
if (!sscanf(args, "%19s %x", &Field, &Match)) {
|
|||
|
Match = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Sign extend the address if necc.
|
|||
|
//
|
|||
|
|
|||
|
if (RestartAddr != 0) {
|
|||
|
if (RestartAddr >= 0x80000000 && RestartAddr <= 0xFFFFFFFF) {
|
|||
|
RestartAddr += 0xFFFFFFFF00000000;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((_stricmp(Field, "userevent") == 0) &&
|
|||
|
(Match != 0)) {
|
|||
|
Context.Filter.FilterRoutine = IrpFilterUserEvent;
|
|||
|
Context.Filter.FilterContext = (PVOID)&Match;
|
|||
|
dprintf("Looking for IRP with UserEvent == %08p\n",Match);
|
|||
|
} else if ((_stricmp(Field, "device") == 0) &&
|
|||
|
(Match != 0)) {
|
|||
|
Context.Filter.FilterRoutine = IrpFilterDevice;
|
|||
|
Context.Filter.FilterContext = (PVOID)&Match;
|
|||
|
dprintf("Looking for IRPs with device object == %08p\n",Match);
|
|||
|
} else if ((_stricmp(Field, "fileobject") == 0) &&
|
|||
|
(Match != 0)) {
|
|||
|
Context.Filter.FilterRoutine = IrpFilterFileObject;
|
|||
|
Context.Filter.FilterContext = (PVOID)&Match;
|
|||
|
dprintf("Looking for IRPs with file object == %08p\n",Match);
|
|||
|
} else if ((_stricmp(Field, "mdlprocess") == 0) &&
|
|||
|
(Match != 0)) {
|
|||
|
Context.Filter.FilterRoutine = IrpFilterMdlProcess;
|
|||
|
Context.Filter.FilterContext = (PVOID)&Match;
|
|||
|
dprintf("Looking for IRPs with mdl process == %08p\n",Match);
|
|||
|
} else if ((_stricmp(Field, "thread") == 0) &&
|
|||
|
(Match != 0)) {
|
|||
|
Context.Filter.FilterRoutine = IrpFilterThread;
|
|||
|
Context.Filter.FilterContext = (PVOID)&Match;
|
|||
|
dprintf("Looking for IRPs with thread == %08p\n",Match);
|
|||
|
} else if ((_stricmp(Field, "arg") == 0) &&
|
|||
|
(Match != 0)) {
|
|||
|
Context.Filter.FilterRoutine = IrpFilterArg;
|
|||
|
Context.Filter.FilterContext = (PVOID)&Match;
|
|||
|
dprintf("Looking for IRPs with arg == %08p\n",Match);
|
|||
|
}
|
|||
|
|
|||
|
TagName = '?prI';
|
|||
|
|
|||
|
SearchPool( TagName, Flags, RestartAddr, &CheckForIrp, &Context );
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterUserEvent(
|
|||
|
IN ULONG64 Irp,
|
|||
|
IN PVOID FilterContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Checks to see if the userevent field of an IRP matches the supplied
|
|||
|
parameter
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - Supplies the irp to filter
|
|||
|
|
|||
|
FilterContext - supplies the user event
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the specified irp has userevent == FilterContext
|
|||
|
FALSE otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG64 pEvent = *((PULONG64) FilterContext);
|
|||
|
ULONG64 UserEvent;
|
|||
|
|
|||
|
if (GetFieldValue(Irp, "nt!_IRP", "UserEvent", UserEvent)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (UserEvent == pEvent) {
|
|||
|
return(TRUE);
|
|||
|
} else {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterDevice(
|
|||
|
IN ULONG64 Irp,
|
|||
|
IN PVOID FilterContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Checks to see if the specified IRP matches the supplied
|
|||
|
device object
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - Supplies the irp to filter
|
|||
|
|
|||
|
FilterContext - supplies the device object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the specified irp has a device == FilterContext
|
|||
|
FALSE otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG64 IrpStack = (Irp+GetTypeSize("nt!_IRP"));
|
|||
|
ULONG StackCount, Stksize;
|
|||
|
ULONG64 DeviceObject;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
if (GetFieldValue(Irp, "nt!_IRP", "StackCount", StackCount)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
if (StackCount > 30) {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
Stksize = GetTypeSize("nt!_IO_STACK_LOCATION");
|
|||
|
|
|||
|
for (i=0; i<StackCount; i++) {
|
|||
|
if (!GetFieldValue(Irp + i*Stksize,
|
|||
|
"nt!_IO_STACK_LOCATION",
|
|||
|
"DeviceObject",
|
|||
|
DeviceObject)) {
|
|||
|
|
|||
|
if (DeviceObject == *((PULONG64) FilterContext)) {
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterFileObject(
|
|||
|
IN ULONG64 Irp,
|
|||
|
IN PVOID FilterContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Checks to see if the Tail.Overlay.OriginalFileObject field of an IRP matches the
|
|||
|
supplied parameter
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - Supplies the irp to filter
|
|||
|
|
|||
|
FilterContext - supplies the file object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the specified irp has userevent == FilterContext
|
|||
|
FALSE otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG64 pFile = *((PULONG64) FilterContext);
|
|||
|
ULONG64 OriginalFileObject;
|
|||
|
|
|||
|
if (GetFieldValue(Irp, "nt!_IRP",
|
|||
|
"Tail.Overlay.OriginalFileObject",
|
|||
|
OriginalFileObject)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (OriginalFileObject == pFile) {
|
|||
|
return(TRUE);
|
|||
|
} else {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterThread(
|
|||
|
IN ULONG64 Irp,
|
|||
|
IN PVOID FilterContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Checks to see if the Tail.Overlay.OriginalFileObject field of an IRP matches the
|
|||
|
supplied parameter
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - Supplies the irp to filter
|
|||
|
|
|||
|
FilterContext - supplies the file object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the specified irp has userevent == FilterContext
|
|||
|
FALSE otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG64 pThread = *((PULONG64) FilterContext);
|
|||
|
ULONG64 Thread;
|
|||
|
|
|||
|
if (GetFieldValue(Irp, "nt!_IRP",
|
|||
|
"Tail.Overlay.Thread",
|
|||
|
Thread)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (Thread == pThread) {
|
|||
|
return(TRUE);
|
|||
|
} else {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterMdlProcess(
|
|||
|
IN ULONG64 Irp,
|
|||
|
IN PVOID FilterContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Checks to see if the Tail.Overlay.OriginalFileObject field of an IRP matches the
|
|||
|
supplied parameter
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - Supplies the irp to filter
|
|||
|
|
|||
|
FilterContext - supplies the file object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the specified irp has userevent == FilterContext
|
|||
|
FALSE otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG64 pProcess = *((PULONG64) FilterContext);
|
|||
|
ULONG64 Process, MdlAddress;
|
|||
|
|
|||
|
if (GetFieldValue(Irp, "nt!_IRP",
|
|||
|
"MdlAddress",
|
|||
|
MdlAddress)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (MdlAddress == 0) {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
if (GetFieldValue(MdlAddress, "nt!_MDL", "Process", Process)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
if (Process == pProcess) {
|
|||
|
return(TRUE);
|
|||
|
} else {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IrpFilterArg(
|
|||
|
IN ULONG64 Irp,
|
|||
|
IN PVOID FilterContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Checks to see if the specified IRP matches the supplied
|
|||
|
argument
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - Supplies the irp to filter
|
|||
|
|
|||
|
FilterContext - supplies the argument to match
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the specified irp has argument == FilterContext
|
|||
|
FALSE otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG64 IrpStack = (Irp+GetTypeSize("nt!_IRP"));
|
|||
|
ULONG StackCount, Stksize;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
if (GetFieldValue(Irp, "nt!_IRP", "StackCount", StackCount)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
Stksize = GetTypeSize("nt!_IO_STACK_LOCATION");
|
|||
|
|
|||
|
if (!Stksize || (StackCount > 30)) {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
for (i=0; i<StackCount; i++) {
|
|||
|
ULONG64 Argument1,Argument2,Argument3,Argument4;
|
|||
|
|
|||
|
GetFieldValue(Irp + i*Stksize, "nt!_IO_STACK_LOCATION",
|
|||
|
"Parameters.Others.Argument1",Argument1);
|
|||
|
GetFieldValue(Irp + i*Stksize, "nt!_IO_STACK_LOCATION",
|
|||
|
"Parameters.Others.Argument2",Argument2);
|
|||
|
GetFieldValue(Irp + i*Stksize, "nt!_IO_STACK_LOCATION",
|
|||
|
"Parameters.Others.Argument3",Argument3);
|
|||
|
GetFieldValue(Irp + i*Stksize, "nt!_IO_STACK_LOCATION",
|
|||
|
"Parameters.Others.Argument4",Argument4);
|
|||
|
if ((Argument1 == *((PULONG64)FilterContext)) ||
|
|||
|
(Argument2 == *((PULONG64)FilterContext)) ||
|
|||
|
(Argument3 == *((PULONG64)FilterContext)) ||
|
|||
|
(Argument4 == *((PULONG64)FilterContext))) {
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
}
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
GetIrpInfo(
|
|||
|
ULONG64 Irp,
|
|||
|
PDEBUG_IRP_INFO pIrp
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG Type;
|
|||
|
UCHAR TypeName[]= "nt!_IRP";
|
|||
|
ULONG irpStackIndex;
|
|||
|
ULONG64 irpStackAddress;
|
|||
|
|
|||
|
ZeroMemory(pIrp, sizeof(DEBUG_IRP_INFO));
|
|||
|
pIrp->SizeOfStruct = sizeof(DEBUG_IRP_INFO);
|
|||
|
pIrp->IrpAddress = Irp;
|
|||
|
if ( (GetFieldValue(Irp, TypeName, "Type", Type)) ) {
|
|||
|
//dprintf("%08p: Could not read Irp\n", IrpToDump);
|
|||
|
return E_INVALIDARG;
|
|||
|
}
|
|||
|
if (Type != IO_TYPE_IRP) {
|
|||
|
return E_INVALIDARG;
|
|||
|
}
|
|||
|
|
|||
|
GetFieldValue(Irp, TypeName, "StackCount", pIrp->StackCount);
|
|||
|
GetFieldValue(Irp, TypeName, "CurrentLocation", pIrp->CurrentLocation);
|
|||
|
GetFieldValue(Irp, TypeName, "MdlAddress", pIrp->MdlAddress);
|
|||
|
GetFieldValue(Irp, TypeName, "CancelRoutine", pIrp->CancelRoutine);
|
|||
|
GetFieldValue(Irp, TypeName, "Tail.Overlay.Thread", pIrp->Thread);
|
|||
|
|
|||
|
for (irpStackIndex = pIrp->StackCount,
|
|||
|
irpStackAddress = Irp + GetTypeSize("nt!_IRP") + (pIrp->StackCount - 1)* GetTypeSize("nt!_IO_STACK_LOCATION");
|
|||
|
irpStackIndex >= 1;
|
|||
|
irpStackIndex++, irpStackAddress -= GetTypeSize("nt!_IO_STACK_LOCATION")) {
|
|||
|
|
|||
|
if ( InitTypeRead(irpStackAddress, nt!_IO_STACK_LOCATION)) {
|
|||
|
return E_INVALIDARG;
|
|||
|
}
|
|||
|
|
|||
|
pIrp->CurrentStack.DeviceObject = ReadField(DeviceObject);
|
|||
|
|
|||
|
if (!pIrp->CurrentStack.DeviceObject) {
|
|||
|
// To be implemented later, we are only interested in current one now
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
pIrp->CurrentStack.StackAddress = irpStackAddress;
|
|||
|
pIrp->CurrentStack.CompletionRoutine = ReadField(CompletionRoutine);
|
|||
|
pIrp->CurrentStack.FileObject = ReadField(FileObject);
|
|||
|
pIrp->CurrentStack.Major = (UCHAR) ReadField(MajorFunction);
|
|||
|
pIrp->CurrentStack.Minor = (UCHAR) ReadField(MinorFunction);
|
|||
|
break;
|
|||
|
}
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
EXTENSION_API( GetIrpInfo )(
|
|||
|
PDEBUG_CLIENT Client,
|
|||
|
ULONG64 Irp,
|
|||
|
PDEBUG_IRP_INFO pIrp
|
|||
|
)
|
|||
|
{
|
|||
|
HRESULT Hr = E_FAIL;
|
|||
|
|
|||
|
INIT_API();
|
|||
|
|
|||
|
if (pIrp && (pIrp->SizeOfStruct == sizeof(DEBUG_IRP_INFO))) {
|
|||
|
Hr = GetIrpInfo(Irp, pIrp);
|
|||
|
}
|
|||
|
EXIT_API();
|
|||
|
return Hr;
|
|||
|
}
|