1、gdb+gdbserver整體介紹
遠程調試環境由宿主機GDB和目標機調試stub共同構成,二者經過串口或TCP鏈接。使用 GDB標準程串行協議協同工做,實現對目標機上的系統內核和上層應用的監控和調試功能。調試stub是嵌入式系統中的一段代碼,做爲宿主機GDB和目標機 調試程序間的一個媒介而存在。 html
就目前而言,嵌入式Linux系統中,主要有三種遠程調試方法,分別適用於不一樣場合的調試工做:用ROM Monitor調試目標機程序、用KGDB調試系統內核和用gdbserver調試用戶空間程序。這三種調試方法的區別主要在於,目標機遠程調試stub 的存在形式的不一樣,而其設計思路和實現方法則是大體相同的。 linux
而咱們最經常使用的是調試應用程序。就是採用gdb+gdbserver的方式進行調試。在不少狀況下,用戶須要對一個應用程序進行反覆調試,特別是復 雜的程序。採用GDB方法調試,因爲嵌入式系統資源有限性,通常不能直接在目標系統上進行調試,一般採用gdb+gdbserver的方式進行調試。 c++
2、源代碼下載
嵌入式Linux的GDB調試環境由Host和Target兩部分組成,Host端使用 arm-linux-gdb,Target Board端使用gdbserver。這樣,應用程序在嵌入式目標系統上運行,而gdb調試在Host端,因此要採用遠程調試(remote)的方法。進 行GDB調試,目標系統必須包括gdbserver程序(在主機上正對硬件平臺編譯成功後下載到目標機上),宿主機也必須安裝GDB 程序。通常Linux發行版中都有一個能夠運行的GDB,但開發人員不能直接使用該發行版中的GDB來作遠程調試,而要獲取GDB的源代碼包,針對arm 平臺做一個簡單配置,從新編譯獲得相應GDB。GDB的源代碼包能夠從 bash
http://www.gnu.org/software/gdb/download/ app
http://ftp.gnu.org/gnu/gdb/ 211.95.105.202:3128能夠上去的,全部的版本都有啊 ide
http: //ftp.cs.pu.edu.tw/linux/sourceware/gdb/releases/下載 函數
外網的ftp我常常上不去,國內常見的開源社區的下載頻道一般都有下載的http://download.chinaunix.net/download/0004000/3482.shtml,最新版本爲gdb-6.5.tar.bz2。下載到某個目錄,筆者下載到/opt/。 但要注意,gdb的版本須要和croostool 相匹配。 this
3、配置編譯及安裝下載
下載完後,進入/opt/目錄,配置編譯步驟以下: es5
#tar jxvf gdb-6.5-tar-bz2
#cd gdb-6.5
#./configure --target=arm-linux --prefix=/usr/local/arm-gdb –v
(--target配置gdb的目標平臺,--prefix配置安裝路徑,固然其餘路徑也能夠, .跟下面配置一致便可,須在環境變量中聲明,啓動arm-linux-gdb須要,可更改/etc/profile或~/.bash_profile或~ /.bashrc,添加export PATH=$PATH:/usr/local/arm-gdb/bin,這樣能夠找到路徑)
#make
這裏的時候
configure: error: no termcap library found
make[1]: *** [configure-gdb] 錯誤 1
解決方法:sudo apt-get install libncurses5-dev
安裝完後,在make就OK了!
#make install
(生成arm-linux-gdb,並存入/usr/local/arm-gdb /bin/,查詢確認下)
也能夠啓動arm-linux-gdb,若成功,則證實安裝無誤
進入gdb/gdbserver目錄:
[root@dding gdbserver]# pwd
/opt/gdb-6.5/gdb/gdbserver
[root@dding gdbserver]# 必須在gdbserver目錄下運行配置命令,此時才能用相對路徑
#./configure --target=arm-linux --host=arm-linux
(--target=arm-linux表示目標平臺,--host表示主機端運行的是arm-linux-gdb,不須要配置—prefix,由於gdbserver不在主機端安裝運行)
#make CC=/usr/local/arm/2.95.3/bin/arm-linux-gcc
(這一步要指定你本身的arm-linux-gcc的絕對位置,我試過相對的不行,提示make: arm-linux-gcc: Command not found,可好多人都用的相對路徑,即直接賦值arm-linux-gcc,可採起make時傳遞參數,也能夠直接修改gdbserver目錄下的 Makefile文件中的環境變量CC)
沒有錯誤的話就在gdbserver目錄下生成gdbserver可執行文件,注意此時要更改其屬性,不然可能會出現沒法訪問的情 況,chmod 777 gdbserver將其更改成任何人均可以讀寫執行;使用arm-linux-strip命令處理一下gdbserver,將多餘的符號信息刪除,可以讓 elf文件更精簡,一般在應用程序的最後發佈時使用;而後把它燒寫到flash的根文件系統分區的/usr/bin(在此目錄下,系統能夠自動找到應用程 序,不然必須到gdbserver所在目錄下運行之),或經過nfs mount的方式均可以。只要保證gdbserver能在開發板上運行就行。
4、gdb+gdbserver nfs調試流程
下面就能夠用gdb+gdbserver調試咱們開發板上的程序了。在目標板上運行 gdbserver,其實就是在宿主機的minicom下。我是在minicom下#mount 192.168.2.100:/ /tmp後作的(這裏參數-o nolock能夠不加,不加這一步執行得反而更快些),hello和gdbserver都是位於Linux根目錄下,把主機根目錄掛在到開發板的/tmp 目錄下。
要進行gdb調試,首先要在目標系統上啓動gdbserver服務。在gdbserver所在目錄下輸入命令:
(minicom下)
#cd /tmp
#./gdbserver 192.168.2.100:2345 hello
192.168.2.100爲宿主機IP,在目標系統的2345端口(你也能夠設其餘可用的值,固然必須跟主機的gdb一致)開啓了一個調試進程,hello爲要調試的程序(必須-g加入調試信息)。
出現提示:
Process /tmp/hello created: pid=80
Listening on port 2345
(另外一個終端下)
#cd /
#export PATH=$PATH:/usr/local/arm-gdb/bin
#arm-linux-gdb hello
最後一行顯示:This GDB was configured as 「--host=i686-pc-linux-gnu,--target=arm-linux」...,若是不一致說明arm-linux-gdb有問題
說明此gdb在X86的Host上運行,可是調試目標是ARM代碼。
(gdb) target remote 192.168.2.223:2345
(192.168.2.223爲開發板IP)
出現提示:
Remote debugging using 192.168.2.223:2345
[New thread 80]
[Switching to thread 80]
0x40002a90 in ??()
同時在minicom下提示:
Remote debugging from host 192.168.2.100
(gdb)
注意:你的端口號必須與gdbserver開啓的端口號一致,這樣才能進行通訊。創建連接後,就能夠進行調試了。調試在Host端,跟gdb調試方 法相同。注意的是要用「c」來執行命令,不能用「r」。由於程序已經在Target Board上面由gdbserver啓動了。結果輸出是在Target Board端,用超級終端查看。鏈接成功,這時候就能夠輸入各類GDB命令如list、run、next、step、break等進行程序調試了。
以上針對經過nfs mount和tftp的方式,只能在主機上調試好後下載到開發板上運行,若是有錯誤要反覆這個過程,繁瑣不說,有些程序只能在開發板上調試。因此筆者採用了gdbserver的遠程調試方式。但願對你們調試程序有用!
5、如何利用串口調試
若是你用串口1調試hello的話,你就要如今板子上運行命令:
gdbserver hello /dev/ttyS0 (詳情能夠參考gdbserver目錄下的readme文件)
這時gdbserver就在等待gdb的應答信號了。
而後在pc機上運行命令:
xxx-linux-gdb hello
在xxx-linux-gdb裏敲入入下命令:
set remotedevice /dev/ttyS0(這裏設置串口1)
set remote baud 9600 (這裏設置串口波特率)
set debug remote 1(可選)
target remote /dev/ttyS0
操做到這兒,gdb就應該和gdbserver聯繫上了。
6、實戰調試
1.編輯文件
# vi gdbtest.c
1 #include <stdio.h>
2
3 int
4 func(int n){
5 int sum=0, i;
6 for (i=0; i<n; i++){
7 sum += i;
8 }
9 return sum;
10 }
11
12 int
13 main(void)
14 {
15 int i;
16 long result = 0;
17 for (i=0; i<=100; i++){
18 result += i;
19 }
20
21 printf("result[1-100] = %d /n", result);
22 printf("resutl[1-225] = %d /n", func(255));
23
24 return 0;
25 }
# arm-linux-gcc -g gdbtest.c -o gdbtest // 交叉編譯
2.下載文件到目標板: gdbtest和gdbserver
假設 host pc ip:192.168.1.45
board ip:192.168.1.180
將文件拷貝到目標板上:
先將gdbtest和gdbserver兩個文件拷貝到主機的/tftpboot目錄下,此時系統主機和目標機都必須可以支持nfs
在目標板的Linux中運行:
#mount 192.168.1.108:/tftpboot /mnt/nfs
#cd /mnt/nfs
#ls
看是否有gdbtest和gdbserver兩個文件。
3.運行調試
client board:
#./gdbserver 192.168.1.45:1234 gdbtest // 目標板上運行gdbtest 監聽端口1234
[root@AT91RM9200DK arm]$./gdbserver 192.168.0.12:2345 mainparacarm
./gdbserver: error in loading shared libraries: libthread_db.so.1: cannot open [root@AT91RM9200DK arm]$
host pc:
#cd /usr/local/arm-gdb/bin/ 以便可以運行arm-linux-gdb,可是無此必要,可在環境變量中設置此路徑便可。
#copy gdbtest /usr/local/arm-gdb/bin/ // 將前面編譯的文件gdbtest拷貝到此目錄
#./arm-linux-gdb gdbtest
(gdb)target remote 192.168.1.180:1234 // 鏈接到開發板 成功後就能夠
進行調試
(gdb)list or l
(gdb)break func
(gdb)break 22
(gdb)info br
(gdb)continue or c // 這裏不能用 run
(gdb)next or n
(gdb)print or p result
(gdb) finish // 跳出func函數
(gdb) next
(gdb) quit
創建鏈接後進行gdb遠程調試和gdb本地調試方法相同
7、 linux下安裝gdbserver問題
toolchain version: gdb的版本可能和交叉編譯器有很大的關係
gcc-3.3.2
glibc-2.2.5
binutils-2.15 此爲croostool 3.3.2
安裝步驟:
下載解壓gdb-6.6
#cd gdb-6.6
#./configure --target=arm-linux --prefix=/usr/local/arm-gdb –v
#make & make install
OK,而後:
#export PATH=$PATH:/usr/local/arm-gdb
進入gdbserver目錄:
#./configure --target=arm-linux --host=arm-linux
#make CC=/usr/local/armv5l/3.3.2/bin/armv5l-linux-gcc
出錯:
/usr/local/armv5l/3.3.2/bin/armv5l-linux-gcc -c -Wall -g -O2 -I. -I. -I./../regformats -I./http://www.cnblogs.com/include -Ihttp://www.cnblogs.com/bfd -I./http://www.cnblogs.com/bfd linux-arm-low.c
linux-arm-low.c:35:21: sys/reg.h: 沒有那個文件或目錄
make: *** [linux-arm-low.o] 錯誤 1
而後把/usr/include/sys/reg.h copy到/usr/local/armv5l-2.6.x/3.3.2/armv5l-linux/include/sys/reg.h,即將該文件拷貝到交叉編譯器的include目錄下,再make,顯示錯誤:
/usr/local/armv5l/3.3.2/bin/armv5l-linux-gcc -c -Wall -g -O2 -I. -I. -I./../regformats -I./http://www.cnblogs.com/include -Ihttp://www.cnblogs.com/bfd -I./http://www.cnblogs.com/bfd thread-db.c
thread-db.c: In function `thread_db_err_str':
thread-db.c:95: error: `TD_VERSION' undeclared (first use in this function)
thread-db.c:95: error: (Each undeclared identifier is reported only once
thread-db.c:95: error: for each function it appears in.)
thread-db.c: In function `thread_db_get_tls_address':
thread-db.c:336: warning: implicit declaration of function `td_thr_tls_get_addr'
thread-db.c:336: warning: cast to pointer from integer of different size
thread-db.c:340: warning: cast from pointer to integer of different size
make: *** [thread-db.o] 錯誤 1
本想繼續fix error,可是感受不太對,請問各位,是什麼緣由呢?
是否是CC的target寫錯了?應該是arm-linux仍是armv5l-linux?
1.
make: *** [linux-arm-low.o] Error 1
[root@dding gdbserver]#
[root@dding gdbserver]# gedit config.h
/* Define to 1 if you have the <sys/reg.h> header file. */
/*define HAVE_SYS_REG_H 1 */
/*have no <sys/reg.h> header file. so undefine 20070402 dding */
2.
thread-db.c: In function `thread_db_err_str': gdb6.5
thread-db.c:95: `TD_VERSION' undeclared (first use in this function)
[root@dding gdbserver]# gedit config.h
94 #ifdef HAVE_TD_VERSION
95 case TD_VERSION:
96 return "version mismatch between libthread_db and libpthread";
97 #endif
/* Define if TD_VERSION is available. */
/*#define HAVE_TD_VERSION 1 */
/*have no TD_VERSION. so undefine 20070402 dding */
gdb6.1 沒有此問題
3.
[root@AT91RM9200DK arm]$./gdbserver 192.168.0.12:2345 mainparacarm gdb6.5
./gdbserver: error in loading shared libraries: libthread_db.so.1: cannot open
[root@AT91RM9200DK arm]$./gdbserver 192.168.0.14:2345 mainparacarm gdb6.1
./gdbserver: error in loading shared libraries: libthread_db.so.1: cannot open shared object file: No such file or directory
我已經加了libthread_db.so.1共享庫爲何還打不開呢????共享庫和cpu類型有關嗎?
gdbserver: error while loading shared libraries: libthread_db.so.1: cannot open
shared object file: No such file or director
****編譯GDB的時候搞成靜態的就行了.我想編譯選項裏應該有. 要不你就在Makefile里加上CFLAGS += -static
LDFLAGS += -static
這兩個的其中一個應該就能夠了,不過仍是兩個都加上吧.
***/lib there is no libthread_db.so.1 Can i use nfs to copy libthread_db.so.1 to /lib? But now i cannot find this file, and is there any for cross 3.3.2?
libpthread-0.8.so
libpthread.so libpthread.so.0 libresolv-2.1.3.so
libresolv.so.2 libstdc++.a.2.10.0 libtermcap.so.2
[root@AT91RM9200DK arm]$cp libthread_db-1.0.so libthread_db.so.1
[root@AT91RM9200DK arm]$cp libthread_db.so.1 /lib/
[root@AT91RM9200DK arm]$./gdbserver 192.168.0.12:2345 mainparacarm
./gdbserver: /lib/libc.so.6: version `GLIBC_2.2' not found (required by /lib/li)
難道目前的gdb 6.5 版本過高,須要內核版本和交叉編譯器與之匹配?實在不行,就試試低版本的gdb