使用GDB调试程序一般有三种方式:
gdb filename
gdb attach pid
dgb filename corename
也对应这本节课的核心内容:
直接调试目标程序
附加进程
调试core文件
接下来我们逐一讲解。
2.1直接调试目标程序
在开发阶段或者研究别人的项目时,当编译成功生成目标二进制文件后,可以使用gdb filename直接启动这个程序的调试,其中filename是需要启动的调试程序文件名,这种方式是直接使用GDB启动一个程序进行调试。注意这里说的启动一个程序进行调试其实不严谨,因为实际上只是附加了一个可执行文件,并没有把程序启动起来;接着需要输入run命令,程序才会真正的运行起来;接着需要输入run命令,程序才会真正的运行起来。关于run命令后面的课程中会详细介绍。上一课的GDB调试hello_server系列就是使用的这种方式。
假设现在有一个程序叫fileserver,使用gdb fileserver附加该程序,然后使用run面过了启动该程序。如下图所示:
2.2附加进程
在某些情况下,一个程序已经启动了,我们向调试这个程序,但是又不想重启这个程序。假设有这样一个场景,我们的测试服务器程序正在运行,运行一段时间之后,发现这个服务器不能接受新的客户端连接了,这时肯定是不能重启的,如果重启,当前程序的各种状态信息就丢失了。怎么办呢?可以使用gdb attach 进程ID来将GDB调试器附加到测试服务器程序上。例如,假设聊天程序叫myserver,可以使用ps命令获取进程的PID,然后使用gdb attach就可以调试了,操作如下:
[email protected]:~/Desktop/unimrcp-1.5.0-client-build-dir/unimrcp/bin$ ps -ef | grep unimrcpserver wzq 23316 23213 0 18:10 pts/1 00:00:00 ./unimrcpserver wzq 23339 23329 0 18:10 pts/2 00:00:00 grep unimrcpserver
实际执行如下图所示:
通过以上代码得到myserver的PID为23329,然后使用gdb attach 23329把GDB附加到myserver进程中,操作并输入如下:
当提示“Attaching to process 23940”时就说明我们已经成功地将GDB附加到目标程序进程了。需要注意的是,程序使用了一些系统库(如libc.so),由于这时发行版本的Linux系统,这些库是没有调试符号的,因而GDB会提示找不到这些库的调试符号。因为目的是调试myserver,对系统API调用的内部实现并不关注,所以这些提示可以不用关注,只要myserver这个文件有调试信息即可。
当用gdb attach上目标进程后,调试器会暂停下来,此时可以使用continue命令让程序继续运行,或者加上相应的断电再继续运行程序(这里提到的continue命令不熟悉也没有关系,后续会详细介绍这些命令的使用方法)。
当调试完程序想结束此调试时,而且不对当前进程myserver有任何影响,也就是说想让这个程序继续运行,可以在GDB的命令界面输入detach命令让程序与GDB调试器分离,这样myserver就可以继续运行了:
然后再退出GDB就可以了:
2.3调试生成core文件
有时候,服务器程序运行一段时间后会突然崩溃,这并不是我们希望看到的,需要解决这个问题。只要程序在崩溃的时候有 core 文件产生,就可以使用这个 core 文件来定位崩溃的原因。当然,Linux 系统默认是不开启程序崩溃产生 core 文件这一机制的,我们可以使用 ulimit -c 命令来查看系统是否开启了这一机制。
发现 core file size 那一行默认是 0,表示关闭生成 core 文件,可以使用“ulimit 选项名 设置值”来修改。例如,可以将 core 文件生成改成具体某个值(最大允许的字节数),这里我们使用 ulimit -c unlimited(unlimited 是 -c 选项值)直接修改成不限制大小。
还有一个问题就是,这样修改以后,当我们关闭这个 Linux 会话,设置项的值就会被还原成 0,而服务器程序一般是以后台程序(守护进程)长周期运行,也就是说当前会话虽然被关闭,服务器程序仍然继续在后台运行,这样这个程序在某个时刻崩溃后,是无法产生 core 文件的,这种情形不利于排查问题。因此,我们希望这个选项永久生效,永久生效的方式是把“ulimit -c unlimited”这一行加到 /etc/profile 文件中去,放到这个文件最后一行即可。
原文地址:https://www.cnblogs.com/wzqstudy/p/10235007.html