linux下异常的处理技术
Linux下实现Windows的结构化异常处理
李
摘
双
要:针对Linux环境下对于异常处理支持的不足,提出了一种解决方案,实现了类似于
Windows平台下的结构化异常处理技术,使程序可以更加方便地处理异常,这样提高了代
码的健壮性和可维护性。
关键词:Linux;异常;结构化异常处理
在编写程序的过程中,经常会遇到代码因为种种原因发生异常的情况。用户模式下的应用程序还比较好,通常系统不会挂掉,不论是检查现场环境以便调试或是重新运行都比较方便。可驱动程序出现异常麻烦就比较大了,要么丢失错误现场,要么就等着重启动才能再次运行。实在是件让人头痛的事情。
在Windows平台下,这个问题很好解决:SEH(Structure
_Origin_GP_Entry_=(void*)((pdesc->basehigh<<16)|pdesc->baselow);
pdesc->basehigh=((unsignedlong)_ExceptionEntry>>16);pdesc->baselow=((unsignedlong)_ExceptionEntry&0xffff);}
注意:在程序退出时必须恢复原来的GP异常入口。
2异常处理
在自己的异常服务程序中检测相应的异常处理程序是否
ExceptionHandling)技术的出现为程序员提供了一个标准解决
方案,程序员只需要注册好异常处理函数(由编译器负责,通常不是一个完整的函数,而是和可能发生异常的代码在同一个函数中),当因为当前线程的代码引发异常时,系统会自动调用异常处理函数,完成善后工作。
而Linux下却没有类似的机制,异常处理例程是静态包含在内核代码中,而且必须精确定位出可能产生异常的代码的地址,这无疑会给异常处理带来很大的麻烦。不过反正Linux是开放式的,既然内核自己不提供类似的机制,那就自己来实现它。
要实现SEH,首先需要能够拦截异常,其次是在拦截到异常之后转移到相关的代码,最后,要能在可能产生异常的代码之前注册异常处理例程,并且在代码结束部分取消异常处理例程。
已经注册,如果是,则恢复现场,然后跳转到注册的异常处理程序运行;如果没有注册,就把控制权转交给内核的异常处理程序。
新的异常服务程序分为两个部分,第一部分用汇编语言实现,用于保护现场以及完成一些C代码无法实现的操作,其代码如下:
1异常拦截
要拦截异常,直接修改IDT表,用自己的GP(general-
protection)异常处理服务代码替换掉内核的异常处理代码就
行,这个功能很容易实现。以下代码实现了拦截异常的功能:
void*_Origin_GP_Entry_;void_hook_generalfalut(){
dtridtr;
desc*pdesc;
asm("sidt%0":"=m"(idtr));
*pdesc=phys_to_virt(idtr->base);
pdesc+=0xd;//pointtoGPdescription
Unsignedchar__ExceptionEntry[]={0x9c,//1pushfd0x60,//2pushad
0x8d,0x44,0x24,0x24//3leaeax,[esp+9*4]0x50,//4pusheax0xe8,0,0,0,0,//5call__c__ExceptionEntry0x8d,0x64,0x24,4,//6leaesp,[esp+4]0xb,0xc0,//7oreax,eax0x74,0x11,//8jz__call_system_handler0x8b,0x44,0x24,0x30,
//9moveax,dwordptr[esp+0x0c*4]
0x89,0x44,0x24,0x20,//10movdwordptr[esp+0x20],eax0x61,//11popad0x9d,//12popfd0x8d,0x64,0x24,4,//13leaesp,[esp+4]0xca,4,0,//14retf40x61,//15__call_system_handler:popad0x9d,//16popfd0xe9,0,0,0,0//17jmp__system_handler};
首先,这一部分代码为什么要使用机器码而不是汇编代
2009.11