IRP和IO_STACK_LOCATION结构的关联

    IRP结构中的IRP!StackCount--IRP!CurrentLocation--IRP!CurrentStackLocation三个字段关系错综,仅以此文已做备忘。

//IRP结构后面接一个IO_STACK_LOCATION数组
typedef struct _IRP {
  CSHORT  Type;
  USHORT  Size;
  struct _MDL  *MdlAddress;
  ULONG  Flags;
  union {
    struct _IRP  *MasterIrp;
    volatile LONG  IrpCount;
    PVOID  SystemBuffer;
  } AssociatedIrp;
  LIST_ENTRY  ThreadListEntry;
  //返回值
  IO_STATUS_BLOCK  IoStatus;
  KPROCESSOR_MODE  RequestorMode;
  BOOLEAN  PendingReturned;
  //整个设备栈中从顶层到底层的栈深度(IO_STACK_LOCATION数组的长度)
  CHAR  StackCount;
  //当前设备栈深度,从1开始计数
  /*
   另外,IofCallDriver函数中一段代码:
   Irp->CurrentLocation--;
    if (Irp->CurrentLocation <= 0)
    {
        KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR)Irp, 0, 0, 0);
    }
    在调用下一层设备之前,先对Irp->CurrentLocation减一,如果Irp->CurrentLocation==0就bugcheck了,
    从这里可以确定,CurrentLocation是从1开始计数的
    CurrentLocation就如同日常口语中第一层(对应数组元素0)第二层(数组元素1)的概念
   */
  CHAR  CurrentLocation;
BOOLEAN  Cancel;
  KIRQL  CancelIrql;
  CCHAR  ApcEnvironment;
  UCHAR  AllocationFlags;
  PIO_STATUS_BLOCK  UserIosb;
  //同步对象
  PKEVENT  UserEvent;
  union {
    struct {
      PIO_APC_ROUTINE  UserApcRoutine;
      PVOID  UserApcContext;
    } AsynchronousParameters;
    LARGE_INTEGER  AllocationSize;
  } Overlay;
  volatile PDRIVER_CANCEL  CancelRoutine;
  PVOID  UserBuffer;
  union {
    struct {
      _ANONYMOUS_UNION union {
        KDEVICE_QUEUE_ENTRY  DeviceQueueEntry;
        _ANONYMOUS_STRUCT struct {
          PVOID  DriverContext[4];
        } DUMMYSTRUCTNAME;
      } DUMMYUNIONNAME;
      //发出IRP的线程
      PETHREAD  Thread;
      PCHAR  AuxiliaryBuffer;
      _ANONYMOUS_STRUCT struct {
        LIST_ENTRY  ListEntry;
        _ANONYMOUS_UNION union {
            //当前使用的堆栈数组元素指针
            /*
            StackCount/CurrentLocation/CurrentStackLocation三者的关系还是得从IoSizeOfIrp和IoInitializeIrp确立
            */
          struct _IO_STACK_LOCATION  *CurrentStackLocation;
          ULONG  PacketType;
        } DUMMYUNIONNAME;
      } DUMMYSTRUCTNAME;
      //设备对象所关联的文件对象
      struct _FILE_OBJECT  *OriginalFileObject;
    } Overlay;
    //整个IRP异步返回时用到的APC对象
    KAPC  Apc;
    PVOID  CompletionKey;
  } Tail;
} IRP;
如同注释中说,

StackCount/CurrentLocation/CurrentStackLocation三者的关系还是得从IoSizeOfIrp和IoInitializeIrp确立
接下来看下IoSizeOfIrp和IoInitializeIrp对IRP中这些字段的操作

VOID
NTAPI
IoInitializeIrp(IN PIRP Irp,
                IN USHORT PacketSize,
                IN CCHAR StackSize)
{
    /* Clear it */
    IOTRACE(IO_IRP_DEBUG,
            "%s - Initializing IRP %p\n",
            __FUNCTION__,
            Irp);
    RtlZeroMemory(Irp, PacketSize);

    /* Set the Header and other data */
    Irp->Type = IO_TYPE_IRP;
    Irp->Size = PacketSize;
    Irp->StackCount = StackSize;
	//初始状态时当前堆栈深度为实际深度(StackSize)+1
	//因为此时的IRP还没有进入设备对象堆栈
    Irp->CurrentLocation = StackSize + 1;
    Irp->ApcEnvironment =  KeGetCurrentThread()->ApcStateIndex;
	//IO_STACK_LOCATION数组紧贴IRP后面,数组中一共只有StackSize个元素,
	//下标从0到StackSize-1,所以指针已经越界一个元素。
	//最重要的,调用IoCallDriver时会调用一次IoGetNextIrpStackLocation,把数组
	//指针拨动到正确的位置,然后再把irp传递下去
	/*
	还是以老式设备StackSize=1为例:
	Irp->CurrentLocation=2,设备栈中第二个设备(很可惜堆栈上一共只有1个设备),
	Irp->Tail.Overlay.CurrentStackLocation=&IO_STACK_LOCATION[1].数组中只有元素0,因此还是越界
	状态.
	调用IofCallDriver时,IoSetNextIrpStackLocation(Irp),因此Irp->CurrentLocation=1,意为取堆栈中
	第一个元素,Irp->Tail.Overlay.CurrentStackLocation--堆栈指针指向&IO_STACK_LOCATION[0],取
	堆栈元素0
	*/
    Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;

    /* Initialize the Thread List */
    InitializeListHead(&Irp->ThreadListEntry);
}

 /*
 StackSize是设备栈中从顶层到底层设备数量,以老式设备为例StackSize=1.
 因此这个宏将在池中获得sizeof(IRP)和只有一个IO_STACK_LOCATION元素的数组,
 下标为0
 */
#define IoSizeOfIrp(_StackSize) \
  ((USHORT) (sizeof(IRP) + ((_StackSize) * (sizeof(IO_STACK_LOCATION)))))


你可能感兴趣的:(win内核)