GDB調試器提供了兩種不同的調試代理用于支持遠程調試,即gdbserver方式和stub(插樁)方式。
這兩種遠程調試方式是有區(qū)別的。gdbserver本身的體積很小,能夠在具有很少存儲容量的目標系統上獨立運行,因而非常適合于嵌入式環(huán)境;而stub
方式則需要通過鏈接器把調試代理和要調試的程序鏈接成一個可執(zhí)行的應用程序文件,如果程序運行在沒有操作系統的機器上,那么stub需要提供異常和中斷處
理序,以及串口驅動程序,如果程序運行在有操作系統的嵌入式平臺上,那么stub需要修改串口驅動程序和操作系統異常處理。顯然,對于在有嵌入式操作系統
支持下的開發(fā)而言,gdbserver比stub程序更容易使用。這里使用的是GDB+gdbserver的方式,建立遠程調試的環(huán)境。 gdbserver是一個可以獨立運行的控制程序,它可以運行在類UNIX操作系統上,當然,也可以運行在Linux的諸多變種。gdbserver允許遠程GDB調試器通過target remote命令與運行在目標板上的程序建立連接。 GDB和gdbserver之間可以通過串口線或TCP/IP網絡連接通信,采用的通信協議是標準的GDB遠程串行協議( Remote Serial Protocol RSP)。
使用gdbserver調試方式時,在目標機端需要一份要調試的程序的拷貝,這通常是通過ftp或NFS下載到目標機上的,宿主機端也需要這信一份拷貝。
由于gdbserver不處理程序符號表,所以如果有必要,可以用strip工具將要復制到目標機上的程序中的符號表去掉以節(jié)省空間。符號表是由運行在主
機端的GDB調試器處理的,不能將主機端的程序中的符號表去掉。
雖然大部分的Linux發(fā)行版都已經安裝了GDB,但是那都是基于PC的平臺的,我們要使用的是在ARM平臺上,所以要重新下載gdb的源碼,并修改以
適應自己的目標平臺。可以從http://www./software/gdb/download,獲得。這里使用的是GDB的最新的版本
7.1。首先將下載到的gdb-7.1.tar.bz2復制到/home/zfz/gdb目錄下。在控制臺下輸入下面的解包命令
#tar -jxvf gdb-7.1.tar.bz2
| 解包之后會生成gdb-7.1/目錄,所有的源碼都在這個目錄下,在gdb目錄下新建立一個目錄arm-linux-gdb,把生成的可執(zhí)行文件都放在這個目錄下, 在gdb-7.1目錄下,輸入下面的命令,配置GDB源碼:
./configure --target=arm-linux --prefix=/home/frank/gdb --program-prefix=arm-linux-
|
其中
--target=arm-linux選項,表示針對的目標平臺是運行l(wèi)inux內核的ARM體系結構的平臺,后面的選項--prefix=/home
/frank/gdb 則是指定編譯完成后的安裝目錄,最后一個選項--program-prefix=arm- linux-用來指定在編譯生成的二進制可執(zhí)行文件名之前加上前綴,這里加上的前綴是arm-linux-。這樣就可以和宿主機上的調試文件相區(qū)別。把源文件編譯成相應的目標文件,并連接成可執(zhí)行的二進制文件 。然后,再執(zhí)行下面的命令,
執(zhí)行完該命令后,就會在我們剛才建立的arm-linux-gdb目錄下生成bin/,lib/,share/這幾個子目錄,其中在bin下有三個可執(zhí)行
文件分別為:arm-linux-gdb. arm-linux-run ,arm-linux-gdbui.arm-linux-gdb,就是我們需要的調試器。 編譯完arm-linux-gdb之后,接下來就需要編譯在目標板上運行的gdbserver了,在gdb/gdb7.1/gdb下有一個gdbserver的子目錄,這個目錄包括了編譯gdbserver所需要的所有的東西。 首先,進行gdbserver目錄./configure --target=arm-linux --host=arm-linux
| 此時,如果要直接進行編譯的話,會出現錯誤,linux-arm-low.c:26:21:sys/reg.h: 沒有那個文件 或目錄
make:*****[linux-arm-low.0] Error 1
|
這里的sys/reg.h是指/usr/include/sys/reg.h,在該文件中定義的寄存器都是針對x86平臺的,對于運行
在ARM平臺上的gdbserver顯然是不對的,在configure后,將會生成一個config.h文件,在這個文件中定
義了相應的宏,在config.h中我們可以看到這樣一個C語言的宏定義,
|
#define HAVE_SYS_REG_H 1
在linux-arm-low.c文件中出錯的代碼行:
#ifdef HAVE_SYS_REG_H
#include <sys/reg.h>
#endif
| 這
里我們只需要把conifg.h文件中的#define HAVE_SYS_REG_H
1注釋掉就OK了。由于gdbserver是運行在ARM-linux平臺上的,因此需要使用交叉編譯器arm-linux-gcc,這可以通過給
make加上CC參數來實現這里我使用的是默認的,你也可以使用一個絕對的路徑來指定一個arm-linux-gcc.
所有的工作都已經完成了,只要把生成的gdbserver下載到目標板上,或者是通過NFS掛載到目標板上就可能進行遠程的調試了,如果就是足夠幸運的
話,編譯中沒有出現什么錯誤的話,這樣完全可以了,不過在我的系統上卻不是那么幸運。我一直使用的是友善之臂的arm-linux-gcc-4.3.2交
叉編譯器,這個版本的編譯器中,已經自帶了arm-linux-gdb. 在終端中輸入arm-linux-gdb -v 可以看到下面的信息GNU gdb (Sourcery G++ Lite 2008q3-72) 6.8.50.20080821-cvs
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http:///licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-none-linux-gnueabi".
For bug reporting instructions, please see:
<https:
|
這里可以看出arm-linux-gcc-4.3.2自帶的arm-linux-gdb的版本是6.8版的,而我們一直編譯的是7.1版本的。一開始我并
沒有注意arm-linux-gdb的版本信息,不過在使用過程中,我把用生成的gdbserver的7.1版本用NFS加載到目標板上,而在宿主機上用
的arm-linux-gcc 6.8版本,一直出現下面的錯誤: 先在目標機上運行下面的gdbserver,注意這里的IP地址是宿主機上的IP地址。[root@Frankzfz]$gdbserver 10.27.10.48:9000 ./test_seg_fault
Process ./test_seg_fault created; pid = 760
Listening on port 9000
Remote debugging from host 10.27.10.48
| 然后在宿主機上運行arm-linux-gdb/bin$ arm-linux-gdb
GNU gdb (Sourcery G++ Lite 2008q3-72) 6.8.50.20080821-cvs
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http:///licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-none-linux-gnueabi".
For bug reporting instructions, please see:
<https://support.codesourcery.com/GNUToolchain/>.
(gdb) target remote 10.27.10.23:9000
Remote debugging using 10.27.10.23:9000
Malformed packet(b) (missing colon): ore:0;
Packet: 'T050b:00000000;0d:804ebdbe;0f:b0070040;thread:2f8;core:0;'
(gdb) symbol-file test_seg_fault
Reading symbols from /home/zfz/kernel/fs/arm-linux-gdb/bin/test_seg_fault...done.
(gdb) break main
Breakpoint 1 at 0x84a8: file test_seg_fault.c, line 7.
(gdb) info main
Undefined info command: "main". Try "help info".
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x000084a8 in main at test_seg_fault.c:7
(gdb) c
The program is not being run.
(gdb)
| 輸入c命令時說是程序沒有運行,可是程序已經在目標板上運行了,不用輸入run命令,當輸入 target remote 10.27.10.23:9000結束后,在minicom中可以看到目標板上的輸出信息有了變化.[root@Frankzfz]$gdbserver 10.27.10.48:9000 ./test_seg_fault
Process ./test_seg_fault created; pid = 760
Listening on port 9000
Remote debugging from host 10.27.10.48
readchar: Got EOF
Remote side has terminated connection. GDBserver will reopen the connection.
Listening on port 9000
| 在這里搗鼓了一整天沒有弄明白錯誤在那里,看到了arm-linux-gdb 和gdbserver的版本不匹配,所以就變換arm-linux-gdb,這里要把arm-linux-gdb加入到.profile文件中,或者environment文件中,PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/j
dk1.6.0_17/bin:/home/zfz/kernel/fs/arm-linux-gdb/bin:/home/zfz/linux-
tool/usr/local/arm/4.3.2/bin"
|
當時一直在,arm-linux-gdb/bin目錄下執(zhí)行,其實執(zhí)行的也都是arm-linux-gcc-4.3.2中的arm-linux-gdb,
如果這樣你看到的版本信息還是6.8版本的話,也可以直接在arm-linux-gcc-4.3.2中把arm-linux-gdb文件刪除掉。 這樣再一次查看arm-linux-gdb的信息。GNU gdb (GDB) 7.1
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http:///licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=arm-linux".
For bug reporting instructions, please see:
<http://www./software/gdb/bugs/>.
|
使用GDB進行調試,首先,我的宿主機的IP 10.27.10.48,開發(fā)板上的IP 10.27.10.23在開發(fā)板上運行gdbserver
10.27.10.48:9000 test,這里是通過NFS,把要調試的程序加載到目標版上面的。這樣就可從在宿主機上運行。
zfz@zfz:~/kernel/fs/arm-linux-gdb/bin$ ./arm-linux-gdb test
./arm-linux-gdb: Symbol `acs_map' has different size in shared object, consider re-linking
GNU gdb (GDB) 7.1
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http:///licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=arm-linux".
For bug reporting instructions, please see:
<http://www./software/gdb/bugs/>...
Reading symbols from /home/zfz/kernel/fs/arm-linux-gdb/bin/test...done.
(gdb) target remote 10.27.10.23:9000
Remote debugging using 10.27.10.23:9000
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
0x400007b0 in ?? ()
(gdb) l
Cannot access memory at address 0x0
1 #include <stdio.h>
2 int main( void )
3 {
4 int i=2;
5 int x, y;
6
7 x=(++i);
8 printf(" %d %d\n", i,x);
9 x+=(++i);
10 printf(" %d %d\n", i,x);
(gdb) l
11 x+=(++i);
12 printf(" %d %d\n", i,x);
13 i=2;
14 y=(i++)+(i++)+(i++);
15 printf(" %d %d\n", i,y);
16
17 return 0;
18 }
19
(gdb) break 9
Breakpoint 1 at 0x83b8: file test.c, line 9.
(gdb) c
Continuing.
Error while mapping shared library sections:
`/lib/libc.so.6': not in executable format: File format not recognized
Error while mapping shared library sections:
/lib/ld-linux.so.3: No such file or directory.
Breakpoint 1, main () at test.c:9
9 x+=(++i);
(gdb) step
10 printf(" %d %d\n", i,x);
(gdb) next
11 x+=(++i);
(gdb) next
12 printf(" %d %d\n", i,x);
(gdb) next
13 i=2;
(gdb) next
14 y=(i++)+(i++)+(i++);
(gdb) next
15 printf(" %d %d\n", i,y);
(gdb) next
17 return 0;
(gdb) next
18 }
(gdb) next
| 在目標板上的輸出:[root@Frankzfz]$gdbserver 10.27.10.48:9000 ./test
Process ./test created; pid = 746
Listening on port 9000
Remote debugging from host 10.27.10.48
3 3
4 7
5 12
5 6
|
補充:前面還有庫文件錯誤的問題,這里可以通過下面這樣的方法的來解決。需要說明的是,遠程調試,可能程序動態(tài)庫,我們可以這樣設置:
set solib-absolute-prefix /nfsroot/rootfs
set solib-search-path /nfsroot/rootfs/lib
|
調試找不到源代碼,如下設置: directory xfer-1.0.0/src/
|
下面是調試的情況: (gdb) set solib-absolute-prefix /home/kernel/fs/root_nfs
(gdb) set solib-search-path /home/kernel/fs/root_nfs/lib
(gdb) target remote 10.27.10.23:9000
Remote debugging using 10.27.10.23:9000
Reading symbols from /home/kernel/fs/root_nfs/lib/ld-linux.so.3...(no debugging symbols
found)...done.
Loaded symbols for /home/kernel/fs/root_nfs/lib/ld-linux.so.3
0x400007b0 in ?? () from /home/kernel/fs/root_nfs/lib/ld-linux.so.3
(gdb) l
3 {
4 int i=2;
5 int x, y;
6
7 x=(++i);
8 printf(" %d %d\n", i,x);
9 x+=(++i);
10 printf(" %d %d\n", i,x);
11 x+=(++i);
12 printf(" %d %d\n", i,x);
(gdb) l
13 i=2;
14 y=(i++)+(i++)+(i++);
15 printf(" %d %d\n", i,y);
16
17 return 0;
18 }
19
(gdb) b 8
Note: breakpoint 1 also set at pc 0x83a8.
Breakpoint 2 at 0x83a8: file test.c, line 8.
(gdb) c
Continuing.
Breakpoint 1, main () at test.c:8
8 printf(" %d %d\n", i,x);
(gdb) n
9 x+=(++i);
(gdb) b 12
Breakpoint 3 at 0x8400: file test.c, line 12.
(gdb) n
10 printf(" %d %d\n", i,x);
(gdb) n
11 x+=(++i);
(gdb) n
Breakpoint 3, main () at test.c:12
12 printf(" %d %d\n", i,x);
(gdb) n
13 i=2;
(gdb) n
14 y=(i++)+(i++)+(i++);
(gdb) n
15 printf(" %d %d\n", i,y);
(gdb) n
17 return 0;
(gdb) n
18 }
(gdb) n
0x4003b004 in __libc_start_main ()
from /home/kernel/fs/root_nfs/lib/libc.so.6
(gdb)
|
|