Linux中对异常的处理

Linux中对异常的处理

异常处理程序发送相应的信号给发生异常的当前进程,或者进行故障恢复,然后返回到断点处执行。

例如,若执行了非法操作,CPU就产生6号异常(#UD),在对应的异常处理程序中,向当前进程发送一个SIGILL信号,以通知当前进程终止运行。

采用向发生异常的进程发送信号的机制实现异常处理,可尽快完成在内核态的异常处理过程,因为异常处理过程越长,嵌套执行异常的可能性越大,而异常嵌套执行会付出较大的代价。

并不是所有异常处理都只是发送一个信号到发生异常的进程。

例如对于14号页故障异常(#PE),需要判断是否访问越级、越权或越界等,若发生了这些无法恢复的故障,则页故障处理程序发送SIGSEGV信号给发生页故障异常的进程;若只是缺页,则页故障处理程序负责把所缺失页面从磁盘装入主存,然后返回到发生缺页故障的指令继续执行。

阶段

所有异常处理程序的结构是一致的,都可划分成以下3个部分:

准备阶段:在内核栈保存通用寄存器内容(称为现场信息),这部分大多用汇编语言程序实现。

处理阶段:采用C函数进行具体处理。函数名由do_前缀和处理程序名组成,如do_overflow为溢出处理函数。

大部分函数的处理方式:保存硬件出错码(如果有的话)和异常类型号,然后向当前进程发送一个信号。当前进程接收到信号后,若有对应信号处理程序,则转到信号处理程序执行;若没有,则调用内核abort例程执行,以终止当前进程。

恢复阶段:恢复保存在内核栈中的各个寄存器的内容,切换到用户态并返回到当前进程的断点处继续执行。

用户进程——>movl–>页故障—>OS的页故障处理程序,检测到地址越界或访问越权,发送“SIGSEGV”信号给用户进程。

demo

没有异常处理程序

#include <cstdio>
#include <cstdlib>
#include <setjmp.h>
sigjmp_buf buf;

void FLPhandler(int sig)
{
    printf("error type is SIGFPE!\n");
    siglongjmp(buf, 1);
}

int main()
{
    int a, t;
    if (!sigsetjmp(buf, 1)) {
        printf("starting\n");
        a = 100;
        t = 0;
        a = a / t;
    }
    printf("I am still alive...\n");
    exit(0);
}

运行结果是

m@ubuntu:~$ ./a.out 
starting
Floating point exception (core dumped)

有异常处理程序

#include <cstdio>
#include <cstdlib>
#include <setjmp.h>
#include <signal.h>
sigjmp_buf buf;

void FLPhandler(int sig)
{
    printf("error type is SIGFPE!\n");
    siglongjmp(buf, 1);
}

int main()
{
    int a, t;
    signal(SIGFPE,FLPhandler);
    if (!sigsetjmp(buf, 1)) {
        printf("starting\n");
        a = 100;
        t = 0;
        a = a / t;
    }
    printf("I am still alive...\n");
    exit(0);
}

结果

m@ubuntu:~$ ./a.out 
starting
error type is SIGFPE!
I am still alive...
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值