您的位置:首页 > 运维架构 > Linux

关于Segmentation fault (core dumped)几个简单问题

2017-08-09 17:09 435 查看
有的程序可以通过编译,但在运行时会出现Segment fault(段错误)。这通常都是指针错误引起的。但这不像编译错误一样会提示到文件一行,而是没有任何信息。一种办法是用gdb的step, 一步一步寻找。但要step一个上万行的代码让人难以想象。 我们还有更好的办法,这就是core file。
如果想让系统在信号中断造成的错误时产生core文件, 我们需要在shell中按如下设置:#设置core大小为无限 ulimit -c unlimited#设置文件大小为无限 ulimit unlimited发生core dump之后,用gdb进行查看core文件的内容, 以定位文件中引发core dump的行:gdb [exec file] [core file]如: gdb ./test test.core 在进入gdb后, 用bt命令查看backtrace以检查发生程序运行到哪里,来定位core dump的文件->行。另外需要注意的是,如果你的机器上跑很多的应用,你生成的core又不知道是哪个应用产生的,你可以通过下列命令进行查看:file core 几个问题:1. 什么是Core:在使用半导体作为内存的材料前,人类是利用线圈当作内存的材料(发明者为王安),线圈就叫作 core ,用线圈做的内存就叫作 core memory。如今 ,半导体工业澎勃发展,已经没有人用 core memory 了,不过,在许多情况下,人们还是把记忆体叫作 core 。2. 什么是Core Dump:我们在开发(或使用)一个程序时,最怕的就是程序莫明其妙地当掉。虽然系统没事,但我们下次仍可能遇到相同的问题。于是这时操作系统就会把程序当掉 时的内存内容 dump 出来(现在通常是写在一个叫 core 的 file 里面),让 我们或是 debugger 做为参考。这个动作就叫作 core dump。 3. Core Dump时会生成何种文件:Core Dump时,会生成诸如 core.进程号 的文件。 4. 为何有时程序Down了,却没生成 Core文件。Linux下,有一些设置,标明了resources available to the shell and to processes。 可以使用#ulimit -a 来看这些设置。 (ulimit是bash built-in Command)从这里可以看出,如果 -c是显示:core file size。如果这个值为0,则无法生成core文件。所以可以使用:#ulimit -c 1024 或者 #ulimit -c unlimited 来使能 core文件。如果程序出错时生成Core 文件,则会显示Segmentation fault (core dumped) 。 5. Core Dump的核心转储文件目录和命名规则:/proc/sys/kernel /core_uses_pid可以控制产生的core文件的文件名中是否添加pid作为扩展,如果添加则文件内容为1,否则为0可通过以下命令修改此文件:echo "1" > /proc/sys/kernel/core_uses_pid 6. 如何使用Core文件:在linux下,使用:#gdb -c core.pid program_name就可以进入gdb模式。输入where,就可以指出是在哪一行被Down掉,哪个function内,由谁调用等等。(gdb) where或者输入 bt。(gdb) bt7. 如何让一个正常的程序down:#kill -s SIGSEGV pid8. 察看Core文件输出在何处:存放Coredump的目录即进程的当前目录,一般就是当初发出命令启动该进程时所在的目录。但如果是通过脚本启动,则脚本可能会修改当前目录,这时进程真正的当前目录就会与当初执行脚本所在目录不同。这时可以查看”/proc/<进程pid>/cwd“符号链接的目标来确定进程真正的当前目录地址。通过系统服务启动的进程也可通过这一方法查看。proc/sys/kernel /core_pattern可以控制core文件保存位置和文件名格式。可通过以下命令修改此文件:echo "/corefile/core-%e-%p-%t" >core_pattern可以将core文件统一生成到/corefile目录下,产生的文件名为core-命令名-pid-时间戳以下是参数列表: %p - insert pid into filename 添加pid%u - insert current uid into filename 添加当前uid%g - insert current gid into filename 添加当前gid%s - insert signal that caused the coredump into the filename 添加导致产生core的信号%t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间 %h - insert hostname where the coredump happened into filename 添加主机名%e - insert coredumping executable name into filename 添加命令名 在Linux下要保证程序崩溃时生成 Coredump要注意这些问题:一、要保证存放Coredump的目录存在且进程对该目录有写权限。存放Coredump 的目录即进程的当前目录,一般就是当初发出命令启动该进程时所在的目录。但如果是通过脚本启动,则脚本可能会修改当前目录,这时进程真正的当前目录就会与当初执行脚本所在目录不同。这时可以查看”/proc/进程pid>/cwd“符号链接的目标来确定进程真正的当前目录地址。通过系统服务启动的进程也可通过这一方法查看。二、若程序调用了seteuid()/setegid()改变了进程的有效用户或组,则在默认情况下系统不会为这些进程生成Coredump。很多服务程序都会调用seteuid(),如MySQL,不论你用什么用户运行 mysqld_safe启动mysql,mysqld进行的有效用户始终是msyql用户。如果你当初是以用户A运行了某个程序,但在ps里看到的这个程序的用户却是B的话,那么这些进程就是调用了seteuid了。为了能够让这些进程生成core dump,需要将/proc/sys/fs/suid_dumpable 文件的内容改为1(一般默认是0)。三、这个一般都知道,就是要设置足够大的Core文件大小限制了。程序崩溃时生成的 Core文件大小即为程序运行时占用的内存大小。但程序崩溃时的行为不可按平常时的行为来估计,比如缓冲区溢出等错误可能导致堆栈被破坏,因此经常会出现某个变量的值被修改成乱七八糟的,然后程序用这个大小去申请内存就可能导致程序比平常时多占用很多内存。因此无论程序正常运行时占用的内存多么少,要保证生成Core文件还是将大小限制设为unlimited为好。四、异常退出就一定会生成core吗? 难道没有不生成core的异常退出?如果不是正常退出的那就是有信号引起的程序退出,有些信号确实能引起程序退出但不生成core。SIGHUP 终止进程 终端线路挂断SIGINT 终止进程 中断进程SIGQUIT 建立CORE文件终止进程,并且生成core文件SIGILL 建立CORE文件 非法指令SIGTRAP 建立CORE文件 跟踪自陷SIGBUS 建立CORE文件 总线错误SIGSEGV 建立CORE文件 段非法错误SIGFPE 建立CORE文件 浮点异常SIGIOT 建立CORE文件 执行I/O自陷SIGKILL 终止进程 杀死进程SIGPIPE 终止进程 向一个没有读进程的管道写数据SIGALARM 终止进程 计时器到时SIGTERM 终止进程 软件终止信号SIGSTOP 停止进程 非终端来的停止信号SIGTSTP 停止进程 终端来的停止信号SIGCONT 忽略信号 继续执行一个停止的进程SIGURG 忽略信号 I/O紧急信号SIGIO 忽略信号 描述符上可以进行I/OSIGCHLD 忽略信号 当子进程停止或退出时通知父进程SIGTTOU 停止进程 后台进程写终端SIGTTIN 停止进程 后台进程读终端SIGXGPU 终止进程 CPU时限超时SIGXFSZ 终止进程 文件长度过长SIGWINCH 忽略信号 窗口大小发生变化SIGPROF 终止进程 统计分布图用计时器到时SIGUSR1 终止进程 用户定义信号1SIGUSR2 终止进程 用户定义信号2SIGVTALRM 终止进程 虚拟计时器到把可能的信号都设置上句柄,看是那种情况。
Segmentation fault(段错误)是由于虚拟内存管理单元的异常所致,而该异常则通常是由于解引用一个未初始化或非法值的指针引起的。Linux中提供了core dump的功能,使得对这类错误的调试更为容易。
一般情况下,linux系统是不允许产生core文件的,因此首先要解除这个限制:ulimit -c unlimited接下来,运行含segmentation fault的段程序,如:./test这时,segmentation fault的错误信息会显示为:Segmentation fault (core dumped)在该文件夹下会出现一个名为core的文件使用生成的core文件进行调试gdb test core(gdb) bt#0 0x00a5c920 in ?? () from /lib/i386-linux-gnu/libc.so.6
#1 0x00a5ca0d in exit () from /lib/i386-linux-gnu/libc.so.6
#2 0x00a4311b in __libc_start_main () from /lib/i386-linux-gnu/libc.so.6
#3 0x080483d1 in _start ()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux kernel