GDB调试动态库

转载:https://blog.csdn.net/huluedeai/article/details/52225923

一:方法

gdb如何调试动态链接库的问题。比如我想调试的代码为动态链接库代码,我设置断点后却得到以下错误
(gdb) b mps_guide_db.c:1699
No source file named mps_guide_db.c.
Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal]

可以通过 以下方式得到解决:
(gdb) set breakpoint pending on
(gdb) b db_subscr_no_lookup
Function "db_subscr_no_lookup" not defined.
Breakpoint 1 (db_subscr_no_lookup) pending.
(gdb) r mcap06 2
Starting program: /usr1/arbor/bin/MCAP mcap06 2
[Thread debugging using libthread_db enabled]
Traceback (most recent call last):
  File "/usr/share/gdb/auto-load/usr/lib64/libstdc++.so.6.0.13-gdb.py", line 19, in <module>
    import os
ImportError: No module named os
[New Thread 0x7ffff1165700 (LWP 7449)]


Breakpoint 1, db_subscr_no_lookup (cat_connection=0x699520, cdr=0x623300, external_id=0x7fffffff9944 "yy_tc01", db_active_dt=0x7fffffff98b0, db_inactive_dt=0x7fffffff98a0, target_origin_flag=0, network_delay=0) at guide/mps_guide_db.c:1711
1711        if ( giUseHierarchyRt )
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.80.el6.x86_64 libaio-0.3.107-10.el6.x86_64 libgcc-4.4.6-4.el6.x86_64 libstdc++-4.4.6-4.el6.x86_64 numactl-2.0.7-3.el6.x86_64
(gdb) list
1706        static char *mps_subscr_no_lookup_inline = "SELECT \
1707    server_id, account_no, subscr_no, subscr_no_resets, active_date, inactive_date \
1708    FROM EXTERNAL_ID_EQUIP_MAP \
1709    WHERE external_id = :v1 AND external_id_type = :v2 ORDER by active_date";
1710
1711        if ( giUseHierarchyRt )
1712        {
1713           switch( target_origin_flag )
1714           {
1715           case SL_ORIGIN:

(gdb) help set breakpoint pending 
Set debugger's behavior regarding pending breakpoints. 
If on, an unrecognized breakpoint location will cause gdb to create a 
pending breakpoint. If off, an unrecognized breakpoint location results in 
an error. If auto, an unrecognized breakpoint location results in a 
user-query to see if a pending breakpoint should be created.

http://blog.csdn.net/yasi_xi/article/details/18552871

在 Linux 可以用 gdb 来调试应用程序,当然前提是用 gcc 编译程序时要加上 -g 参数。我这篇文章里将讨论一下用 gdb 来调试动态链接库的问题。首先,假设我们准备这样的一个动态链接库:引用:库名称是: ggg 动态链接库文件名是: libggg.so 头文件是: get.h 提供这样两个函数调用接口:

   int get ();
   int set (int a);
要生成这样一个动态链接库,我们首先编写这样一个头文件:


/************关于本文档********************************************
*filename: get.h
*********************************************************************/
int get ();
int set (int a);
然后准备这样一个生成动态链接库的源文件:


/************关于本文档********************************************
*filename:  get.cpp
*********************************************************************/
#include <stdio.h>
#include "get.h"


static int x=0;
int get ()
{
        printf ("get x=%d\n", x);
        return x;
}


int set (int a)
{
        printf ("set a=%d\n", a);
        x = a;
        return x;
}
然后我们用 GNU 的 C/C++ 编译器来生成动态链接库,编译命令如下:


g++ get.cpp -shared -g -DDEBUG -o libggg.so
g++ get.cpp -shared -g -fPIC -DDEBUG -o libggg.so (64位机器)
这样我们就准备好了动态链接库了,下面我们编写一个应用程序来调用此动态链接库,源代码如下:


/************关于本文档********************************************
*filename: pk.cpp
*********************************************************************/
#include <stdio.h>
#include "get.h"
int main (int argc, char** argv)
{
        int a = 100;
        int b = get ();
        int c = set (a);
        int d = get ();


        printf ("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);


        return 0;
}
编译此程序用下列命令,如果已经把上面生成的 libggg.so 放到了库文件搜索路径指定的文件目录,比如 /lib 或 /usr/lib 之类的,就用下面这条命令:


g++ pk.cpp -o app -Wall -g -lggg
否则就用下面这条命令:


g++ pk.cpp -o app -Wall -g -lggg -L`pwd`
下面我们就开始调试上面命令生成的 app 程序吧。如果已经把上面生成的 libggg.so 放到了库文件搜索路径指定的文件目录,比如 /lib 或 /usr/lib 之类的,调试就顺利完成,如下:


#gdb ./app
GNU gdb 6.4-debian
Copyright 2005 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".


(gdb) b main    /* 这是在程序的 main 处设置断点 */
Breakpoint 1 at 0x804853c: file pk.cpp, line 7.
(gdb) b set      /* 这是在程序的 set 处设置断点 */
Function "set" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y /* 这里必须选择 y 调试程序才会跟踪到动态链接库内部去 */
Breakpoint 2 (set) pending.
(gdb) run /* 开始运行我们的程序,直到遇见断点时暂停 */
Starting program: /data/example/c/app
Breakpoint 3 at 0xb7f665f8: file get.cpp, line 11.
Pending breakpoint "set" resolved


Breakpoint 1, main (argc=1, argv=0xbf990504) at pk.cpp:7
7               int a = 100;
(gdb) n     /* 继续执行程序的下一行代码 */
8               int b = get ();
(gdb) n      /* 程序执行到了我们断点所在的动态链接库了 */
get x=0
9               int c = set (a);
(gdb) n


Breakpoint 3, set (a=100) at get.cpp:11
11              printf ("set a=%d\n", a);
(gdb) list   /* 查看当前代码行周围的代码,证明我们已经跟踪到动态链接库的源代码里面了 */
6               printf ("get x=%d\n", x);
7               return x;
8       }
9       int set (int a)
10      {
11              printf ("set a=%d\n", a);
12              x = a;
13              return x;
14      }
(gdb) n
set a=100
12              x = a;
(gdb) n
13              return x;
(gdb) n
14      }
(gdb) n
main (argc=1, argv=0xbf990504) at pk.cpp:10
10              int d = get ();
(gdb) n
get x=100
11              printf ("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);
(gdb) n
a=100,b=0,c=100,d=100
12              return 0;
(gdb) c
Continuing.


Program exited normally.
(gdb) quit  /* 程序顺利执行结束 */


如果我们没有把动态链接库放到指定目录,比如/lib里面,调试就会失败,过程如下:


# gdb ./app
GNU gdb 6.4-debian
Copyright 2005 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".


(gdb) b main
Breakpoint 1 at 0x804853c: file pk.cpp, line 7.
(gdb) b set
Function "set" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (set) pending.
(gdb) run  /* 虽然调试操作都一样,但程序执行失败 */
Starting program: /data/example/c/app
/data/example/c/app: error while loading shared libraries: libggg.so: cannot open shared object file: No such file or directory


Program exited with code 0177.
(gdb) quit 
调试失败的原因是因为gdb不能找到libggg.so,可以通过下面的方法解决:


1) 将库路径加到LD_LIBRARY_PATH里
2) 执行:ldconfig YOUR_LIB_PATH
3) 在/etc/ld.so.conf里加入库所在路径。然后执行:ldconfig


上面3个方法任意一个都可以,然后再去用gdb调试就没有问题了。
另:


1、假设我的可执行程序是ServerName,共享库为worker.so
2、我用gdb调试ServerName,想在B的某个源文件(比如worker.cpp,worker.cpp与ServerName不在同一个目录下)中设置断点,使用下面的命令行break worker.cpp:123


若找不到源文件可使用如下命令设定源文件目录:


设定gdb环境变量 LD_PRELOAD,在执行程序前先把共享库代码load进来
指定你的链接库的位置,可以通过设定环境变量LD_LIBRARY_PATH来实现


拷贝到标准的lib搜寻目录下,例如/usr/lib等


b main, r,然后再设置断点就可以了,共享库只有当程序运行才开始加载的
linuxGDB下动态链接库的调试


gdb) file <你的exe>
(gdb) load <你的so>                #这条应该是可选的
(gdb) dir <so'dir>
(gdb) sharedlibrary <你的so>
(gdb) breakpoint <你的so中somewhere>
(gdb) run
load 是将动态库加载入内存。
sharedlibrary是将动态库的符号读入gdb,为了你能找到变量和函数名。
它们本身是没明显的动作,但后面当你直接设置断点到动态库的函数(或行号时,你就可以成功了。在此之前要记得用dir将动态库的源码也加入搜索路径。

二:方法

 

原文地址:

http://www.gonwan.com/?tag=gdb

在本例中使用了libcurl.so.4库

step1:

编译libcurl.so.4的可调试版本:

 

 
  1. # sudo apt-get source libcurl3-dbg

  2. # cd curl-7.19.7/

  3. # ./configure --prefix=/usr/local --enable-debug --enable-static=0

  4. # make

编译好的带调试信息的动态库放在了这个隐藏目录:

 

LD_LIBRARY_PATH=/home/gonwan/testgdb/curl-7.19.7/lib/.libs/ gdb ./testcurl


step2:编写调试程序并编译

 

 
  1. #include <curl/curl.h>

  2. int main() {

  3. curl_easy_init();

  4. return 0;

  5. }

</pre><pre name="code" class="html"><span style="font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; font-size: 13px; line-height: 14.3000001907349px; white-space: pre;"> gcc -g testcurl.c -o testcurl /usr/lib/libcurl.so.4</span>


step3:启动gdb,调试上述代码

 

 

LD_LIBRARY_PATH=/home/gonwan/testgdb/curl-7.19.7/lib/.libs/ gdb ./testcurl

LD_LIBRARY_PATH的作用只制定加载动态库的位置,在这里指定了程序运行加载的动态库的位置

 

关于这个环境变量的详细解释,参见这里:

http://linuxmafia.com/faq/Admin/ld-lib-path.html

 

step4:调试程序:

  1. root@localhost:/home/smb/curl-7.26.0# LD_LIBRARY_PATH=/home/smb/curl-7.26.0/lib/.libs gdb ./testcurl

  2. GNU gdb (GDB) 7.4.1-debian

  3. Copyright (C) 2012 Free Software Foundation, Inc.

  4. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

  5. This is free software: you are free to change and redistribute it.

  6. There is NO WARRANTY, to the extent permitted by law. Type "show copying"

  7. and "show warranty" for details.

  8. This GDB was configured as "i486-linux-gnu".

  9. For bug reporting instructions, please see:

  10. <http://www.gnu.org/software/gdb/bugs/>...

  11. Reading symbols from /home/smb/curl-7.26.0/testcurl...done.

  12. (gdb) r

  13. Starting program: /home/smb/curl-7.26.0/testcurl

  14. [Thread debugging using libthread_db enabled]

  15. Using host libthread_db library "/lib/i386-linux-gnu/i686/cmov/libthread_db.so.1".

  16. [Inferior 1 (process 30604) exited normally]

  17. (gdb) l

  18. 1 #include "./include/curl/curl.h"

  19. 2 int main() {

  20. 3 curl_easy_init();

  21. 4 return 0;

  22. 5 }

  23. (gdb) b 3

  24. Breakpoint 1 at 0x80485da: file testcurl.c, line 3.

  25. (gdb) c

  26. The program is not being run.

  27. (gdb) r

  28. Starting program: /home/smb/curl-7.26.0/testcurl

  29. [Thread debugging using libthread_db enabled]

  30. Using host libthread_db library "/lib/i386-linux-gnu/i686/cmov/libthread_db.so.1".

  31.  
  32. Breakpoint 1, main () at testcurl.c:3

  33. 3 curl_easy_init();

  34. <strong>(<span style="color:#ff6666;">gdb) s

  35. curl_easy_init () at easy.c:351

  36. 351 if(!initialized) {</span></strong>

  37. (gdb)

  38. 352 res = curl_global_init(CURL_GLOBAL_DEFAULT);

  39. (gdb) q

  40. A debugging session is active.


可见已经进入了动态库进行调试了
 

总结:可见可以通过让应用程序加载带调试信息的动态库,进行动态库的调试

 

三:方法

转自:https://blog.csdn.net/zz7zz7zz/article/details/42238115

当自己开发了一个so文件,如何调试呢?

对于如何编写一个so,请参考文章:http://blog.csdn.net/zz7zz7zz/article/details/41448987

对于如何进行gdb调试,请参考文章:http://blog.csdn.net/zz7zz7zz/article/details/41654457

 

我们的源文件分别如下:

filea.c

 

 
  1. #include <stdio.h>

  2. void fun1()

  3. {

  4. printf("i am from filea fun1 \n");

  5. printf("i am from filea fun11 \n");

  6. printf("i am from filea fun12 \n");

  7. }

  8.  


fileb.c

 

 

 
  1. #include <stdio.h>

  2. void fun2()

  3. {

  4. printf("i am from fileb fun2 \n");

  5. printf("i am from fileb fun21 \n");

  6. printf("i am from fileb fun22 \n");

  7. }

  8.  


CLoadSo.h

 

 

 
  1. #ifndef _CLOADSO_H

  2. #define _CLOADSO_H

  3.  
  4. #ifdef _cplusplus

  5. extern "C" {

  6. #endif

  7.  
  8. void fun1();

  9. void fun2();

  10.  
  11. #ifdef _cplusplus

  12. }

  13. #endif

  14.  
  15.  
  16. #endif

  17.  

 

 

CLoadSo.c

 

 
  1. #include <stdio.h>

  2. #include <dlfcn.h>

  3. #include "CLoadSo.h"

  4.  
  5. int main(int argc,char **argv)

  6. {

  7.  
  8. void *soHandle;

  9. int (*fun)();

  10. char *errorMsg;

  11.  
  12. soHandle=dlopen("first.so",RTLD_LAZY);

  13. errorMsg=dlerror();

  14.  
  15.  
  16. printf("A1---------loadSo is %s \n",soHandle ? "success" : "failed");

  17. if(errorMsg)

  18. {

  19. printf("A2--------loadSo error , Msg is: %s \n",errorMsg);

  20. return -1;

  21. }

  22.  
  23. fun=dlsym(soHandle,"fun1");

  24. errorMsg=dlerror();

  25. printf("B1---------fun1 , fun1 is %s \n",fun ? "success" : "Null");

  26. if(fun)

  27. {

  28. fun();

  29. }

  30. if(errorMsg)

  31. {

  32. printf("B2---------fun1 error , Msg is: %s \n",errorMsg);

  33. }

  34.  
  35. fun=dlsym(soHandle,"fun2");

  36. errorMsg=dlerror();

  37. printf("B3---------fun2 , fun2 is %s \n",fun ? "success" : "Null");

  38. if(fun)

  39. {

  40. fun();

  41. }

  42. if(errorMsg)

  43. {

  44. printf("B4---------fun2 error , Msg is: %s \n",errorMsg);

  45. }

  46.  
  47. fun=dlsym(soHandle,"fun3");

  48. errorMsg=dlerror();

  49. printf("B5---------fun3 , fun3 is %s \n",fun ? "success": "Null");

  50. if(fun)

  51. {

  52. fun();

  53. }

  54. if(!errorMsg)

  55. {

  56. printf("B6---------fun3 error , Msg is: %s \n",errorMsg);

  57. }

  58.  
  59.  
  60. dlclose(soHandle);

  61. printf("C---------close LoadSo \n");

  62.  
  63. return 0;

  64. }

  65.  


用命令 gcc -Wall -fpic -g -shared filea.c fileb.c -o first.so 生成first.so文件

 

用命令 gcc -g -Wall CLoadSo.c -o CLoadSo -ldl生成可执行文件CLoadSo

 

gdb步骤如下(请注意观察注释语句):

 

 

结果:成功进入到了so的fun1中

大概步骤:

1.启动gdb调试:gdb CLoadSo

2.打断点 gdb) : break 28

3.执行 gdb) : run

4.将动态库的符号读入gdb,为了你能找到变量和函数名 gdb)sharedlibrary first.so

5.s进入函数,l列出源代码,n单步执行,直到结束.

 

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值