You must know this to understand Windows Driver Model
//++
//
// PIO_STACK_LOCATION
// IoGetCurrentIrpStackLocation(
// IN PIRP Irp
// )
//
// Routine Description:
//
// This routine is invoked to return a pointer to the current stack location
// in an I/O Request Packet (IRP).
//
// Arguments:
//
// Irp - Pointer to the I/O Request Packet.
//
// Return Value:
//
// The function value is a pointer to the current stack location in the
// packet.
//
//--
#define IoGetCurrentIrpStackLocation( Irp ) ( (Irp)->Tail.Overlay.CurrentStackLocation )
//++
//
// PIO_STACK_LOCATION
// IoGetNextIrpStackLocation(
// IN PIRP Irp
// )
//
// Routine Description:
//
// This routine is invoked to return a pointer to the next stack location
// in an I/O Request Packet (IRP).
//
// Arguments:
//
// Irp - Pointer to the I/O Request Packet.
//
// Return Value:
//
// The function value is a pointer to the next stack location in the packet.
//
//--
#define IoGetNextIrpStackLocation( Irp ) (\
(Irp)->Tail.Overlay.CurrentStackLocation - 1 )
//++
//
// VOID
// IoSetNextIrpStackLocation (
// IN OUT PIRP Irp
// )
//
// Routine Description:
//
// This routine is invoked to set the current IRP stack location to
// the next stack location, i.e. it "pushes" the stack.
//
// Arguments:
//
// Irp - Pointer to the I/O Request Packet (IRP).
//
// Return Value:
//
// None.
//
//--
#define IoSetNextIrpStackLocation( Irp ) { \
(Irp)->CurrentLocation--; \
(Irp)->Tail.Overlay.CurrentStackLocation--; }
//++
//
// VOID
// IoSkipCurrentIrpStackLocation (
// IN PIRP Irp
// )
//
// Routine Description:
//
// This routine is invoked to increment the current stack location of
// a given IRP.
//
// If the caller wishes to call the next driver in a stack, and does not
// wish to change the arguments, nor does he wish to set a completion
// routine, then the caller first calls IoSkipCurrentIrpStackLocation
// and the calls IoCallDriver.
//
// Arguments:
//
// Irp - Pointer to the I/O Request Packet.
//
// Return Value:
//
// None
//
//--
#define IoSkipCurrentIrpStackLocation( Irp ) { \
(Irp)->CurrentLocation++; \
(Irp)->Tail.Overlay.CurrentStackLocation++; }
//++
//
// VOID
// IoCopyCurrentIrpStackLocationToNext(
// IN PIRP Irp
// )
//
// Routine Description:
//
// This routine is invoked to copy the IRP stack arguments and file
// pointer from the current IrpStackLocation to the next
// in an I/O Request Packet (IRP).
//
// If the caller wants to call IoCallDriver with a completion routine
// but does not wish to change the arguments otherwise,
// the caller first calls IoCopyCurrentIrpStackLocationToNext,
// then IoSetCompletionRoutine, then IoCallDriver.
//
// Arguments:
//
// Irp - Pointer to the I/O Request Packet.
//
// Return Value:
//
// None.
//
//--
#define IoCopyCurrentIrpStackLocationToNext( Irp ) { \
PIO_STACK_LOCATION __irpSp; \
PIO_STACK_LOCATION __nextIrpSp; \
__irpSp = IoGetCurrentIrpStackLocation( (Irp) ); \
__nextIrpSp = IoGetNextIrpStackLocation( (Irp) ); \
RtlCopyMemory( __nextIrpSp, __irpSp, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); \
__nextIrpSp->Control = 0; }
#define FIELD_OFFSET(type, field) ( (LONG) (LONG_PTR) &(((type*) 0)->field))
//++
//
// PDRIVER_CANCEL
// IoSetCancelRoutine(
// IN PIRP Irp,
// IN PDRIVER_CANCEL CancelRoutine
// )
//
// Routine Description:
//
// This routine is invoked to set the address of a cancel routine which
// is to be invoked when an I/O packet has been canceled.
//
// Arguments:
//
// Irp - Pointer to the I/O Request Packet itself.
//
// CancelRoutine - Address of the cancel routine that is to be invoked
// if the IRP is cancelled.
//
// Return Value:
//
// Previous value of CancelRoutine field in the IRP.
//
//--
#define IoSetCancelRoutine( Irp, NewCancelRoutine ) ( \
(PDRIVER_CANCEL) InterlockedExchangePointer( (PVOID *) &(Irp)->CancelRoutine, (PVOID) (NewCancelRoutine) ) )
//++
//
// VOID
// IoSetCompletionRoutine(
// IN PIRP Irp,
// IN PIO_COMPLETION_ROUTINE CompletionRoutine,
// IN PVOID Context,
// IN BOOLEAN InvokeOnSuccess,
// IN BOOLEAN InvokeOnError,
// IN BOOLEAN InvokeOnCancel
// )
//
// Routine Description:
//
// This routine is invoked to set the address of a completion routine which
// is to be invoked when an I/O packet has been completed by a lower-level
// driver.
//
// Arguments:
//
// Irp - Pointer to the I/O Request Packet itself.
//
// CompletionRoutine - Address of the completion routine that is to be
// invoked once the next level driver completes the packet.
//
// Context - Specifies a context parameter to be passed to the completion
// routine.
//
// InvokeOnSuccess - Specifies that the completion routine is invoked when the
// operation is successfully completed.
//
// InvokeOnError - Specifies that the completion routine is invoked when the
// operation completes with an error status.
//
// InvokeOnCancel - Specifies that the completion routine is invoked when the
// operation is being canceled.
//
// Return Value:
//
// None.
//
//--
#define IoSetCompletionRoutine( Irp, Routine, CompletionContext, Success, Error, Cancel ) { \
PIO_STACK_LOCATION __irpSp; \
ASSERT( (Success) | (Error) | (Cancel) ? (Routine) != NULL : TRUE ); \
__irpSp = IoGetNextIrpStackLocation( (Irp) ); \
__irpSp->CompletionRoutine = (Routine); \
__irpSp->Context = (CompletionContext); \
__irpSp->Control = 0; \
if ((Success)) { __irpSp->Control = SL_INVOKE_ON_SUCCESS; } \
if ((Error)) { __irpSp->Control |= SL_INVOKE_ON_ERROR; } \
if ((Cancel)) { __irpSp->Control |= SL_INVOKE_ON_CANCEL; } }
//++
//
// VOID
// IoMarkIrpPending(
// IN OUT PIRP Irp
// )
//
// Routine Description:
//
// This routine marks the specified I/O Request Packet (IRP) to indicate
// that an initial status of STATUS_PENDING was returned to the caller.
// This is used so that I/O completion can determine whether or not to
// fully complete the I/O operation requested by the packet.
//
// Arguments:
//
// Irp - Pointer to the I/O Request Packet to be marked pending.
//
// Return Value:
//
// None.
//
//--
#define IoMarkIrpPending( Irp ) ( \
IoGetCurrentIrpStackLocation( (Irp) )->Control |= SL_PENDING_RETURNED )
//
//
// NTKERNELAPI
// NTSTATUS
// FASTCALL
// IofCallDriver(
// IN PDEVICE_OBJECT DeviceObject,
// IN OUT PIRP Irp
// );
//
// Routine Description:
//
// This routine is invoked to pass an I/O Request Packet (IRP) to another
// driver at its dispatch routine.
//
// Arguments:
//
// DeviceObject - Pointer to device object to which the IRP should be passed.
//
// Irp - Pointer to IRP for request.
//
// Return Value:
//
// Return status from driver's dispatch routine.
//
//
NTKERNELAPI
NTSTATUS
FASTCALL
IofCallDriver(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
)
{
UCHAR MajorFunction;
ASSERT( Irp->Type == IO_TYPE_IRP );
Irp->CurrentLocation--;
if( Irp->CurrentLocation == 0 )
{
KeBugCheckEx( NO_MORE_IRP_STACK_LOCATIONS, Irp, NULL, NULL, NULL );
}
Irp->Tail.Overlay.CurrentStackLocation--;
Irp->Tail.Overlay.CurrentStackLocation->DeviceObject = DeviceObject;
// Call dispatcher routine
MajorFunction = Irp->Tail.Overlay.CurrentStackLocation->MajorFunction;
return ( *(DeviceObject->DriverObject->MajorFunction[MajorFunction])(DeviceObject, Irp) );
}
WinDbg FASTCALL analyze nt!IofCallDriver
FASTCALL - the first two DWORD-or-smaller arguments are passed
in the ecx and edx registers. The remaining parameters are passed
on the stack, pushed right to left. The callee cleans the stack.
kd> bp nt!IofCallDriver
kd> g
Breakpoint 0 hit
nt!IofCallDriver:
804e37c5 ff2500295580 jmp dword ptr [nt!pIofCallDriver (80552900)]
kd> r
eax=81df2158 ebx=00000000 ecx=81e67020 edx=81df2158 esi=81e7c180 edi=81e67c08
eip=804e37c5 esp=f8973ec0 ebp=f8973ed0 iopl=0 nv up ei ng nz na po nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000282
nt!IofCallDriver:
804e37c5 ff2500295580 jmp dword ptr [nt!pIofCallDriver (80552900)] ds:0023:80552900={nt!IopfCallDriver (804e37d0)}
kd> !irp edx
Irp is active with 5 stacks 5 is current (= 0x81df2258)
Mdl=81e98d38: No System Buffer: Thread 00000000: Irp stack trace. Pending has been returned
cmd flg cl Device File Completion-Context
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
[ f, 0] 0 e0 81f87d98 00000000 f8590635-81e7c188 Success Error Cancel
\Driver\atapi CLASSPNP!ClasspMediaChangeDetectionCompletion
Args: 81e7c188 00000000 001b0011 00000000
>[ 0, 0] 2 0 81e67b50 00000000 00000000-00000000
\Driver\Cdrom
Args: 00000000 00000000 00000000 00000000
kd> !devobj ecx
Device object (81e67020) is for:
\Driver\Imapi DriverObject 81e68f38
Current Irp 00000000 RefCount 0 Type 0000002d Flags 00004010
DevExt 81e670d8 DevObjExt 81e67660
ExtensionFlags (0000000000)
AttachedDevice (Upper) 81e67b50 \Driver\Cdrom
AttachedTo (Lower) 81f87d98 \Driver\atapi
Device queue is not busy.
kd> dt nt!_IRP 81df2158
+0x000 Type : 6
+0x002 Size : 0x190
+0x004 MdlAddress : 0x81e98d38 _MDL
+0x008 Flags : 0
+0x00c AssociatedIrp : __unnamed
+0x010 ThreadListEntry : _LIST_ENTRY [ 0x81df2168 - 0x81df2168 ]
+0x018 IoStatus : _IO_STATUS_BLOCK
+0x020 RequestorMode : 0 ''
+0x021 PendingReturned : 0x1 ''
+0x022 StackCount : 5 ''
+0x023 CurrentLocation : 5 ''
+0x024 Cancel : 0 ''
+0x025 CancelIrql : 0 ''
+0x026 ApcEnvironment : 0 ''
+0x027 AllocationFlags : 0x4 ''
+0x028 UserIosb : (null)
+0x02c UserEvent : (null)
+0x030 Overlay : __unnamed
+0x038 CancelRoutine : (null)
+0x03c UserBuffer : (null)
+0x040 Tail : __unnamed
kd> dt nt!_DEVICE_OBJECT 81e67020
+0x000 Type : 3
+0x002 Size : 0x640
+0x004 ReferenceCount : 0
+0x008 DriverObject : 0x81e68f38 _DRIVER_OBJECT
+0x00c NextDevice : (null)
+0x010 AttachedDevice : 0x81e67b50 _DEVICE_OBJECT
+0x014 CurrentIrp : (null)
+0x018 Timer : (null)
+0x01c Flags : 0x4010
+0x020 Characteristics : 0x101
+0x024 Vpb : (null)
+0x028 DeviceExtension : 0x81e670d8
+0x02c DeviceType : 0x2d
+0x030 StackSize : 2 ''
+0x034 Queue : __unnamed
+0x05c AlignmentRequirement : 1
+0x060 DeviceQueue : _KDEVICE_QUEUE
+0x074 Dpc : _KDPC
+0x094 ActiveThreadCount : 0
+0x098 SecurityDescriptor : (null)
+0x09c DeviceLock : _KEVENT
+0x0ac SectorSize : 0
+0x0ae Spare1 : 1
+0x0b0 DeviceObjectExtension : 0x81e67660 _DEVOBJ_EXTENSION
+0x0b4 Reserved : (null)
kd> k
ChildEBP RetAddr
f8973ebc f85905cb nt!IofCallDriver
f8973ed0 f8590731 CLASSPNP!ClasspSendMediaStateIrp+0xb9
f8973ef8 804e3d38 CLASSPNP!ClasspMediaChangeDetectionCompletion+0x141
f8973f28 f849965e nt!IopfCompleteRequest+0xa2
f8973f54 f8499b94 atapi!IdeProcessCompletedRequest+0x664
f8973fd0 804dbbd4 atapi!IdePortCompletionDpc+0x204
f8973ff4 804db89e nt!KiRetireDpcList+0x46
f8973ff8 f860fa0c nt!KiDispatchInterrupt+0x2a