最近使用GDB调试程序的一点经验之谈:
1、程序运行中生成一个Core文件便于保护现场,调试程序,gcore可以满足这种需求:
gcore:对正在运行的进程生成一个内存转储文件,方便保护现场。例如:
– gcore -s -c test.core pid
– 用-s选项使进程在转储过程中处于停止状态,可以保证转储文件的一致性。若不用-c选项指定转储文件名,则会使用默认的core.pid形式的文件名。
2、我的linux虚拟机中调试程序时,发现直接run程序没问题,但gdb调试的时候就提示找不到某个动态库
原因如下:
1)我的虚拟机里同一个用户下由于要编译测试多个不同版本的代码,而每个版本都有不同的运行环境(如:PATH、LD_LIBRARY_PATH等环境变量设置)
2)我目前使用csh,为了快速切换不同的编译环境,我把运行环境所需的环境变量写到不同的.cshrc脚本中,需要切换时运行source .cshrc_XXX
3) GDB调试程序时会启一个新的shell,而且新shell启动时使用默认的.cshrc脚本,从而导致上述的问题,从本质上来说GDB使用的shell的环境非我们要调试程序所需的shell环境设置
解决方法:
1)最简单:将所有动态库的查找位置都设置到默认.cshrc中的LD_LIBRARY_PATH的环境变量中
2)其他方法有待探索
下面转载一篇不错的gdb总结
gdb基本用法
• 调用方式:gdb program [corefile|pid]
• 基本命令:
– r(un) [shell args]:开始运行程序。后面可跟传给被调试程序的命令行参数。
– s(tep) [N]:单步运行程序,进入函数调用。
– n(ext) [N]:单步运行程序,不进入函数调用。
– b(reak) [LOCATION]:设置断点。断点位置可以用如下形式表示:
• LINENUM 位置为当前源码文件的特定行号
• FILE:LINENUM 位置为指定源码文件的特定行号
• FUNCTION 位置为特定函数入口
• FILE:FUNCTION 位置为指定源码文件中的特定函数入口。主要用于存在多个同名的静态函数的情况下。
• *ADDRESS 位置为指定的地址
– c(ontinue) [N]:从之前中断的位置继续运行程序。
– sta(rt) [shell args]:同run命令类似,但自动停止在main函数入口处,比break+run更方便。
– l(ist) [LOC1[,[LOC2]]:显示源码文件内容。例如:
• l func,main
• l 10,*0x40107d
• l main,
• l ,func
– d(elete) [bpno1 [bpno2 […]]]:删除指定编号的断点,若不指定断点编号则删除所有断点。
– disp(lay) [/FMT] [EXP]:设置每当程序中断时要显示的表达式。
– p(rint) [/FMT] [EXP]:显示指定的表达式内容。
– h(elp):帮助命令,救命用的!
gdb高级用法
• fin(ish):持续运行至当前堆栈帧结束,并显示返回值。
• adv(ance) [LOC]:持续运行至指定的位置。例如:
– adv func
– adv *0x40107b
• att(ach) pid:将gdb附加到指定的进程上并中断在该进程当前执行位置处。
• det(ach):使gdb不再附加在当前进程上并恢复被调试进程的运行。
• info addr
• info sym
• 当符号自动补全的范围太大时可以用单引号开头强制前缀匹配,这样来补全C++类成员很方便。
• bt [full]:查看所有堆栈帧,若加上full选项则还会显示每个堆栈帧内的局部变量值。
• f(rame) [FRAMENO]:选择或显示当前堆栈帧。
• up/down:将向上/向下一层的堆栈帧作为当前选择的帧。
常用辅助调试工具
• gcore:对正在运行的进程生成一个内存转储文件,方便保护现场。例如:
– gcore -s -c test.core pid
– 用-s选项使进程在转储过程中处于停止状态,可以保证转储文件的一致性。若不用-c选项指定转储文件名,则会使用默认的core.pid形式的文件名。
• pstack:查看转储文件/正在运行的进程中的完整堆栈帧。例如:
– pstack -t -O pid/corefile
– 用-t选项可以显示提取堆栈帧时进程被pstack暂停的时间;用-O选项可以显示堆栈帧中每个函数所处目标文件的完整路径。
– 默认情况下,为了保证结果的一致性,pstack在提取堆栈帧时会暂停对应进程的活动,但在进程逻辑对时间很敏感时这样可能导致逻辑混乱引起进程崩溃;此时可以使用-n选项强制pstack不暂停要查看的进程,不过相应地取得的堆栈帧数据就有可能出现问题。
• truss:仅用于FreeBSD,跟踪命令行或已运行进程的系统调用序列和信号。例如:
– 跟踪命令行:truss /bin/echo hello
– 跟踪已运行的进程:truss -p 1377
• strace:可用于FreeBSD/Linux,功能同truss相近,输出结果详细一些,包含了系统调用的具体参数。一般用法同truss。
• ltrace:可用于FreeBSD/Linux,跟踪命令行或已运行进程的运行库调用序列。一般用法同truss。
• ktrace/kdump:它们是FreeBSD提供的内核级进程跟踪工具,会监控进程的系统调用、文件系统节点转换、信号处理等各种内核级操作。用法:
– 跟踪命令行并记录在ktrace.out中:ktrace command
– 跟踪活动进程并记录在ktrace.out中:ktrace -p pid
– 关闭所有跟踪活动:ktrace -C
– 显示ktrace.out中的跟踪结果:kdump
• valgrind:x86硬件虚拟机,其中的memcheck模块可用来检测程序是否存在内存泄漏:
– valgrind -v --num-callers=20 --leak-check=yes --leak-resolution=high--show-reachable=yes command
– 结果中的LEAK SUMMARY总结了内存泄漏情况,其中需要注意的是definitely lost和possibly lost两部分。
调试建议
• 产品程序在编译时留下尽可能多的调试符号信息(用-g3选项编译),这些信息不会减慢运行速度,但在出现问题时对调试工作很有帮助。
• 调试用程序不使用优化,并关闭STL的存储池分配方式,这样可以避免valgrind错误地报告内存泄漏,选项为-O0 -g3 –DGLIBCXX_FORCE_NEW