您现在的位置:首页 >> 基础算法 >> window基础 >> 内容

Delphi中异常的处理

时间:2011/9/3 15:32:15 点击:

  核心提示:这里讲的是windows操作系统下的异常处理方式,由于只是自己的笔记,如果想知道详细的细节,可以参考《Windows核心编程》一书。在windows操作系统中,每一个任务的LTD结构存放在用户空间里面...
这里讲的是windows操作系统下的异常处理方式,由于只是自己的笔记,如果想知道详细的细节,可以参考《Windows核心编程》一书。
在windows操作系统中,每一个任务的LTD结构存放在用户空间里面的,FS寄存器指向一个复杂的结构,但是在偏移为0的地方,指向的是一个异常处理程序的结构链。
而异常处理程序是一个回调函数,并且每个参数的格式以及参数的顺序都是固定的,这个windows的规定,毕竟在异常出现后,我们程序自己是没有处理机会的,只有交给系统了,然后系统再来调用我们程序中已经按格式定义好的异常处理例程。
下面是异常处理程序的声明:
function (ExceptionRecord: PExceptionRecord; EstablisherFrame: Pointer;
  ContextRecord: PContext; DispatcherContext: Pointer): TExceptionDisposition; Cdecl;
注意这里采用的Cdecl参数传递方式。而其中的参数就是处理异常的关键了:
PExceptionRecord中的域ExceptionCode包含有到底出现的是什么错误(因为我们有时候只要处理一种或者几种异常,并不要处理所有的异常),例如堆栈溢出:STATUS_STACK_OVERFLOW。ContextRecord结构其实就是一个CPU寄存器组,我们可以在这里修改各个寄存器的值,甚至包括EIP寄存器,当然还有ESP了,这个就是我们异常处理可以还原现场的关键了^_^
函数的返回值是一个TExceptionDisposition(一个枚举),它作如下定义:TExceptionDisposition = (
    ExceptionContinueExecution = 0,//继续执行遇到异常的线程(回调已经作了修复工作)
    ExceptionContinueSearch    = 1,//回调未作处理, 请在寻找其他回调
    ExceptionNestedException   = 2,
    ExceptionCollidedUnwind    = 3 ) ;
有了这些垫底,我相信作一个自己的异常处理钩子应该不复杂吧^_^
有些时候为了方便,我们还会定义一个TExcFrame结构:
TExcFrame = record
    PStruct: PExcFrame; // 上一节点位置
    Handler: Pointer; // 异常回调地址
    SafeEip: Pointer; // 安全指令地址
  end;
然后可以在栈中构建好结构后(利用push反向操作,因为栈是向小地址递增的),然后直接一个MOV FS[0],[ESP]就可以安装好这个钩子了,其实我们在异常例程中使用到的EstablisherFrame参数就是这里传入的,是不是很简单啊!这里借用别人的一个例子来看看如何为一个过程添加保护代码:
asm
  // 在堆栈中构建异常结构
  PUSH OFFSET  @@SafeEip     // TExcFrame.SafeEip安全的指令地址,其实这里有个小的技巧,由于这个
  //结构是在栈中构造的,所以我们传入参数的同时实际上也得到了栈的安全地址了,同时保护到栈了,
  //如果一个结构可以同时保护到ESP和EIP,那么函数再出错都可以恢复现场了^_^
  //这里栈是函数调用前的栈,也就是干净的栈,恢复到这里最好不过了
  PUSH OFFSET  ExceptFilter // TExcFrame.Handler
  PUSH FS:[0]                // TExcFrame.PStruct
  // 将该结构插入链表首部
  MOV  FS:[0], ESP           // FS:[0]乃TIB.ExceptionList
  // 参数/返回值均在EAX中
  CALL CustomFunc  //需要保护的函数或者过程
  // 遇到异常时的跳转位置
@@SafeEip:
  // 从链表去除我们的结构并恢复原来的异常处理例程,因为处理例程可能有很多,
  //而我们的只是其中一个
  MOV  EDX   , [ESP]         // 上个节点地址
  MOV  FS:[0], EDX           // 设其为首节点
  // 清除异常结构占用堆栈
  ADD  ESP   , 12            // 修改栈顶指针!
end;

作者:sundy 来源:转载
共有评论 0相关评论
发表我的评论
  • 大名:
  • 内容:
  • 盒子文章(www.2ccc.com) © 2024 版权所有 All Rights Reserved.
  • 沪ICP备05001939号