GDB 调试调用可执行文件
文章目录
起因是因为在运行一份可执行文件的时候,包错:
Not supported!
Segmentation fault (core dumped)
因为看不懂,所以希望能弄明白到底是什么问题导致的这个,于是开始搜。
网上其实这方面得教程挺多的,下面列了一些,大家自取:
- 使用coredump帮助解决segmentation fault的问题
- linux下生成core dump方法与gdb解析core dump文件
- coredump详解
其实主要就是先找到这个 coredump 文件。我也看了办天,最后兜兜转转的让它出来了。
下面记录一下我这里的历程。
检查是否开启 coredump 功能
如果该功能没有开启,那么生成不了文件的。以我的一个可执行文件为例:
这个可执行文件所在的目录是:
/home/be/workspace/BionicEyes/bin/
那么首先需要确认当前会话的 core dump 功能是否开启,0为关闭:
cd /home/be/workspace/BionicEyes/bin/
// 然后再运行网上的那些命令
ulimit -c
0
可以直到当前可执行文件的 core dump 功能处于关闭状态。
此时运行这个命令:
ulimit -c unlimited
即可对生成的core dump文件大小不做限制。
但是ulimit的作为范围是当前shell进程及其派生出的子进程,如果用户同时运行了两个shell终端进程,只是在其中一个环境中设置了ulimit -c unlimited,那只会在该进程里创建的core dump文件生效,另一个shell终端及其上运行的子进程都不会受其影响。
要想在全部shell窗口生效,需要修改/etc/profile文件:
在 /etc/profile 中添加:
ulimit -c unlimited
// 保存并关闭之后
source /etc/profile
在所有shell窗口中生效。
先找到 core_pattern
找这份文件其实简单,一般路径都是在根目录的 /proc/sys/kernel/core_pattern 路径下面。
网上有的教程推荐是对它进行编写,将 coredump 文件保存在别的目录下。我这里尝试过,如果使用 echo 命令,那么命令的权限不够,即便使用 sudo 权限同样不够,因此改变了方法。
这个方法同样也是修改 coredump 文件的保存目录,只不过是修改了 /etc/sysctl.conf 路径的这个文件。
还是参考这篇博客:Linux下更改 coredump文件生成路径
临时的方法就是上面说的拿个,权限不够,因此采用永久方法。
在 /etc/sysctl.conf 文件中添加如下一行:
kernel.core_pattern = /var/crash/%t-%e-%p-%c.core //这个属于我自己的路径,大家可以自行更改。
里面字符的意思可以参考上面的博客。
然后再运行:
sudo sysctl -p
这样就能实现永久修改 coredump 文件的路径啦。之后运行程序崩溃时会在 /var/crash 目录下生成对应的 coredump 文件,例如:
其中 ! 表示 / ,所以这个文件其实就是在路径 /home/be/workspace/BionicEyes/bin/ 目录下面的可执行文件的 coredump 文件。
coredump 被 ubuntu 系统中 apport.service 服务程序自动处理
这个是因为什么呢?
ubuntu 系统默认情况下,开启了一种服务程序 apport.service。即自动生成崩溃报告,官方为了自动收集错误的。
在查看 core_patten 文件时,结果如下:
cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c %d %P
表示由 apport 来处理 coredump 文件;
处理的方法: 可以关闭系统的 apport.service 服务程序(注意:这种方法只是一种临时关闭的,当系统重启后,apport.service 服务程序又会开启)。
输入如下命令,可以临时关闭该服务:
sudo service apport stop //关闭错误报告
永久关闭 apport,修改 /etc/default/apport,设置 enabled =0
之后,重启 Ubuntu,apport 就不会再启动了。
导致coredump的常见原因分析
- 内存访问越界
使用错误的下标,导致数组访问越界; - 多线程程序使用了线程不安全的函数
- 多线程读写的数据没有加锁保护;
- 非法指针
a) 使用空指针,
b) 随意使用指针转换; - 堆栈溢出
不要使用大的局部变量(因为局部变量都分配在栈上),容易造成堆栈溢出,破坏系统的栈和堆结构,导致莫名其妙的错误。
使用 GDB and 常用的几个GDB命令
在可执行文件所在文件夹进入终端,输入 gdb ,可以进入对应的调试环境:
然后在(gdb)后面输入对应的命令调试即可。
- l(list):显示源代码,可以看到对应的行号;
- b(break) N:N是行号,表示在对应的行号处设置断点;
- p(print) X:X是变量名,表示打印变量X的值;
- r(run) :继续执行到断点的位置
- n(next):单步执行下一步
- c(continue):继续执行;
- q(quit):退出gdb;
- backtrace:查看出错前的函数调用栈信息;
- info threads:查看所有线程正在运行的指令信息;
- thread apply all bt:打开所有线程的堆栈信息;
- thread apply threadID bt:查看指定线程堆栈信息(threadID 为第几个堆栈的数字);
例如: