KTRAP_FRAME (amd64)

The KTRAP_FRAME (formally a _KTRAP_FRAME) is a structure in which the kernel saves the state of execution that gets interrupted for diversion to the kernel, whether from external hardware, the processor itself (for a trap or fault) or by software executing an int or syscall instruction. The KTRAP_FRAME is highly specific to the processor architecture. This page concerns itself only with 64-bit Windows for the processor architecture that’s variously named amd64 or x64. The x86 KTRAP_FRAME is presented separately.

Because of the structure’s role in all ways in and out of the kernel, the KTRAP_FRAME may be the best known of all formally undocumented kernel-mode structures. Indeed, this article exists only for the occasional convenience of having the names and offsets for ready reckoning (and, for the historian, of tracking the strikingly few changes).

Documentation Status

Though the KTRAP_FRAME structure is not formally documented, the structure’s x64 implementation has a C-language definition in NTDDK.H from every applicable Device Driver Kit (DDK) or Windows Driver Kit (WDK).

Layout

The KTRAP_FRAME for 64-bit Windows is 0x0190 bytes in all known versions. Names, types and offsets in the following are from NTDDK.H in various driver kits, checked against the kernel’s symbol files.

Offset (x64) Definition Versions
0x00
ULONG64 P1Home;
all
0x08
ULONG64 P2Home;
all
0x10
ULONG64 P3Home;
all
0x18
ULONG64 P4Home;
all
0x20
ULONG64 P5;
all
0x28
KPROCESSOR_MODE PreviousMode;
all
0x29
KIRQL PreviousIrql;
all
0x2A
UCHAR FaultIndicator;
all
0x2B
UCHAR ExceptionActive;
all
0x2C
ULONG MxCsr;
all
0x30
ULONG64 Rax;
all
0x38
ULONG64 Rcx;
all
0x40
ULONG64 Rdx;
all
0x48
ULONG64 R8;
all
0x50
ULONG64 R9;
all
0x58
ULONG64 R10;
all
0x60
ULONG64 R11;
all
0x68
union {
    ULONG64 GsBase;
    ULONG64 GsSwap;
};
all
0x70
M128A Xmm0;
all
0x80
M128A Xmm1;
all
0x90
M128A Xmm2;
all
0xA0
M128A Xmm3;
all
0xB0
M128A Xmm4;
all
0xC0
M128A Xmm5;
all
0xD0
union {
    ULONG64 FaultAddress;
    ULONG64 ContextRecord;
    ULONG64 TimeStamp;
};
5.2 only
union {
    ULONG64 FaultAddress;
    ULONG64 ContextRecord;
    ULONG64 TimeStampCKCL;
};
6.0 to 1607
union {
    ULONG64 FaultAddress;
    ULONG64 ContextRecord;
};
1703 and higher
0xD8
ULONG64 Dr0;
all
0xE0
ULONG64 Dr1;
all
0xE8
ULONG64 Dr2;
all
0xF0
ULONG64 Dr3;
all
0xF8
ULONG64 Dr6;
all
0x0100
ULONG64 Dr7;
all
0x0108
union {
    struct {
        ULONG64 DebugControl;
        ULONG64 LastBranchToRip;
        ULONG64 LastBranchFromRip;
        ULONG64 LastExceptionToRip;
        ULONG64 LastExceptionFromRip;
    };
    struct {
        ULONG64 LastBranchControl;
        ULONG LastBranchMSR;
    };
};
5.2 to 6.3
struct {
    ULONG64 DebugControl;
    ULONG64 LastBranchToRip;
    ULONG64 LastBranchFromRip;
    ULONG64 LastExceptionToRip;
    ULONG64 LastExceptionFromRip;
};
10.0 and higher
0x0130
USHORT SegDs;
all
0x0132
USHORT SegEs;
all
0x0134
USHORT SegFs;
all
0x0136
USHORT SegGs;
all
0x0138
ULONG64 TrapFrame;
all
0x0140
ULONG64 Rbx;
all
0x0148
ULONG64 Rdi;
all
0x0150
ULONG64 Rsi;
all
0x0158
ULONG64 Rbp;
all
0x0160
union {
    ULONG64 ErrorCode;
    ULONG64 ExceptionFrame;
};
5.2 only
union {
    ULONG64 ErrorCode;
    ULONG64 ExceptionFrame;
    ULONG64 TimeStampKlog;
};
6.0 to 1607
union {
    ULONG64 ErrorCode;
    ULONG64 ExceptionFrame;
};
1703 and higher
0x0168
ULONG64 Rip;
all
0x0170
USHORT SegCs;
all
0x0172
USHORT Fill1 [3];
5.2 only
UCHAR Fill0;
6.0 and higher
0x0173
UCHAR Logging;
6.0 and higher
0x0174
USHORT Fill1 [2];
6.0 and higher
0x0178
ULONG EFlags;
all
0x017C
ULONG Fill2;
all
0x0180
ULONG64 Rsp;
all
0x0188
USHORT SegSs;
all
0x018A
USHORT Fill3 [1];
5.2 only
USHORT Fill3;
6.0 and higher
0x018C
LONG CodePatchCycle;
5.2 to 6.2
ULONG Fill4;
6.3 and higher

The KTRAP_FRAME ends—from offset 0x0160 onwards—with items that the processor itself either does or may put on the stack before the kernel sees the interrupt. The structure’s formal layout has always provided that the kernel may squeeze in items of its own where the processor allows 8 bytes though only 16 or 32 bits are meaningful.

Note that the structure does not provide for saving all the general registers. The kernel does not itself use r12 to r15 during entry or exit, and does not save them in anticipation that code deeper into the handling may use them. The understanding is instead that all kernel-mode routines that use r12 to r15 (or xmm6 or xmm7) will do the saving and restoring themselves. In practice, of course, this knowledge is built into the compiler.