快速业务通道

Win32结构化异常处理(SEH)探秘(上)

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-29
凡响。如果你慢慢研究,其实并没有那么糟。例如,忽略返回类型(EXCEPTION_DISPOSITION)。基本上你看到的就是一个叫做 _except_handler  的函数,这个函数带有四个参数。

第一个参数是指向 EXCEPTION_RECORD 结构指针,该结构在 WINNT.H 中定义如下:

typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode;
DWORD ExceptionFlags;
struct _EXCEPTION_RECORD *ExceptionRecord;
PVOID ExceptionAddress;
DWORD NumberParameters;
DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;

ExceptionCode 参数是由操作系统赋值给异常的一个数。你可以在 WINNT.H 文件中搜一下“STATUS_”开始的 #defines 内容便可以得到一系列不同的异常编码。例如 STATUS_ACCESS_VIOLATION 是大家再熟悉不过的异常编码了,其值是 0xC0000005。更复杂的异常编码可以从 Windows NT DDK 的 NTSTATUS.H 文件中找到。EXCEPTION_RECORD 结构中的第四个元素是异常发生的地址。剩下的 EXCEPTION_RECORD 域现在可以忽略,不用管它。

_except_handler 回调函数的第二个参数是指向建立者框架(establisher frame)结构的指针,在 SEH 中它是一个至关重要的参数,但现在可以不用关心它。

_except_handler 回调函数的第三个参数是 CONTEXT 结构的指针。CONTEXT 结构在 WINNT.H 中定义,它表示特定线程异常发生时寄存器的值:

typedef struct _CONTEXT
{
DWORD ContextFlags;
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
FLOATING_SAVE_AREA FloatSave;
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
DWORD Ebp;
DWORD Eip;
DWORD SegCs;
DWORD EFlags;
DWORD Esp;
DWORD SegSs;
} CONTEXT;

此外,这个 CONTEXT 结构与 GetThreadContext 和 SetThreadContext API 函数使用的结构是相同的。

_except_handler 回调函数的第四个参数是 DispatcherContext。现在也可以忽略它。

为了简化起见,当异常发生时,你有一个回调函数被调用。此回调函数带四个参数,其中三个是结构指针。在这些结构中,某些域是很重要的,其余的不是那么重要。关键是 _except_handler 回调函数接收

很多信息,比如发生了什么类型的异常,在哪里发生的。利用这些信息,异常回调机制需要确定要做什么。

虽然我迫不急但地想抛出例子程序示范 _except_handler 回调的运行,但还有一些事情不能漏掉,需要说明。特别是当错误发生时,操作系统如何知道到哪里调用?答案仍然涉及另外一个结构 EXCEPTION_REGISTRATION。你将自始自终在本文中看到这个结构,所以不要掠过这部分内容。我能找到正式定义 EXCEPTION_REGISTRATION 结构的唯一地方是 EXSUP.INC 文件,该文件来自 Visual C++ 运行库的源:

_EXCEPTION_REGISTRATION struc
prev dd ?
handler dd ?
_EXCEPTION_REGISTRATION ends

你还将看到该结构在 WINNT.H 文件中定义的 NT_TIB 结构中被引用为 _EXCEPTION_REGISTRATION_RECORD。唉,除此之外,没有什么地方能找到 _EXCEPTION_REGISTRATION_RECORD 的定义,所以我只能使用 EXSUP.INC 文件中定义的汇编语言结构。这也是我为什么在本文前述内容中说过的 SEH 缺乏文档的一个例证。

不管怎样,让我们回到手头的问题,当某个异常发生时,OS 如何知道到哪里调用回调函数?EXCEPTION_REGISTRATION 由两个域构成,第一个你现在可以忽略。第二个域是句柄,它包含 _except_handler 回调函数的指针。这让你更接近一点了,但目前问题来了,OS 在哪里查找并发现 EXCEPTION_REGISTRATION 结构?

为了回答这个问题

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号