例如想搞懂wget这个软件的代码实现:
- 下载wget 源码
- 编译debug版本的binary (取消编译优化选项)
- 导出函数符号
$ nm wget | grep '[0-9a-z] [tT]' > wget.map
- gdb 7.0 以后版本支持python 扩展,可用python 脚本调用gdb 命令。 写个简单的 gdb_wget.py,目的是将所有的函数打上断点,断住后打印调用栈并继续运行:
$ cat gdb_wget.py
gdb.execute("set logging on")
gdb.execute("set height 0")
f = open("wget.map", 'r')
for line in f:
gdb.execute("b " + line[19:len(line)-1]);
f.close()
gdb.execute("run www.baidu.com");
while 1:
gdb.execute("bt");
gdb.execute("c");
- 运行gdb 调试wget,将所有输出保存到gdb.log中,起来后执行 source gdb_wget.py, 控制权交给python 脚本。
$ gdb ./wget | tee gdb.log
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./wget...done.
(gdb) source gdb_wget.py
...............
运行结果见下图(1),左边部分,得到wget运行时执行到的所有函数及调用栈。
下图(2): 写个程序parse gdb.log, 得到可读性很好的程序运行路线。
下图(3): 在Emacs中折叠部分非重要函数调用过程,高亮显示重点函数,我相信一眼即可理解wget大致代码原理。
就算我死磕代码,花大量时间研究得很透彻,我相信过了一个多月,头脑里剩下保存的差不多也就图(3)显示的调用过程。
而用这种方法,整个过程不到5分钟。
如果要我在wget的代码上增加个新功能,我就顺着这些调用过程,在恰当的位置加些函数实现。
当然除了显示图(3)的样子外,还可以显示成类似UML格式的,只要有了原始的raw格式数据,即可将它们转成画图工具的输入数据,生成适合自己理解的图。
我收集的辅助画图工具: