前言
要想使用 gdb
调试程序,必须让 gdb
程序和被调试程序建立联系,这种联系可以通过程序的可执行文件、core文件或者正在运行的进程来建立,具体调试的时候使用的选项不同,涉及到参数的传递,选项的顺序,多进程启动前的设置等等,接下来可以看一些常见用法。
测试样例
首先来写一段简单的但是会自动崩溃的代码,主要是为了展示core文件的调试方法,通过调试崩溃产生的core文件是一种很直接的查找问题的方法,可以帮助我们快速定位到问题的栈帧,进而找到具体的逻辑代码。
代码内容
新建文件 examplepro.cpp,编写代码内容如下:
1 |
|
代码编译
1 | g++ examplepro.cpp -o examplepro -g |
运行程序
1 | albert@home-pc:~/WorkSpace/cpp$ ./examplepro |
我们发现程序在运行之后发生了段错误,这是一种比较常见的BUG,通常由访问无效内存导致,查看程序目录下内容,多了一个叫 core
的文件。
1 | albert@home-pc:~/WorkSpace/cpp$ ls |
通过这一步你可能看不到这个 core
文件,需要检查两点,第一是编译的时候需要加 -g
选项,第二是使用 ulimit -c unlimited
命令设置core文件占用空间的最小限制,默认大小为0,也就是不产生 core
文件,需要改为 unlimited
才可以,如果你确定产生的 core
文件不会太大,也可以设置一个具体的数值。
使用gdb调试
有了上面的程序我们就可以进行调试了,因为已经产生了 core 文件,所以先来调试一下 core 文件,看下程序崩溃的原因。
使用gdb调试core文件
启动程序的语法如下,gdb
命令之后跟程序名,然后后面跟着 core 文件的名字:
1 | gdb examplepro core |
具体调试的时候需要换成自己的崩溃的程序名,而core文件大多数是 core.进程id
的形式。
调试过程
1 | albert@home-pc:~/WorkSpace/cpp$ gdb examplepro core |
从调试信息来看一下就定位到了问题,在代码的第15行发生了段错误,也就是我们刚刚给野指针赋值的代码。
使用gdb直接启动程序
这种情况就是调试运行,相当于在 gdb
的监控下启动程序,一旦发生错误,gdb
会给出响应的提示,启动方式很简单,gdb
命令之后直接跟着程序名字就可以了。
1 | gdb examplepro |
调试过程
1 | albert@home-pc:~/WorkSpace/cpp$ gdb examplepro |
这种情况下,启动之后需要输入 run
命令才可以运行程序,这时发现程序又崩溃了。
如果被调试的程序有参数的话,需要将启动的命令进行修改,写成 gdb --args examplepro testparam1
,加上 --args
选项,然后将参数罗列在后面就好了,因为看这些声明很麻烦,我们利用之前学过的 -q
选项来屏蔽启动说明,测试如下:
1 | albert@home-pc:~/WorkSpace/cpp$ gdb -q --args examplepro NB |
还有一种写法就是启动 gdb 之后再传参数,具体操作方法如下:
1 | albert@home-pc:~/WorkSpace/cpp$ gdb -q examplepro |
这种情况是先启动 gdb,然后在执行 run
命令的时候传递参数。
使用gdb调试正在运行的文件
这时需要获得被套是程序的进程id,可以使用 ps
、top
或者 pidof
命令来获取进程id,然后通过 attch
的方式附加到进程。
比如查到需要调试的 examplepro 程序进程号是 3598,那么可以直接启动 gdb
附加到这个进程:
1 | gdb examplepro 3598 |
也可以先启动 gdb
,然后使用 attach
命令附加到进程:
1 | albert@home-pc:~/WorkSpace/cpp$ gdb -q examplepro |
如果此时提示进程拒绝被附加通常是权限问题,可以使用所属账号调试,或者可以尝试 sudo
命令。
语法对比
常见的调试方式就文中提到的这几种,特整理成表格方便对比和查找:
语法 | 解释 |
---|---|
gdb examlepro |
直接 gdb 调试启动 |
gdb examlepro core.3598 |
调试崩溃的 core 文件 |
gdb examlepro 3598 gdb -p 3598 |
附加到正在运行的程序进程上 |
gdb attach 3598 |
先启动gdb,后附加到程序上 |
总结
- gdb 不但可以调试 core 文件,还可以调试正在运行的程序,这对于难重现的 bug 来说非常有帮助
- 在调试正在运行的程序时可以使用
pidof
命令来直接获取被调试程序的进程号 - gdb 调试附加的进程的时候要注意权限问题,如果不成功可以尝试 sudo 命令
==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==
兜兜转转又换了一个住所,匆匆忙忙如蝼蚁般迁徙,路程短了,可选的路却少了。回头看看,一个窝、一段事、一群人而已~
2020-8-25 00:24:01