A-A+

gdb调试技巧-持续更新

2016年11月27日 编程 暂无评论 阅读 2,679 次
摘要:

gdb的一些调试技巧,包括打印格式、断点、gdb脚本编写和一些经验。

Gdb是linux下C/C++代码调试神器,本文综合了一些比较好的国内外博客,加上我自己的一些使用经验,希望能对读者有用。

使用gdb前,代码要用gcc -g选项编译以带上符号表。

 

调试C++程序的基本环境设置

 

在gdb里面临时执行一些shell命令,可以用gdb的shell命令

 

查看当前堆栈

 

断点的几个技巧

条件断点:

在x>0时,停止并执行一系列commands。

 

打印变量或内存print命令

打印格式的调整:

 

打印函数局部static __thread变量

不过这个命令在某些环境下不能生效,不知道为什么。

 

打印真实类型

 

disassemble

除了查看汇编之外,这个命令在某些情况下还可以用来查看某个地址上存放的是什么对象。因为C++对象布局的原因,假设可以确认某个地址(例如内存分配器的一块内存)存放了一个C++对象(假设有虚表指针),那么直接disassemble这个对应到虚表指针的地址,可以看到一个mangled符号名字,基本就可以确定上面存放的是什么对象了。

我之前在排查一个内存泄漏的问题时用过这个技巧,内存分配器实现时可以检测是否有泄漏,并且能够知道哪些内存块被泄漏了,但是因为只能在分配器对象析构时才能确定内存泄漏,所以并不方便知道是哪个使用者泄漏了(把使用者id传进来太麻烦)。通过这种办法能够先确定是哪个使用者泄漏了,进而缩小问题范围。

dump memory把一段内存内容转储到文件中

我之前在排查某个问题时,需要在coredump中将一个哈希表的内容打印出来。假设哈希表实现为大数组(数组内的元素只存放指针),拉链解决冲突。那么,就可以用gdb脚本(我们后面会给出一个详细的例子)将所有的元素打印出来。不过这里有个问题:gdb是解释执行的,非常慢,导致打印一个大的哈希表耗时可能达到几天之久。

假设哈希表数组大小为一千万,但是实际有效元素只有几万,并且数组中无效元素都是NULL指针。那么就可以先将数组dump memory到文件,用shell脚本先过滤掉NULL元素,只遍历剩下的有效指针,在我遇到的这个场景下,遍历耗时从7天降到了10分钟。

不过还遇到一个麻烦,gdb不支持将shell命令结果存入gdb变量中,所以只能拼凑一个临时的gdb脚本,里面有shell脚本生成的诸如set my_gdb_var = ‘pwd’等内容,然后在gdb环境下source这个临时脚本,曲线地将内容加载到gdb变量中。

 

gdb脚本示例

gdb脚本是一个非常好用的利器,比如在coredump文件中,你可能想知道某个链表/哈希表等数据结构里面都有什么元素,可以写脚本遍历打印出来。这里给一个例子。

gdb脚本代码print_my_list_script.gdb

执行脚本

 

gdb打印STL库

大部分内置STL库对应的gdb脚本,都可以在这里下载 http://www.yolinux.com/TUTORIALS/src/dbinit_stl_views-1.03.txt

 

不过这里没有unordered_map,这里我写了一个例子,读者如果需要,可以自己写一个。

注意:$curr_node的类型,可以在gdb下print 这个map看下(可能需要先disable pretty-printer)。

 

 

 

标签:

给我留言