一、gdb 调试-源代码关联
在调试程序的过程中,可以*地查看相关的源代码(如果有源代码的话)是一项最基本的特性。gdb 当然也提供了这项特性,虽然不如IDE直观,但在一定程度上要比IDE更加灵活和快捷。
gdb之所以能够知道对应的源代码,是因为调试版的可执行程序中记录了源代码的位置;因为源代码的位置在编译之后可能会移动到其它地方,所以gdb还会在当前目录中查找源代码,另外gdb也允许明确指定源代码的搜索位置。
在一个调试会话中,gdb维护了一个源代码查找目录列表,默认值是编译目录和当前工作目录。当gdb需要一个源文件的时候,它依次在这些目录中查找,直到找到一个或者抛出错误。
gdb还维护了一个路径替换规则,将要搜索的原始路径按照找到的第一个规则做前缀替换,然后再在源码搜索目录中查找文件。
因此,源代码关联默认情况下搜索路径如下:
- gdb在编译时目录中搜索 ($cdir : compilation directory)
- 当前目录中搜索 ($cwd : current working directory)
- 源代码搜索目录列表 (substitute-path)
除了默认搜索路径,还可以通过如下方式来设置源代码搜索位置和替换规则
- gdb允许明确指定源代码位置,以应付源代码位置迁移的情况。
- directory path-list:将一个或者多个源代码搜索目录加入到当前源码搜索目录列表的前面,目录之间使用空格间隔。
- directory:不带参数的directory将源码搜索目录恢复为默认值。
- set directories path-list:将源码目录设置为path-list,但是会补上默认目录(同 directory path-list)。
- show directories:显示源码搜索目录列表。
2. gdb允许设置路径替换规则,以应付源代码位置迁移的情况。
- set substitute-path from to :设置目录替换规则,放置在规则列表的末端。
- unset substitute-path [path] :删除path对应的替换规则,或者删除所有的替换规则。
show substitute-path [path] :显示path对应的替换规则,或者显示所有的替换规则。
二、gdb 动态库搜索路径
当gdb无法显示so动态库的信息或者显示信息有误时,通常是由于库搜索路径错误导致的,可使用set sysroot、set solib-absolute-prefix、set solib-search-path来指定库搜索路径。
1. set sysroot 与 set solib-absolute-prefix 是同一条命令,实际上,set sysroot是set solib-absolute-prefix 的别名。
2. set solib-search-path设置动态库的搜索路径,该命令可设置多个搜索路径,路径之间使用“:”隔开(在linux中为冒号,DOS和Win32中为分号)。
3. set solib-absolute-prefix 与 set solib-search-path 的区别:
总体上来说solib-absolute-prefix设置库的绝对路径前缀,只对绝对路径有效;而solib-search-path设置库的搜索路径,对绝对路径和相对路径均起作用。
(编译器自动链接的so库多采用绝对路径)。
在载入动态库信息时Coredump会碰到两种路径:绝对路径和相对路径。编译时链接的库通常是绝对路径,例如"/lib/libc.so.6"、"/lib/libdl.so.2"等,
此时在Coredump文件中也同样保存为绝对路径;而程序用dlopen函数载入的so库可能使用相对路径,例如"./libddd.so",此时Coredump文件原封不动地保存相同的路径。
为便于表述,用A表示set solib-absolute-prefix设置的路径,R(A)表示A去掉根前缀后的路径(即去掉前缀“/”符号),用Bn表示set solib-search-path设置的每一条路径,
用X表示Coredump中保存的库路径,即待搜索的库文件路径,F(X)表示X中去掉目录后的文件名(路径最后“/”符号后的字符串)。
- 绝对路径,搜索顺序
1) A / X ; 先添加solib-absolute-prefix前缀进行搜索,成功则不再继续,否则继续2)
2) R(A) / X ; 再把1)的根前缀去掉后进行搜索,成功则不再继续,否则继续3)
3) Bn / R(A) / X ; 再在2)的基础上逐一添加solib-search-path中的每条路径进行搜索,成功则不再继续,否则继续4)
4) Bn / F(X) ; 再只使用2)中的文件名(去掉目录段),并逐一添加solib-search-path中的每条路径进行搜索,成功则不再继续,否则继续5)
5) $PATH / R(A) / X ; 在2)的基础上使用环境变量$PATH中的每条路径进行搜索,成功则不再继续,否则继续6)
6) $LD_LIBRARY_PATH / R(A) / X ;在2)的基础上使用环境变量$LD_LIBRARY_PATH中的每条路径进行搜索,成功则不再继续,否则继续7)
7) 返回失败
- 相对路径,搜索顺序
1) X ; 直接使用原始路径进行搜索,成功则不再继续,否则继续2)
2) Bn / X ; 再逐一添加solib-search-path中的每条路径进行搜索,成功则不再继续,否则继续3)
3) Bn / F(X) ; 再只使用文件名(去掉目录段),并逐一添加solib-search-path中的每条路径进行搜索,成功则不再继续,否则继续4)
4) $PATH / X ; 再使用环境变量$PATH中的每条路径进行搜索,成功则不再继续,否则继续5)
5) $LD_LIBRARY_PATH / X ; 再使用环境变量$LD_LIBRARY_PATH中的每条路径进行搜索,成功则不再继续,否则继续6)
6) 返回失败
GDB动态库搜索路径: http://blog.csdn.net/_xiao/article/details/23289971
三、gdb 调试-查看机器码
在一些必要的时候,我们需要查看汇编代码来诊断问题。gdb 提供了这种可能。
gdb提供了两种能力:
- 显示源代码位置与指令地址之间的映射;
- 显示指定位置的汇编代码。
- info line xx
- info line linespec:显示源代码linespec处对应的汇编地址范围。linespec 可以是函数名
- info line *addr:显示地址addr处对应的源代码位置。
2. disassemble,disassemble /m [/m表示混合输出源代码和汇编代码],disassemble /r [/r表示混合输出二进制和汇编代码]
显示指定地址范围内的汇编代码,有4种使用形式: [参数可以是16进制的地址,也可以是函数名]
- 第一种不带参数,显示当前正在执行的函数的汇编代码;
- 第二 种是一个参数,显示该地址所在函数的汇编代码;
- 第三种是两个参数的disassemble start,end,显示地址[start,end)内的汇编代码;
- 第四种是两个参数的 disassemble start,+length,显示地址[start,start+length)内的汇编代码。
set disassembly-flavor instruction-set:设置显示汇编代码时使用的风格,目前只针对intel x86系列,可取的值为att和intel,默认是att。
show disassembly-flavor:显示disassembly-flavor设置
set disassemble-next-line on|off|auto:当程序停止下来的时候,是否显示下一行源代码的汇编代码,默认为off。
show disassemble-next-line:显示disassemble-next-line设置。
默认情况时,gdb和gcc输出的汇编都是AT&T格式的,但是它们都有方式来转换为Intel格式。
gcc -S -masm=intel test.c
gdb则是设置环境变量
set disassembly-flavor intel
gas事实上也支持Intel格式,只是用得比较少。
四、 gdb + gdbsever 联合调试
参考:
[1]. 使用GDB进行调试: http://www.cnblogs.com/frydsh/p/3367015.html
[2]. 使用GDB的源代码查看功能: http://www.cnblogs.com/frydsh/p/3388828.html