【C++|Linux系统编程】GDB调试
目录一、 GDB简介二、安装与基本配置三、 基本命令与使用四、GDB初步使用五、进阶调试技巧5.1 调试core dump程序5.2 调试正在运行中的程序5.3 调试多进程程序5.4 调试多线程5.5 死锁调试5.6 内存泄漏调试六、更多调试例子可以看这篇博客参考文献一、 GDB简介GNU Debugger简称GDB是GNU项目开发的一款功能强大的命令行调试工具。GDB支持多种编程语言C、C、Go、Rust等和多种处理器架构x86、ARM等是系统程序员和应用程序开发者的必备工具。学习GDB调试最好的教程就是官方文档 https://sourceware.org/gdb/documentation/。但对于小白直接上手常看官方文档是有难度的通关这篇博客带大家入个门使大家能对GDB调试有个基本的掌握然后再通过官方文档进行查漏补缺。二、安装与基本配置1、安装GDB在大多数Linux发行版上GDB可以通过包管理器安装sudoapt-getinstallgdb# Debian/Ubuntusudoyuminstallgdb#CentOS/Redhat2、编译可调试的程序要使用GDB调试程序需要在编译时加入调试信息使用-g选项gcc-g program.c-o program g-g program.cpp-o program三、 基本命令与使用1、启动GDBgdb[可执行文件]# 直接启动gdb-p[进程ID]# 附加到运行中的进程gdb[可执行文件][core dump文件]# 分析核心转储文件2、常用命令命令命令缩写命令说明set args设置主程序的参数 例如./program “张三” “李四”设置参数的方法gdb ./program(gdb) set args “张三” “李四”breakb设置断点,b 20表示在第20行设置断点可以设置多个断点info b查看设置的断点信息runr开始运行程序程序运行到断点的位置会停下来如果没有遇到断点程序一直运行下去。nextn执行当前行语句如果该语句为函数调用不会进入函数内部执行。steps执行当前行语句如果该语句为函数调用则进入函数执行其中的第一条语句。注意了如果函数是库函数或第三方提供的函数用s也是进不去的因为没有源代码如果是您自定义的菡数只要有源码就可以进去。printp显示变量值例如p name表示显示变量name的值continuec继续程序的运行直到遇到下一个断点。set var nameval设置变量的值假设程序有两个变量inticharname[21];set var ii10 把ii的值设置为10;set var name“西施” 把name的值设置为西施注意不是strcpy。quitq退出breaktracebt查看函数调用栈四、GDB初步使用下面我们通过一个简单的程序来使用一下gdb调试功能#includeiostreamusingnamespacestd;intmain(intargc,char*argv[]){if(argc!3){cout算上自身总共参数个数不为3endl;}coutargv[0]argv[0]endl;coutargv[1]argv[1]endl;coutargv[2]argv[2]endl;for(inti0;i1000;i){coutiendl;}return0;}首先使用g 编译命令编译程序g-g-oprogram program.cpp#注意一定要有-g然后使用gdb调试命令进入gdb调试状态命令前面会出现gdb)gdb ./program设置参数setargs张三李四设置断点b5#在第五行暂停运行程序r运行下一行n打印变量p argv[0]退出q五、进阶调试技巧5.1 调试core dump程序程序挂掉时系统缺省不会生成core 文件ulimit -a查看系统参数ulimit -c unlimit把core文件的大小设置为无限制查看core文件大小限制命令:ulimit -c设置core文件生成位置:echo ./core.%e.%p | sudo tee /proc/sys/kernel/core_pattern这个很多博主都没讲运行程序生成core文件使用gdb调试命令:gdb [程序名] [core文件名]下面我们通过一个程序尝试一下#includeiostreamusingnamespacestd;intmain(){int*pnullptr;*p100;return0;}g-g-otestCore testCore.cppulimit-cunlimited#放开core文件限制./testCore#运行程序崩溃生成core.testCore.13487 注意进程号不一样后面那串数字也不一样gdb ./testCore core.testCore.134875.2 调试正在运行中的程序首先我们写一个for循环程序然后让程序每输出一个数就沉睡1秒#includeiostream#includeunistd.husingnamespacestd;voidfunc(inta){coutaendl;return;}voidfunc2(){for(inti0;i10000;i){func(i);sleep(1);//沉睡1秒}return;}intmain(){func2();return0;}首选我们编译程序g-g-otest3 test3.cpp然后重新打开一个终端查看当前运行程序的进程ps-ef|greptest3启用gdb调试正在运行的程序gdb ./test-p进程号5.3 调试多进程程序调试父进程set follow-fork-mode parent(缺省调试子进程:set follow-fork-mode child设置调试模式set detach-on-fork[on|off]缺省是on表示调试当前进程的时候其它的进程继续运行如果用off,调试当前进程的时候其他的进程被gdb挂起。查看调试的进程 info inferiors切换当前调试的进程inferior 进程id下面我们同样可以用一个程序来进行尝试/* process.cpp */#includeiostream#includecstdio#includecstdlib#includeunistd.husingnamespacestd;intmain(){coutbeginendl;if(fork()!0){cout我是父进程:pidgetpid(),ppidgetppid()endl;for(inti0;i10;i){coutiiendl;sleep(1);}exit(0);}else{cout我是子进程:pidgetpid(),ppidgetppid()endl;for(intj0;j10;j){{coutjjendl;sleep(1);}}exit(0);}}g-g-oprocess process.cpp#编译程序gdb ./process#启动调试程序b11#设置断点b14#设置断点b24#设置断点r#运行到断点处setfollow-fork-mode child#调试子进程n#运行到下一个断点5.4 调试多线程/* thread.cpp */#includeiostream#includeunistd.h#includepthread.husingnamespacestd;pthread_t pthid1,pthid2;void*pth1_main(void*arg);void*pth2_main(void*arg);intmain(){if(pthread_create(pthid1,NULL,pth1_main,(void*)0)!0){coutpthread_create pthid1 failed.endl;return-1;}if(pthread_create(pthid2,NULL,pth2_main,(void*)0)!0){coutpthread_create pthid2 failed.endl;return-1;}cout1111endl;pthread_join(pthid1,NULL);cout2222endl;pthread_join(pthid2,NULL);cout3333endl;}void*pth1_main(void*arg){for(intx0;x100;x){coutxxendl;sleep(1);}pthread_exit(NULL);}void*pth2_main(void*arg){for(inty0;y100;y){coutyyendl;sleep(1);}pthread_exit(NULL);}在shell中查看进程的方法查看当前运行的进程ps aux |grep thread查看当前运行的轻量级进程:ps -aL| grep thread查看主线程和新线程的关系:pstree -p 主线程id多线程调试相关命令查看线程info threads切换线程:thread 线程id只运行当前线程:set scheduler-locking on运行全部线程:set scheduler-locking off指定某线程执行gdb命令:thread apply 线程id cmd全部的线程执行gdb命令:thread apply all cmd这里不加赘述大家设置断点后多试试5.5 死锁调试https://blog.csdn.net/m0_46967529/article/details/1511474105.6 内存泄漏调试ASanAddress Sanitizerhttps://blog.csdn.net/wohu1104/article/details/125085228GDB调试https://www.cnblogs.com/TechNomad/p/17982660valgrind 调试https://blog.csdn.net/u012770580/article/details/103065995六、更多调试例子可以看这篇博客【Linux】GDB调试器完全指南从入门到高级技巧实战增强版参考文献【Linux】GDB保姆级调试指南什么是GDBGDB如何使用gdb调试【Linux】GDB调试器完全指南从入门到高级技巧实战增强版