1. 程式人生 > >gdb如何除錯動態連結庫問題

gdb如何除錯動態連結庫問題

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將動態庫的原始碼也加入搜尋路徑。