gdb 查找动态库方法

转自:IT超人

当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库多采用绝对路径)。

  详细规则有:

  set solib-search-path由于是路径前缀,所以只能设置一个路径,而solib-search-path可以设置多个搜索路径。

  在载入动态库信息时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) 返回失败

博主注:在gdb中设置环境变量,如LD_LIBRARY_PATH可以通过以下gdb命令实现:

(gdb) set env LD_LIBRARY_PATH /tmp

对相对路径,搜索顺序是:

  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) 返回失败

  ======================================================================

  举例说明:

  set solib-absolute-prefix /root/temp
  set solib-search-path /home/evan:/home/peter
  $PATH is /usr/sbin:/usr/bin
  $LD_LIBRARY_PATH is /opt:/usr/games

  那么对绝对路径"/lib/libc.so.6"的搜索顺序是:

  1) A/X
      /root/temp/lib/libc.so.6
  2) R(A)/X
      root/temp/lib/libc.so.6
  3) Bn/R(A)/X
      /home/evan/root/temp/lib/libc.so.6
      /home/peter/root/temp/lib/lic.so.6
  4) Bn/F(X)
      /home/evan/libc.so.6
      /home/peter/libc.so.6
  5) $PATH/R(A)/X
      /usr/sbin/root/temp/lib/libc.so.6
      /usr/bin/roo/temp/lib/lic.so.6
  6) $LD_LIBRARY_PATH/R(A)/X
      /opt/root/temp/lib/libc.so.6
      /usr/games/root/temp/lib/libc.so.6

  对相对路径"./libddd.so"的搜索顺序是

  1) X
      ./libddd.so
  2) Bn/X
      /home/evan/./libddd.so
      /home/peter/./libddd.so
  3) Bn/F(X)
      /home/evan/libddd.so
      /home/peter/libddd.so
  4) $PATH/X
      /usr/sbin/./libddd.so
      /usr/bin/./libddd.so
  5) $LD_LIBRARY_PATH/X
      /opt/./libddd.so
      /usr/games/./libddd.so

  从上面看到,对绝对路径和相对路径都有一步是采用文件名和solib-search-path拼接来查找(绝对路径的第4步和相对路径的第3步),所以只要用set solib-search-path设置了每一个库文件所在的直接目录,那么就能保证每一个库都能被找到。

4. 查看so库的加载路径是否正确可使用info sharedlibrary命令,如果已找到对应的文件则其From和To的加载地址会有值,并且右边路径显示的就是加载文件所在的地址,这个时候,如果so库文件含符号信息,则syms Read的值为Yes,否则为No,如果未找到对应的文件则From和To的地址为空,syms Read的值为No,此时右边路径显示的是Coredump文件中库文件路径。

5. 如果在Coredump文件载入过程中,或者info sharedlibrary命令时,出现" Cannot access memory at address 0x87000069 "这样的错误,这通常是由于所使用的主执行文件("file"命令或"exec-file"命令)与Coredump文件("core"命令或"core-file"命令)两者不匹配导致的。这个时候应检查主执行文件是否是生成Coredump时所用的主执行文件,只要差一点,就可能导致动态库信息读取错误。

6. 如果载入过程中有" warning: .dynamic section for "/lib/librt.so.1" is not at the expected address (wrong library or version mismatch?) "这样的提示,这通常是库搜索路径设置错误,GDB载入了错误的库文件导致的。这时,应使用info sharedlibrary命令查看相应库的载入路径,并使用set sysroot或set solib-search-path修改搜索路径来将错误的库修正到正确的路径上。

7. 在设置了搜索路路径后,最好先用file命令载入主执行文件,再用core命令载入Coredump文件,这样才能保证正确载入库的符号表。否则,如果先用core命令载入Coredump文件,再用file命令载入主执行文件,那么会造成库只是被搜索但并不载入符号(使用info sharedlibrary命令可以看到),这时再重新执行一次core命令就可以了。

8. 一个实际的搜索例子:

当前目录为/home

主执行文件在/home/evan/gdbso/mips/gdbso

Core文件在/home/evan/gdbso/mips/Coredump

所用动态库与拷贝到主执行文件同一目录下

编译主执行文件所用的标准库被拷贝到主执行文件的lib目录下/home/evan/gdbso/mips/lib/libxxx.so

进入GDB,用file命令载入主执行文件:

evan@ubunu:/home$ mips-linux-gnu-gdb
 ...
 (gdb) file evan/gdbso/mips/gdbso
 Reading symbols from /home/evan/gdbso/mips/gdbso...done.
 (gdb) info sharedlibrary 
 No shared libraries loaded at this time.

可以看到只载入了主执行文件时,是无法得到动态库信息的。再用core命令载入Coredump文件:

(gdb) core evan/gdbso/mips/Coredump
 ...
 warning: .dynamic section for "/lib/libc.so.6" is not at the expected address (wrong library or version mismatch?)
 ...
 (gdb) info sharedlibrary 
 From        To          Syms Read   Shared Object Library
 0x2aad98c0  0x2aadd6d8  Yes         /lib/librt.so.1
 0x2aaf3460  0x2ab0db98  Yes         /lib/libm.so.6
 0x2ab7e2e0  0x2ab89b28  Yes         /lib/libpthread.so.0
 0x2abba9a0  0x2acb2bd8  Yes         /lib/libc.so.6
 0x2ad06a40  0x2ad07988  Yes         /lib/libdl.so.2
                         No          /lib/ld.so.1
                         No          ./libddd.so
 (gdb) 

在同时有了主执行文件和Coredump文件后,用info sharedlibrary就可以看到动态库信息了。但在载入过程中有库版本不匹配的提示。通过info sharedlibrary也看到GDB错误地载入了系统中自带的标准库。我们将绝对路径设置到一个不存在的目录来看看Coredump中保存的原始路径名:

(gdb) set sysroot /noexist
 ...
 (gdb) info sharedlibrary 
 From        To          Syms Read   Shared Object Library
                         No          /lib/librt.so.1
                         No          /lib/libm.so.6
                         No          /lib/libpthread.so.0
                         No          /lib/libc.so.6
                         No          /lib/libdl.so.2
                         No          /lib/ld.so.1
                         No          ./libddd.so
 (gdb) 

Coredump中保存的原始路径名为/lib/librt.so.1,为了让GDB使用正确的库/home/evan/gdbso/mips/lib/librt.so.1,只需要将绝对路径前缀设置为/home/evan/gdbso/mips即可,这里设置为evan/gdbso/mips来演示效果:

(gdb) set sysroot evan/gdbso/mips
 ...
 (gdb) info sharedlibrary 
 From        To          Syms Read   Shared Object Library
 0x2aad98c0  0x2aade270  Yes         evan/gdbso/mips/lib/librt.so.1
 0x2aaf3110  0x2ab31b70  Yes         evan/gdbso/mips/lib/libm.so.6
 0x2ab7e320  0x2ab8e620  Yes         evan/gdbso/mips/lib/libpthread.so.0
 0x2abba6a0  0x2accc3f0  Yes         evan/gdbso/mips/lib/libc.so.6
 0x2ad06b50  0x2ad07c70  Yes         evan/gdbso/mips/lib/libdl.so.2
 0x2aaa8810  0x2aac2e40  Yes         evan/gdbso/mips/lib/ld.so.1
                         No          ./libddd.so
 (gdb) 

可以看到,GDB已经正确地载入了绝对路径。但相对路径"./libddd.so"还没有找到,为了使用/home/evan/gdbso/mips/libddd.so,设置库搜索路径包含/home/evan/gdbso/mips即可。为了查看效果,这里还添加了一个不存在的搜索路径:

 (gdb) set solib-search-path /noexist:/home/evan/gdbso/mips
 ...
 (gdb) info sharedlibrary 
 From        To          Syms Read   Shared Object Library
 0x2aad98c0  0x2aade270  Yes         evan/gdbso/mips/lib/librt.so.1
 0x2aaf3110  0x2ab31b70  Yes         evan/gdbso/mips/lib/libm.so.6
 0x2ab7e320  0x2ab8e620  Yes         evan/gdbso/mips/lib/libpthread.so.0
 0x2abba6a0  0x2accc3f0  Yes         evan/gdbso/mips/lib/libc.so.6
 0x2ad06b50  0x2ad07c70  Yes         evan/gdbso/mips/lib/libdl.so.2
 0x2aaa8810  0x2aac2e40  Yes         evan/gdbso/mips/lib/ld.so.1
 0x2ad1a590  0x2ad1a770  Yes         /home/evan/gdbso/mips/libddd.so
 (gdb) 

可以看到,所有的库都找到正确的路径了,Syms也被正确地载入。

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《debugging with gdb》是一本关于使用GDB进行调试的指南。GDB(GNU调试器)是一个强大的调试工具,可以用于调试各种编程语言,如C、C++、Fortran等。 这本书详细介绍了GDB的安装和配置,并提供了许多示例来说明如何使用它来调试程序。它从基本的调试命令开始,如设置断点、单步执行、查看变量的值等。然后,它介绍了更高级的调试功能,如条件断点、观察点、跟踪函数调用等。 书中还介绍了如何使用GDB来调试多线程程序和动态库。它解释了如何设置线程断点、查看线程状态和跟踪线程的执行路径。此外,它还介绍了如何对动态链接库进行调试,包括加载和卸载库、查看库中的符号和调用库中的函数等。 此外,《debugging with gdb》还介绍了如何使用GDB进行内存调试。它涵盖了诸如检测内存泄漏、跟踪指针问题和查找内存错误等主题。通过这本书,读者可以学习如何使用GDB来诊断和解决各种程序错误和问题。 总之,《debugging with gdb》是一本全面而详细的关于使用GDB进行调试的指南。无论是有经验的开发人员还是初学者,都可以从中学习到如何使用GDB来快速定位和解决程序中的错误。 ### 回答2: GDB是一个调试器,用于帮助开发者在程序中找出错误并进行调试。它提供了许多功能和命令,可以让开发者在程序运行过程中获取各种有用的信息。 在使用GDB进行调试之前,首先需要将程序编译成可调试的二进制文件。可以使用编译器的参数“-g”来生成包含调试信息的可执行文件。编译完成后,可以通过终端命令"gdb <可执行文件名>"启动GDB,并载入要调试的程序。 一旦进入GDB调试界面,可以使用各种命令来控制程序的执行。例如,可以使用"break <函数名>"命令在特定的函数内设置断点,当程序执行到该函数时会触发断点,并暂停程序的执行。可以使用"run"命令来运行程序,当程序遇到断点时会暂停,并在终端显示相关的调试信息。 一旦程序暂停在断点处,就可以使用GDB提供的许多命令来检查程序状态和寻找错误。例如,可以使用"print <变量名>"命令来打印特定变量的值,以确定其是否符合预期。还可以使用"step"命令来逐行执行程序,并跟踪程序的执行流程,以查找错误所在。 在调试过程中,还可以使用其他命令来查看函数调用栈,设置条件断点,监视特定变量的值等。通过这些命令的使用,可以逐步分析程序的执行过程,找出其中的问题,并进行修复。 在调试完成后,可以使用"quit"命令退出GDB调试界面。调试信息和步骤可以记录下来并与其他开发者共享,以便更好地协作解决问题。 总之,GDB是一个功能强大的调试器,它可以帮助开发者定位和修复程序中的错误。通过使用GDB,开发者可以更加高效地进行程序调试,提高开发效率。 ### 回答3: 《debugging with gdb》是一本介绍使用GDB进行调试的书籍。GDB是GNU工具链中的一个强大的调试工具,用于分析和修复程序中的错误。 该书详细介绍了GDB的各种功能和用法,并通过实例演示了如何利用GDB进行程序调试。它提供了许多实用技巧和建议,帮助读者快速定位和解决程序中的bug。 书中首先介绍了GDB的基本用法,包括启动程序、设置断点、执行程序、查看变量值等。接着,它详细阐述了GDB的高级功能,例如条件断点、观察点、内存调试等。 此外,书中还介绍了GDB调试多线程程序、动态链接程序和嵌入式程序的方法。针对不同的调试需求,它还介绍了GDB的执行控制、堆栈跟踪和源代码级别的调试等高级特性。 《debugging with gdb》还提供了一些常见问题的解决方案,如内存泄漏、数组越界、死锁等。它还解释了一些常见错误的原因和调试技巧,帮助读者更好地理解和定位程序中的问题。 通过阅读《debugging with gdb》,读者可以更好地理解和掌握GDB的使用方法,提高程序调试的效率和准确性。无论是新手还是有经验的程序员,都可以从中受益,提升自己的调试能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值