Windows软件调试初探-中断和异常管理
中断描述符表
保护模式下有中断或异常发生时,CPU通过中断描述符表IDT寻找处理函数。
启动时0号处理器称为BSP,其他的称为AP。
在BSP中,IDT最初建立和初始化工作在Windows加载程序WinLoad在实模式下完成。准备好一个内存块后加载程序执行CLI指令关闭中断处理,用LIDT
指令将IDT位置和长度信息加载到CPU,加载程序将CPU从实模式切换到保护模式,将执行权移交给NT内核入口函数KiSystemStartup
。接下来,啮合处理器初始化函数通过SIDT
指令取得IDT信息,对其调整后作为参数传给KiInitializePcr
,后者将其记录到PCR和PRCB中。
对于每个AP,KeStartAllProcessors
为其建立一个单独的处理器状态区,包括其IDT,再用KiInitProcessor
,后者根据启动CPU的IDT为要初始化的AP复制一份。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| 3: kd> !pcr KPCR for Processor 3 at ffff968074fad000: //KPCR线性内存地址 Major 1 Minor 1 //KPCR主版本号和子版本号 NtTib.ExceptionList: ffff968074fbcfb0 //异常处理注册链表 NtTib.StackBase: ffff968074fbb000 NtTib.StackLimit: 000000000009e5b8 NtTib.SubSystemTib: ffff968074fad000 NtTib.Version: 0000000074fad180 NtTib.UserPointer: ffff968074fad870 NtTib.SelfTib: 00000000003ac000
SelfPcr: 0000000000000000 //本结构起始地址 Prcb: ffff968074fad180 //KPRCB地址 Irql: 0000000000000000 //IRQL IRR: 0000000000000000 IDR: 0000000000000000 InterruptMode: 0000000000000000 IDT: 0000000000000000 //IDT基地址 GDT: 0000000000000000 //GDT基地址 TSS: 0000000000000000 //TSS地址
CurrentThread: ffff968074fb8140 //当前正执行的线程 ETHREAD地址 NextThread: 0000000000000000 //下一个准备执行的线程 IdleThread: ffff968074fb8140 //IDLE线程的ETHREAD地址
DpcQueue: Unable to read nt!_KDPC_DATA.DpcListHead.Flink @ ffff968074fb0240 1: kd> dt nt!_KPCR ffff968074fad000 +0x000 NtTib : _NT_TIB +0x000 GdtBase : 0xffff9680`74fbcfb0 _KGDTENTRY64 +0x008 TssBase : 0xffff9680`74fbb000 _KTSS64 +0x010 UserRsp : 0x9e5b8 +0x018 Self : 0xffff9680`74fad000 _KPCR +0x020 CurrentPrcb : 0xffff9680`74fad180 _KPRCB +0x028 LockArray : 0xffff9680`74fad870 _KSPIN_LOCK_QUEUE +0x030 Used_Self : 0x00000059`5a425000 Void +0x038 IdtBase : 0xffff9680`74fba000 _KIDTENTRY64 +0x040 Unused : [2] 0 +0x050 Irql : 0 '' +0x051 SecondLevelCacheAssociativity : 0xc '' +0x052 ObsoleteNumber : 0x3 '' +0x053 Fill0 : 0 '' +0x054 Unused0 : [3] 0 +0x060 MajorVersion : 1 +0x062 MinorVersion : 1 +0x064 StallScaleFactor : 0x973 +0x068 Unused1 : [3] (null) +0x080 KernelReserved : [15] 0 +0x0bc SecondLevelCacheSize : 0x2400000 +0x0c0 HalReserved : [16] 0x90321000 +0x100 Unused2 : 0 +0x108 KdVersionBlock : (null) +0x110 Unused3 : (null) +0x118 PcrAlign1 : [24] 0 +0x180 Prcb : _KPRCB
|
IDT每一项为一个门描述符结构,IDT包含3种门描述符:任务门、中断门、陷阱门。
任务门用于任务切换,里面包含用于选择任务状态段TSS的段选择子。中断门用于描述中断处理例程入口。陷阱门用于描述异常处理例程的入口。
列出IDT中每个项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 1: kd> !idt -a
Dumping IDT: ffff968074e74000
00: fffff80732bffc00 nt!KiDivideErrorFault 01: fffff80732bfff40 nt!KiDebugTrapOrFault Stack = 0xFFFF968074ECE000 02: fffff80732c00440 nt!KiNmiInterrupt Stack = 0xFFFF968074EE3000 03: fffff80732c00900 nt!KiBreakpointTrap 04: fffff80732c00c40 nt!KiOverflowTrap 05: fffff80732c00f80 nt!KiBoundFault 06: fffff80732c014c0 nt!KiInvalidOpcodeFault 07: fffff80732c019c0 nt!KiNpxNotAvailableFault 08: fffff80732c01cc0 nt!KiDoubleFaultAbort Stack = 0xFFFF968074ED5000 09: fffff80732c01fc0 nt!KiNpxSegmentOverrunAbort 0a: fffff80732c022c0 nt!KiInvalidTssFault 0b: fffff80732c025c0 nt!KiSegmentNotPresentFault 0c: fffff80732c02980 nt!KiStackFault 0d: fffff80732c02cc0 nt!KiGeneralProtectionFault 0e: fffff80732c03000 nt!KiPageFault 0f: fffff80732bf7a48 nt!KiIsrThunk+0x78 10: fffff80732c03640 nt!KiFloatingErrorFault 11: fffff80732c03a00 nt!KiAlignmentFault 12: fffff80732c03d40 nt!KiMcheckAbort Stack = 0xFFFF968074EDC000 13: fffff80732c04840 nt!KiXmmException 14: fffff80732c04c00 nt!KiVirtualizationException 15: fffff80732c05100 nt!KiControlProtectionFault 16: fffff80732bf7a80 nt!KiIsrThunk+0xB0 ...
|
异常的描述与登记
用RaiseException
产生的异常称为CPU异常或硬件异常,用编程语言的throw
关键字称为软件异常。这两类异常的描述和分发是统一的,用EXCEPTION_RECORD结构描述异常:
1 2 3 4 5 6 7 8
| typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; struct _EXCEPTION_RECORD* ExceptionRecord; PVOID ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; } EXCEPTION_RECORD;
|
太抽象了不学了。