如何在 Linux 下調試動態鏈接庫


大家都知道在 Linux 可以用 gdb 來調試應用程序,當然前提是用 gcc 編譯程序時要加上

-g 參數。
我這篇文章里將討論一下用 gdb 來調試動態鏈接庫的問題。


  首先,假設我們准備這樣的一個動態鏈接庫:

QUOTE:
庫名稱是: ggg
動態鏈接庫文件名是: libggg.so
頭文件是: get.h
提供這樣兩個函數調用接口:
    int get ();
    int set (int a);

要生成這樣一個動態鏈接庫,我們首先編寫這樣一個頭文件:

[Copy to clipboard]
CODE:
/************關於本文檔********************************************
*filename: get.h
*purpose:  一個動態鏈接庫頭文件示例
*tided by: zhoulifa() 周立發 ()
Linux 愛好者 Linux 知識傳播者 SOHO 族 開發者 最擅長 C 語言
*date time: 2006-11-15 21:11:54
*Note: 任何人可以任意復制代碼並運用這些文檔,當然包括你的商業用途
* 但請遵循 GPL
*Hope:希望越來越多的人貢獻自己的力量,為科學技術發展出力
* 科技站在巨人的肩膀上進步更快!感謝有開源前輩的貢獻!
*感謝 提供原始代碼,

我在他的基礎上整理了此文
*********************************************************************/
int get ();
int set (int a);

然后准備這樣一個生成動態鏈接庫的源文件:

[Copy to clipboard]
CODE:
/************關於本文檔********************************************
*filename:  get.cpp
*purpose: 一個動態鏈接庫源文件示例
*tided by: zhoulifa() 周立發 ()
Linux 愛好者 Linux 知識傳播者 SOHO 族 開發者 最擅長 C 語言
*date time:2006-11-15 21:11:54
*Note: 任何人可以任意復制代碼並運用這些文檔,當然包括你的商業用途
* 但請遵循 GPL
*Hope:希望越來越多的人貢獻自己的力量,為科學技術發展出力
* 科技站在巨人的肩膀上進步更快!感謝有開源前輩的貢獻!
*感謝 提供原始代碼,

我在他的基礎上整理了此文
*********************************************************************/
#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++ 編譯器來生成動態鏈接庫,編譯命令如下:

QUOTE:
g++ get.cpp -shared -g -DDEBUG -o

libggg.so


這樣我們就准備好了動態鏈接庫了,下面我們編寫一個應用程序來調用此動態鏈接庫,源代碼如下:

[Copy to clipboard]
CODE:
/************關於本文檔********************************************
*filename: pk.cpp
*purpose: 一個調用動態鏈接庫的示例
*tided by: zhoulifa() 周立發 ()
Linux 愛好者 Linux 知識傳播者 SOHO 族 開發者 最擅長 C 語言
*date time:2006-11-15 21:11:54
*Note: 任何人可以任意復制代碼並運用這些文檔,當然包括你的商業用途
* 但請遵循 GPL
*Hope:希望越來越多的人貢獻自己的力量,為科學技術發展出力
* 科技站在巨人的肩膀上進步更快!感謝有開源前輩的貢獻!
*感謝 提供原始代碼,

我在他的基礎上整理了此文
*********************************************************************/
#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 之類的,就用下面這條命令:

QUOTE:
g++ pk.cpp -o app -Wall -g -lggg

否則就用下面這條命令:

QUOTE:
g++ pk.cpp -o app -Wall -g -lggg -L`pwd`

下面我們就開始調試上面命令生成的 app 程序吧。如果已經把上面生成的 libggg.so 放到了庫文件搜索路徑指定的文件目錄,比如 /lib或 /usr/lib 之類的,調試就順利完成,如下

QUOTE:
./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 theconditions.


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里面,調試就會失敗,過程如下:

QUOTE:
# 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 arewelcome to change it and/or distribute

copies of it under certain conditions.


Type "show copying" to see theconditions.
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
#

本次實驗的環境是:
CPU:AMD Athlon(tm) 64 Processor 3000+
內存:512M
OS:Ubuntu GNU/Linux 6.06 dapper LTS
gcc:gcc 版本 4.0.3 (Ubuntu 4.0.3-1ubuntu5)

 

break(b) 行號:在某一行設置斷點
break 函數名:在某個函數開頭設置斷點
break...if...:設置條件斷點
continue(或c):從當前位置開始連續而非單步執行程序
delete breakpoints:刪除所有斷點
delete breakpoints n:刪除序號為n的斷點
disable breakpoints:禁用斷點
enable breakpoints:啟用斷點
info(或i) breakpoints:參看當前設置了哪些斷點
run(或r):從開始連續而非單步執行程序
display 變量名:跟蹤查看一個變量,每次停下來都顯示它的值
undisplay:取消對先前設置的那些變量的跟蹤


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM