CatCoding

GDB 调试动态链接库

2012-06-25

今天解决了一个长期会碰到的问题,就是用 GDB 如何来调试动态链接库。我这个问题的难点是我的需要调试代码是在动态链接库里面,但是启动的不是普通的可以调试的二进制文件,换句话说这不是我所能控制的代码所编译出来的,甚至可能是由脚本程序来控制启动的。这个问题时不时地困扰着我,总结一下尝试过几种调试方式:

1 使用 print 来打印 log,有时候有用,不好的地方是有时候定位出问题的代码位置还是稍显麻烦。很常用的会定义一对宏,进入函数和退出某个函数的时候都相应调用。

#define APP_LOG(X)                                  \
    fprintf(stderr, "log: %s %d %s %s\n",           \
            __FILE__, __LINE__, __FUNCTION__, X);   \

#define LOG_ENTER     \
    APP_LOG("enter")
    
#define LOG_LEAVE \
    APP_LOG("leave")

2 对于 crash 掉的 bug,打印出来调用栈是非常有用的。使用libc 提供的 Backtraces 函数来获取调用栈。这是在不能提供 GDB 环境下拿到调用栈的不错方法。不过经过我的实验这对于动态链接库有一定的问题。

3 最后就是今天试用的比较通用办法。

我们不管是如何调用到动态链接库文件的,但是肯定会调用进来。所以需要想办法让代码在库代码处停下来,然后把找机会把 GDB 弄进去。于是乎有这么一个变态的办法,在动态链接库入口处来这么一段,就是执行到这里停住,等待 GDB attach 这个进程,然后在 GDB 里设置一个断点,touch 创建当前文件夹 debug 文件就跳出死循环,接下来就是一切在 GDB 控制下了。

void wait_attach() {
    fprintf(stderr, "Waiting attach pid: %d\n", getpid());
    while(1) {
        if((access("./debug", F_OK)) != -1) {
            break;
        }
        else
            ;
    }
}

这是一个 stupid and work 的方法,不过我总觉得还有更好的办法来在这种情况下调试。

在查找资料的过程中有点意外收获,顺便推荐 GDB 一个选项,gdb -tui,以 texture gui 方式启动 GDB,这是非常方便的文字界面。如果不用这个选项也可以在运行 GDB 以后按下快捷键盘 C-x C-a(怎么这么像 Emacs 快捷键) 来进行 gui 和非 gui 的切换。CLI 爱好者可以试用一下,DDD 什么的可以放下了,嘿嘿。

另外一些有用的 GDB 命令:

rbreak: break on function matching regular expression
where: Line number currently being executed
tbreak: Break once, and then remove the breakpoint
watch: Suspend the process when a certain condition is met
finish: Continue till end of function
info locals: View all local variables
backtrace full: Complete backtrace with local variables
up, down, frame: Move through frames
set print pretty on: Prints out prettily formatted C source code
set print array on: Pretty array printing
enable and disable: Enable/disable breakpoints
set logging on: Log debugging session to show to others for support

公号同步更新,欢迎关注👻