如何运行时调试共享库?

Posted

技术标签:

【中文标题】如何运行时调试共享库?【英文标题】:How to runtime debug shared libraries? 【发布时间】:2010-10-22 12:47:45 【问题描述】:

谁能告诉我如何对共享库进行运行时调试?

我需要在我的共享库中运行时调试一个函数,但它被另一个程序调用。 如何使用共享库执行 dbx 之类的操作?

我在 AIX 上使用 dbx。 对于我想做的事情,gdb 比 dbx 好吗?

【问题讨论】:

【参考方案1】:

洛塔尔回答的另一个例子:

我正在使用python 和python 的单元测试库unittest 调用tests/test_pwmbasic.py 在Linux 中对动态库test.so(从test.c 编译)运行测试。 (命名方案有点单调,我现在意识到了)

~/my/test/path/
    tests/
        __init__.py
        test_pwmbasic.py
    test.c
    test.so

我想从test_pwmbasic.py 中的刺激中调试test.so 中的内容。 所以这就是我让它工作的方式......

$ cd ~/my/test/path
$ gdb $(which python)
   ... gdb blah ...
(gdb) b test.c:179
(gdb) run
>>> from tests.test_pwmbasic import *
>>> import unittest
>>> unittest.main()
   ... unittest blah ...
Breakpoint 1, pwmTest_setDutyCycles (dutyCycles=0x7ffff7ece910) at ./test.c:179
(gdb) print pwm_errorCode
$1 = PWM_ERROR_NONE

现在我想嫁给gdb

注意:test.c 还包括 ../pwm.c,所以我也可以在该库中设置断点

(gdb) b pwm.c:123

【讨论】:

【参考方案2】:

您只需要使用可执行文件调用 gdb(它是您的还是第 3 方的都没有关系)。这是我调试 ls 命令并在(共享)c 库 中设置断点的示例。此示例使用支持延迟(待处理)断点的 gdb 6.8,这使得这很容易:

gdb /bin/ls
GNU gdb 6.8-debian
Copyright (C) 2008 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"...
(no debugging symbols found)
(gdb) b write
Function "write" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (write) pending.
(gdb) r
Starting program: /bin/ls
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
[Thread debugging using libthread_db enabled]
(no debugging symbols found)
(no debugging symbols found)
[New Thread 0x7f98d2d23780 (LWP 7029)]
[Switching to Thread 0x7f98d2d23780 (LWP 7029)]

Breakpoint 1, 0x00007f98d2264bb0 in write () from /lib/libc.so.6
(gdb)

如您所见,gdb 自动管理可执行文件使用的所有线程。您不必为那里的线程做任何特别的事情。断点可以在任何线程中工作。

或者,如果您想将调试器附加到已经运行的应用程序(我在这里使用 tail -f /tmp/ttt 作为示例):

ps ux | grep tail
lothar    8496  0.0  0.0   9352   804 pts/3    S+   12:38   0:00 tail -f /tmp/ttt
lothar    8510  0.0  0.0   5164   840 pts/4    S+   12:39   0:00 grep tail

gdb
GNU gdb 6.8-debian
Copyright (C) 2008 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"...
(no debugging symbols found)
(gdb) attach 8496
Attaching to program: /usr/bin/tail, process 8496
Reading symbols from /lib/librt.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/librt.so.1
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/libpthread.so.0...(no debugging symbols found)...done.
[Thread debugging using libthread_db enabled]
[New Thread 0x7f24853f56e0 (LWP 8496)]
Loaded symbols for /lib/libpthread.so.0
Reading symbols from /lib/ld-linux-x86-64.so.2...
(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
(no debugging symbols found)
0x00007f2484d2bb50 in nanosleep () from /lib/libc.so.6
(gdb) b write
Breakpoint 1 at 0x7f2484d57bb0
(gdb) c
Continuing.
[Switching to Thread 0x7f24853f56e0 (LWP 8496)]

Breakpoint 1, 0x00007f2484d57bb0 in write () from /lib/libc.so.6
(gdb)

【讨论】:

我在 AIX 上使用了 dbx。如果你说 gdb 可以用线程应用程序来做到这一点..那么 dbx 很糟糕..我一直都是个傻瓜。 我不知道dbx,但应该有类似的功能 这个方法在尝试调试Oracle的SQLPlus时不起作用【参考方案3】:

自从我不得不在 AIX 上使用 dbx 已经很久了,我也遇到了这个问题。安装 gdb 对我来说不是一个选项。

dbx  /path/to/your/program
(dbx) run [args to your program]
(dbx) set $ignoreonbptrap           # I kept hitting a trace/bpt trap
(dbx) set $deferevents              # allows setting bp in not loaded shared library
(dbx) set $repeat                   # useful, repeat commands with <enter> tjust like gdb
(dbx) stop in MySharedLibraryFunc   # defers breakpoint
(dbx) cont

【讨论】:

【参考方案4】:

您可以尝试静态编译和链接库来调试它。 如果您的错误仅在编译为共享时出现,那么这可能会给您一些线索。

【讨论】:

【参考方案5】:

通常调试共享库的过程与调试可执行文件的过程大致相同 - 主要区别在于您可能无法设置断点,直到共享库加载到内存中。您将调试器附加到主可执行文件。

如果您正在调试不属于您的应用程序,但在插件架构中使用您的模块,您仍然使用相同的方法。确保(一如既往)您有可用于共享库的调试信息。在 Windows 中,您将生成一个 .pdb 文件。使用 gcc,我认为您指定了一个特殊的编译器标志 (-g?) 以确保提供调试信息。您将调试器附加到第三方应用程序。

【讨论】:

如果主可执行文件不是我的并且它的某个第 3 方的......但是我正在编写一个将由第 3 方使用的模块......那你如何调试呢? 您仍然使用 gdb 启动可执行文件(或附加到进程)。加载库后,gdb 可以毫无问题地在那里设置断点。 但是当您在共享库代码中设置断点并且如果主可执行文件调用它时,主可执行文件不会被阻止吗?? 它的工作方式与您在主可执行文件中设置的任何其他断点完全相同 好吧,如果你在主可执行文件中有线程怎么办......在这种情况下我将如何调试我的共享库代码......它不是那么简单......我尝试为我的函数设置断点..但从未停止过..我什至看到我的符号...而且我有日志确认我的共享库代码正在执行..【参考方案6】:

我记得通过创建一个使用它的模拟应用程序来测试共享库。如果您愿意做很多工作,您可以创建第二个模拟共享库,该库仅收集有关第三方应用程序如何使用该库的信息,然后让您的模拟应用程序重放该信息。

当然,永远不要怀疑正确的 printf 和 fprintf 调用的威力。

【讨论】:

以上是关于如何运行时调试共享库?的主要内容,如果未能解决你的问题,请参考以下文章

如何在运行时确定共享库中全局变量的地址范围?

如何找出在 Linux 上运行 Java 类需要哪些共享库?

如何使共享库符号强大?

如何在共享库中找到 C++ isfinite() 的解析位置?

如何在运行时读取共享库数据段开头的绝对加载地址?

在共享库中全局声明的非 POD 对象的语义是啥?