Linux平台Segmentation fault(段错误)调试方法
1. 段错误是什么
一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址、访问了系统保护的内存地址、访问了只读的内存地址等等情况。
2. 段错误的原因
段错误,英文segmentation fault
- 段错误的定义
- segementation fault (often shortened to segfault) or access violation
- often raised by hardware with memory protection, notifying an operation system(OS) the software has attempted to access a restricted area of memory.
段错误常见于提供低级别的内存访问机制(如C语言)的语言程序中,通常由非法访问导致,即错误地使用指针访问虚拟内存。
原因列举
- 对空指针赋值——由内存管理硬件所导致
- 尝试去访问一个不存在的内存地址(超出进程分配的地址)
- 尝试去访问程序无权限访问的地址(如进程上下文中的内核结构(kernel structures))
- 尝试去访问只读的内存(如代码段)
对应着程序中的情况分别为:
- 引用或者赋值一个为初始化的指针(野指针(wild pointer),随机指向一个内存地址)
- 引用或者赋值一个已经被free的指针(dangling pointer,指向一个已经被freed/deallocated/deleted的内存地址)
- A buffer overflow
- A stack overflow
3. 段错误信息的获取
3.1 dmesg
dmesg可以在应用程序crash掉时,显示内核中保存的相关信息。如下所示,通过dmesg命令可以查看发生段错误的程序名称、引起段错误发生的内存地址、指令指针地址、堆栈指针地址、错误代码、错误原因等。
3.2 -g
使用gcc编译程序的源码时,加上-g参数,这样可以使得生成的二进制文件中加入可以用于gdb调试的有用信息。
3.3 nm
使用nm命令列出二进制文件中的符号表,包括符号地址、符号类型、符号名等,这样可以帮助定位在哪里发生了段错误。
3.4 ldd
使用ldd命令查看二进制程序的共享链接库依赖,包括库的名称、起始地址,这样可以确定段错误到底是发生在了自己的程序中还是依赖的共享库中。
4. 段错误的调试方法
4.1 使用gcc和gdb
4.1.1 调试步骤
为了能够使用gdb调试程序,在编译阶段加上-g参数,以程序segfault3.c为例。
root@twq2018:~/segfault$ gcc -g -o segfault3 segfault3.c
root@twq2018:~/segfault$ gdb ./segfault3
(gdb) run
Starting program: /home/twq/segfault/segfault3 Program received signal SIGSEGV, Segmentation fault.
0x001a306a in memcpy () from /lib/tls/i686/cmov/libc.so.6
(gdb)
从输出看出,程序segfault3.c收到SIGSEGV信号,触发段错误,并提示地址0x001a306a、调用memcpy报的错,位于/lib/tls/i686/cmov/libc.so.6库中。
4.1.2 适用场景
1、仅当能确定程序一定会发生段错误的情况下使用。
2、当程序的源码可以获得的情况下,使用-g参数编译程序。
3、一般用于测试阶段,生产环境下gdb会有副作用:使程序运行减慢,运行不够稳定,等等。
4、即使在测试阶段,如果程序过于复杂,gdb也不能处理。
4.2 使用gdb和core文件
在4.1节中提到段错误会触发SIGSEGV信号,通过man 7 signal,可以看到SIGSEGV默认的handler会打印段错误出错信息,并产生core文件,由此我们可以借助于程序异常退出时生成的core文件中的调试信息。
使用gdb工具来调试程序中的段错误,用bt命令查看backtrace以检查发生程序运行到哪里, 来定位core dump的文件->行.。
4.2.1 调试步骤
1、在一些Linux版本下,默认是不产生core文件的,首先可以查看一下系统core文件的大小限制:
root@twq2018:~/segfault$ ulimit -c
0
2、可以看到默认设置情况下,本机Linux环境下发生段错误时不会自动生成core文件,下面设置下core文件的大小限制(单位为KB),其中使用ulimit -c unlimited来设置无限大,则任意情况下都会产生core文件。
root@twq2018:~/segfault$ ulimit -c 1024
root@twq2018:~/segfault$ ulimit -c
1024
3、运行程序segfault3.c,发生段错误生成core文件:
root@twq2018:~/segfault$ ./segfault3
段错误 (core dumped)
3、加载core文件,使用gdb工具进行调试:
root@twq2018:~/segfault$ gdb ./segfault3 ./core
4.2.2 适用场景
1、适合于在实际生成环境下调试程序的段错误(即在不用重新发生段错误的情况下重现段错误)。
2、当程序很复杂,core文件相当大时,该方法不可用。
4.3 使用objdump
4.3.1 调试步骤
1、使用dmesg命令,找到最近发生的段错误输出信息:
root@twq2018:~/segfault$ dmesg
... ...
[17257.502808] segfault3[3320]: segfault at 80484e0 ip 0018506a sp bfc1cd6c error 7 in libc-2.10.1.so[110000+13e000]
其中,对我们接下来的调试过程有用的是发生段错误的地址:80484e0和指令指针地址:0018506a。
2、使用objdump生成二进制的相关信息,重定向到文件中:
root@twq2018:~/segfault$ objdump -d ./segfault3 > segfault3Dump
其中,生成的segfault3Dump文件中包含了二进制文件的segfault3的汇编代码。
3、在segfault3Dump文件中查找发生段错误的地址:
root@twq2018:~/segfault$ grep -n -A 10 -B 10 "80484e0" ./segfault3Dump
121- 80483df: ff d0 call *%eax
122- 80483e1: c9 leave
123- 80483e2: c3 ret
124- 80483e3: 90 nop
125-
126-080483e4 <main>:
127- 80483e4: 55 push %ebp
128- 80483e5: 89 e5 mov %esp,%ebp
129- 80483e7: 83 e4 f0 and $0xfffffff0,%esp
130- 80483ea: 83 ec 20 sub $0x20,%esp
131: 80483ed: c7 44 24 1c e0 84 04 movl $0x80484e0,0x1c(%esp)
132- 80483f4: 08
133- 80483f5: b8 e5 84 04 08 mov $0x80484e5,%eax
134- 80483fa: c7 44 24 08 05 00 00 movl $0x5,0x8(%esp)
135- 8048401: 00
136- 8048402: 89 44 24 04 mov %eax,0x4(%esp)
137- 8048406: 8b 44 24 1c mov 0x1c(%esp),%eax
138- 804840a: 89 04 24 mov %eax,(%esp)
139- 804840d: e8 0a ff ff ff call 804831c <memcpy@plt>
140- 8048412: c9 leave
141- 8048413: c3 ret
通过对以上汇编代码分析,得知段错误发生main函数,对应的汇编指令是movl $0x80484e0,0x1c(%esp),接下来打开程序的源码,找到汇编指令对应的源码,也就定位到段错误了。
4.3.2 适用场景
1、不需要-g参数编译,不需要借助于core文件,但需要有一定的汇编语言基础。
2、如果使用了gcc编译优化参数(-O1,-O2,-O3)的话,生成的汇编指令将会被优化,使得调试过程有些难度。
参考:https://www.cnblogs.com/lidabo/p/5014591.html
Linux平台Segmentation fault(段错误)调试方法相关推荐
- 几种Linux段错误调试方法
一.产生段错误的原因 段错误就是指某一进程访问了不属于它权限范围的内存空间,比如:访问了不存在的内存,访问了受系统保护的内存,访问了只读的内存等.下面是一段会产生段错误的实例代码:main.c #in ...
- Segmentation fault段错误出现原因分析及解决方法笔记
Segmentation fault段错误出现原因分析及解决方法 1.局部变量的大小过大,超过栈分配的空间导致段错误,如double a[500][500], 解决方法:大数据不要放在栈区中,可以考虑 ...
- 关于Segmentation fault(段错误)探究
在rhel5.4上用GCC编程好长时间了(其实也就1个多月!),经常遇到这种情况:一个程序编译没有任何问题,当执行 ./a.out的时候出现:"Segmentation fault(段错误) ...
- Linux下的段错误调试方法
转自http://wenku.baidu.com/view/7416d23710661ed9ad51f33f.html 执行socket文件时,出现段错误 (core dumped) 产生段错误就是访 ...
- 偶然出现 segmentation fault 时的调试方法与 SIGSEGV 信号
问题描述 最近遇到一个 bug,有一定的偶然性会出现段错误.第一步需要确定的是段错误出现在哪里.可由于这个 bug 的偶然性,常规的方法无法确定问题. 根据经验,这个问题有两个方案可以使用. 生成 c ...
- python遇到Segmentation fault (core dumped)调试方法
python3执行某一个程序时,报Segmentation fault (core dumped)错,但没有告知到底哪里出错,无法查问题 同时在根目录下生成core文件,典型的可以用gdb进行调试.这 ...
- linux段错误core dumped,Linux下Segmentation fault(core dumped)简单调试方法
** 什么是Segmentation fault? ** Segmentation fault就是段错误,一般指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保 ...
- Linux内存不够调试,Linux系统内存错误调试方法
而言之,产生段错误就是访问了错误的内存段,一般是你没有权限,或者根本就不存在对应的物理内存,尤其常见的是访问0地址. 一般来说,段错误就是指访问的内存超出了系统所给这个程序的内存空间,通常这个值是由g ...
- Linux下如何生成core dump 文件(解决segment fault段错误的问题)
Linux下如何生成core dump 文件(解决segment fault段错误的问题) 参考文章: (1)Linux下如何生成core dump 文件(解决segment fault段错误的问题) ...
最新文章
- 第十六届全国大学生智能车汽车竞赛第二次扩大会议
- [备忘]silverlight中关于“复制到输出目录”和“生成操作”
- 设计模式---建造者模式(DesignPattern_Builder)
- vivado实现VGA
- C#综合揭秘——细说多线程(上)
- 从《王者荣耀》来聊聊游戏的帧同步
- 0-1背包问题 题目:国王和金矿问题 描述:有一个国家发现了max_n座金矿,参与挖矿工人的总数是max_people人。每座金矿的黄金储量不同为一维数组gold[],需要参与挖掘的工人数也不同为一维
- Java生鲜电商平台-缓存架构实战
- springboot 上传文件_基于SpringBoot的文件上传
- 配置 jvisualvm 监控Java虚拟机
- mybatis3 配置文件解析
- EditorGridPanel 中使用checkbox列,并包含afterEdit事件
- Illustrator中文版教程,如何在AI中以不同的方式组合形状?
- java file 其他电脑上_将MultipartFile转换为java.io.File而不复制到本地计算机
- 冲压模具设计之弹簧导套连续拉深模具设计方法
- Linux实战教学笔记18:linux三剑客之awk精讲
- 重置SMC与重置NVRAM(PRAM)
- 基于Cisco Packet Tracer的中小型网吧组网设计方案
- 免费的几款内网穿透工具
- lvgl cont(容器)