分享
 
 
 

系统故障解析:Windows异常处理流程

王朝system·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

先来说说异常和中断的区别。中断可在任何时候发生,与CPU正在执行什么指令无关,中断主要由I/O设备、处理器时钟或定时器等硬件引发,可以被允许或取消。而异常是由于CPU执行了某些指令引起的,可以包括存储器存取违规、除0或者特定调试指令等,内核也将系统服务视为异常。中断和异常更底层的区别是当广义上的中断(包括异常和硬件中断)发生时如果没有设置在服务寄存器(用命令号0xb向8259-1中断控制器0x20端口读出在服务寄存器1,用0xb向8259-2中断控制器的0xa0端口读出在服务寄存器2)相关的在服务位(每个在服务寄存器有8位,共对应IRQ 0-15)则为CPU的异常,否则为硬件中断。

下面是WINDOWS2000根据INTEL x86处理器的定义,将IDT中的前几项注册为对应的异常处理程序(不同的操作系统对此的实现标准是不一样的,这里给出的和其它一些资料不一样是因为这是windows的具体实现):

中断号

名字

原因

0x0

除法错误

1、DIV和IDIV指令除0

2、除法结果溢出

0x1

调试陷阱

1、EFLAG的TF位置位

2、执行到调试寄存器(DR0-DR4)设置的断点

3、执行INT 1指令

0x2

NMI中断

将CPU的NMI输入引脚置位(该异常为硬件发生非屏蔽中断而保留)

0x3

断点

执行INT 3指令

0x4

整数溢出

执行INTO指令且OF位置位

0x5

BOUND边界检查错误

BOUND指令比较的值在给定范围外

0x6

无效操作码

指令无法识别

0x7

协处理器不可用

1、CR0的EM位置位时执行任何协处理器指令

2、协处理器工作时执行了环境切换

0x8

双重异常

处理异常时发生另一个异常

0x9

协处理器段超限

浮点指令引用内存超过段尾

0xA

无效任务段

任务段包含的描述符无效(windows不

使用TSS进行环境切换,所以发生该异常说明有其它问题)

0xB

段不存在

被引用的段被换出内存

0xC

堆栈错误

1、被引用内存超出堆栈段限制

2、加载入SS寄存器的描述符的present位置0

0xD

一般保护性错误

所有其它异常处理例程无法处理的异常

0xE

页面错误

1、访问的地址未被换入内存

2、访问操作违反页保护规则

0x10

协处理器出错

CR0的EM位置位时执行WAIT或ESCape指令

0x11

对齐检查错误

对齐检查开启时(EFLAG对齐位置位)访问未对齐数据

其它异常还包括获取系统启动时间服务int 0x2a、用户回调int 0x2b、系统服务int 0x2e、调试服务int 0x2d等系统用来实现自己功能的部分,都是通过异常的机制,触发方式就是执行相应的int指令。

这里给出几个异常处理中重要的结构:

陷阱帧TrapFrame结构(后面提到的异常帧ExceptionFrame结构其实也是一个KTRAP_FRAME结构):

typedef struct _KTRAP_FRAME {

ULONG

DbgEbp;

ULONG

DbgEip;

ULONG

DbgArgMark;

ULONG

DbgArgPointer;

ULONG

TempSegCs;

ULONG

TempEsp;

ULONG

Dr0;

ULONG

Dr1;

ULONG

Dr2;

ULONG

Dr3;

ULONG

Dr6;

ULONG

Dr7;

ULONG

SegGs;

ULONG

SegEs;

ULONG

SegDs;

ULONG

Edx;

ULONG

Ecx;

ULONG

Eax;

ULONG

PreviousPreviousMode;

PEXCEPTION_REGISTRATION_RECORD ExceptionList;

ULONG

SegFs;

ULONG

Edi;

ULONG

Esi;

ULONG

Ebx;

ULONG

Ebp;

ULONG

ErrCode;

ULONG

Eip;

ULONG

SegCs;

ULONG

EFlags;

ULONG

HardwareEsp;

ULONG

HardwareSegSs;

ULONG

V86Es;

ULONG

V86Ds;

ULONG

V86Fs;

ULONG

V86Gs;

} KTRAP_FRAME;

环境Context结构:

typedef struct _CONTEXT {

ULONG ContextFlags;

ULONG

Dr0;

ULONG

Dr1;

ULONG

Dr2;

ULONG

Dr3;

ULONG

Dr6;

ULONG

Dr7;

FLOATING_SAVE_AREA FloatSave;

ULONG

SegGs;

ULONG

SegFs;

ULONG

SegEs;

ULONG

SegDs;

ULONG

Edi;

ULONG

Esi;

ULONG

Ebx;

ULONG

Edx;

ULONG

Ecx;

ULONG

Eax;

ULONG

Ebp;

ULONG

Eip;

ULONG

SegCs;

ULONG

EFlags;

ULONG

Esp;

ULONG

SegSs;

UCHAR

ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

} CONTEXT;

异常记录ExceptionRecord结构:

typedef struct _EXCEPTION_RECORD {

NTSTATUS ExceptionCode;

ULONG ExceptionFlags;

struct _EXCEPTION_RECORD *ExceptionRecord;

PVOID ExceptionAddress;

ULONG NumberParameters;

ULONG_PTR ExceptionInformatio[EXCEPTION_MAXIMUM_PARAMETERS];

} EXCEPTION_RECORD;

当发生异常后,CPU记录当前各寄存器状态并在内核堆栈中建立陷阱帧TrapFrame,然后将控制交给对应异常的陷阱处理程序。当陷阱处理程序能处理异常时,比如缺页时通过调页程序MmAccessFault将页换入物理内存后通过iret返回发生异常的地方。但大多数无法处理异常,这时先是调用CommonDispatchException在内核堆栈中建立异常记录ExceptionRecord和异常帧ExceptionFrame。ExceptionRecord很重要,它记录了异常代码、异常地址以及一些其它附加的参数。然后调用KiDispatchException进行异常的分派。这个函数是WINDOWS下异常处理的核心函数,负责异常的分派处理。

KiDispatchException的处理流程(每当异常被某个例程处理时处理的例程将返回TRUE到上一个例程,未处理则返回FALSE。当任何一个例程处理了异常返回TRUE时,则KiDispatchException正常返回):

在进行用户态内核态的异常的分派前,先判断异常是否来自用户模式,是的话将Context.ContextFlags(这时候Context结构还刚初始化完,还未赋初值) or上CONEXT_FLOATING_POINT,意味着对来自用户模式的异常总是尝试分派浮点状态,这样可以允许异常处理程序或调试器检查和修改协处理器的状态。然后从陷阱帧中取出寄存器值填入Context结构,并判断是否是断点异常(int 0x3和int 0x2d),如果是的话先将Context.Eip减一使它指向int 0x3指令(无论是由int 0x3还是由int 0x2d引起的异常,因为前面的陷阱处理程序里已经改变过TrapFrame里面的Eip了)。然后判断异常是发生于内核模式还是用户模式,根据不同模式而采取不同处理过程。

如果异常发生于内核模式,会给予内核调试器第一次机会和第二次机会处理异常。当异常被处理后就将设置好陷阱帧并返回到陷阱处理程序,在那里iret返回发生异常的地方继续执行。

内核模式异常处理流程为:

(第一次机会)判断KiDebugRoutine是否为空,不为空就将Context、陷阱帧、异常记录、异常帧、发生异常的模式等压入栈并将控制交给KiDebugRoutine。

若KiDebugRoutine为空(正常的系统这里不为空。正常启动的系统KiDebugRoutine为KdpStub,在Boot.ini里加上/DEBUG启动的系统的KiDebugRoutine为KdpTrap。如果这里为空的话会因为处理不了DbgPrint这类int 0x2d产生的异常而导致系统崩溃)或者KiDebugRoutine未处理异常,则将Context结构和异常记录ExceptionRecord压栈并调用内核模式的RtlDispatchException在内核堆栈中查找基于帧的异常处理例程。

RtlDispatchException调用RtlpGetRegistrationHead从fs:[0](0xffdff000)处获取当前线程异常处理链表指针,并调用RtlpGetStackLimits从0xffdff004和0xffdff008取出当前线程堆栈底和顶。然后开始由异常处理链表指针遍历链表查找异常处理例程(若在XP和2003下先处理VEH再处理SEH),其实这就是SEH,只是和用户态有一点不同是既没有顶层异常处理例程(TOP LEVEL SEH)也没有默认异常处理例程。然后对每个当前异常处理链表指针检查判断堆栈是否有效(是否超出了堆栈范围或者未对齐)及堆栈是否是DPC堆栈。若0xffdff80c处DpcRoutineActive为TRUE且堆栈顶和底在0xffdff81c处取出的DpcStack到DpcStack-0x3000(一个内核堆栈大小),若是则更新堆栈顶和底为DpcStack和DpcStack-0x3000并继续处理,否则将异常记录结构里的异常标志ExceptionRecord.ExceptionFlags设置EXCEPTION_STACK_INVALID表示为无效堆栈并返回FALSE。

调用异常处理链表上的异常处理例程之前会在异常处理例程链表上插入一个新的节点,对应的异常处理例程是用来处理嵌套异常,也就是在处理异常时发生另一个异常。处理后

RtlDispatchException判断异常处理例程的返回值:

若为ExceptionContinueExecution,若异常标志ExceptionRecord.ExceptionFlags未设置EXCEPTION_NONCONTINUABLE不可恢复执行,则返回TRUE到上一层,否则在做了一些工作后调用RtlRaiseException进入到KiDispatchException的第二次机会处理部分。

若为ExceptionContinueSearch,则继续查找异常处理例程。

若为ExceptionNestedException,嵌套异常。保留当前异常处理链表指针为内层异常处理链表并继续查找异常处理例程。当发现当前异常处理链表地址大于保留的内层异常处理链表时,表示当前的异常处理链表比保留的更内层(因为堆栈是由高向低扩展的,地址越高则入栈越早,表示更内层),则将其值赋予内层异常处理链表指针,除了第一次赋初值外发生修改保留的内层

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有