debug-段错误

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/andrewgithub/article/details/86634840

大多数的linux发型版本关闭了内核转存储功能,使用:

ulimit  -c 

查看自己的linux内核是否关闭了核心转存储功能;

andrew@andrew-Thurley:/proc/net$ ulimit -c
0

输出为0 说明内核关闭了核心转存储功能,-c选项表示内核转存储文件的大小限制,使用如下命令可以放开内核转存储功能:

ulimit -c unlimited

这个命令是不限制内核转存储文件的大小,但是内存有限的情况下可能会想限制一下内核转存储文件的大小,可以使用以下命令设置内核转存储文件的大小,如下命令限制内核转存储文件的大小为1G;

ulimit -c 1073741824
  1. ulimit -c

查看系统的核心转存储是否被限制为0 ,若是被限制为0使用

  1. ulimit -c unlimited

将核心转存储设置为无限制

  1. 编译程序加上-g 选项

  2. 调试
    要想使用GDB调试内核转存储文件,应当以以下方式启动GDB

gdb -c core文件 ./a.out

在使用大型文件系统时,会希望将内核转存储放在固定的位置。默认情况下会在当前目录下生成,但是可能很难弄清文件在哪在哪生成。这种情况下可以配置/etc/systl.conf文件,来决定文件的生成目录和文件的命名;

例如在/etc/systl.conf 文件中添加如下内容:
kernel.core_pattern = /var/core/%t-%e-%p-%c.core
kernel.core_uses_pid = 0
然后执行

扫描二维码关注公众号,回复: 6206264 查看本文章

sysctl -p

上述生成核心转存储文件的命名:
时刻-进程名-PID-内核转存储最大大小.core
kernel.core_pattern中可以设置的格式符:

格式符                    说明
%%		          %字符自身
%p                        被转存储进程的进程ID(PID)
%u                        被转存储进程的真实用户ID(real UID)
%g                        被转存储进程的真实组ID(real GID)
%s                        引发转存储的信号编号
%t                        转存储时刻(从1970年1月1日 0:00 开始的秒数)
%h                        主机名(同uname(2)返回的nodename)
%e                        可执行文件名
%c                        转存储文件的大小上限(内核版本2.6.24以后可以使用)

kernel.core_uses_pid = 0 设置为0是因为我们改变了文件名中的PID的位置,如果设置该值为1,文件名末尾就会添加.PID


segment.c文件示例

andrew@andrew-Thurley:/work/linux-sys/DEBUG/segmentation$ gdb -c core ./segment
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./segment...done.
[New LWP 7103]
Core was generated by `./segment'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00000000004004ed in main (argc=1, argv=0x7ffcab228948) at segment.c:16
16	    (*a) = 1;
(gdb) bt full
#0  0x00000000004004ed in main (argc=1, argv=0x7ffcab228948) at segment.c:16
        a = 0x0
(gdb) bt
#0  0x00000000004004ed in main (argc=1, argv=0x7ffcab228948) at segment.c:16
(gdb) frame 0
#0  0x00000000004004ed in main (argc=1, argv=0x7ffcab228948) at segment.c:16
16	    (*a) = 1;

(gdb) disassemble 0x00000000004004ed
Dump of assembler code for function main:
   0x00000000004004d6 <+0>:	push   %rbp
   0x00000000004004d7 <+1>:	mov    %rsp,%rbp
   0x00000000004004da <+4>:	mov    %edi,-0x14(%rbp)
   0x00000000004004dd <+7>:	mov    %rsi,-0x20(%rbp)
   0x00000000004004e1 <+11>:	movq   $0x0,-0x8(%rbp)
   0x00000000004004e9 <+19>:	mov    -0x8(%rbp),%rax
=> 0x00000000004004ed <+23>:	movl   $0x1,(%rax)
   0x00000000004004f3 <+29>:	mov    $0x0,%eax
   0x00000000004004f8 <+34>:	pop    %rbp
   0x00000000004004f9 <+35>:	retq   
End of assembler dump.
(gdb) list
11	
12	    int *a = NULL;
13	
14	
15	
16	    (*a) = 1;
17	
18	
19	
20	    return 0;

GDB list命令可以查看函数周围的源代码

可以看出代码在中为指向NULL的指针赋值,产生段错误;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
加粗样式
4.使用内核转储掩码来排除要转储的内存块
你可能会因为不希望设置ulimit 的时候太僵硬导致空间不够没有得到完整的转储,所以设置ulimit 为"unlimited" (不限制)。但是如果执行一个占用内存很恐怖的程序,当这个程序内核转储的时候也就会生成体积很恐怖的转储文件。

为了避免这种情况,可以指定内核转储掩码来排除要转储的内存段。

掩码请查看/usr/src/linux/Documentation/sysctl/kernel.txt 中的3.4 小节,没有内核源码可以到这里的网络版,这里摘录出来如下:

The following 7 memory types are supported:

  • (bit 0) anonymous private memory(匿名私有内存段)
  • (bit 1) anonymous shared memory(匿名共享内存段)
  • (bit 2) file-backed private memory(file-backed 私有内存段)
  • (bit 3) file-backed shared memory(file-bakced 共享内存段)
  • (bit 4) ELF header pages in file-backed private memory areas (it is
    effective only if the bit 2 is cleared)(ELF 文件映射,只有在bit 2 复位的时候才起作用)
  • (bit 5) hugetlb private memory(大页面私有内存)
  • (bit 6) hugetlb shared memory(大页面共享内存)

设置方法很简单:找到程序的PID,然后修改/proc/PID/coredump_filter 的值。

如果你要设置某些还没有运行的进程的内核转储掩码,请修改/proc/self/coredump_filter 的值。

PS:

a. 默认的coredump_filter 的值一般是0x23,至于代表什么,请换成二进制00100011,从右向左看,bit 0、bit 1、bit 5 被置位,也就是说会转储所有的匿名内存段和大页面私有内存段。

b. 共享内存段都是一样的,可以不必转储。

  1. 在系统中全局设置转储功能
    全局设置没有什么好说的,把你的配置写入/etc/profile.d/ 目录下任意一个新建的文件当中,别忘了设置属组和所有者为root:root,权限为751。

根据上面说的,写入的要有一条ulimit 指令,可能还有一条sysctl 指令,最后可能还有一条cat 指令。

更多的设置请查看上面提到的kernel.txt 和proc.txt,例如你想把SUID 程序也转储,你需要

sysctl -w 'fs.suid_dumpable=1'

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/andrewgithub/article/details/86634840