abort c linux
2015-04-09 22:26:03 kanguolaikanguolaik 阅读数 2693

一、代码

        abort()、exit()

#include <stdio.h>
#include <stdlib.h>

static void atexit_handle_1(void)
{
        printf("atexit_handle_1\n");
}

static void atexit_handle_2(void)
{
        printf("atexit_handle_2\n");
}


//abort()、exit()
int main(int argc, char*argv[])
{
        atexit(atexit_handle_1);
        atexit(atexit_handle_2);

        printf("output.\n");

        //abort()
        //abort();

        //exit()
        exit(EXIT_SUCCESS);

        printf("this line should never output.\n");

        return 0;
}

二、输出结果

        abort()输出结果:


        exit()输出结果:


2016-02-09 22:12:40 u013378057 阅读数 243

 int sigsuspend(const sigset_t *mask)  //总是返回-1   并将errno设置为EINTR

提供了一个原子操作  现将信号屏蔽字设置为mask然后挂起程序  直到捕捉一个信号而且从信号处理程序返回  则sigsuspend返回

返回之后  进程屏蔽字会恢复为调用sigsuspend之前的值

如果信号终止进程那么挂起也失效


void abort(void)


向进程发送SIGABRT信号  并且阻塞与忽略它都无效

捕获:进入信号处理函数  信号处理函数返回后abort终止进程   

信号处理程序可以做一些善后工作、

根据实现不同  对于各种流的冲洗工作还不确定




2019-04-12 10:10:45 rikeyone 阅读数 146

SIGABRT被阻塞

还有一个信号SIGABRT要特别说明,表示异常终止信号,当系统调用abort()时会发送SIGABRT信号,那么如果阻塞了该信号会影响abort()函数的使用吗?
经过测试,事实证明并不会,因为abort()的内部实现已经确保了该函数调用器件,SIGALRM信号不会被阻塞。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void sig_handler(int sig)
{
    printf("signal catch:%d\n", sig);
}

int handle_test(void)
{
    signal(SIGABRT, sig_handler);
    printf("abort after 3 seconds\n");
    sleep(3);
    abort();
}

int block_test(void)
{
    sigset_t mask;

    sigemptyset(&mask);
    sigaddset(&mask, SIGABRT);
    sigprocmask(SIG_BLOCK, &mask, NULL);
    printf("abort after 3 seconds\n");
    sleep(3);
    abort();
}


int main()
{
//  handle_test();
    block_test();
    while(1);
}
                   

结果如下:

$ ./abort 
abort after 3 seconds
已放弃 (核心已转储)

SIGABRT被捕捉

如果SIGABRT被注册了一个捕获函数,那么执行abort()还会导致进程终止吗?
经过测试,事实证明依然会让系统终止,因为abort()执行完捕获函数后会恢复为默认,然后重新发送SIGABRT。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void sig_handler(int sig)
{
    printf("signal catch:%d\n", sig);
}

int handle_test(void)
{
    signal(SIGABRT, sig_handler);
    printf("abort after 3 seconds\n");
    sleep(3);
    abort();
}

int block_test(void)
{
    sigset_t mask;

    sigemptyset(&mask);
    sigaddset(&mask, SIGABRT);
    sigprocmask(SIG_BLOCK, &mask, NULL);
    printf("abort after 3 seconds\n");
    sleep(3);
    abort();
}

int main()
{
    handle_test();
    while(1);
}

结果如下:

$ ./abort 
abort after 3 seconds
signal catch:6
已放弃 (核心已转储)

abort使用注意

经过前面的测试可知,abort()函数一定会使得进程终止。

abort实现:

void
abort(void)         /* POSIX-style abort() function */
{
    sigset_t            mask;
    struct sigaction    action;

    /* Caller can't ignore SIGABRT, if so reset to default */
    sigaction(SIGABRT, NULL, &action);
    if (action.sa_handler == SIG_IGN) {
        action.sa_handler = SIG_DFL;
        sigaction(SIGABRT, &action, NULL);
    }
    if (action.sa_handler == SIG_DFL)
        fflush(NULL);           /* flush all open stdio streams */

    /* Caller can't block SIGABRT; make sure it's unblocked */
    sigfillset(&mask);
    sigdelset(&mask, SIGABRT);  /* mask has only SIGABRT turned off */
    sigprocmask(SIG_SETMASK, &mask, NULL);
    kill(getpid(), SIGABRT);    /* send the signal */

    /* If we're here, process caught SIGABRT and returned */
    fflush(NULL);               /* flush all open stdio streams */
    action.sa_handler = SIG_DFL;
    sigaction(SIGABRT, &action, NULL);  /* reset to default */
    sigprocmask(SIG_SETMASK, &mask, NULL);  /* just in case ... */
    kill(getpid(), SIGABRT);                /* and one more time */
    exit(1);    /* this should never be executed ... */
}

从这个实现中可以看出:

  1. 它保证该信号不能被忽略,也保证该信号不能被阻塞,
  2. 如果有对SIGABRT注册了捕获函数,那么会先执行捕获函数
  3. 捕获函数执行后如果依然进程没有退出,那么恢复捕获函数为默认(终止),然后再次发送SIGABRT给进程。
2009-06-01 22:00:00 yylklshmyt20090217 阅读数 8721

#include <stdlib.h>

函数名: abort

 功 能: 异常终止一个进程

 用 法: void abort(void);

 

abort()是使异常程序终止,同时发送SIGABRT信号给调用进程。

 

程序例:

#include  <stdio.h>
#include  <stdlib.h>
void main( void )
{
   FILE *stream;
   if( (stream = fopen( "NOSUCHF.ILE", "r" )) == NULL )
   {
      perror( "Couldn't open file" );
      abort();
   }
   else
      fclose( stream );
}

输出:
Couldn't open file: No such file or directory
abnormal program termination

 

 

2017-06-30 11:22:02 chenpuo 阅读数 232

 

 

data abortARM体系定义的异常之一。异常发生时,ARM会自动跳转到异常向量表中,通过向量表中的跳转命令跳转到相应的异常处理中去

   

 

 

svc模式进入data abort

 

svc模式进入data abort,也就是Linux的内核模式进入data aboart时,会跳转到__dabt_svc。

__dabt_svc:

       svc_entry               @ 保护寄存器现场

 

       mrs  r9, cpsr

       tst    r3, #PSR_I_BIT            @ 检查是否要开中断

       biceq       r9, r9, #PSR_I_BIT

       bl    CPU_DABORT_HANDLER  处理异常之前的准备工作

 

       msr  cpsr_c, r9

       mov r2, sp

       bl    do_DataAbort        @ 就是这里跳转到内核C函数

 

       disable_irq

 

       ldr   r0, [sp, #S_PSR]

       msr  spsr_cxsf, r0

       ldmia      sp, {r0 - pc}^                @ load r0 - pc, cpsr

ENDPROC(__dabt_svc)

 

 

 

 

 

/*
 * Dispatch a data abort to the relevant handler.
 */
asmlinkage void __exception
do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
struct siginfo info;


if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
return;


printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
inf->name, fsr, addr);


info.si_signo = inf->sig;
info.si_errno = 0;
info.si_code  = inf->code;
info.si_addr  = (void __user *)addr;
arm_notify_die("", regs, &info, fsr, 0);
}

 

 

 

 

static struct fsr_info fsr_info[] = {
/*
* The following are the standard ARMv3 and ARMv4 aborts.  ARMv5
* defines these to be "precise" aborts.
*/
{ do_bad, SIGSEGV, 0, "vector exception"  },
{ do_bad, SIGBUS, BUS_ADRALN,"alignment exception"   },
{ do_bad, SIGKILL, 0, "terminal exception"  },
{ do_bad, SIGBUS, BUS_ADRALN,"alignment exception"   },
{ do_bad, SIGBUS, 0, "external abort on linefetch"   },
{ do_translation_fault,SIGSEGV, SEGV_MAPERR, "section translation fault"  },
{ do_bad, SIGBUS, 0, "external abort on linefetch"   },
{ do_page_fault,SIGSEGV, SEGV_MAPERR, "page translation fault"  },
{ do_bad, SIGBUS, 0, "external abort on non-linefetch"  },
{ do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault"  },
{ do_bad, SIGBUS, 0, "external abort on non-linefetch"  },
{ do_bad, SIGSEGV, SEGV_ACCERR, "page domain fault"  },
{ do_bad, SIGBUS, 0, "external abort on translation"   },
{ do_sect_fault,SIGSEGV, SEGV_ACCERR, "section permission fault"  },
{ do_bad, SIGBUS, 0, "external abort on translation"   },
{ do_page_fault,SIGSEGV, SEGV_ACCERR, "page permission fault"  },
/*
* The following are "imprecise" aborts, which are signalled by bit
* 10 of the FSR, and may not be recoverable.  These are only
* supported if the CPU abort handler supports bit 10.
*/
{ do_bad, SIGBUS,  0, "unknown 16"  },
{ do_bad, SIGBUS,  0, "unknown 17"  },
{ do_bad, SIGBUS,  0, "unknown 18"  },
{ do_bad, SIGBUS,  0, "unknown 19"  },
{ do_bad, SIGBUS,  0, "lock abort"  }, /* xscale */
{ do_bad, SIGBUS,  0, "unknown 21"  },
{ do_bad, SIGBUS,  BUS_OBJERR, "imprecise external abort"  }, /* xscale */
{ do_bad, SIGBUS,  0, "unknown 23"  },
{ do_bad, SIGBUS,  0, "dcache parity error"  }, /* xscale */
{ do_bad, SIGBUS,  0, "unknown 25"  },
{ do_bad, SIGBUS,  0, "unknown 26"  },
{ do_bad, SIGBUS,  0, "unknown 27"  },
{ do_bad, SIGBUS,  0, "unknown 28"  },
{ do_bad, SIGBUS,  0, "unknown 29"  },
{ do_bad, SIGBUS,  0, "unknown 30"  },
{ do_bad, SIGBUS,  0, "unknown 31"  },
};

 

 

fsr_info对大多数abort都调用do_bad函数处理,do_bad函数简单返回1,这样就可以继续执行上面提到的arm_notify_die。

fsr_info对以下四种特殊abort将作单独处理:

l        "section translation fault"      do_translation_fault
段转换错误,即找不到二级页表

l        "page translation fault"         do_page_fault
页表错误,即线性地址无效,没有对应的物理地址

l        "section permission fault"     do_sect_fault
段权限错误,即二级页表权限错误

l        "page permission fault"         do_page_fault
页权限错误

 

段权限错误 do_sect_fault

do_sect_fault函数直接调用do_bad_area作处理,并返回0,所以不会再经过arm_notify_die。do_bad_area中,判断是否属于用户模式。如果是用户模式,调用__do_user_fault函数;否则调用__do_kernel_fault函数。

void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)

      if (user_mode(regs))

             __do_user_fault(tsk, addr, fsr, SIGSEGV, SEGV_MAPERR, regs);

      else

             __do_kernel_fault(mm, addr, fsr, regs);

__do_user_fault中,会发送信号给当前线程。

__do_kernel_fault则比较复杂:

l        调用fixup_exception进行修复操作,fixup的具体细节可在内核文档exception.txt中找到,它可用于处理get_user之类函数传入的地址参数无效的情况。

l        如果不能修复,调用die函数处理oops。

l        如果没有进程上下文,内核会在上一步的oops中panic。所以到这里肯定有一个进程与之关联,于是调用do_exit(SIGKILL)函数退出进程,SIGKILL会被设置在task_struct的exit_code域。

段表错误     do_translation_fault

do_translation_fault函数中,会首先判断引起abort的地址是否处于用户空间。

l        如果是用户空间地址,调用do_page_fault,转入和页表错误、页权限错误同样的处理流程。

l        如果是内核空间地址,会判断该地址对应的二级页表指针是否在init_mm中。如果在init_mm里面,那么复制该二级页表指针到当前进程的一级页表;否则,调用do_bad_area处理(可能会调用到fixup)。

对段表错误的处理逻辑的个人理解如下(不保证完全准确):
Linux产生段表错误,除了fixup之外还有两种原因:一个是用户空间映射的线性地址出现异常,另一个是内核中调用vmalloc分配的线性地址出现异常。对用户空间地址的异常处理很容易理解。对于内核地址,从vmalloc的实现代码中可以看到,它分配的线性空间的映射关系都会保存到全局变量init_mm中,所以,任何vmalloc生成的线性空间的二级页表都应该在init_mm中找到。(init_mm是内核的mm_struct,管理整个内核的内存映射)。

从这里也可以看出,对vmalloc的地址访问可能会产生两次异常:第一次是段表错误,生成二级页表;第二次是页表错误,分配真正的物理页面到线性空间。

关于init_mm的细节可以参考http://my.chinaunix.net/space.php?uid=25471613&do=blog&id=323374,大概意思是内核页表改变时只改变init进程的内核页表init_mm,其它进程通过缺页异常从init_mm更新自己维护的内核页表。

页表错误     do_page_fault

页权限错误 do_page_fault

do_page_fault完成了真正的物理页面分配工作,另外栈扩展、mmap的支持等也都在这里。对于物理页面的分配,会调用到do_anonymous_page->。。。-> __rmqueue,__rmqueue中实现了物理页面分配的伙伴算法。

如果当前没有足够物理页面供内存分配,即分配失败:

l        内核模式下的abort会调用__do_kernel_fault,这与段权限错误中的处理一样。

l        用户模式下,会调用do_group_exit退出该任务所属的进程。

用户程序申请内存空间时,如果库函数本身的内存池不能满足分配,会调用brk系统调用向系统申请扩大堆空间。但此时扩大的只是线性空间,直到真正使用到那块线性空间时,系统才会通过data abort分配物理页面。用户空间的malloc函数返回不为NULL只能说明得到了线性空间的资源,但物理内存可能并没有映射上去,所以真正物理内存分配失败时,进程还是会以资源不足为由,直接退出。

 

 

 

 

比如段错误:

 do_translation_fault

       do_bad_area

__do_kernel_fault

die("Oops", regs, fsr);

 

这里 fsr_info分类的几种错误类型,详细介绍请参考博文:

http://blog.csdn.net/walkingman321/article/details/6230334

http://blog.csdn.net/walkingman321/article/details/6238608

 

 

 

Linux Host "Abort command issued"

阅读数 3483

Istillinvestigatethisissue,anditnownarrowdownafterwehardwork.Thanksmyteammate.Somethingwealred

博文 来自: kinges

ARM Linux异常处理之data abort

阅读数 2245

本文简要分析了ARMLinux的dataabort异常处理过程,内核版本2.6.28,s3c6410平台。1异常向量与程序跳转dataabort是ARM体系定义的异常之一。异常发生时,ARM会自动跳转到异常向量表中,通过向量表中的跳转命令跳转到相应的异常处理中去。ARM的异常处理向量表在entry-armv.S文件中:.globl__vectors

博文 来自: coldsnow33

ARM Linux 异常处理 ---data abort

阅读数 3287

简要分析arm 数据异常的处理过程异常向量与程序跳转dataabort是ARM体系定义的异常之一。异常发生时,ARM会自动跳转到异常向量表中,通过向量表中的跳转命令跳转到相应的异常处理中去。ARM的异常处理向量表在entry-armv.S文件中:       .globl      __vectors_start__vectors_start:       swi

博文 来自: ee230

ARM/linux异常abort学习

阅读数 350

ARM定义了有七种异常,当有异常发生时,ARM会根据异常的类型自动执行异常向量表中的指令。这几种异常具体如下:reset     SVC+0x00undefine  UND+0x04SWI       SVC+0x08prefetch  ABT+0x0cdataabortABT+0x10IRQ       IRQ+0x18FIQ      

博文 来自: boyxulin1986

windows __asm int 3; linux abort()

阅读数 1

windows下直接用__asm("int3")是不标准的做法,应该是调用DebugBreak();linux下可以用abort();本文转自zhegaozhouji51CTO博客,原文链接:http://blog.51cto.com/1038741/1763687...

博文 来自: weixin_34210740
没有更多推荐了,返回首页